diff --git a/docs/features/agent-browser-pip/plan.md b/docs/features/agent-browser-pip/plan.md
new file mode 100644
index 0000000000..571039204d
--- /dev/null
+++ b/docs/features/agent-browser-pip/plan.md
@@ -0,0 +1,421 @@
+# Agent Browser Surfaces and Picture-in-Picture Implementation Plan
+
+## Status
+
+The read-only mirror revision is implemented. The workspace/tab and Fit-desktop sections below
+remain future architecture work if visible multi-tab automation becomes necessary. Packaged
+Windows and Linux validation remains open.
+
+## Delivery Strategy
+
+Implement lifecycle identity and the single-parent placement controller before rendering PiP or
+adaptive page modes. A floating UI built on the current one-page/session model would encode the
+wrong ownership and would race the existing panel attach/detach logic.
+
+```text
+LoopRun.runId
+ |
+ v
+Tool execution context -> YoBrowserToolHandler
+ | |
+ | begin/end run | touches Agent tab
+ v v
+Browser workspace ------> placement controller
+ | | |
+ v v v
+ panel PiP detached
+```
+
+## Architecture Changes
+
+### 1. Propagate the Agent run identity
+
+Extend the internal `ToolCallOptions`/execution context with `runId` and pass it from each
+`LoopRun` through the tool batch/deferred tool paths, `ToolService`, `AgentToolManager`, and
+`YoBrowserToolHandler`.
+
+Add an explicit browser lifecycle port with idempotent methods equivalent to:
+
+```ts
+beginAgentBrowserActivity(sessionId, runId, toolCallId)
+finishAgentRun(sessionId, runId, outcome)
+```
+
+The first method marks/touches the Agent tab immediately before a browser command. The second is
+called from the central terminal path for completed, failed, aborted, and superseded runs. It must
+also run during session teardown.
+
+Do not subscribe to coarse renderer session status as a substitute. The runtime already owns the
+exact identity and terminal boundary.
+
+### 2. Migrate one-page state to a browser workspace
+
+Refactor `YoBrowserPresenter` from `Map` to a workspace that owns:
+
+- a tab map and order;
+- selected panel tab ID;
+- primary Agent tab ID;
+- active Agent run ID and last touched Agent tab ID;
+- current host window/session activation state;
+- panel and conversation bounds;
+- Browser-surface visibility;
+- PiP container/chrome state and current position;
+- dismissed PiP run ID;
+- a serialized placement operation queue.
+
+Keep `BrowserTab` as the page/CDP abstraction. Add owner/run/placement metadata around it rather
+than teaching it UI policy.
+
+Preserve existing callers with an internal compatibility step: session-level navigation methods
+resolve the relevant user or Agent active tab, while new typed tab methods are added for panel UI.
+Remove the compatibility layer after all call sites and tests migrate; do not maintain duplicate
+long-term APIs.
+
+### 3. Create the single placement controller
+
+Add one main-process function that computes desired placement from workspace state and performs all
+native parent changes. No renderer component may call low-level attach/detach independently after
+migration.
+
+Responsibilities:
+
+1. Reject stale layout/activation versions.
+2. Evaluate the eligibility predicate.
+3. Select the latest current-run Agent tab for PiP.
+4. Detach its page from the old parent.
+5. Attach it to the panel root or PiP container, or leave it detached.
+6. Set the page and chrome bounds.
+7. Move/rebound the activity overlay.
+8. Publish final placement/status.
+
+Use a per-workspace promise queue or equivalent narrow serialization. Avoid a general state-machine
+library.
+
+### 4. Build the read-only mirror pipeline
+
+Create one focusless render-host `BaseWindow` lazily for each active Agent page that needs
+background rendering. Reparent the existing page `WebContentsView` into it at 1280 x 800. The host
+must be transparent, offscreen, non-focusable, excluded from taskbar/Mission Control, and destroyed
+after the page returns to panel or no longer needs background rendering.
+
+Use `webContents.capturePage` because the Electron 40.10.5 macOS feasibility spike showed that
+`beginFrameSubscription` produced no frames for this WebContentsView while capture succeeded from a
+technically visible transparent host. Limit capture to one in-flight request, resize in main to the
+PiP output size, encode in memory, and publish a typed binary frame event. Never write frames to
+disk.
+
+The existing Vue PiP component owns a Canvas, read-only activity halo, title, and controls. Decode a
+new frame completely before drawing it so the previous Canvas pixels remain visible during capture,
+handoff, and loading. The remote page never receives PiP input.
+
+### 5. Centralize renderer layout reporting
+
+Move browser placement facts out of the current panel-only attach/detach watcher. A renderer
+controller near `ChatTabView.vue` reports:
+
+- active session ID and sender webContents identity;
+- current conversation content rectangle;
+- panel rectangle;
+- side-panel open state and active surface;
+- monotonically increasing layout version.
+
+Use VueUse `useResizeObserver` and `useEventListener` for mechanical observation. Keep the existing
+stable-rectangle wait for panel transitions, but make it a layout readiness signal rather than
+direct native attachment ownership.
+
+Validate every report in main against the sender's BrowserWindow and current activated session.
+
+### 6. Add panel tabs
+
+Migrate `YoBrowserStatus` from a single `page` to `tabs`, `activeTabId`, and placement data. Add
+typed operations to create/select/close tabs and navigate the selected user tab.
+
+Refactor `BrowserPanel.vue` into:
+
+- a compact tab strip using existing shadcn-vue Button/Tooltip patterns;
+- navigation controls bound to the selected tab;
+- the native page placeholder/bounds container;
+- no direct destroy-on-session-switch policy.
+
+User link navigation explicitly creates/selects a user tab and may keep opening the Browser panel.
+Agent tools resolve the primary Agent tab. A popup inherits its opener's ownership.
+
+Retain inactive workspace pages after loop completion for inspection. Add no speculative persistent
+tab database in V1; state remains process-lifetime only. If memory becomes a measured problem, add a
+separate idle eviction policy after profiling.
+
+### 7. Make Browser chrome container-responsive
+
+Refactor the Browser panel's fixed toolbar into width-aware chrome owned by `BrowserPanel.vue` or a
+focused child component:
+
+- wide: full tab strip and navigation controls;
+- compact: scrollable tabs, icon controls, flexible address field, overflow menu;
+- narrow: active title/host, essential navigation, and overflow commands;
+- expanded: full controls with a restore-chat action.
+
+Prefer CSS/container queries and normal flex/grid layout. Keep one `ResizeObserver` at the surface
+owner only for native bounds/reporting; do not create breakpoint watchers per tab. Reuse shadcn-vue
+Button, Tooltip, DropdownMenu, and Tabs-compatible semantics where they fit.
+
+Generalize the existing Workspace fullscreen shell state into a narrow side-panel surface mode that
+can be `normal` or `expanded` for either Workspace or Browser. Keep this local to the
+`ChatSidePanel`/route shell rather than adding global persisted state.
+
+Fix target-session compatibility by deriving the user-agent Chromium version from the runtime and
+keeping desktop semantics at every surface width.
+
+### 8. Add page presentation policy and feasibility proof
+
+Add per-tab `presentationMode: 'responsive' | 'fit-desktop'` to main-process workspace state.
+Responsive mode uses real content bounds and 100% zoom.
+
+Before implementing Fit desktop, build a throwaway proof comparing:
+
+- `webContents.enableDeviceEmulation` with `viewSize` and `scale`;
+- `webContents.setZoomFactor`/zoom level with its documented same-origin propagation.
+
+Test a fixture matrix containing responsive layouts, fixed 1024/1280 px layouts, sticky/fixed
+elements, iframes, canvas, editors, forms, context menus, and long pages. Verify renderer mouse/wheel
+input, CDP input, screenshot dimensions, DOM coordinates, selection, navigation, panel/PiP movement,
+and reset behavior.
+
+Select no fit API until the proof produces one coordinate model for both the user and Agent. If
+neither path is reliable, ship Responsive plus Expand and defer Fit desktop.
+
+### 9. Implement PiP commands
+
+#### Dismiss
+
+Validate that the command's workspace/tab/run still matches, set `dismissedPipRunId`, and recompute.
+Do not navigate, close, or interrupt tools.
+
+#### Open in panel
+
+Publish a renderer intent to open/activate Browser and select the Agent tab. Keep PiP visible until
+the renderer returns stable visible panel bounds, then reparent atomically. If readiness times out,
+leave PiP in place.
+
+#### Drag
+
+Use pointer capture on the entire PiP surface except buttons. Treat movement beyond a small
+threshold as drag; otherwise toggle the controls. Keep drag and clamping renderer-local because the
+PiP is now ordinary DOM inside the already-clipped conversation region. Avoid writing settings in
+V1.
+
+### 10. Integrate foreground/session lifecycle
+
+Combine existing BrowserWindow focus/show/hide/resize/close listeners with typed session activation
+events. Also handle minimize/restore explicitly.
+
+On deactivation or loss of foreground:
+
+- detach PiP synchronously;
+- hide activity overlay;
+- retain run/tab state.
+
+On valid reactivation, recompute from current facts. On terminal run, clear active run state and
+detach. On session destruction, destroy every page and the local chrome.
+
+### 11. Adapt the activity overlay
+
+First, make `YoBrowserOverlayWindow.updateBounds` accept the page-content bounds produced by the
+placement controller for both panel and PiP. Cross-platform test z-order, pointer pass-through,
+focus, movement, and rounded clipping.
+
+If it cannot reliably follow nested PiP, replace only the activity drawing surface with a trusted
+local child view in the PiP container. Do not replace it preemptively and do not create a second
+remote page.
+
+## Implementation Phases
+
+### Phase 0: interaction decisions
+
+- Confirm PiP close suppresses only the current run.
+- Confirm one retained Agent tab per session.
+- Confirm behavior while a run waits for permission/question.
+- Confirm Responsive + explicit Fit desktop + Expand as the adaptation model.
+- Obtain the reference screenshot or approve a visual baseline.
+
+Resolved requirements:
+
+- when any right-side panel surface is open, each new Agent browser action activates Browser and
+ selects the Agent tab;
+- if the user returns to Workspace, do not force another switch until the next Agent browser action;
+- use a compact activity strip when the conversation cannot fit a usable page card.
+
+Exit criterion: no unresolved product branch changes placement semantics.
+
+### Phase 1: lifecycle and workspace foundation
+
+- Thread `runId` through every immediate and deferred tool path.
+- Add explicit browser run finalization.
+- Introduce workspace/tab ownership and status contracts.
+- Add unit tests for loop/tab ownership and terminal cleanup.
+
+Exit criterion: tests can distinguish user and Agent tabs and hide current-run presentation exactly
+at terminal state without any PiP UI.
+
+### Phase 2: placement controller, panel tabs, and responsive chrome
+
+- Centralize layout reports and remove renderer-owned native attachment races.
+- Add the single-parent placement controller.
+- Add panel tab UI and migrate navigation commands.
+- Add container-responsive navigation/tab chrome and Browser expanded mode.
+- Replace the stale hard-coded Chromium user-agent version with runtime-derived data.
+- Preserve the same page across detach/panel transitions.
+
+Exit criterion: multiple tabs work in the Browser panel and every view satisfies the placement
+invariant under stress tests.
+
+### Phase 3: page-presentation proof and PiP surface
+
+- Prove input/screenshot coordinate fidelity for Fit desktop candidates.
+- Ship Fit desktop only if one candidate passes; otherwise keep Responsive + Expand.
+- Add trusted local chrome and in-window View container.
+- Add eligibility, show/hide, drag, dismiss, and open-panel handoff.
+- Add size/clamp behavior, accessibility, i18n, and activity indicator.
+- Add the compact activity-strip fallback for undersized chat regions.
+- Integrate the existing activity overlay.
+
+Exit criterion: the complete acceptance matrix passes in development builds on macOS, Windows, and
+Linux.
+
+### Phase 4: resilience and packaged QA
+
+- Test focus, minimize, multiple windows, session switches, route changes, panel animation, window
+ resize, display scale, tab/page/chrome crashes, and app shutdown.
+- Test simultaneous Agent tool completion and user PiP/panel commands.
+- Validate packaged local chrome routing and security settings.
+- Profile page retention and native view churn.
+
+Exit criterion: no cross-session frame leak, duplicate attachment, unexpected panel opening, or
+tool interruption is observed in packaged builds.
+
+## Expected File Areas
+
+Likely implementation areas, subject to final naming:
+
+- `src/main/agent/deepchat/**` for `runId` propagation and terminal lifecycle calls;
+- `src/main/tool/**` and `src/shared/types/tool.d.ts` for internal execution context;
+- `src/main/desktop/browser/YoBrowserPresenter.ts` for workspace orchestration;
+- focused new files under `src/main/desktop/browser/` for workspace placement and PiP chrome;
+- `src/shared/types/browser.ts`, browser routes, and browser events for tab/layout/placement state;
+- `src/preload/` for typed commands and a narrow PiP chrome bridge;
+- `src/renderer/src/components/sidepanel/BrowserPanel.vue` for tab UI;
+- `src/renderer/src/stores/ui/sidepanel.ts` and `ChatSidePanel.vue` for generalized expanded mode;
+- a renderer controller near `ChatTabView.vue` for layout facts;
+- `src/renderer/src/components/sidepanel/ChatSidePanel.vue` to remove unconditional Agent open;
+- `src/renderer/src/i18n/` for visible strings;
+- mirrored main and renderer tests.
+
+Avoid coupling this to `src/main/desktop/tab.ts`; standalone browser windows have a different
+window/tab lifecycle and do not need Agent PiP policy.
+
+## Contract Migration
+
+Current session-level routes can be migrated in two steps:
+
+1. Expand status with tabs while preserving derived `page` fields temporarily for existing
+ renderer callers.
+2. Move panel/client callers to explicit `tabId`, then remove the derived single-page fields and old
+ attach/detach routes in the same feature branch.
+
+The final architecture must not retain two attachment owners. Route schemas should reject stale tab
+IDs and return stable `tab_not_found`, `tab_closed`, `stale_layout`, or `placement_failed` results.
+
+## Test Strategy
+
+### Pure state tests
+
+Use a table-driven reducer/decision function for desired placement. Cover every boolean in the
+predicate and every transition in the spec, including dismiss-current-run versus next-run behavior.
+
+### Main-process tests
+
+- single parent across panel/PiP/detached transitions;
+- exact page WebContents identity across moves;
+- serialized races between bounds, focus, loop finish, and tab close;
+- stale sender/layout rejection;
+- multiple sessions and windows without cross-session display;
+- popup ownership inheritance;
+- Agent tab recreation after explicit close;
+- chrome/page/host destruction cleanup;
+- overlay bounds for both placements.
+
+Wrap native `View` operations behind a narrow testable adapter only where Electron objects cannot be
+constructed in Vitest. Do not build a general UI framework.
+
+### Runtime tests
+
+- browser tool receives the exact `LoopRun.runId`;
+- immediate and deferred tool execution use the same identity;
+- completed, failed, aborted, and superseded runs all finalize once;
+- a later run does not inherit dismissal or activity from the prior run;
+- permission/question pauses do not appear terminal.
+
+### Renderer tests
+
+- Agent open events do not open a closed panel;
+- user navigation still opens the panel intentionally;
+- panel tab selection, close, Agent marker, and navigation state;
+- layout versioning and stable bounds readiness;
+- open-panel handoff timeout keeps PiP rather than losing the page;
+- all visible controls have i18n labels and keyboard focus;
+- container-width breakpoints preserve the address bar and all commands at minimum panel width;
+- expanded/restore focus behavior and page identity;
+
+### Packaged cross-platform tests
+
+- click/focus/input routing between chat, PiP chrome, and remote page;
+- responsive, fit-desktop, and expanded rendering across representative site fixtures;
+- CDP input and screenshot coordinates at every approved presentation scale;
+- drag and clamping at multiple DPI/display scales;
+- z-order during panel animation and other overlays;
+- focus/blur, minimize/restore, hide/show, and full-screen behavior;
+- multiple app windows with different active sessions;
+- no PiP outside chat bounds and no flash from an inactive session.
+
+## Performance and Retention
+
+- One retained Agent page per active session is the initial memory budget.
+- PiP chrome is lazy and destroyed with its host/workspace.
+- Reparent and bound updates do not recreate CDP sessions or reload pages.
+- Drag updates are coalesced to one per animation frame.
+- Layout reports use equality checks and versions to avoid redundant native calls.
+- Browser chrome uses CSS/container layout rather than reactive resize fan-out.
+- Presentation scaling is applied only after stable bounds, never on every resize sample.
+- Measure retained page memory before adding an eviction abstraction. If needed, prefer a simple
+ idle timeout tied to session state over a general cache.
+
+## Rejected Approaches
+
+- **Transparent child BrowserWindow as the user-facing PiP**: platform-dependent movement/focus and
+ poor in-chat clipping.
+- **Live native WebContentsView inside PiP**: cannot be made reliably read-only and creates focus,
+ z-order, and renderer blur/attach feedback loops.
+- **Offscreen shared texture**: requires a native graphics module and complicates moving the same
+ WebContents back into the visible panel; bounded capture is sufficient for a low-frame-rate
+ preview.
+- **Second WebContentsView pointing at the same URL**: duplicates navigation, page state, CDP, and
+ potentially side effects.
+- **Inject controls into the remote page**: unsafe, spoofable, and breaks arbitrary sites.
+- **Renderer CSS iframe/webview**: changes the security model and cannot adopt the existing page
+ WebContents.
+- **Use session `working` status as loop identity**: cannot distinguish runs or terminal races.
+- **Always scale narrow pages automatically**: horizontal overflow is not a reliable signal of site
+ intent and silent scaling can break readability and Agent coordinates.
+- **Use only `setZoomFactor` for per-tab fit**: Chromium zoom is same-origin and may propagate beyond
+ the intended tab.
+- **Switch to a mobile user-agent in narrow surfaces**: changes site behavior and session/device
+ assumptions instead of solving layout.
+- **Create one tab per Agent URL load**: unbounded tab growth without a user need.
+- **Persist full browser workspace/PiP geometry in V1**: adds restore/migration work before the
+ lifecycle is proven.
+
+## Complexity Budget
+
+No new runtime dependency is expected. Use Electron View/WebContentsView/webContents APIs, existing
+VueUse helpers, shadcn-vue controls, typed routes/events, and a small placement decision function.
+The feature needs one workspace state owner, one surface layout owner, and one placement owner;
+additional window managers or state-machine libraries would make correctness harder, not easier.
diff --git a/docs/features/agent-browser-pip/spec.md b/docs/features/agent-browser-pip/spec.md
new file mode 100644
index 0000000000..601e6494e3
--- /dev/null
+++ b/docs/features/agent-browser-pip/spec.md
@@ -0,0 +1,641 @@
+# Agent Browser Surfaces and Picture-in-Picture Spec
+
+## Status
+
+V1 mirror revision implemented on 2026-07-17. The first implementation placed the live
+`WebContentsView` inside the PiP, which made the preview interactive and introduced a renderer
+focus/blur feedback loop. The revised contract keeps the Agent page at a fixed 1280 x 800 render
+size and shows a low-frame-rate, read-only Canvas mirror in PiP. A visible multi-tab strip and
+Fit-desktop emulation remain deferred. Packaged Windows and Linux validation remains open.
+
+The referenced screenshot was not available in the current task context, so the interaction and
+layout are specified here while exact visual styling remains provisional.
+
+## Problem
+
+Today, any YoBrowser `loadUrl` call publishes `browser.open.requested`, and
+`ChatSidePanel.vue` responds by opening and activating the right-side Browser panel. This lets a
+background Agent tool unexpectedly take over the user's layout.
+
+YoBrowser also has only one page per chat session. It cannot distinguish a user-opened page from an
+Agent automation page or expose multiple browser tabs in the panel.
+
+The current Browser panel is physically constrained to a default width of 520 px and a minimum of
+420 px. `BrowserPanel.vue` keeps all navigation controls in one fixed row, while the remote page
+receives the exact narrow native view bounds with no presentation-mode choice. Responsive sites may
+adapt, but desktop-oriented sites can become horizontally cramped or unusable.
+
+The target session also hard-codes a Chrome/142 user-agent string while the pinned Electron 40.10.5
+runtime embeds Chromium 144.0.7559.236. That mismatch is not the main cause of narrow layout, but it
+is a compatibility defect and must not become part of a new adaptive-surface design.
+
+The requested behavior is:
+
+- never open a closed right-side panel merely because an Agent uses YoBrowser;
+- show the Agent-operated page in the existing Browser panel when that surface is already visible;
+- otherwise show it as a draggable in-chat floating preview;
+- make the floating preview read-only while the Agent operates the same live page in a normal-size
+ background render host;
+- move the same live page between the background render host and panel without reload or state
+ loss;
+- never float user-opened browser pages;
+- hide the floating preview when its Agent loop ends, the chat is no longer active/foreground, the
+ page is closed, or the Browser panel becomes visible.
+- make the Browser panel chrome responsive at its current supported widths;
+- give desktop-oriented pages a deliberate wide/fit escape hatch instead of leaving them trapped in
+ an unusable narrow viewport.
+
+## Critical Architecture Correction
+
+The user-facing PiP is not another operating-system window and never contains the remote page's
+native View. Electron `View` does not expose a reliable view-level ignore-mouse-input contract, and
+native child views sit outside normal Vue DOM hit testing. The trusted chat renderer therefore owns
+the complete PiP surface and draws captured frames into a Canvas.
+
+The live Agent `WebContentsView` is temporarily reparented into a focusless render-host
+`BaseWindow`. The render host is technically visible so Chromium owns a valid display surface, but
+it is transparent, moved offscreen, excluded from taskbar/Mission Control, and never accepts input.
+Its page bounds remain 1280 x 800. Opening Browser reparents that exact View into the visible panel.
+
+```text
+focusless render-host BaseWindow
++-- Agent page WebContentsView at 1280 x 800
+ +-- capturePage -> resize/encode -> typed frame event
+
+host BrowserWindow.contentView
++-- chat renderer WebContentsView
+ +-- trusted PiP Canvas mirror and controls
++-- panel placement: the same Agent page WebContentsView when Browser is visible
+```
+
+There is still one page `WebContents`, one page `WebContentsView`, and one session. The mirror is
+only a transient compressed frame, never a second browser. Moving the page changes only its native
+parent and bounds. It does not navigate, clone cookies, recreate CDP, or copy page state.
+
+## Goals
+
+- Preserve the user's panel open/closed choice when an Agent opens a URL.
+- Add browser tabs so user and Agent pages have explicit identity and lifecycle.
+- Reuse one Agent automation tab per chat session in the first release.
+- Track which Agent loop owns the current automation activity by `runId`.
+- Put each page view in exactly one native placement: Browser panel, render host, or detached.
+- Show at most one PiP for the foreground chat window.
+- Keep PiP fully inside the active conversation region and let the user drag it.
+- Keep the background Agent viewport at 1280 x 800 while PiP scales only its visual mirror.
+- Keep responsive page rendering as the safe default and offer explicit desktop-fit and expanded
+ modes for pages that do not work well at narrow widths.
+- Let the user dismiss PiP for the current loop without closing or disrupting the automation tab.
+- Let the user open the Browser panel and transfer the same page into it.
+- Hide PiP deterministically on every loop/session/window/tab lifecycle edge.
+- Preserve the existing Agent activity visualization over whichever placement contains the page.
+
+## Non-Goals
+
+- Native video picture-in-picture or `documentPictureInPicture`.
+- A free-floating OS window outside the DeepChat window.
+- Multiple simultaneous PiP cards.
+- Floating pages created and navigated only by the user.
+- Persisting PiP position or size across application restarts in V1.
+- Guessing that every horizontally overflowing page should be silently scaled down.
+- Pretending to be a mobile browser or changing touch/user-agent semantics merely because the
+ surface is narrow.
+- Letting the renderer own or directly manipulate remote-page `webContents`.
+- Creating a new Agent tab for every `load_url` call.
+- A general browser-window/tab architecture shared with standalone DeepChat browser windows.
+- Closing the underlying Agent tab when the PiP close button is pressed.
+- Forwarding PiP pointer, wheel, keyboard, selection, or focus events to the remote page.
+- Full-frame-rate video streaming or a GPU shared-texture/native-module pipeline.
+
+## Current Repository Contract
+
+- `YoBrowserPresenter` owns `Map` with exactly one
+ `WebContentsView`, one `BrowserTab`, and one `YoBrowserOverlayWindow` per chat session.
+- `YoBrowserToolHandler` can identify the chat session but does not receive the active Agent
+ `runId`.
+- `BrowserPanel.vue` attaches the single view to bounds reported by the Browser panel and destroys
+ inactive-session pages once work stops.
+- `sidepanel.ts` clamps the panel to 420-960 px, defaults to 520 px, and caps it at 62% of the
+ renderer width.
+- `BrowserPanel.vue` uses one fixed navigation row and has no compact toolbar, expanded-browser
+ mode, or page-presentation mode.
+- `yoBrowserSession.ts` hard-codes Chrome/142 rather than deriving the user-agent version from the
+ bundled Chromium runtime.
+- `ChatSidePanel.vue` automatically calls `sidepanelStore.openBrowser()` for every
+ `browser.open.requested` event.
+- `useMarkdownLinkNavigation.ts` intentionally opens the Browser panel for user navigation.
+- `LoopRun` and the DeepChat runtime already own a stable `runId`; it is not currently threaded
+ through `ToolCallOptions` to YoBrowser.
+- `YoBrowserOverlayWindow` is a transparent transient activity effect, not a PiP surface.
+
+## Terminology
+
+- **Browser workspace**: all YoBrowser tabs for one chat session.
+- **User tab**: a page explicitly created from user UI. It is never PiP-eligible.
+- **Agent tab**: the session's automation page, created or reused by an Agent browser tool.
+- **Touched run**: the Agent `runId` that most recently operated an Agent tab.
+- **Browser surface visible**: the right-side panel is open and its Browser surface is the active
+ panel content.
+- **Native placement**: `panel`, `render-host`, or `detached`.
+- **Mirror state**: `capturing`, `rendering`, or `stopped`; only `capturing` publishes PiP frames.
+- **Presentation mode**: `responsive` or `fit-desktop` for how a page uses the available content
+ rectangle.
+- **Active session**: the chat route currently activated in the host renderer/webContents.
+- **Foreground host**: the containing DeepChat window is shown, not minimized, and focused.
+
+## Browser Tab Model
+
+The current `SessionBrowserState` becomes a per-session workspace:
+
+```ts
+type BrowserTabOwner = 'user' | 'agent'
+type BrowserPlacement = 'panel' | 'pip' | 'detached'
+
+type YoBrowserTabState = {
+ id: string
+ owner: BrowserTabOwner
+ page: BrowserPage
+ view: WebContentsView
+ placement: BrowserPlacement
+ lastAgentRunId: string | null
+ closed: boolean
+ createdAt: number
+ updatedAt: number
+}
+```
+
+The public status becomes a tab collection plus `activeTabId`. User commands act on the selected
+user-facing tab. Agent tools act on the dedicated Agent tab unless a future tool explicitly accepts
+a tab ID.
+
+V1 rules:
+
+- create at most one primary Agent tab per session;
+- reuse it across URL loads and across loops until the user explicitly closes it or the workspace
+ is destroyed;
+- set `lastAgentRunId` before executing every Agent browser tool, not only `load_url`;
+- pages opened by an Agent-owned popup inherit Agent ownership and the same touched run, but the
+ panel may list them as additional tabs;
+- never change a user tab to Agent ownership implicitly;
+- if a closed Agent tab is needed by a later browser tool, create a new Agent tab;
+- choose only one current Agent tab for PiP, preferring the page touched by the latest tool.
+
+## Responsive Surface Design
+
+There are two different adaptation problems and they must not be conflated:
+
+1. **Browser chrome adaptation** controls DeepChat-owned tabs, buttons, address bar, and PiP header.
+2. **Page presentation** controls how the untrusted website interprets and fills its native content
+ rectangle.
+
+### Browser chrome breakpoints
+
+Use container width, not the application viewport, because the Browser panel and PiP can have
+different widths in the same window.
+
+| Content width | DeepChat chrome behavior |
+| --- | --- |
+| `>= 640 px` | Full tab strip, back, forward, reload, address bar, presentation, and expand controls |
+| `480-639 px` | Scrollable compact tabs, icon navigation, flexible address bar, presentation/expand in overflow |
+| `< 480 px` | Active-tab title/host, back, reload, address bar, and one overflow menu; hide nonessential labels |
+
+The address bar remains the flexible element with `min-width: 0`. Tab titles truncate, the tab strip
+scrolls horizontally instead of squeezing every tab, and all hidden commands remain keyboard
+reachable through the overflow menu.
+
+```text
+Wide panel
++----------------------------------------------------------------+
+| [User tab] [Agent tab *] [+] |
+| [<-] [->] [reload] [ URL ] [Fit] [Expand]|
++----------------------------------------------------------------+
+
+Compact panel
++----------------------------------------------+
+| [User] [Agent *] ... |
+| [<-] [reload] [ URL ] [...]|
++----------------------------------------------+
+
+Narrow PiP
++--------------------------------------+
+| agent · site.example [Panel] [...] [x]|
++--------------------------------------+
+```
+
+Use CSS/container-query layout for renderer-owned chrome where possible. Native page bounds still
+come from the measured content rectangle.
+
+### Page presentation modes
+
+#### Responsive, default
+
+- The website viewport equals the actual native content bounds.
+- Page zoom is 100%.
+- CSS media queries, viewport units, and normal responsive behavior work as designed by the site.
+- PiP/panel movement changes only bounds after the destination layout is stable.
+
+This is the only mode that can be selected automatically without guessing site intent.
+
+#### Fit desktop, explicit per tab
+
+For desktop-oriented sites, the user can choose **Fit desktop**. YoBrowser presents a wider virtual
+desktop viewport and scales it into the available surface. A target virtual width near 1024 CSS px
+is a starting hypothesis, not a committed constant.
+
+Implementation must choose between Electron `webContents.enableDeviceEmulation` and a controlled
+zoom strategy only after a feasibility proof verifies:
+
+- layout/media-query behavior in panel and PiP;
+- text readability and minimum scale;
+- mouse, wheel, keyboard, focus, selection, and context-menu coordinates;
+- CDP `Input.dispatchMouseEvent` coordinates;
+- visible and full-page screenshot dimensions used by Agent tools;
+- no per-origin zoom leakage into another tab;
+- deterministic reset to Responsive mode after navigation, tab reuse, and view reparenting.
+
+Electron's Chromium zoom policy is same-origin, so `setZoomFactor` must not be assumed to provide
+isolated per-tab fit behavior. CDP/device emulation changes CSS viewport coordinates and may affect
+Agent screenshots/input. Until the proof passes, the product contract is Responsive plus **Expand**,
+not unverified automatic scaling.
+
+Presentation mode belongs to the tab. It survives panel/PiP movement and the current process
+lifetime, but is not persisted across app restarts in V1.
+
+### Expanded Browser mode
+
+Add an explicit **Expand** action that temporarily lets the Browser surface occupy the full
+`ChatTabView` content area, reusing the existing Workspace fullscreen shell behavior. This is the
+reliable escape hatch for complex desktop sites, wide tables, editors, and login flows where a
+scaled page would become unreadable.
+
+Expanded mode does not create a new window or page. It changes the side-panel shell geometry, keeps
+the same selected tab/view, provides a clear **Restore chat** action, and returns focus to the
+originating control.
+
+### Safe adaptation policy
+
+- DeepChat chrome adapts automatically.
+- Website viewport stays Responsive automatically.
+- DeepChat may detect persistent document-level horizontal overflow and offer **Fit desktop** or
+ **Expand**, but it does not silently switch modes based on `scrollWidth` heuristics.
+- Recompute native bounds during drag/resize at animation-frame cadence, but apply presentation-mode
+ changes only after bounds stabilize or resizing ends.
+- Derive the desktop user-agent Chromium version from the runtime; do not switch to a mobile
+ user-agent for narrow surfaces.
+
+## Visibility Predicate
+
+PiP is visible only when all of these are true:
+
+```text
+tab.owner == agent
+AND tab.lastAgentRunId == workspace.activeAgentRunId
+AND active Agent run is not terminal
+AND tab is not closed
+AND right-side panel is closed
+AND workspace session is the active chat in its host renderer
+AND host window is foreground
+AND workspace.dismissedPipRunId != workspace.activeAgentRunId
+```
+
+Every input is main-process-authoritative or validated against the sender's host window. The
+renderer reports layout facts; it does not decide whether an arbitrary tab may float.
+
+### Confirmed panel-open behavior
+
+If the right-side panel is already open, an Agent browser action activates the Browser surface,
+selects the current Agent tab, waits for stable Browser bounds, and places the page in the panel. It
+does this even when Workspace was the active surface. No PiP is shown during that handoff.
+
+The Browser surface is not pinned. The user may switch back to Workspace afterward. That switch
+detaches the Agent page without showing PiP because the panel remains open; the next Agent browser
+tool action activates Browser again. This prevents a continuous tab-switch fight while still making
+each new Agent operation visible.
+
+## Loop Lifecycle
+
+An Agent run becomes relevant to YoBrowser only after its first browser tool starts. There is no
+empty PiP at run start.
+
+```text
+run starts
+ -> no browser action: no PiP state
+ -> first browser tool: mark Agent tab with runId
+ -> right-side panel open: activate Browser, then place in panel
+ -> panel closed: place page in render host
+ -> session/host foreground and not dismissed: capture mirror into PiP
+ -> more browser tools: reuse tab and recompute placement
+ -> run completes / fails / aborts: stop capture and hide PiP immediately
+```
+
+A permission or question pause is not a terminal loop state. PiP remains eligible unless the user
+dismisses it or another visibility condition becomes false. Terminal means completed, failed,
+cancelled, superseded, or session teardown.
+
+Loop completion hides PiP but does not close the tab. This preserves the result for later inspection
+in the Browser panel. A separate retention policy handles eventual destruction.
+
+## Placement Invariant and Transitions
+
+For each page view:
+
+```text
+number of native parents <= 1
+placement == panel => parent is host.contentView
+placement == render-host => parent is focusless renderHost.contentView at 1280 x 800
+placement == detached => no native parent
+```
+
+All transitions go through one main-process placement controller. It removes the old parent before
+adding the new parent, applies bounds, and starts or stops frame capture. The PiP Canvas is not a
+native parent and never owns the page. Concurrent renderer mode requests, panel bounds, captures,
+and Agent tool events are serialized per workspace.
+
+| Event | From | Result |
+| --- | --- | --- |
+| First Agent browser action, panel open | Detached | Activate Browser, then Panel |
+| First Agent browser action, panel closed | Detached | Render host; mirror if eligible |
+| User clicks **Open in panel** | Render host | Open/activate Browser, then Panel |
+| Browser surface becomes visible | Render host | Panel |
+| User switches Browser to Workspace while panel stays open | Panel | Detached until next Agent browser action |
+| User closes panel during active eligible run | Panel | Render host and mirror |
+| User clicks PiP **Close** | Render host | Keep rendering; stop frames and suppress mirror for this run |
+| Chat session deactivates | Render host or Panel | Stop frames; retain render host only while Agent work requires it |
+| Host blurs/hides/minimizes | Render host | Stop frames; keep Agent rendering |
+| Same host returns foreground with eligible run | Render host | Resume mirror capture |
+| Agent run becomes terminal | Render host | Stop capture, release host, retain page detached |
+| Agent tab closes | Any | Destroy and no PiP |
+
+The panel transition waits for a stable content rectangle before reparenting. During the short
+handoff, show the existing Browser placeholder; never display the remote page twice.
+
+## User Experience
+
+### Before: Agent navigation forces the panel open
+
+```text
++--------------------------------------+-----------------------+
+| Active conversation | Browser |
+| | [Back] [ URL ] |
+| Agent is working... | |
+| | agent-operated page |
+| | |
++--------------------------------------+-----------------------+
+```
+
+### After: closed panel stays closed and Agent page floats inside the chat
+
+```text
++----------------------------------------------------------------+
+| Active conversation |
+| |
+| Agent is working... +-------------------------------+ |
+| | | |
+| | read-only Agent page mirror | |
+| | | |
+| | [Open panel] [x] | |
+| +-------------------------------+ |
+| |
++----------------------------------------------------------------+
+```
+
+### After: Browser panel was already visible
+
+```text
++--------------------------------------+-------------------------+
+| Active conversation | Browser |
+| | [User tab] [Agent tab] |
+| Agent is working... | |
+| | same live Agent page |
+| | |
++--------------------------------------+-------------------------+
+```
+
+### PiP controls
+
+- Controls are hidden initially. A click without drag on any non-button point toggles a toolbar with
+ a truncated title, **Open in panel**, and **Close**.
+- Every point in the PiP except buttons is a drag handle. Movement beyond the drag threshold must not
+ also toggle the toolbar.
+- The Canvas and decorative overlays use no remote-page input forwarding. Pointer, wheel, keyboard,
+ selection, and focus stay in the trusted chat renderer.
+- **Close** sets `dismissedPipRunId` to the current run and stops mirror capture. It does not close
+ the tab, stop the 1280 x 800 render host, cancel CDP, or abort the Agent loop.
+- **Open in panel** opens and activates the Browser panel, selects the Agent tab, and reparents the
+ same page after the panel bounds stabilize.
+- A keyboard user can focus both buttons. Dragging is pointer-based; keyboard movement is a later
+ enhancement unless accessibility review requires it for V1.
+
+### Geometry
+
+- Default to the bottom-right of the measured conversation content with a 12 px inset.
+- Prefer a 400 x 250 px 16:10 mirror when the conversation has room. Keep the captured frame at
+ 480 x 300 so the smaller display remains legible without changing the background page's
+ 1280 x 800 CSS viewport.
+- Reveal the top actions and a centered drag affordance on hover or keyboard focus. A non-drag tap
+ keeps those controls visible for pointer devices without hover.
+- Clamp height to at most 58% of the conversation region and keep the full header reachable.
+- On smaller regions, shrink to the available bounds. If usable page content would fall below
+ 360 x 240, replace the page card with a compact Agent-browser activity strip containing
+ **Open in panel** and **Dismiss** rather than obscuring the entire conversation with an unusable
+ webpage.
+- Drag updates are renderer-local, throttled to animation-frame cadence, and clamped against the
+ measured conversation bounds.
+- Remember the last position only for the current host window lifetime. Re-clamp on resize, panel
+ animation, route changes, and display scale changes.
+
+Exact radius, shadow, header height, and icon treatment should be matched to the missing reference
+screenshot during implementation review.
+
+## Panel Tab Interaction
+
+The Browser panel adds a compact tab strip below its existing Workspace/Browser selector and above
+navigation controls. This is browser-tab state, not a second copy of the global side-panel tabs.
+
+```text
++--------------------------------------------------+
+| [Workspace] [Browser] [x] |
+| [User page] [Agent page *] [+] |
+| [<-] [->] [reload] [ URL ] |
+| |
+| active page |
++--------------------------------------------------+
+```
+
+- User navigation from a markdown link may keep its current explicit behavior of opening the
+ Browser panel and creates/selects a user tab.
+- Agent navigation never selects a user tab and never creates one tab per URL.
+- An Agent marker distinguishes automation tabs.
+- Closing an Agent tab destroys that page and removes PiP eligibility. The Agent receives a stable,
+ recoverable page-closed result if a concurrent command loses the tab.
+- Closing the panel detaches user pages. During an eligible Agent run, its active Agent page moves
+ to PiP; otherwise it also detaches.
+- **Expand** is available for user and Agent tabs. Presentation mode is stored per tab and follows
+ the same live page into panel, PiP, and expanded placement.
+
+## Active Session and Foreground Semantics
+
+- Bind workspace visibility to the renderer `webContentsId` that reports the session as activated.
+- Reject layout reports whose sender does not own the target host window/session route.
+- A session visible in another window wins only when it is the currently activated copy; do not
+ mirror one page view into two windows.
+- Window blur, hide, minimize, close, route replacement, or session deactivation hides the Canvas
+ mirror and stops frame delivery. These events are derived from BrowserWindow state, not
+ `document.hasFocus()`, because focus can legitimately move between WebContents in one window.
+- Window refocus may restore PiP only if the same non-terminal Agent run remains active and was not
+ dismissed.
+- Switching to another chat cannot expose the previous chat's page even for one frame.
+
+## Activity Overlay
+
+The existing `YoBrowserOverlayWindow` visualizes pointer, keyboard, navigation, and vision activity.
+It should remain an activity layer, not become the PiP implementation.
+
+Its native bounds follow the page only in the visible Browser panel. PiP reuses the typed activity
+event and draws a trusted renderer halo over the Canvas, avoiding another native overlay window,
+z-order interaction, or focus change.
+
+## Events and Public State
+
+Replace the ambiguous open request with intent-rich state. Proposed public concepts:
+
+- workspace/tabs status: IDs, owner, URL/title/favicon, page status, active tab, placement;
+- per-tab presentation mode and current effective page viewport/scale metadata;
+- Agent browser activity: `sessionId`, `runId`, `tabId`, tool activity phase;
+- layout report: host window, active session, conversation bounds, panel bounds, Browser surface
+ visibility;
+- placement status: `panel`, `pip`, `detached`, plus a redacted reason;
+- preview-mode command: `capturing`, `rendering`, or `stopped`;
+- typed preview-frame event: session/run/sequence, dimensions, MIME type, and bounded binary data;
+- PiP commands: dismiss current run and open the current page in panel. Drag position remains local.
+
+`runId` must be added to the internal tool execution context and passed through the Agent tool
+manager into `YoBrowserToolHandler`. Do not derive loop ownership from session `working` status or
+from a timeout: a session can wait for permission, queue another turn, or be superseded.
+
+## Security and Isolation
+
+- Remote page execution remains in its existing sandbox/session. PiP receives only an inert,
+ downscaled image frame and never remote DOM or script.
+- PiP chrome loads only a packaged local route with no remote navigation, no Node integration, and a
+ narrow validated IPC surface.
+- Remote pages cannot receive PiP input, drag the PiP, close it, activate the panel, spoof Agent
+ ownership, or send PiP commands.
+- Preview frames remain memory-only, are bounded in dimensions and rate, and are never logged,
+ cached, or written to disk.
+- Device-emulation or zoom state is applied only by main-process tab policy; remote pages cannot
+ change the stored presentation mode.
+- Bounds and IDs received from renderers are validated and clamped in main.
+- The page's DevTools/CDP attachment remains unchanged during reparenting.
+- No page URL, title, or favicon from an inactive session is shown after a session switch.
+- The trusted header truncates untrusted title/host text and never interprets it as HTML.
+
+## Failure Semantics
+
+- A failed render-host creation or reparent falls back to `detached`, publishes `placement_failed`,
+ and never leaves the page registered under two parents.
+- A capture or decode failure retains the last Canvas frame and retries on the next bounded tick;
+ it never clears the PiP to a blank frame.
+- At most one capture is in flight per page. New ticks are dropped rather than queued.
+- A destroyed host window clears placement synchronously and destroys its PiP chrome.
+- A stale bounds or session-activation update is ignored by monotonically increasing layout
+ versions.
+- If panel bounds never stabilize, keep the PiP visible and report the handoff failure; do not reload
+ the page.
+- If PiP chrome crashes, detach PiP and keep the Agent page alive for tools.
+- If the remote page crashes, show the existing browser error state in the panel/placeholder and let
+ tool calls return the current page error.
+- Loop-finalization cleanup is idempotent and safe when the page or window has already closed.
+
+## Feasibility Assessment
+
+| Requirement | Feasibility | Evidence / risk |
+| --- | --- | --- |
+| Same page in render host and panel by movement | High | Electron View supports child-view reparenting; serialize parent changes |
+| Read-only in-chat mirror and dragging | High | Canvas stays in the trusted renderer and cannot target remote content |
+| Preserve page/CDP/session state | High | Reuse the same `WebContentsView`; no navigation or recreation |
+| macOS transparent render host capture | High | Proven locally against Electron 40.10.5 with 1280 x 800 animated content |
+| Windows/Linux transparent render host capture | Medium | Requires packaged compositor/window-manager validation |
+| Bounded frame cost | Medium-high | 480 x 300 output, adaptive 1-4 FPS, one in-flight capture, stop when ineligible |
+| Agent-only eligibility | High | Requires `runId` propagation and explicit tab ownership |
+| Hide exactly at loop terminal state | High | Runtime owns `LoopRun.runId`; add an explicit finalization port |
+| Multiple browser tabs | Medium-high | Current single-page status/contracts and panel must be migrated |
+| Responsive DeepChat chrome | High | Container-width layout can reuse current panel ownership and existing UI primitives |
+| Responsive website rendering | High for native Responsive mode | Current native bounds already drive the page viewport |
+| Fit desktop mode | Medium | Must prove emulation/zoom input and Agent screenshot coordinate fidelity |
+| Expanded Browser surface | High | Reuse the existing side-panel fullscreen shell behavior |
+| Existing activity overlay in nested PiP | Medium | Separate transparent window may need a local-view fallback after cross-platform QA |
+| Identical cross-platform window behavior | High with in-window View | Avoids child `BrowserWindow` platform differences |
+
+The largest implementation risk is not rendering the card. It is lifecycle correctness across
+Agent finalization, session switching, panel animation, window focus, tab closing, and concurrent
+bounds updates. The placement invariant and run ID are mandatory, not optional polish.
+
+## Acceptance Criteria
+
+- An Agent browser tool never opens a closed right-side panel.
+- A user-opened page never appears in PiP.
+- The first browser tool in an active loop creates/reuses an Agent tab and associates the exact
+ `runId`.
+- If the Browser surface is visible, the Agent tab is shown there with no PiP.
+- If any right-side panel surface is open when an Agent browser action starts, DeepChat activates
+ Browser and shows the Agent tab there instead of opening PiP.
+- Switching back to Workspace is respected until the next Agent browser action; DeepChat does not
+ continuously force Browser active.
+- If all PiP predicate conditions hold, exactly one PiP appears inside the active conversation.
+- PiP is read-only: clicking, dragging, scrolling, typing, or focusing it never affects the page.
+- The live remote page exists in only one native placement; the Canvas contains only its last
+ completed image frame.
+- While mirrored, page layout reports a stable 1280 x 800 CSS viewport independent of PiP size.
+- Moving PiP to the panel preserves URL, DOM state, scroll, focusable page state, cookies, and CDP
+ target identity without reload.
+- Closing PiP suppresses it for the rest of that run without closing the page or interrupting the
+ Agent.
+- A later Agent run may show the retained Agent tab again after its first browser action.
+- Completing, failing, cancelling, or superseding the loop hides PiP immediately.
+- Session deactivation and real BrowserWindow blur/hide/minimize hide PiP; internal focus movement
+ between chat and page WebContents does not hide or flash it.
+- New frames replace Canvas pixels only after decode, so capture and handoff never create a blank
+ intermediate frame.
+- Dragging stays inside current chat bounds through resize and scale changes.
+- Browser tabs and controls remain usable at 420 px panel width without clipping the address bar or
+ hiding commands from keyboard users.
+- Responsive mode exposes the real content bounds at 100% page zoom.
+- Fit desktop is never selected silently and passes user-input/CDP/screenshot coordinate tests
+ before release.
+- Expand/restore preserves the exact tab and page state without reload.
+- The YoBrowser user-agent Chromium version matches the bundled runtime rather than a stale literal.
+- Panel tabs distinguish user and Agent pages and closing a tab destroys only that page.
+- Tool operations remain correct while the page moves between placements.
+- Cross-platform focus, input, z-order, overlay, and accessibility tests pass.
+- Format, i18n, lint, typecheck, and focused tests pass after implementation.
+
+## Decision Gates
+
+1. **What does PiP close mean?** Recommendation: dismiss presentation for the current run only; it
+ must not close the tab or disrupt automation.
+2. **Agent tab retention**: recommendation is one retained Agent tab per session, destroyed when the
+ session/browser workspace is explicitly destroyed or by a later memory-pressure policy.
+3. **Run pause behavior**: recommendation is to keep PiP eligible while waiting for permission or a
+ question, because the loop has not ended; the user can dismiss it.
+4. **Page adaptation**: recommendation is automatic responsive chrome plus Responsive page mode by
+ default, with explicit Fit desktop and Expand actions. Silent overflow-based scaling is too
+ unpredictable for arbitrary sites and Agent coordinates.
+5. **Fit implementation**: choose device emulation versus controlled zoom only after the coordinate
+ fidelity proof; no API is approved by this spec yet.
+6. **Exact styling**: requires the referenced screenshot or a new visual decision before UI polish.
+
+Confirmed product decisions:
+
+- an already open right-side panel automatically switches from Workspace to Browser for each new
+ Agent browser action;
+- an undersized conversation shows a compact Agent-browser activity strip instead of forcing an
+ unusably small webpage.
+
+## Verified References
+
+- [Electron View API](https://www.electronjs.org/docs/latest/api/view)
+- [Electron WebContentsView API](https://www.electronjs.org/docs/latest/api/web-contents-view)
+- [Electron BaseWindow child-window behavior](https://www.electronjs.org/docs/latest/api/base-window)
+- [Electron webContents zoom and device-emulation APIs](https://www.electronjs.org/docs/latest/api/web-contents)
+- [Electron 40.10.5 runtime versions](https://releases.electronjs.org/release/v40.10.5)
+- [Chrome DevTools Protocol Input coordinates](https://chromedevtools.github.io/devtools-protocol/tot/Input/)
diff --git a/docs/features/agent-browser-pip/tasks.md b/docs/features/agent-browser-pip/tasks.md
new file mode 100644
index 0000000000..29fa302343
--- /dev/null
+++ b/docs/features/agent-browser-pip/tasks.md
@@ -0,0 +1,121 @@
+# Agent Browser Surfaces and Picture-in-Picture Tasks
+
+## Status
+
+V1 read-only mirror revision implemented. Visible browser multi-tabs, Fit-desktop emulation, and
+packaged cross-platform validation remain open.
+
+## Completed Discovery
+
+- [x] Trace current YoBrowser page, native view, CDP, overlay, panel, and session lifecycles.
+- [x] Identify the unconditional Agent `browser.open.requested` panel-opening behavior.
+- [x] Confirm the current model is one page per session with no user/Agent ownership.
+- [x] Locate stable `LoopRun.runId` ownership and the missing tool-context propagation.
+- [x] Verify Electron View/WebContentsView reparenting and child-window platform constraints.
+- [x] Define the single-parent invariant, eligibility predicate, interaction matrix, and failure
+ behavior.
+- [x] Diagnose the current 420-520 px panel constraints, fixed Browser toolbar, native viewport
+ behavior, and stale hard-coded Chromium user-agent version.
+- [x] Write the proposal, implementation plan, feasibility assessment, and acceptance criteria.
+
+## Product Decisions Required Before Implementation
+
+- [x] Automatically switch an already open Workspace surface to Browser for each new Agent browser
+ action, without pinning Browser afterward.
+- [x] Confirm PiP **Close** dismisses only the current run and never closes the Agent page.
+- [x] Confirm one primary Agent page is retained per session and reused across loops.
+- [x] Confirm PiP remains eligible while the renderer session remains in the working state.
+- [x] Use a compact Agent-browser activity strip instead of a webpage below the usable PiP size.
+- [ ] Confirm Responsive default, explicit Fit desktop, and Browser Expand as the page-adaptation
+ model.
+- [x] Confirm undersized chats use a compact Agent activity strip instead of an unusable page card.
+- [x] Confirm PiP is a low-frame-rate read-only mirror with a 1280 x 800 background viewport.
+- [ ] Supply the referenced screenshot or approve a visual baseline for radius, shadow, toolbar,
+ sizing, and placement.
+
+## Phase 1: Run Identity and Workspace Foundation
+
+- [x] Add `runId` to internal tool execution options.
+- [ ] Thread `runId` through immediate, batch, resumed, and deferred tool paths.
+- [x] Pass `runId` through `AgentToolManager` into `YoBrowserToolHandler`.
+- [ ] Add an idempotent browser run-finalization port for every terminal outcome.
+- [ ] Replace per-session single-page state with workspace/tab state.
+- [x] Add explicit user/Agent page ownership and last-touched run identity.
+- [ ] Reuse one primary Agent tab per session and define popup inheritance.
+- [x] Expand shared browser status/events for ownership and run identity.
+- [x] Add runtime tests for ownership and run-sensitive placement.
+
+## Phase 2: Placement Ownership and Panel Tabs
+
+- [ ] Add a versioned renderer layout report for conversation and panel bounds.
+- [ ] Validate layout sender, host window, and active session in main.
+- [ ] Add one serialized placement controller per workspace.
+- [ ] Enforce panel/PiP/detached single-parent invariants.
+- [ ] Remove direct competing attach/detach ownership from `BrowserPanel.vue`.
+- [ ] Add browser tab create/select/close operations.
+- [ ] Add a compact panel tab strip and Agent marker using existing UI primitives.
+- [ ] Add container-responsive wide, compact, and narrow Browser chrome.
+- [ ] Keep the address bar usable and every hidden command keyboard-accessible at 420 px.
+- [x] Generalize the existing Workspace fullscreen shell behavior into Browser Expand/Restore.
+- [x] Derive the YoBrowser desktop user-agent Chromium version from the runtime.
+- [x] Route user navigation and Agent tools through explicit page ownership.
+- [x] Stop destroying a completed Agent page merely because the session becomes inactive.
+- [ ] Remove the compatibility single-page status/routes after all callers migrate.
+- [ ] Add main/renderer tests for tab and placement races.
+
+## Phase 3: Page Presentation, PiP Surface, and Interaction
+
+- [ ] Build representative responsive/fixed-width website fixtures.
+- [ ] Compare device emulation and controlled zoom for per-tab Fit desktop.
+- [ ] Verify user input, CDP input, DOM, screenshot, iframe, fixed/sticky, and reset coordinates.
+- [ ] Ship Fit desktop only if one path passes the complete coordinate proof.
+- [ ] Add per-tab Responsive/Fit presentation state without restart persistence.
+- [x] Replace the native-page PiP with a lazy Canvas mirror.
+- [x] Add the focusless render host and explicit `capturing`/`rendering`/`stopped` modes.
+- [x] Add bounded capture, resize, encoding, and typed in-memory frame delivery.
+- [x] Keep preview chrome in the trusted chat renderer and expose only typed mode/frame contracts.
+- [x] Render sanitized title, Agent activity, **Open in panel**, and **Close**.
+- [x] Implement the V1 eligibility predicate.
+- [x] Remove the unconditional Agent-triggered `sidepanelStore.openBrowser()` behavior.
+- [x] Implement default responsive bounds and small-region fallback.
+- [x] Implement compact Agent activity-strip fallback below usable page size.
+- [x] Make every non-button PiP point draggable and distinguish click from drag by threshold.
+- [x] Toggle the close/expand toolbar on a non-drag click without forwarding page input.
+- [x] Implement current-run dismissal without page/tool interruption.
+- [x] Implement panel handoff with no reload or duplicate display.
+- [x] Move the Agent page to the 1280 x 800 render host when Browser hides during an active run.
+- [x] Keep panel activity overlay behavior and render the PiP activity halo in trusted Canvas chrome.
+- [x] Add accessible labels, focus behavior, and i18n strings.
+- [x] Add focused tests for mirror eligibility, frame retention, input isolation, dismissal, drag,
+ focus, and panel handoff.
+
+## Phase 4: Lifecycle and Cross-Platform Validation
+
+- [ ] Test loop fail, abort, supersede, and teardown cleanup.
+- [x] Test loop completion cleanup.
+- [ ] Test permission/question pause behavior.
+- [ ] Test session switch, route change, multi-window activation, and stale events.
+- [x] Test focus/blur mode transitions and host-focus isolation.
+- [ ] Test show/hide, minimize/restore, resize, maximize, and display scale.
+- [ ] Test tab close and page/chrome/host crash recovery.
+- [ ] Test concurrent user commands and Agent tool activity.
+- [ ] Test page input, chat focus, native z-order, and activity overlay on macOS.
+- [ ] Test Browser chrome at every container breakpoint and at non-integer display scales.
+- [ ] Test Responsive, Fit desktop if approved, Expand, and Restore without page reload/state loss.
+- [ ] Repeat packaged focus/z-order/drag tests on Windows and Linux.
+- [ ] Verify the exact page WebContents/CDP identity survives every placement move.
+- [ ] Verify no inactive-session content appears, including transient frames.
+- [ ] Profile retained Agent-tab memory before considering eviction.
+- [x] Run `pnpm run format`.
+- [x] Run `pnpm run i18n`.
+- [x] Run `pnpm run lint`.
+- [x] Run typecheck, build, focused suites, and the full main/renderer test suite.
+- [ ] Capture BEFORE/AFTER screenshots or GIFs and include the ASCII layouts in the PR.
+
+## Deferred Work
+
+- [ ] Persist PiP position/size only if users demonstrate a need.
+- [ ] Add a measured idle Agent-tab eviction policy only if memory profiling requires it.
+- [ ] Add keyboard PiP movement if accessibility review requires it.
+- [ ] Generalize Agent tools to explicit tab IDs only when multi-tab automation is requested.
+- [ ] Share architecture with standalone browser windows only after a separate convergence design.
diff --git a/docs/features/browser-profile-import/plan.md b/docs/features/browser-profile-import/plan.md
new file mode 100644
index 0000000000..7a83753990
--- /dev/null
+++ b/docs/features/browser-profile-import/plan.md
@@ -0,0 +1,362 @@
+# Browser Website Data and Session Import Implementation Plan
+
+## Status
+
+V1 implemented. This document remains the design record; unchecked tasks are validation or later
+data-category work rather than claims about the shipped cookie importer.
+
+The smallest credible first release is explicit, one-way Chrome website-session import backed by
+cookies on one platform whose supported decryption path passes packaged fixtures. Passwords,
+tab-bound `sessionStorage`, Windows App-Bound data, and generic profile cloning are separate from
+that milestone.
+
+## Recommended Delivery Shape
+
+```text
+Settings renderer
+ |
+ | typed routes: scan -> preview -> apply -> status
+ v
+BrowserProfileImportPresenter (main process)
+ |
+ +-- source discovery
+ +-- Chromium-profile cookie reader
+ +-- platform key access
+ +-- staging and validation
+ +-- target mutation lock
+ +-- CDP target writer and verifier
+ +-- redacted progress/events
+ |
+ v
+persist:yo-browser Electron session
+```
+
+Keep this in the main process. Source paths, encryption keys, decrypted values, rollback data, and
+CDP cookie parameters must never cross into a renderer.
+
+## Architecture
+
+### 1. One presenter, explicit source readers
+
+Add a `BrowserProfileImportPresenter` owned by the desktop presenter layer. It coordinates a single
+import operation and exposes only discovery, preview, apply, cancel-before-mutation, and last-result
+operations.
+
+Do not start with a plugin framework. Use a small internal reader contract and concrete readers for
+only the combinations that have passed fixtures, for example:
+
+```ts
+type BrowserProfileSourceReader = {
+ discover(): Promise
+ previewCookies(profile: DetectedBrowserProfile): Promise
+}
+```
+
+The reader returns normalized in-memory records, not source-specific database rows. Chrome and Arc
+must not share a reader merely because both are Chromium-derived; shared decoding helpers are fine
+after their fixtures prove identical behavior.
+
+### 2. Typed renderer boundary
+
+Add browser-data import routes and events under the existing shared contract structure. Proposed
+operations:
+
+- `browserDataImport.scan`
+- `browserDataImport.preview`
+- `browserDataImport.apply`
+- `browserDataImport.cancel`
+- `browserDataImport.getStatus`
+
+Renderer-visible payloads contain IDs, display names, capabilities, counts, progress, and stable
+redacted error codes. They never contain profile secrets, cookie names, cookie domains beyond an
+explicit aggregate preview decision, values, encryption metadata, keychain labels, or raw paths.
+
+Use an opaque scan token to bind preview/apply to the exact discovered profile. Resolve the source
+path again in main and reject a token after the source metadata changes.
+
+### 3. Source discovery
+
+Implement deterministic known-location discovery per browser and OS. For every candidate:
+
+1. Canonicalize the user-data and profile paths.
+2. Require the expected metadata and category files.
+3. Read profile names from `Local State` when valid.
+4. Fall back to validated `Default` / `Profile N` directories.
+5. Detect a running source through lock files and process-independent file-open behavior; never kill
+ the browser.
+6. Compute category capability from browser, version, platform, key access, and source state.
+
+No recursive home-directory scan is needed.
+
+### 4. Consistent snapshots
+
+Use a private temporary directory with mode `0700`.
+
+- For SQLite, use the existing `better-sqlite3-multiple-ciphers` backup support where the source can
+ be opened consistently, or copy the database plus WAL/SHM only after proving consistency.
+- Validate `PRAGMA integrity_check`, schema version, required columns, and row decoding on the
+ snapshot.
+- For a future LevelDB category, require the source browser to be closed and copy the complete
+ storage directory except transient lock files before opening the snapshot.
+- Register startup cleanup for abandoned DeepChat import directories.
+
+The operation must not mutate YoBrowser until the entire selected source category is staged and
+validated.
+
+### 5. Platform key access
+
+Build only the platform path selected for V1.
+
+For a macOS Chrome proof, trigger the system-owned Keychain authorization surface and retrieve the
+exact source browser's Safe Storage secret through a main-process-only OS adapter. Derive the
+Chromium key according to the source version and decrypt the staged `v10` records. The proof may use
+the system `security` executable to avoid a new native dependency, provided arguments and output are
+never logged, DeepChat never receives the password typed into the OS prompt, and denial is handled
+normally. A production implementation should keep that choice only if authorization behavior,
+signing, and sandboxed packaging tests pass.
+
+Do not implement Windows Chrome/Arc App-Bound decryption in V1. User account or UAC authorization
+does not give DeepChat Chrome's application identity. Do not add a browser extension, companion
+service, `SYSTEM` process, process injection, memory scan, reverse-engineered
+`elevation_service.exe` key, or remote-debugging workaround. Report the source/category as
+unsupported before preview mutates anything.
+
+Use Chromium as a reference implementation, not as a library dependency. The minimal reader needs
+only deterministic profile discovery, a consistent SQLite snapshot, explicit encrypted-record
+version dispatch, the supported platform key adapter, authenticated record decryption, and cookie
+normalization. Do not embed Chromium's `ProfileManager` or copy its profile lifecycle machinery into
+DeepChat.
+
+### 6. Cookie normalization and CDP application
+
+Normalize source rows into a target-independent cookie record that retains:
+
+- name and value;
+- domain and host-only semantics;
+- path;
+- expiry or session-only state;
+- Secure, HttpOnly, SameSite, and prefix constraints;
+- priority, source scheme, and source port;
+- partition key and cross-site ancestor state where available.
+
+Version the mapper by the source schema and target Electron Chromium/CDP major versions. Unknown
+enum values or unsupported partition metadata block preview rather than being silently discarded.
+
+The target operation is transactional at the application level:
+
+```text
+acquire target lock
+ -> snapshot current target cookies
+ -> clear target cookies
+ -> apply staged source cookies in bounded batches
+ -> read back and normalize
+ -> compare identities and values
+ -> success: flush + release lock + reload tabs
+ -> failure: clear + restore target snapshot + verify + release lock
+```
+
+Use CDP `Storage`/`Network` cookie commands against `persist:yo-browser`; do not use Electron's
+public Cookies API as the sole writer because it cannot express the full partitioned-cookie shape.
+
+### 7. Mutation ownership
+
+Add one target-data mutation coordinator shared by import and the existing clear-sandbox action.
+While it is held:
+
+- a second import or clear request is rejected as `target_busy`;
+- source preview may continue because it is read-only;
+- YoBrowser navigation may remain visible, but the final clear/apply window should be short;
+- affected tabs reload only after verified success;
+- application shutdown waits for rollback/apply completion within a bounded deadline, then records
+ recovery-required state if safe completion is impossible.
+
+### 8. Settings UX
+
+Extend the existing YoBrowser sandbox card in `DataSettings.vue`. Reuse shadcn-vue Dialog, Button,
+Checkbox/Field, Alert, Badge, Progress/Spinner, and existing settings patterns. Use i18n keys for all
+visible copy.
+
+The renderer drives a strict state machine from main-process status. It does not infer readiness
+from counts and cannot enable apply before a successful preview token is returned.
+
+The confirmation screen must say that selected target categories are replaced, that the source is
+not modified, and that an OS/source-browser authorization prompt may appear. The result screen
+reports imported, skipped, expired, unsupported, and failed counts separately. It reports data
+transfer success, not a guarantee that every site server will accept the session.
+
+## Feasibility Proofs Before Product Work
+
+### Proof A: macOS Chrome cookie round trip
+
+Create a sanitized Chrome fixture containing persistent, session, HttpOnly, SameSite variants,
+prefix-constrained, and partitioned cookies. Prove:
+
+- snapshot succeeds with Chrome open and closed;
+- system-owned key authorization is understandable and denial is recoverable;
+- every supported row decrypts;
+- CDP writes and reads back normalized values;
+- session cookies remain non-persistent;
+- target rollback restores its original cookies byte-for-value where public fields permit.
+
+This is high feasibility based on the current local Chrome schema, but it is not complete until a
+packaged, signed application passes the test.
+
+### Proof B: Arc source compatibility
+
+Collect sanitized Arc fixtures on macOS. Verify user-data paths, profile metadata,
+cookie schema, keychain identifiers, encryption versions, and running-browser snapshot behavior.
+Until this passes, Arc remains experimental rather than inheriting Chrome support. Do not spend
+fixture effort on Windows while that platform is outside the release scope.
+
+### Proof C: partitioned-cookie fidelity
+
+Test the exact Electron-bundled CDP version with partitioned cookies. If `partitionKey` and
+cross-site ancestor state cannot round-trip, block that profile preview or explicitly exclude those
+records with user-visible counts; never flatten them into unpartitioned cookies.
+
+### Proof D: `localStorage` inactive-origin write
+
+Only if `localStorage` is still desired for the same milestone, prove CDP can clear, write, and read
+back multiple inactive origins without navigating real remote pages. Failure moves the category to
+a later release.
+
+## Implementation Phases
+
+### Phase 0: decisions and fixtures
+
+- Choose the first directly supported V1 platform and its OS-owned authorization surface.
+- Freeze V1 categories.
+- Collect legally safe, sanitized fixtures for every supported browser/OS/version combination.
+- Record source and target Chromium version support ranges.
+
+Exit criterion: the selected path has passing feasibility proofs and no unsupported category is
+presented as importable.
+
+### Phase 1: main-process cookie core
+
+- Add discovery, source snapshot, schema decoder, platform key access, cookie normalization, and
+ redacted errors.
+- Add target lock, CDP snapshot/apply/readback, rollback, and recovery cleanup.
+- Add focused unit and fixture tests without renderer work.
+
+Exit criterion: a headless integration test can repeat source-authoritative cookie sync and can
+recover from injected apply failures.
+
+### Phase 2: typed contracts and settings UI
+
+- Add routes, events, preload/browser client calls, and status types.
+- Add scan, preview, confirmation, progress, result, and clear-conflict UX.
+- Add accessibility, keyboard, i18n, and settings tests.
+
+Exit criterion: a user can understand platform/category limitations before any target mutation.
+
+### Phase 3: packaged platform validation
+
+- Validate notarized macOS builds and Windows/Linux packages selected for support.
+- Test OS key prompts, source-browser open/closed states, multi-profile discovery, rollback on crash
+ injection, and app restart cleanup.
+- Document the support matrix and known non-transferable login systems.
+
+Exit criterion: release checks pass on every advertised platform.
+
+### Later phases, only if separately approved
+
+- `localStorage` import after Proof D.
+- Live-tab `sessionStorage` handoff.
+- A separate credential-vault SDD for passwords.
+
+## Expected File Areas
+
+Exact names may change after the feasibility proof, but implementation should remain localized to:
+
+- `src/main/desktop/browser/import/` for discovery, readers, crypto, normalization, and coordinator;
+- `src/main/desktop/browser/yoBrowserSession.ts` for target session access/flush hooks;
+- `src/main/desktop/browser/YoBrowserPresenter.ts` for tab reload coordination only;
+- `src/shared/contracts/routes/` and `src/shared/contracts/events/` for typed boundaries;
+- `src/shared/types/` for redacted public state;
+- `src/preload/` for the existing safe route exposure pattern;
+- `src/renderer/settings/components/DataSettings.vue` and a focused import dialog component;
+- mirrored `test/main/**` and `test/renderer/**` suites plus sanitized fixtures.
+
+Do not place source-profile parsing in the renderer or generalize the standalone browser tab system
+to solve this feature.
+
+## Test Strategy
+
+### Unit
+
+- path discovery and canonicalization;
+- schema version/column validation;
+- Chromium timestamp and enum mapping;
+- cookie identity normalization, prefix rules, and expiry filtering;
+- platform decrypt success, denial, corrupt ciphertext, and unknown versions;
+- state-machine transitions and redacted error serialization;
+- target comparison and rollback planning.
+
+### Main-process integration
+
+- repeat import with changed and deleted source cookies;
+- source-authoritative clearing of target-only cookies;
+- session and persistent cookie behavior across restart;
+- CHIPS round trip;
+- apply failure at every batch boundary;
+- rollback failure and recovery-required state;
+- import versus clear lock contention;
+- source browser open/closed fixtures;
+- no secret values in captured logs/events;
+- no authorization password enters a DeepChat renderer, IPC payload, log, or process-owned field.
+
+### Renderer
+
+- per-profile/per-category capability rendering;
+- preview before confirmation;
+- apply disabled for stale/failed previews;
+- cancellation only before mutation;
+- result and error accessibility;
+- no accidental source-path or secret rendering.
+
+### Packaged smoke tests
+
+- OS key prompt behavior;
+- signing/notarization permissions;
+- multiple browser channels and profiles;
+- unsupported browser/version messaging;
+- removal of temporary snapshots after success, failure, crash, and restart.
+
+## Rollout and Compatibility
+
+- Hide the entry point when no supported source exists, but keep an explanation in the settings
+ card rather than an empty dialog.
+- Gate experimental Arc and `localStorage` support independently from Chrome cookies.
+- Store only non-secret last-sync metadata: browser ID, opaque profile ID, categories, timestamp,
+ counts, source version, and importer version.
+- Do not automatically re-run old imports after an app upgrade.
+- If the target Electron Chromium major changes, rerun CDP fidelity fixtures before keeping support
+ enabled.
+
+## Rejected Approaches
+
+- **Point Electron at Chrome's user-data directory**: risks concurrent profile corruption and mixes
+ incompatible browser-owned state.
+- **Copy the whole profile directory**: brings locks, caches, extensions, keys, versioned formats,
+ and non-transferable credentials without a safe rollback boundary.
+- **Attach remote debugging to the user's normal Chrome profile**: current Chrome restricts this and
+ it is not a stable import contract.
+- **Run a privileged App-Bound decryption proof of concept**: the referenced Chrome 130 script
+ creates a Windows service, executes under `SYSTEM`, and uses a hard-coded key recovered from
+ `elevation_service.exe`. This bypasses the protection, depends on browser internals, and is outside
+ the product's authorization and maintenance contract.
+- **Install a companion browser extension**: its implementation, distribution, broad cookie
+ permissions, and ongoing browser-store policy cost are not justified for a platform fallback.
+- **Use only Electron `cookies.set`**: loses modern cookie fields.
+- **Make password decryption part of cookie import**: still leaves no target password manager and
+ creates a much larger secret-handling surface.
+- **Add a general background sync daemon in V1**: creates consent, locking, freshness, and failure
+ semantics before the manual import is proven.
+
+## Complexity Budget
+
+V1 should add no new runtime dependency unless the packaged macOS key-access proof shows the system
+API cannot be used safely. It should support one browser/platform/category combination completely
+before adding adapters. A generic migration framework, scheduler, diff viewer, and bidirectional
+sync engine are explicitly out of scope.
diff --git a/docs/features/browser-profile-import/spec.md b/docs/features/browser-profile-import/spec.md
new file mode 100644
index 0000000000..33c0f1750b
--- /dev/null
+++ b/docs/features/browser-profile-import/spec.md
@@ -0,0 +1,495 @@
+# Browser Website Data and Session Import Spec
+
+## Status
+
+V1 implemented on 2026-07-17. The shipped scope is explicit, one-way, source-authoritative
+non-partitioned cookie import from macOS Chrome, with Arc exposed as experimental. Windows and
+Linux report unsupported. Passwords, `localStorage`, `sessionStorage`, and partitioned cookies
+remain deferred.
+
+Last verified against the repository and upstream documentation on 2026-07-17.
+
+## Problem
+
+YoBrowser currently uses one independent persistent Electron session,
+`persist:yo-browser`. The right-side browser panel and standalone DeepChat browser windows share
+that session, but it does not share authentication state with Chrome, Arc, or another installed
+Chromium browser.
+
+Users who are already signed in elsewhere therefore have to sign in again. Clearing the YoBrowser
+sandbox is supported, but importing or refreshing source-browser state is not.
+
+The requested product behavior is a repeatable, user-initiated, one-way import where a selected
+Chromium profile is the source of truth and supported website data replaces the corresponding
+YoBrowser data. The intended outcome is practical session portability: after import, YoBrowser
+should open supported sites with the same transferable signed-in state and site preferences as the
+selected source profile.
+
+## Product Contract
+
+This is not a whole-profile clone. It is a website-data import whose success is measured by useful
+session continuity.
+
+- Cookies can be imported with useful fidelity, subject to operating-system encryption and newer
+ device-bound session protections.
+- `localStorage` can potentially be imported, but Chromium's on-disk format is internal and must
+ pass a compatibility proof before it becomes a supported category.
+- `sessionStorage` belongs to a specific top-level browsing context. Copying a profile directory
+ does not attach a Chrome tab's namespace to an Electron tab.
+- Saved passwords are not required to carry an already authenticated website session. Electron
+ exposes encrypted application storage but no public API for importing records into a Chromium
+ password manager. Making imported passwords useful would require a DeepChat credential vault and
+ explicit autofill UX.
+- Passkeys, Device Bound Session Credentials, client certificates, and hardware-bound tokens are
+ intentionally non-transferable or may remain unusable after a cookie copy.
+
+The product may say "website data imported" or "session data synced" when the selected categories
+were verified. It must not claim that every site is signed in: expired server sessions,
+device-bound credentials, and site-side risk checks can still request authentication.
+
+## Goals
+
+- Discover supported installed browsers and their local profiles without modifying the source.
+- Let the user select one source browser/profile and preview what can actually be imported.
+- Support repeated, explicit, one-way synchronization.
+- Make the source authoritative for each selected and supported category.
+- Optimize for the user-visible outcome that supported sites retain their transferable signed-in
+ session after the target tabs reload.
+- Preserve modern cookie attributes where the target Chromium/CDP version supports them.
+- Stage and validate all source data before mutating YoBrowser.
+- Roll back the target category when an apply step fails.
+- Report imported, skipped, expired, unsupported, and failed records without exposing secret values.
+- Keep all processing local to the device.
+
+## Non-Goals
+
+- Real-time or bidirectional synchronization.
+- Writing anything back to Chrome, Arc, or another source browser.
+- Copying an entire live Chromium profile directory into Electron.
+- Circumventing Chrome App-Bound Encryption, operating-system authorization, enterprise policy, or
+ device-bound authentication. Authorization must use an OS-owned or source-browser-owned prompt.
+- Asking the user to type an operating-system, Chrome, Arc, or keychain password into a DeepChat
+ renderer form.
+- Claiming every Chromium-derived browser is supported by one generic adapter.
+- Importing browsing history, bookmarks, downloads, the user's installed extensions, payment cards,
+ passkeys, client certificates, or browser settings in the first release.
+- Giving an Agent access to raw saved passwords.
+- Installing a browser extension or companion service to extract source data.
+- Creating a Windows service, running code as `SYSTEM`, injecting into a source-browser process,
+ scraping process memory, or using reverse-engineered browser keys to defeat App-Bound Encryption.
+
+## Terminology
+
+- **Source browser**: An installed Chrome, Arc, or later explicitly supported Chromium browser.
+- **Source profile**: One profile directory selected by the user.
+- **Target session**: DeepChat's shared `persist:yo-browser` Electron session.
+- **Quick sync**: A cookie-only import that may be possible while the source browser is running.
+- **Full storage sync**: Any import that includes Chromium storage directories or LevelDB data and
+ may require the source browser to be closed.
+- **Source authoritative**: Existing target data in the selected category and scope is removed
+ before validated source data is applied.
+- **Session portability**: Transferable client-side website state is present in YoBrowser after
+ import; it does not imply that the website's server accepts every copied session indefinitely.
+- **Direct importer**: A small main-process reader that discovers a supported Chromium profile,
+ snapshots only the selected data stores, uses the supported OS/browser cryptography path, and
+ normalizes records before applying them to YoBrowser. It never loads the source profile as a
+ DeepChat browser profile.
+
+## Current Repository Contract
+
+- `src/main/desktop/browser/yoBrowserSession.ts` owns the persistent target session.
+- `src/main/desktop/browser/YoBrowserPresenter.ts` creates Agent browser views with that session.
+- `src/main/desktop/tab.ts` also assigns that session to standalone DeepChat browser windows.
+- `src/renderer/settings/components/DataSettings.vue` currently exposes only a destructive clear
+ action for the YoBrowser sandbox.
+- `better-sqlite3-multiple-ciphers` already provides read-only SQLite access and an online backup
+ API.
+- `level` is already installed and is used by the existing provider-import code for LevelDB
+ snapshots.
+
+The import target is therefore global to YoBrowser, not per chat session.
+
+## Source Discovery
+
+Discovery must be adapter-driven and read-only.
+
+Each detected source must include:
+
+- browser ID, display name, channel, and executable presence;
+- user-data directory and profile directory;
+- profile display name when safely available;
+- last modified time;
+- whether the source appears to be running;
+- per-category capability and the reason for any unsupported state.
+
+Initial discovery scope:
+
+| Browser | macOS | Windows | Linux | Notes |
+| --- | --- | --- | --- | --- |
+| Google Chrome stable | Required | Unsupported in V1 | Feasibility gate | Direct cookie support varies by OS |
+| Chromium | Optional after Chrome | Unsupported in V1 | Optional after Chrome | Separate key-store identity |
+| Arc | Experimental in V1 | Unsupported in V1 | Not available | Uses an explicit Arc source identity |
+| Edge / Brave | Future | Future | Future | Do not imply support from Chromium ancestry alone |
+
+Chromium documents that profiles are subdirectories of the user-data directory, commonly
+`Default` or `Profile N`. Profile metadata may be read from `Local State`, but discovery must fall
+back to validated directory inspection when metadata is missing.
+
+[GUESS] Arc's storage and keychain identifiers remain compatible enough with Chromium for a shared
+reader. This must be proven with sanitized Arc fixtures on every supported OS before Arc is labeled
+supported. Arc's public documentation confirms that profiles contain cookies, logins, passwords,
+history, and extensions, but it does not define a stable on-disk contract.
+
+## Capability Matrix
+
+### Data categories
+
+| Category | Direct profile read | Target apply | Proposed release status |
+| --- | --- | --- | --- |
+| Cookies | Platform-dependent | High via CDP | V1 candidate |
+| Partitioned cookies (CHIPS) | Platform-dependent | Medium-high via CDP | V1 only after protocol tests |
+| `localStorage` | Medium, internal LevelDB schema | Medium | Feasibility gate |
+| `sessionStorage` | Low without source tab mapping | Medium per target tab | Later live-tab handoff research |
+| IndexedDB | Low-medium, internal schema and blobs | Low-medium | Not V1 |
+| Service workers / Cache Storage | Low value and high compatibility risk | Medium | Not V1 |
+| Saved passwords | Platform-dependent decryption | No Electron password-manager import API | Separate product decision |
+| Passkeys / DBSC / client keys | Intentionally restricted | Not transferable | Unsupported |
+
+### Operating-system constraints
+
+| Platform | Direct cookie feasibility | Main constraint | Recommended path |
+| --- | --- | --- | --- |
+| macOS | High for Chrome after proof | Source Keychain item and system-owned user authorization | Direct reader first |
+| Windows | Unsupported in V1 | Chrome App-Bound Encryption binds cookies to Chrome identity | No extension and no bypass; show unsupported state |
+| Linux | Medium | Secret Service/KWallet availability and browser-specific key identity | Direct reader only after desktop-matrix proof |
+
+Chrome introduced App-Bound Encryption for Windows cookies in Chrome 127. Entering the Windows
+account password does not grant an unrelated application Chrome's app identity. DeepChat must not
+use process injection, memory scraping, `SYSTEM` elevation, a reverse-engineered browser key, or
+another bypass. The product decision is to omit Windows support instead of building a companion
+extension or privileged helper. Chrome 136 also rejects remote-debugging switches against the
+default user-data directory, so "attach CDP to the user's current Chrome profile" is not an
+acceptable general solution.
+
+The direct importer should reuse Chromium's documented profile layout, source schemas, timestamp
+conventions, and OS cryptography behavior where those form a supportable contract. Chromium's
+`ProfileManager` is useful as a reference for discovering and selecting profiles owned by Chromium,
+but it is not a cross-application migration or decryption API.
+
+The linked `thewh1teagle` Windows proof of concept is not an acceptable implementation path. It was
+tested against Chrome 130, creates a local Windows service through `pypsexec`, executes part of the
+unwrap under `SYSTEM`, and uses a hard-coded AES key recovered from `elevation_service.exe`. That is
+an App-Bound Encryption bypass built from version-specific internals, not an OS-owned authorization
+flow. Its useful input is limited to the neutral importer mechanics: locate `Local State`, recognize
+encrypted-record versions, snapshot the SQLite cookie store, authenticate AES-GCM records, and
+handle the 32-byte cookie plaintext prefix for schema versions where fixtures prove it.
+
+## Authorization Contract
+
+Import is always initiated by the user. Authorization is explicit and may include Touch ID,
+Windows Hello, an operating-system account password, or a keychain/keyring prompt.
+
+The authorization surface must be owned by the operating system or source browser whenever it
+protects source secrets. DeepChat may trigger that surface and explain why it appears, but it must
+not render a look-alike password prompt, receive the password, store it, or pass it through IPC.
+
+Authorization does not change the support matrix:
+
+- on macOS/Linux, successful OS key access may unlock a supported direct reader;
+- on Windows, current Chrome App-Bound Encryption remains unsupported in V1 even if the user can
+ approve a UAC or account prompt, because authorization does not grant Chrome's application
+ identity;
+- denial or cancellation returns to preview without changing YoBrowser;
+- the user authorizes each import operation in V1; no reusable background authorization token is
+ retained.
+
+## Cookie Import Contract
+
+Cookies are the recommended first category because they produce most of the requested
+signed-in-session benefit without creating a password manager.
+
+Before target mutation, the importer must:
+
+1. Create a consistent source SQLite snapshot.
+2. Validate the `meta.version` and required columns.
+3. Decrypt every non-expired source cookie selected for import.
+4. Map Chromium time values and enum fields to CDP cookie parameters.
+5. Validate domain, path, prefix, SameSite, Secure, HttpOnly, source scheme, source port, priority,
+ and partition-key data.
+6. Abort before target mutation if any required encrypted record cannot be handled.
+
+V1 applies only non-partitioned cookies through Electron's public `Session.cookies` API, then reads
+them back and verifies normalized identity/value pairs. Partitioned cookies are counted and skipped
+because the public shape does not expose the required partition key. A future CHIPS-capable release
+must move that category to CDP `Storage.getCookies`, `Storage.clearCookies`, and
+`Storage.setCookies` with protocol fixtures.
+
+Source-authoritative cookie sync means:
+
+- snapshot all target cookies for rollback;
+- clear the target cookie store;
+- set the complete validated source set in bounded batches;
+- read back the target set and compare normalized cookie identities and values;
+- restore the target snapshot if apply or verification fails;
+- flush the cookie store;
+- reload open YoBrowser tabs after success.
+
+Cookie creation and last-access timestamps cannot be set through the public CDP cookie parameter
+shape. The UI must not call this a byte-identical copy.
+
+Session cookies remain session cookies. DeepChat must not invent an expiration date to persist them.
+They may need to be imported again after DeepChat restarts.
+
+## Local Storage Contract
+
+`localStorage` is origin-scoped persistent data, but Chromium stores it in an internal LevelDB
+format. It can become supported only if a feasibility proof demonstrates all of the following:
+
+- consistent source snapshots while the source browser is closed;
+- correct decoding of Chromium storage keys and string encodings;
+- correct handling of storage keys and partitioning in the target Electron Chromium version;
+- authoritative target clearing;
+- target writes without loading arbitrary remote pages or triggering site side effects;
+- round-trip verification on fixtures generated by the exact Chrome and Electron major versions in
+ the support matrix.
+
+The preferred live target path is CDP `DOMStorage.clear` plus `DOMStorage.setDOMStorageItem` against
+an importer target. If CDP cannot write an inactive origin reliably, V1 must defer `localStorage`
+rather than copy target LevelDB files while Electron owns them.
+
+## Session Storage Contract
+
+`sessionStorage` is partitioned by origin and top-level browsing context. A Chrome profile's
+`Session Storage` LevelDB contains namespaces that refer to Chrome tabs. A DeepChat tab does not
+inherit those namespace identities merely because files are copied.
+
+Therefore:
+
+- offline profile-level `sessionStorage` import is not a V1 commitment;
+- a later user-initiated open-tab handoff may be considered only if a supported source-browser API
+ can export the current tab's URL and `sessionStorage` without an extension or encryption bypass;
+- the UI must describe this as "open tab handoff", not profile synchronization;
+- closing either source or target tab ends the relevant page session as normal.
+
+## Password Contract
+
+Saved passwords require a separate implementation track, but they can remain part of the broader
+"make YoBrowser useful with existing browser data" roadmap.
+
+Reading Chrome's `Login Data` does not make Electron autofill those credentials. Electron provides
+`safeStorage` for application-owned encrypted strings, but its documented public session APIs do
+not provide a password-manager import surface. This is an inference from the Electron 40.10.5
+public API and must be rechecked before implementation.
+
+The acceptable password direction is an explicit DeepChat credential-vault feature with:
+
+- user-triggered Chrome/Arc CSV export or another user-mediated export;
+- source-browser or operating-system authorization rather than a DeepChat-owned system-password
+ prompt;
+- immediate encrypted ingestion and a prominent plaintext-file warning;
+- origin-bound, user-triggered fill;
+- no automatic submit;
+- no Agent, tool, renderer, log, export, or telemetry access to decrypted credentials;
+- OS-backed encryption with a hard failure on insecure Linux `basic_text` storage;
+- independent threat modeling, tests, and settings UX.
+
+That work is not required for session portability and should not be hidden inside cookie-sync V1.
+
+## User Experience
+
+### Before
+
+```text
++--------------------------------------------------------------+
+| YoBrowser Sandbox |
+| Independent cookies and local storage. |
+| [Clear YoBrowser data] |
++--------------------------------------------------------------+
+```
+
+### Proposed settings card
+
+```text
++--------------------------------------------------------------+
+| YoBrowser data |
+| Source: Google Chrome / Personal |
+| Last sync: 2026-07-17 14:32 · Cookies: 1,284 |
+| [Import or sync] [Clear YoBrowser] |
++--------------------------------------------------------------+
+```
+
+### Proposed import dialog
+
+```text
++------------------------------------------------------------------+
+| Import browser data [x] |
+| |
+| Browser [Google Chrome v] Profile [Personal v] |
+| |
+| [x] Cookies Ready |
+| [ ] Local storage Experimental · Chrome must be closed |
+| [ ] Session storage Not available for profile import |
+| [ ] Passwords Requires a separate credential vault |
+| |
+| Source data replaces the selected YoBrowser categories. |
+| Chrome is never modified. |
+| System or Chrome authorization may be requested after Preview. |
+| [Cancel] [Preview] |
++------------------------------------------------------------------+
+```
+
+### Unsupported Windows source
+
+This state appears when a Windows Chrome or Arc profile uses App-Bound Encryption.
+
+```text
++------------------------------------------------------------------+
+| Import browser data [x] |
+| |
+| Windows Chrome protects cookies with Chrome's app identity. |
+| This Chrome profile cannot be imported safely by DeepChat. |
+| |
+| DeepChat will not install an extension, elevate a helper, or |
+| bypass Chrome's encryption. |
+| |
+| [Close] |
++------------------------------------------------------------------+
+```
+
+### Interaction flow
+
+1. The user opens Data & Privacy and selects **Import or sync**.
+2. DeepChat scans known locations and shows only validated source profiles.
+3. The user selects a source profile.
+4. DeepChat displays per-category capability, browser-running requirements, and platform limits.
+5. **Preview** performs source snapshot, authorization when required, decryption, validation, and
+ count calculation without changing YoBrowser. Protected authorization UI is owned by the OS or
+ source browser, not DeepChat.
+6. The confirmation view states exactly which target categories will be replaced.
+7. DeepChat pauses conflicting YoBrowser mutations, applies the staged data, verifies, and reloads
+ affected tabs.
+8. The result shows counts and stable error codes, never secret values or source URLs beyond what
+ the user selected.
+9. Running the flow again repeats the same source-authoritative operation.
+
+There is no schedule or background watcher in V1.
+
+## Import States
+
+The renderer may display these stable states:
+
+- `idle`
+- `scanning`
+- `previewing`
+- `ready`
+- `applying`
+- `verifying`
+- `rolling_back`
+- `succeeded`
+- `failed`
+- `cancelled`
+
+Cancellation is allowed before target mutation. After mutation starts, the operation must finish or
+roll back rather than stop halfway.
+
+## Security and Privacy Requirements
+
+- Source paths must be canonicalized and restricted to discovered/explicitly selected profiles.
+- Symlinks and path traversal must not escape the selected profile root.
+- Source databases and LevelDB files are opened read-only.
+- Temporary snapshots use a mode-`0700` directory and are always removed after success, failure, or
+ startup recovery.
+- Decrypted cookie/password values are never logged, serialized to renderer state, included in
+ exceptions, copied to the clipboard, or written to plaintext staging files.
+- Renderer contracts expose counts, capability, progress, and redacted failures only.
+- A source Keychain/keyring denial is a normal unsupported/denied result, not a retry loop.
+- DeepChat never receives or stores the password entered into an OS/source-browser authorization
+ surface.
+- The source profile is never opened as an Electron `Session`.
+- Import is blocked while another import or clear operation owns the target mutation lock.
+- Rollback data receives the same secret handling as source data.
+- Windows App-Bound sources fail capability detection before any key or cookie value is staged.
+
+## Failure Semantics
+
+Stable categories should include:
+
+- `browser_not_found`
+- `profile_not_found`
+- `source_browser_busy`
+- `source_schema_unsupported`
+- `source_snapshot_failed`
+- `key_access_denied`
+- `encryption_unsupported`
+- `record_decryption_failed`
+- `target_busy`
+- `target_apply_failed`
+- `target_verification_failed`
+- `target_rollback_failed`
+- `category_unsupported`
+
+If rollback fails, DeepChat must mark the target as requiring an explicit clear or re-import and
+must not report success.
+
+## Acceptance Criteria
+
+- The settings UI discovers and distinguishes multiple supported source profiles.
+- Every source/profile/category combination reports `ready`, `requires_action`, `experimental`, or
+ `unsupported` with a concrete reason.
+- Preview does not mutate the source or target.
+- A supported cookie sync can be repeated and produces source-authoritative target cookies.
+- After successful import and tab reload, transferable source sessions are available to YoBrowser;
+ sites with expired or device-bound sessions may still request login without invalidating the
+ import result.
+- Partitioned cookie fields are preserved when the target CDP version supports them; otherwise the
+ preview blocks rather than silently flattening them.
+- No target mutation occurs when source decryption or validation is incomplete.
+- A failed target apply restores the previous target cookie set and verifies the rollback.
+- Open YoBrowser tabs reload only after a successful apply.
+- Chrome/Arc files are never written.
+- Windows App-Bound cookies are not decrypted through a bypass.
+- Protected source access uses OS/source-browser authorization; DeepChat never collects the
+ authorization password itself.
+- `sessionStorage` and saved-password limitations are visible before confirmation.
+- Secret values never cross the main-process contract boundary.
+- Focused unit, integration, and fixture tests cover supported schema and platform combinations.
+- Format, i18n, lint, typecheck, and relevant tests pass after implementation.
+
+## Decision Gates
+
+Implementation should not begin until these product decisions are made:
+
+1. **Windows Chrome support (decided)**: current Chrome/Arc App-Bound data is unsupported. Do not
+ build a companion extension, privileged service, process-injection path, or reverse-engineered
+ decryption path. Revisit only if Windows or the source browser exposes a supported export API.
+2. **Delivery sequence**: recommendation is cookie-backed session portability as the first shipping
+ slice. Add `localStorage` after the CDP arbitrary-origin proof, then current-tab
+ `sessionStorage` handoff; these remain roadmap capabilities rather than discarded requirements.
+3. **Password sequencing**: passwords remain in the roadmap, but recommendation is a separate
+ credential-vault SDD after transferable session data because they do not contribute to an already
+ active site session.
+4. **Arc support label**: recommendation is experimental until sanitized macOS Arc fixtures prove
+ profile discovery and key access. Windows Arc remains outside V1 with Windows Chrome.
+
+Confirmed product requirements: import is user-initiated, source-authoritative, repeatable, and does
+not use an encryption bypass. V1 therefore has no startup/background synchronization.
+
+## Verified References
+
+- [Chromium user-data directory and profile locations](https://chromium.googlesource.com/chromium/src/+/main/docs/user_data_dir.md)
+- [Chromium persistent cookie-store schema and encrypted values](https://chromium.googlesource.com/chromium/src/+/main/net/extras/sqlite/sqlite_persistent_cookie_store.cc)
+- [Chromium OS Crypt contract](https://chromium.googlesource.com/chromium/src/+/HEAD/components/os_crypt/sync/README.md)
+- [Chromium ProfileManager lifecycle contract](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/chrome/browser/profiles/profile_manager.h)
+- [Chrome App-Bound Encryption on Windows](https://security.googleblog.com/2024/07/improving-security-of-chrome-cookies-on.html)
+- [Chromium App-Bound Encryption path validation](https://chromium.googlesource.com/chromium/src/+/main/chrome/browser/os_crypt/README.md)
+- [Chrome 136 remote-debugging restrictions](https://developer.chrome.com/blog/remote-debugging-port)
+- [thewh1teagle Chrome 130 App-Bound proof of concept](https://gist.github.com/thewh1teagle/d0bbc6bc678812e39cba74e1d407e5c7)
+- [Chrome DevTools Protocol Storage domain](https://chromedevtools.github.io/devtools-protocol/tot/Storage/)
+- [Chrome DevTools Protocol Network cookie parameters](https://chromedevtools.github.io/devtools-protocol/tot/Network/)
+- [Chrome DevTools Protocol DOMStorage domain](https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage/)
+- [Electron Session API](https://www.electronjs.org/docs/latest/api/session)
+- [Electron Cookies API](https://www.electronjs.org/docs/latest/api/cookies)
+- [Electron safeStorage API](https://www.electronjs.org/docs/latest/api/safe-storage)
+- [HTML Web Storage standard](https://html.spec.whatwg.org/multipage/webstorage.html)
+- [Arc profile behavior](https://resources.arc.net/hc/en-us/articles/19227964556183-Profiles-Separate-Work-Personal-Browsing)
+- [Chrome password export](https://support.google.com/chrome/answer/95606)
diff --git a/docs/features/browser-profile-import/tasks.md b/docs/features/browser-profile-import/tasks.md
new file mode 100644
index 0000000000..ea2a19d5ac
--- /dev/null
+++ b/docs/features/browser-profile-import/tasks.md
@@ -0,0 +1,98 @@
+# Browser Website Data and Session Import Tasks
+
+## Status
+
+V1 cookie-backed session import implemented. Packaged macOS/Arc fixture validation and deferred
+data categories remain open.
+
+## Completed Discovery
+
+- [x] Trace the current `persist:yo-browser` session ownership and clear-data flow.
+- [x] Confirm that Agent and standalone DeepChat browser views share the target session.
+- [x] Inspect the current local Chrome Cookies schema without reading or recording secret values.
+- [x] Verify current Electron public Session, Cookies, `safeStorage`, View, and CDP constraints.
+- [x] Record Chrome App-Bound Encryption and remote-debugging restrictions.
+- [x] Evaluate the referenced Chrome 130 `SYSTEM`/hard-coded-key proof of concept and reject its
+ App-Bound bypass while retaining only neutral schema and snapshot lessons.
+- [x] Separate cookies, `localStorage`, `sessionStorage`, passwords, and non-transferable credentials
+ into honest capability categories.
+- [x] Write the proposal, implementation plan, risks, acceptance criteria, and decision gates.
+
+## Product Decisions Required Before Implementation
+
+- [x] Keep current Windows Chrome/Arc App-Bound data unsupported; do not build a companion extension
+ or privileged/reverse-engineered decryption path.
+- [x] Confirm V1 session portability is cookie-backed, subject to feasibility proofs.
+- [x] Keep passwords in the roadmap through a separate credential-vault proposal.
+- [x] Confirm Arc is labeled experimental until fixture validation passes.
+- [x] Keep synchronization explicitly user-triggered, not scheduled/background.
+- [x] Require OS/source-browser authorization and prohibit encryption bypasses.
+- [x] Decide whether target scope is always the entire global YoBrowser session or may be limited to
+ selected domains in a later release.
+
+## Feasibility Gates
+
+- [ ] Build sanitized Chrome cookie fixtures for each supported source schema.
+- [ ] Prove consistent SQLite snapshot behavior with Chrome open and closed.
+- [ ] Prove packaged macOS Chrome system-owned authorization, key access, decryption, and denial
+ handling without DeepChat receiving the authorization password.
+- [ ] Prove CDP target set/readback for all supported cookie attributes.
+- [ ] Prove partitioned-cookie round trip for the bundled Electron Chromium version.
+- [ ] Prove full target-cookie rollback after injected failures.
+- [ ] Collect and validate sanitized Arc fixtures on every proposed Arc platform.
+- [ ] If `localStorage` remains proposed, prove inactive-origin clear/write/readback before adding it
+ to the release scope.
+
+## Phase 1: Main-Process Cookie Core
+
+- [x] Add deterministic known-location browser/profile discovery.
+- [x] Add canonical path and source-profile validation.
+- [ ] Add a private snapshot workspace with crash/startup cleanup.
+- [x] Add the selected Chrome source schema reader.
+- [x] Add the selected OS key-access/decryption adapter.
+- [x] Ensure protected authorization is rendered by the OS/source browser, never a DeepChat
+ password form.
+- [x] Add versioned cookie normalization and validation.
+- [x] Add stable, redacted error codes.
+- [x] Add one target mutation coordinator shared with clear-sandbox data.
+- [x] Add target snapshot, clear, batch apply, readback, and normalized comparison for
+ non-partitioned cookies.
+- [x] Add rollback handling.
+- [x] Flush the target cookie store and reload open YoBrowser tabs only after verified success.
+- [x] Add unit and main-process integration tests for decryption, replacement, verification, and
+ rollback.
+
+## Phase 2: Contracts and Settings UX
+
+- [x] Add shared schemas for scan, preview, and apply.
+- [x] Add main routes and client exposure through existing patterns.
+- [ ] Extend the YoBrowser settings card with last-sync metadata.
+- [x] Add the source/profile/category selection dialog using existing shadcn-vue primitives.
+- [x] Add preview counts and capability reasons.
+- [x] Add source-authoritative replacement confirmation.
+- [ ] Add apply/verify/rollback progress and final result UX.
+- [ ] Prevent cancellation after target mutation starts.
+- [x] Add accessible labels, keyboard behavior, and i18n strings.
+- [ ] Add renderer tests for state, stale tokens, failures, and secret redaction.
+
+## Phase 3: Platform and Release Validation
+
+- [ ] Test signed/notarized application builds on every advertised platform.
+- [ ] Test multiple source profiles and browser-running states.
+- [ ] Test source schema/version rejection with actionable UI.
+- [ ] Test import/clear contention and app shutdown during apply.
+- [ ] Test temporary-data removal after success, failure, crash, and restart.
+- [ ] Audit logs, telemetry, renderer state, crash reports, and errors for secret leakage.
+- [ ] Verify authorization passwords never enter DeepChat IPC, memory fields, logs, or telemetry.
+- [x] Run `pnpm run format`.
+- [x] Run `pnpm run i18n`.
+- [x] Run `pnpm run lint`.
+- [x] Run typecheck, build, focused suites, and the full main/renderer test suite.
+- [ ] Update user documentation with the exact support matrix and limitations.
+
+## Deferred, Separately Approved Work
+
+- [ ] Add `localStorage` only after its feasibility gate passes.
+- [ ] Design live-tab `sessionStorage` handoff as a separate flow.
+- [ ] Write a separate SDD for an origin-bound credential vault if password autofill is approved.
+- [ ] Evaluate additional browsers only with explicit discovery, crypto, schema, and fixture support.
diff --git a/resources/acp-registry/registry.json b/resources/acp-registry/registry.json
index 3ccb406df5..ac60011f61 100644
--- a/resources/acp-registry/registry.json
+++ b/resources/acp-registry/registry.json
@@ -122,7 +122,7 @@
{
"id": "cline",
"name": "Cline",
- "version": "3.0.42",
+ "version": "3.0.44",
"description": "Autonomous coding agent CLI - capable of creating/editing files, running commands, using the browser, and more",
"repository": "https://github.com/cline/cline",
"website": "https://cline.bot/cli",
@@ -133,7 +133,7 @@
"icon": "https://cdn.agentclientprotocol.com/registry/v1/latest/cline.svg",
"distribution": {
"npx": {
- "package": "cline@3.0.42",
+ "package": "cline@3.0.44",
"args": [
"--acp"
]
@@ -508,7 +508,7 @@
{
"id": "factory-droid",
"name": "Factory Droid",
- "version": "0.173.0",
+ "version": "0.174.0",
"description": "Factory Droid - AI coding agent powered by Factory AI",
"website": "https://factory.ai/product/cli",
"authors": [
@@ -517,7 +517,7 @@
"license": "proprietary",
"distribution": {
"npx": {
- "package": "droid@0.173.0",
+ "package": "droid@0.174.0",
"args": [
"exec",
"--output-format",
@@ -534,7 +534,7 @@
{
"id": "fast-agent",
"name": "fast-agent",
- "version": "0.9.10",
+ "version": "0.9.14",
"description": "Code and build agents with comprehensive multi-provider support",
"repository": "https://github.com/evalstate/fast-agent",
"website": "https://fast-agent.ai",
@@ -544,7 +544,7 @@
"license": "Apache 2.0",
"distribution": {
"uvx": {
- "package": "fast-agent-acp==0.9.10",
+ "package": "fast-agent-acp==0.9.14",
"args": [
"-x"
]
@@ -555,7 +555,7 @@
{
"id": "gemini",
"name": "Gemini CLI",
- "version": "0.50.0",
+ "version": "0.51.0",
"description": "Google's official CLI for Gemini",
"repository": "https://github.com/google-gemini/gemini-cli",
"website": "https://geminicli.com",
@@ -565,7 +565,7 @@
"license": "Apache-2.0",
"distribution": {
"npx": {
- "package": "@google/gemini-cli@0.50.0",
+ "package": "@google/gemini-cli@0.51.0",
"args": [
"--acp"
]
@@ -671,7 +671,7 @@
{
"id": "grok-build",
"name": "Grok Build",
- "version": "0.2.101",
+ "version": "0.2.102",
"description": "xAI's coding agent and CLI",
"website": "https://x.ai/cli",
"authors": [
@@ -680,7 +680,7 @@
"license": "proprietary",
"distribution": {
"npx": {
- "package": "@xai-official/grok@0.2.101",
+ "package": "@xai-official/grok@0.2.102",
"args": [
"agent",
"stdio"
@@ -692,7 +692,7 @@
{
"id": "harn",
"name": "Harn",
- "version": "0.10.19",
+ "version": "0.10.22",
"description": "Harn runs .harn agent pipelines as a native ACP coding agent over stdio.",
"repository": "https://github.com/burin-labs/harn",
"website": "https://harnlang.com",
@@ -703,49 +703,49 @@
"distribution": {
"binary": {
"darwin-aarch64": {
- "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.19/harn-aarch64-apple-darwin.tar.gz",
+ "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.22/harn-aarch64-apple-darwin.tar.gz",
"cmd": "./harn",
"args": [
"serve",
"acp"
],
- "sha256": "05ba15c0cc05a9afa8a05182c0893b02a50242f8cd804005850a331e6155394a"
+ "sha256": "ee2d2fb2172d893c656848b8c25c4b527b162c03cac9931667f6da4d7bc8da07"
},
"darwin-x86_64": {
- "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.19/harn-x86_64-apple-darwin.tar.gz",
+ "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.22/harn-x86_64-apple-darwin.tar.gz",
"cmd": "./harn",
"args": [
"serve",
"acp"
],
- "sha256": "9804e91ce510c51a32e8c801a2865575c3091e577ff8c43aa5e2a67f16484959"
+ "sha256": "6a984d21eb6102bc9993ab89169a2acdc207e453ed88ef09157f1c6d4ed593b5"
},
"linux-aarch64": {
- "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.19/harn-aarch64-unknown-linux-gnu.tar.gz",
+ "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.22/harn-aarch64-unknown-linux-gnu.tar.gz",
"cmd": "./harn",
"args": [
"serve",
"acp"
],
- "sha256": "718ba0a9d42c9f1155bd27d183a6e314900c5829e202d41195545c6071f47033"
+ "sha256": "5d1d16000915e5d20cba00c794581890a44dccf5365a7ee729bc7248a37fddcf"
},
"linux-x86_64": {
- "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.19/harn-x86_64-unknown-linux-gnu.tar.gz",
+ "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.22/harn-x86_64-unknown-linux-gnu.tar.gz",
"cmd": "./harn",
"args": [
"serve",
"acp"
],
- "sha256": "5e1114e04105541a7d456ce6c20c031929b27471c271da34aa8dd9357c0b6122"
+ "sha256": "ac36baa6ddf61e64ee5d499be8c35b461527756f5006dbab333bc518d7ce6fca"
},
"windows-x86_64": {
- "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.19/harn-x86_64-pc-windows-msvc.zip",
+ "archive": "https://github.com/burin-labs/harn/releases/download/v0.10.22/harn-x86_64-pc-windows-msvc.zip",
"cmd": "harn.exe",
"args": [
"serve",
"acp"
],
- "sha256": "ef8bb6b5643071cb482fa44bb56729df9af1a49d9212dcd9852ea817d051fe14"
+ "sha256": "352727aa4be51be711a70838df0f30856b5e6ef79014737d3ebeb867d4b128c4"
}
}
},
@@ -806,7 +806,7 @@
{
"id": "kilo",
"name": "Kilo",
- "version": "7.4.9",
+ "version": "7.4.11",
"description": "The open source coding agent",
"repository": "https://github.com/Kilo-Org/kilocode",
"website": "https://kilo.ai/",
@@ -818,48 +818,48 @@
"distribution": {
"binary": {
"darwin-aarch64": {
- "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.9/kilo-darwin-arm64.zip",
+ "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.11/kilo-darwin-arm64.zip",
"cmd": "./kilo",
"args": [
"acp"
],
- "sha256": "a3fab28d5b97f6d0b297f2d12302e2664344b7fcee3ccc9adc3a84db0be15c96"
+ "sha256": "14a030a354f3b51f0241662627702e7b06cddf3fcb6e0f1415279e9d3a3b8998"
},
"darwin-x86_64": {
- "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.9/kilo-darwin-x64.zip",
+ "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.11/kilo-darwin-x64.zip",
"cmd": "./kilo",
"args": [
"acp"
],
- "sha256": "cf6fe6bc77e63bbdf387e34fc31d1aa86a603b6de48011a86ffdc28708bc1453"
+ "sha256": "66e302e09b96fd9794012bdb608622b589e4810ba31eca35918d8acd1a32a438"
},
"linux-aarch64": {
- "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.9/kilo-linux-arm64.tar.gz",
+ "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.11/kilo-linux-arm64.tar.gz",
"cmd": "./kilo",
"args": [
"acp"
],
- "sha256": "e0c4ff2ec2f65689406c43e6aff06cea30be8d12ed7193e1ed46a0e0e28d86fd"
+ "sha256": "48c5405eb05efb3558d120b521d1a2b097cd8e99d36d7caf015e7c467922793c"
},
"linux-x86_64": {
- "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.9/kilo-linux-x64.tar.gz",
+ "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.11/kilo-linux-x64.tar.gz",
"cmd": "./kilo",
"args": [
"acp"
],
- "sha256": "0d3fc944dbf2b987ce9953d5c4701dbdc950b0905a186c814a24e8915fd7012c"
+ "sha256": "b060dd4e094b0f9966de03d8a0d0d5cc8e6bb23ab04f1d04b7e3951d13079770"
},
"windows-x86_64": {
- "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.9/kilo-windows-x64.zip",
+ "archive": "https://github.com/Kilo-Org/kilocode/releases/download/v7.4.11/kilo-windows-x64.zip",
"cmd": "./kilo.exe",
"args": [
"acp"
],
- "sha256": "2452f063e6149bffca64e862ae5b2063fe2be6a14200012f92743a8d1a3b4c0c"
+ "sha256": "1c04d25b1484526b1eb8abe44bbcfc179fb71b1efa88b0164cd5709ca8bb00e7"
}
},
"npx": {
- "package": "@kilocode/cli@7.4.9",
+ "package": "@kilocode/cli@7.4.11",
"args": [
"acp"
]
@@ -869,7 +869,7 @@
{
"id": "kimi",
"name": "Kimi CLI",
- "version": "1.48.0",
+ "version": "1.49.0",
"description": "Moonshot AI's coding assistant",
"repository": "https://github.com/MoonshotAI/kimi-cli",
"website": "https://moonshotai.github.io/kimi-cli/",
@@ -880,39 +880,44 @@
"distribution": {
"binary": {
"darwin-aarch64": {
- "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.48.0/kimi-1.48.0-aarch64-apple-darwin.tar.gz",
+ "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.49.0/kimi-1.49.0-aarch64-apple-darwin.tar.gz",
"cmd": "./kimi",
"args": [
"acp"
- ]
+ ],
+ "sha256": "15018b20b203aee09658fdc64840c4846fc17c108d8dba1a19a95581d3ce2921"
},
"linux-aarch64": {
- "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.48.0/kimi-1.48.0-aarch64-unknown-linux-gnu.tar.gz",
+ "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.49.0/kimi-1.49.0-aarch64-unknown-linux-gnu.tar.gz",
"cmd": "./kimi",
"args": [
"acp"
- ]
+ ],
+ "sha256": "5ac54cabce16ede27b9d2069b9b88edee25528646e7bb5befa9980a1ca71febb"
},
"linux-x86_64": {
- "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.48.0/kimi-1.48.0-x86_64-unknown-linux-gnu.tar.gz",
+ "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.49.0/kimi-1.49.0-x86_64-unknown-linux-gnu.tar.gz",
"cmd": "./kimi",
"args": [
"acp"
- ]
+ ],
+ "sha256": "6ce0b83f583c45a64cc9f51ffe7e1a8e03ee79acda69945fcf8c23341b9d892f"
},
"windows-aarch64": {
- "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.48.0/kimi-1.48.0-aarch64-pc-windows-msvc.zip",
+ "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.49.0/kimi-1.49.0-aarch64-pc-windows-msvc.zip",
"cmd": "./kimi.exe",
"args": [
"acp"
- ]
+ ],
+ "sha256": "3ac8f05c7bd18d902a324c6c03a71084cfbe785b9669bbd556c071ee1d8f2f26"
},
"windows-x86_64": {
- "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.48.0/kimi-1.48.0-x86_64-pc-windows-msvc.zip",
+ "archive": "https://github.com/MoonshotAI/kimi-cli/releases/download/1.49.0/kimi-1.49.0-x86_64-pc-windows-msvc.zip",
"cmd": "./kimi.exe",
"args": [
"acp"
- ]
+ ],
+ "sha256": "2acbbc7ca8c8ac4b03dab1d970f53a292bd226168151b423499feab9fc203ddd"
}
}
},
@@ -1004,7 +1009,7 @@
{
"id": "opencode",
"name": "OpenCode",
- "version": "1.18.2",
+ "version": "1.18.3",
"description": "The open source coding agent",
"repository": "https://github.com/anomalyco/opencode",
"website": "https://opencode.ai",
@@ -1016,52 +1021,52 @@
"distribution": {
"binary": {
"darwin-aarch64": {
- "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.2/opencode-darwin-arm64.zip",
+ "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.3/opencode-darwin-arm64.zip",
"cmd": "./opencode",
"args": [
"acp"
],
- "sha256": "2cb1eb3301a73598890364dfeb45c535155a3855b37ed1d190172821e74e462c"
+ "sha256": "946f62b155638b911144b7bef520ee4a6442f696297907873463bca3524e40ef"
},
"darwin-x86_64": {
- "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.2/opencode-darwin-x64.zip",
+ "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.3/opencode-darwin-x64.zip",
"cmd": "./opencode",
"args": [
"acp"
],
- "sha256": "3672491ae6383468be40e54ee5c6fcbac354eb5cfb7c6afbd0ee3ae0c6af4b2e"
+ "sha256": "4ea147867ba19e4ec03559df557811f1674f40788aea4d10326dc563b7667c6d"
},
"linux-aarch64": {
- "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.2/opencode-linux-arm64.tar.gz",
+ "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.3/opencode-linux-arm64.tar.gz",
"cmd": "./opencode",
"args": [
"acp"
],
- "sha256": "93352b30d37d8da2e5c226085f1afbf37cf57cfcecedc813520ff2d0f8581540"
+ "sha256": "da0a631174eba380b2a1d51f9d364fa3812da433e72743c72471d4b5da59c69d"
},
"linux-x86_64": {
- "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.2/opencode-linux-x64.tar.gz",
+ "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.3/opencode-linux-x64.tar.gz",
"cmd": "./opencode",
"args": [
"acp"
],
- "sha256": "97c95e004bb73d2039f957ea33be0635ea4e22b8dceaedf8f0983765950cf1b6"
+ "sha256": "60f27b2679f00a511b6539f97e02448afaf58d9c66e2448285ea0c517ca84583"
},
"windows-aarch64": {
- "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.2/opencode-windows-arm64.zip",
+ "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.3/opencode-windows-arm64.zip",
"cmd": "./opencode",
"args": [
"acp"
],
- "sha256": "7eb407240101a0ebca9acb99ed819a09a4211fdafa381161af6ca49f85736e4b"
+ "sha256": "a549fb2e9041db9438bcd9b77bfa0a4b2476caf2d550f37479aabfec1b079bfb"
},
"windows-x86_64": {
- "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.2/opencode-windows-x64.zip",
+ "archive": "https://github.com/anomalyco/opencode/releases/download/v1.18.3/opencode-windows-x64.zip",
"cmd": "./opencode.exe",
"args": [
"acp"
],
- "sha256": "aca23b18d03639c6bd576a2dd23cebfa6dab80d31358f17cfa03fd1f2a5c41fd"
+ "sha256": "68bc62930f6cb5755e0409aa9de0bb270a66ed2b8c9cf0c029e9f2287ed5486e"
}
}
}
@@ -1165,7 +1170,7 @@
{
"id": "qwen-code",
"name": "Qwen Code",
- "version": "0.19.10",
+ "version": "0.19.11",
"description": "Alibaba's Qwen coding assistant",
"repository": "https://github.com/QwenLM/qwen-code",
"website": "https://qwenlm.github.io/qwen-code-docs/en/users/overview",
@@ -1175,7 +1180,7 @@
"license": "Apache-2.0",
"distribution": {
"npx": {
- "package": "@qwen-code/qwen-code@0.19.10",
+ "package": "@qwen-code/qwen-code@0.19.11",
"args": [
"--acp",
"--experimental-skills"
diff --git a/resources/model-db/providers.json b/resources/model-db/providers.json
index 29764373e1..0370d123a8 100644
--- a/resources/model-db/providers.json
+++ b/resources/model-db/providers.json
@@ -493,9 +493,9 @@
"release_date": "2026-05-29",
"last_updated": "2026-05-29",
"cost": {
- "input": 0.2,
- "output": 1.15,
- "cache_read": 0.04,
+ "input": 0.19,
+ "output": 1.14,
+ "cache_read": 0.03,
"cache_write": 0
},
"type": "chat"
@@ -614,9 +614,9 @@
"release_date": "2026-06-12",
"last_updated": "2026-06-12",
"cost": {
- "input": 0.719,
- "output": 3.49,
- "cache_read": 0.149,
+ "input": 0.75,
+ "output": 3.5,
+ "cache_read": 0.16,
"cache_write": 0
},
"type": "chat"
@@ -37554,6 +37554,42 @@
},
"type": "chat"
},
+ {
+ "id": "k3",
+ "name": "Kimi K3",
+ "display_name": "Kimi K3",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "video"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 131072
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "attachment": false,
+ "open_weights": true,
+ "release_date": "2026-07-16",
+ "last_updated": "2026-07-16",
+ "cost": {
+ "input": 0,
+ "output": 0,
+ "cache_read": 0,
+ "cache_write": 0
+ },
+ "type": "chat"
+ },
{
"id": "k2p6",
"name": "Kimi K2.6",
@@ -40434,6 +40470,43 @@
},
"type": "chat"
},
+ {
+ "id": "zai-org/GLM-5.2",
+ "name": "GLM-5.2",
+ "display_name": "GLM-5.2",
+ "modalities": {
+ "input": [
+ "text"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 131072
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "attachment": false,
+ "open_weights": true,
+ "release_date": "2026-06-13",
+ "last_updated": "2026-06-13",
+ "cost": {
+ "input": 1.4375,
+ "output": 5.75
+ },
+ "type": "chat"
+ },
{
"id": "mistralai/Mistral-Medium-3.5-128B",
"name": "Mistral Medium 3.5",
@@ -75663,6 +75736,47 @@
},
"type": "chat"
},
+ {
+ "id": "kimi-k3",
+ "name": "Kimi K3",
+ "display_name": "Kimi K3",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "video"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 131072
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true,
+ "interleaved": true,
+ "summaries": true,
+ "visibility": "summary",
+ "continuation": [
+ "thinking_blocks"
+ ]
+ }
+ },
+ "attachment": true,
+ "open_weights": true,
+ "release_date": "2026-07-16",
+ "last_updated": "2026-07-16",
+ "type": "chat"
+ },
{
"id": "kimi-k2.7-code-highspeed",
"name": "Kimi K2.7 Code Highspeed",
@@ -120641,6 +120755,62 @@
}
]
},
+ "thinkingmachines": {
+ "id": "thinkingmachines",
+ "name": "Thinking Machines",
+ "display_name": "Thinking Machines",
+ "api": "https://tinker.thinkingmachines.dev/services/tinker-prod/oai/api/v1",
+ "doc": "https://tinker-docs.thinkingmachines.ai/tinker/compatible-apis/openai/",
+ "models": [
+ {
+ "id": "inkling",
+ "name": "Inkling",
+ "display_name": "Inkling",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "audio",
+ "pdf"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 256000,
+ "output": 256000
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true,
+ "interleaved": true,
+ "summaries": true,
+ "visibility": "summary",
+ "continuation": [
+ "thinking_blocks"
+ ]
+ }
+ },
+ "attachment": true,
+ "open_weights": true,
+ "release_date": "2026-07-15",
+ "last_updated": "2026-07-15",
+ "cost": {
+ "input": 3.74,
+ "output": 9.36,
+ "cache_read": 0.748
+ },
+ "type": "chat"
+ }
+ ]
+ },
"nebius": {
"id": "nebius",
"name": "Nebius Token Factory",
@@ -129318,54 +129488,9 @@
"type": "chat"
},
{
- "id": "deepseek-v4-flash",
- "name": "DeepSeek V4 Flash",
- "display_name": "DeepSeek V4 Flash",
- "modalities": {
- "input": [
- "text"
- ],
- "output": [
- "text"
- ]
- },
- "limit": {
- "context": 1000000,
- "output": 384000
- },
- "temperature": true,
- "tool_call": true,
- "reasoning": {
- "supported": true,
- "default": true
- },
- "extra_capabilities": {
- "reasoning": {
- "supported": true,
- "interleaved": true,
- "summaries": true,
- "visibility": "summary",
- "continuation": [
- "thinking_blocks"
- ]
- }
- },
- "attachment": false,
- "open_weights": true,
- "knowledge": "2025-05",
- "release_date": "2026-04-24",
- "last_updated": "2026-04-24",
- "cost": {
- "input": 0.14,
- "output": 0.28,
- "cache_read": 0.0028
- },
- "type": "chat"
- },
- {
- "id": "qwen3.5-plus",
- "name": "Qwen3.5 Plus",
- "display_name": "Qwen3.5 Plus",
+ "id": "kimi-k3",
+ "name": "Kimi K3",
+ "display_name": "Kimi K3",
"modalities": {
"input": [
"text",
@@ -129377,8 +129502,8 @@
]
},
"limit": {
- "context": 262144,
- "output": 65536
+ "context": 1048576,
+ "output": 131072
},
"temperature": true,
"tool_call": true,
@@ -129398,22 +129523,20 @@
}
},
"attachment": true,
- "open_weights": false,
- "knowledge": "2025-04",
- "release_date": "2026-02-16",
- "last_updated": "2026-02-16",
+ "open_weights": true,
+ "release_date": "2026-07-16",
+ "last_updated": "2026-07-16",
"cost": {
- "input": 0.2,
- "output": 1.2,
- "cache_read": 0.02,
- "cache_write": 0.25
+ "input": 3,
+ "output": 15,
+ "cache_read": 0.3
},
"type": "chat"
},
{
- "id": "mimo-v2-pro",
- "name": "MiMo V2 Pro",
- "display_name": "MiMo V2 Pro",
+ "id": "deepseek-v4-flash",
+ "name": "DeepSeek V4 Flash",
+ "display_name": "DeepSeek V4 Flash",
"modalities": {
"input": [
"text"
@@ -129423,8 +129546,8 @@
]
},
"limit": {
- "context": 1048576,
- "output": 128000
+ "context": 1000000,
+ "output": 384000
},
"temperature": true,
"tool_call": true,
@@ -129443,38 +129566,186 @@
]
}
},
- "attachment": true,
+ "attachment": false,
"open_weights": true,
- "knowledge": "2024-12",
- "release_date": "2026-03-18",
- "last_updated": "2026-03-18",
+ "knowledge": "2025-05",
+ "release_date": "2026-04-24",
+ "last_updated": "2026-04-24",
"cost": {
- "input": 1,
- "output": 3,
- "cache_read": 0.2,
- "tiers": [
- {
- "input": 2,
- "output": 6,
- "cache_read": 0.4,
- "tier": {
- "type": "context",
- "size": 256000
- }
- }
- ],
- "context_over_200k": {
- "input": 2,
- "output": 6,
- "cache_read": 0.4
- }
+ "input": 0.14,
+ "output": 0.28,
+ "cache_read": 0.0028
},
"type": "chat"
},
{
- "id": "kimi-k2.6",
- "name": "Kimi K2.6",
- "display_name": "Kimi K2.6",
+ "id": "qwen3.5-plus",
+ "name": "Qwen3.5 Plus",
+ "display_name": "Qwen3.5 Plus",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "video"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 262144,
+ "output": 65536
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true,
+ "interleaved": true,
+ "summaries": true,
+ "visibility": "summary",
+ "continuation": [
+ "thinking_blocks"
+ ]
+ }
+ },
+ "attachment": true,
+ "open_weights": false,
+ "knowledge": "2025-04",
+ "release_date": "2026-02-16",
+ "last_updated": "2026-02-16",
+ "cost": {
+ "input": 0.2,
+ "output": 1.2,
+ "cache_read": 0.02,
+ "cache_write": 0.25
+ },
+ "type": "chat"
+ },
+ {
+ "id": "grok-4.5",
+ "name": "Grok 4.5",
+ "display_name": "Grok 4.5",
+ "modalities": {
+ "input": [
+ "text",
+ "image"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 500000,
+ "output": 500000
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "attachment": true,
+ "open_weights": false,
+ "release_date": "2026-07-08",
+ "last_updated": "2026-07-08",
+ "cost": {
+ "input": 2,
+ "output": 6,
+ "cache_read": 0.5,
+ "tiers": [
+ {
+ "input": 4,
+ "output": 12,
+ "cache_read": 1,
+ "tier": {
+ "type": "context",
+ "size": 200000
+ }
+ }
+ ],
+ "context_over_200k": {
+ "input": 4,
+ "output": 12,
+ "cache_read": 1
+ }
+ },
+ "type": "chat"
+ },
+ {
+ "id": "mimo-v2-pro",
+ "name": "MiMo V2 Pro",
+ "display_name": "MiMo V2 Pro",
+ "modalities": {
+ "input": [
+ "text"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 128000
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true,
+ "interleaved": true,
+ "summaries": true,
+ "visibility": "summary",
+ "continuation": [
+ "thinking_blocks"
+ ]
+ }
+ },
+ "attachment": true,
+ "open_weights": true,
+ "knowledge": "2024-12",
+ "release_date": "2026-03-18",
+ "last_updated": "2026-03-18",
+ "cost": {
+ "input": 1,
+ "output": 3,
+ "cache_read": 0.2,
+ "tiers": [
+ {
+ "input": 2,
+ "output": 6,
+ "cache_read": 0.4,
+ "tier": {
+ "type": "context",
+ "size": 256000
+ }
+ }
+ ],
+ "context_over_200k": {
+ "input": 2,
+ "output": 6,
+ "cache_read": 0.4
+ }
+ },
+ "type": "chat"
+ },
+ {
+ "id": "kimi-k2.6",
+ "name": "Kimi K2.6",
+ "display_name": "Kimi K2.6",
"modalities": {
"input": [
"text",
@@ -156277,6 +156548,47 @@
},
"type": "chat"
},
+ {
+ "id": "kimi-k3",
+ "name": "Kimi K3",
+ "display_name": "Kimi K3",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "video"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 131072
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true,
+ "interleaved": true,
+ "summaries": true,
+ "visibility": "summary",
+ "continuation": [
+ "thinking_blocks"
+ ]
+ }
+ },
+ "attachment": true,
+ "open_weights": true,
+ "release_date": "2026-07-16",
+ "last_updated": "2026-07-16",
+ "type": "chat"
+ },
{
"id": "kimi-k2-thinking",
"name": "Kimi K2 Thinking",
@@ -158404,8 +158716,8 @@
]
},
"limit": {
- "context": 1048576,
- "output": 1048576
+ "context": 256000,
+ "output": 256000
},
"temperature": true,
"tool_call": true,
@@ -175414,8 +175726,7 @@
"display_name": "MiMo V2.5 Pro",
"modalities": {
"input": [
- "text",
- "pdf"
+ "text"
],
"output": [
"text"
@@ -176649,36 +176960,44 @@
"type": "chat"
},
{
- "id": "recraft/recraft-v4.1-utility",
- "name": "Recraft V4.1 Utility",
- "display_name": "Recraft V4.1 Utility",
+ "id": "thinkingmachines/inkling",
+ "name": "Inkling",
+ "display_name": "Inkling",
"modalities": {
"input": [
- "text"
+ "text",
+ "image",
+ "pdf"
],
"output": [
- "image"
+ "text"
]
},
"limit": {
- "context": 8192,
- "output": 8192
+ "context": 256000,
+ "output": 256000
},
"temperature": true,
- "tool_call": false,
+ "tool_call": true,
"reasoning": {
- "supported": false
+ "supported": true,
+ "default": true
+ },
+ "attachment": true,
+ "open_weights": true,
+ "release_date": "2026-07-15",
+ "last_updated": "2026-07-15",
+ "cost": {
+ "input": 1,
+ "output": 4.05,
+ "cache_read": 0.17
},
- "attachment": false,
- "open_weights": false,
- "release_date": "2026-05-14",
- "last_updated": "2026-05-14",
"type": "chat"
},
{
- "id": "recraft/recraft-v4",
- "name": "Recraft V4",
- "display_name": "Recraft V4",
+ "id": "recraft/recraft-v4.1-utility",
+ "name": "Recraft V4.1 Utility",
+ "display_name": "Recraft V4.1 Utility",
"modalities": {
"input": [
"text"
@@ -176698,14 +177017,14 @@
},
"attachment": false,
"open_weights": false,
- "release_date": "2026-02-17",
- "last_updated": "2026-02-17",
+ "release_date": "2026-05-14",
+ "last_updated": "2026-05-14",
"type": "chat"
},
{
- "id": "recraft/recraft-v4.1-utility-pro",
- "name": "Recraft V4.1 Utility Pro",
- "display_name": "Recraft V4.1 Utility Pro",
+ "id": "recraft/recraft-v4",
+ "name": "Recraft V4",
+ "display_name": "Recraft V4",
"modalities": {
"input": [
"text"
@@ -176725,14 +177044,41 @@
},
"attachment": false,
"open_weights": false,
- "release_date": "2026-05-14",
- "last_updated": "2026-05-14",
+ "release_date": "2026-02-17",
+ "last_updated": "2026-02-17",
"type": "chat"
},
{
- "id": "recraft/recraft-v4.1-pro",
- "name": "Recraft V4.1 Pro",
- "display_name": "Recraft V4.1 Pro",
+ "id": "recraft/recraft-v4.1-utility-pro",
+ "name": "Recraft V4.1 Utility Pro",
+ "display_name": "Recraft V4.1 Utility Pro",
+ "modalities": {
+ "input": [
+ "text"
+ ],
+ "output": [
+ "image"
+ ]
+ },
+ "limit": {
+ "context": 8192,
+ "output": 8192
+ },
+ "temperature": true,
+ "tool_call": false,
+ "reasoning": {
+ "supported": false
+ },
+ "attachment": false,
+ "open_weights": false,
+ "release_date": "2026-05-14",
+ "last_updated": "2026-05-14",
+ "type": "chat"
+ },
+ {
+ "id": "recraft/recraft-v4.1-pro",
+ "name": "Recraft V4.1 Pro",
+ "display_name": "Recraft V4.1 Pro",
"modalities": {
"input": [
"text"
@@ -177673,6 +178019,69 @@
},
"type": "chat"
},
+ {
+ "id": "anthropic/claude-opus-4.8-fast",
+ "name": "Claude Opus 4.8 (Fast)",
+ "display_name": "Claude Opus 4.8 (Fast)",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "pdf"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1000000,
+ "output": 128000
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": false
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true,
+ "default_enabled": false,
+ "mode": "effort",
+ "effort": "high",
+ "effort_options": [
+ "low",
+ "medium",
+ "high",
+ "xhigh",
+ "max"
+ ],
+ "interleaved": true,
+ "summaries": true,
+ "visibility": "omitted",
+ "continuation": [
+ "thinking_blocks"
+ ],
+ "notes": [
+ "Claude Opus 4.7 and newer Opus models require thinking.type = \"adaptive\" to enable thinking explicitly.",
+ "Manual budget_tokens requests return 400 on Claude Opus 4.7 and newer adaptive-only Opus models.",
+ "task_budget is separate from thinking control and should not be treated as a thinking budget."
+ ]
+ }
+ },
+ "attachment": true,
+ "open_weights": false,
+ "knowledge": "2026-01",
+ "release_date": "2026-05-28",
+ "last_updated": "2026-05-28",
+ "cost": {
+ "input": 10,
+ "output": 50,
+ "cache_read": 1,
+ "cache_write": 12.5
+ },
+ "type": "chat"
+ },
{
"id": "anthropic/claude-opus-4.8",
"name": "Claude Opus 4.8",
@@ -178202,6 +178611,69 @@
},
"type": "chat"
},
+ {
+ "id": "anthropic/claude-opus-4.7-fast",
+ "name": "Claude Opus 4.7 (Fast)",
+ "display_name": "Claude Opus 4.7 (Fast)",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "pdf"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1000000,
+ "output": 128000
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": false
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true,
+ "default_enabled": false,
+ "mode": "effort",
+ "effort": "high",
+ "effort_options": [
+ "low",
+ "medium",
+ "high",
+ "xhigh",
+ "max"
+ ],
+ "interleaved": true,
+ "summaries": true,
+ "visibility": "omitted",
+ "continuation": [
+ "thinking_blocks"
+ ],
+ "notes": [
+ "Claude Opus 4.7 and newer Opus models require thinking.type = \"adaptive\" to enable thinking explicitly.",
+ "Manual budget_tokens requests return 400 on Claude Opus 4.7 and newer adaptive-only Opus models.",
+ "task_budget is separate from thinking control and should not be treated as a thinking budget."
+ ]
+ }
+ },
+ "attachment": true,
+ "open_weights": false,
+ "knowledge": "2026-01-31",
+ "release_date": "2026-04-16",
+ "last_updated": "2026-04-16",
+ "cost": {
+ "input": 30,
+ "output": 150,
+ "cache_read": 3,
+ "cache_write": 37.5
+ },
+ "type": "chat"
+ },
{
"id": "anthropic/claude-opus-4.1",
"name": "Claude Opus 4.1",
@@ -179021,6 +179493,46 @@
},
"type": "chat"
},
+ {
+ "id": "moonshotai/kimi-k3",
+ "name": "Kimi K3",
+ "display_name": "Kimi K3",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "pdf"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1000000,
+ "output": 131072
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "attachment": true,
+ "open_weights": false,
+ "release_date": "2026-07-16",
+ "last_updated": "2026-07-16",
+ "cost": {
+ "input": 3,
+ "output": 15,
+ "cache_read": 0.3
+ },
+ "type": "chat"
+ },
{
"id": "moonshotai/kimi-k2-thinking",
"name": "Kimi K2 Thinking",
@@ -183597,6 +184109,33 @@
"last_updated": "2024-01-25",
"type": "embedding"
},
+ {
+ "id": "openai/gpt-realtime-whisper",
+ "name": "gpt-realtime-whisper",
+ "display_name": "gpt-realtime-whisper",
+ "modalities": {
+ "input": [
+ "audio"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 8192,
+ "output": 8192
+ },
+ "temperature": true,
+ "tool_call": false,
+ "reasoning": {
+ "supported": false
+ },
+ "attachment": false,
+ "open_weights": false,
+ "release_date": "2026-05-07",
+ "last_updated": "2026-05-07",
+ "type": "chat"
+ },
{
"id": "openai/gpt-5.1-thinking",
"name": "GPT 5.1 Thinking",
@@ -226933,6 +227472,25 @@
"name": "PPInfra",
"display_name": "PPInfra",
"models": [
+ {
+ "id": "moonshotai/kimi-k3",
+ "name": "Kimi K3",
+ "display_name": "Kimi K3",
+ "limit": {
+ "context": 1048576
+ },
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "type": "chat"
+ },
{
"id": "zai-org/glm-5.2",
"name": "GLM 5.2",
@@ -234348,6 +234906,38 @@
},
"type": "chat"
},
+ {
+ "id": "kimi-k3",
+ "name": "kimi-k3",
+ "display_name": "kimi-k3",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "video"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 1048576
+ },
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "cost": {
+ "input": 3,
+ "output": 15,
+ "cache_read": 0.3
+ },
+ "type": "chat"
+ },
{
"id": "claude-sonnet-5",
"name": "claude-sonnet-5",
@@ -234835,6 +235425,38 @@
},
"type": "chat"
},
+ {
+ "id": "coding-kimi-k3",
+ "name": "coding-kimi-k3",
+ "display_name": "coding-kimi-k3",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "video"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 1048576
+ },
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "cost": {
+ "input": 0.12,
+ "output": 0.439999,
+ "cache_read": 0.012
+ },
+ "type": "chat"
+ },
{
"id": "coding-glm-5.2-free",
"name": "coding-glm-5.2-free",
@@ -234866,20 +235488,21 @@
"type": "chat"
},
{
- "id": "gemini-3.1-flash-image",
- "name": "gemini-3.1-flash-image",
- "display_name": "gemini-3.1-flash-image",
+ "id": "coding-kimi-k3-free",
+ "name": "coding-kimi-k3-free",
+ "display_name": "coding-kimi-k3-free",
"modalities": {
"input": [
"text",
- "image"
+ "image",
+ "video"
]
},
"limit": {
- "context": 8192,
- "output": 8192
+ "context": 1048576,
+ "output": 1048576
},
- "tool_call": false,
+ "tool_call": true,
"reasoning": {
"supported": true,
"default": true
@@ -234890,11 +235513,11 @@
}
},
"cost": {
- "input": 0.5,
- "output": 3,
- "cache_read": 0.5
+ "input": 0,
+ "output": 0,
+ "cache_read": 0
},
- "type": "imageGeneration"
+ "type": "chat"
},
{
"id": "kimi-k2.7-code",
@@ -234961,34 +235584,9 @@
"type": "chat"
},
{
- "id": "kling-v3-omni",
- "name": "kling-v3-omni",
- "display_name": "kling-v3-omni",
- "modalities": {
- "input": [
- "text",
- "image"
- ]
- },
- "limit": {
- "context": 8192,
- "output": 8192
- },
- "tool_call": false,
- "reasoning": {
- "supported": false
- },
- "cost": {
- "input": 2,
- "output": 0,
- "cache_read": 0
- },
- "type": "chat"
- },
- {
- "id": "kling-video-o1",
- "name": "kling-video-o1",
- "display_name": "kling-video-o1",
+ "id": "gemini-3.1-flash-image",
+ "name": "gemini-3.1-flash-image",
+ "display_name": "gemini-3.1-flash-image",
"modalities": {
"input": [
"text",
@@ -235000,30 +235598,6 @@
"output": 8192
},
"tool_call": false,
- "reasoning": {
- "supported": false
- },
- "cost": {
- "input": 2,
- "output": 0,
- "cache_read": 0
- },
- "type": "chat"
- },
- {
- "id": "longcat-2.0",
- "name": "longcat-2.0",
- "display_name": "longcat-2.0",
- "modalities": {
- "input": [
- "text"
- ]
- },
- "limit": {
- "context": 8192,
- "output": 8192
- },
- "tool_call": true,
"reasoning": {
"supported": true,
"default": true
@@ -235034,11 +235608,11 @@
}
},
"cost": {
- "input": 0.7746,
- "output": 3.0984,
- "cache_read": 0.015492
+ "input": 0.5,
+ "output": 3,
+ "cache_read": 0.5
},
- "type": "chat"
+ "type": "imageGeneration"
},
{
"id": "gemini-3-pro-image",
@@ -235145,6 +235719,86 @@
},
"type": "chat"
},
+ {
+ "id": "kling-v3-omni",
+ "name": "kling-v3-omni",
+ "display_name": "kling-v3-omni",
+ "modalities": {
+ "input": [
+ "text",
+ "image"
+ ]
+ },
+ "limit": {
+ "context": 8192,
+ "output": 8192
+ },
+ "tool_call": false,
+ "reasoning": {
+ "supported": false
+ },
+ "cost": {
+ "input": 2,
+ "output": 0,
+ "cache_read": 0
+ },
+ "type": "chat"
+ },
+ {
+ "id": "kling-video-o1",
+ "name": "kling-video-o1",
+ "display_name": "kling-video-o1",
+ "modalities": {
+ "input": [
+ "text",
+ "image"
+ ]
+ },
+ "limit": {
+ "context": 8192,
+ "output": 8192
+ },
+ "tool_call": false,
+ "reasoning": {
+ "supported": false
+ },
+ "cost": {
+ "input": 2,
+ "output": 0,
+ "cache_read": 0
+ },
+ "type": "chat"
+ },
+ {
+ "id": "longcat-2.0",
+ "name": "longcat-2.0",
+ "display_name": "longcat-2.0",
+ "modalities": {
+ "input": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 8192,
+ "output": 8192
+ },
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "cost": {
+ "input": 0.7746,
+ "output": 3.0984,
+ "cache_read": 0.015492
+ },
+ "type": "chat"
+ },
{
"id": "hy3-preview",
"name": "hy3-preview",
@@ -235463,18 +236117,17 @@
"type": "chat"
},
{
- "id": "grok-4.3",
- "name": "grok-4.3",
- "display_name": "grok-4.3",
+ "id": "coding-glm-5.2",
+ "name": "coding-glm-5.2",
+ "display_name": "coding-glm-5.2",
"modalities": {
"input": [
- "text",
- "image"
+ "text"
]
},
"limit": {
- "context": 1000000,
- "output": 1000000
+ "context": 8192,
+ "output": 8192
},
"tool_call": true,
"reasoning": {
@@ -235487,24 +236140,24 @@
}
},
"cost": {
- "input": 1.25,
- "output": 2.5,
- "cache_read": 0.2
+ "input": 0.06,
+ "output": 0.22
},
"type": "chat"
},
{
- "id": "coding-glm-5.2",
- "name": "coding-glm-5.2",
- "display_name": "coding-glm-5.2",
+ "id": "grok-4.3",
+ "name": "grok-4.3",
+ "display_name": "grok-4.3",
"modalities": {
"input": [
- "text"
+ "text",
+ "image"
]
},
"limit": {
- "context": 8192,
- "output": 8192
+ "context": 1000000,
+ "output": 1000000
},
"tool_call": true,
"reasoning": {
@@ -235517,8 +236170,9 @@
}
},
"cost": {
- "input": 0.06,
- "output": 0.22
+ "input": 1.25,
+ "output": 2.5,
+ "cache_read": 0.2
},
"type": "chat"
},
@@ -241877,13 +242531,12 @@
"type": "chat"
},
{
- "id": "wan2.2-i2v-plus",
- "name": "wan2.2-i2v-plus",
- "display_name": "wan2.2-i2v-plus",
+ "id": "wan2.5-t2v-preview",
+ "name": "wan2.5-t2v-preview",
+ "display_name": "wan2.5-t2v-preview",
"modalities": {
"input": [
- "text",
- "image"
+ "text"
]
},
"limit": {
@@ -241901,12 +242554,13 @@
"type": "chat"
},
{
- "id": "wan2.5-t2v-preview",
- "name": "wan2.5-t2v-preview",
- "display_name": "wan2.5-t2v-preview",
+ "id": "wan2.5-i2v-preview",
+ "name": "wan2.5-i2v-preview",
+ "display_name": "wan2.5-i2v-preview",
"modalities": {
"input": [
- "text"
+ "text",
+ "image"
]
},
"limit": {
@@ -241924,9 +242578,9 @@
"type": "chat"
},
{
- "id": "wan2.5-i2v-preview",
- "name": "wan2.5-i2v-preview",
- "display_name": "wan2.5-i2v-preview",
+ "id": "wan2.2-i2v-plus",
+ "name": "wan2.2-i2v-plus",
+ "display_name": "wan2.2-i2v-plus",
"modalities": {
"input": [
"text",
@@ -247299,24 +247953,6 @@
},
"type": "chat"
},
- {
- "id": "tencent/Hunyuan-A13B-Instruct",
- "name": "tencent/Hunyuan-A13B-Instruct",
- "display_name": "tencent/Hunyuan-A13B-Instruct",
- "limit": {
- "context": 8192,
- "output": 8192
- },
- "tool_call": false,
- "reasoning": {
- "supported": false
- },
- "cost": {
- "input": 0.14,
- "output": 0.56
- },
- "type": "chat"
- },
{
"id": "MiniMaxAI/MiniMax-M1-80k",
"name": "MiniMaxAI/MiniMax-M1-80k",
@@ -247451,6 +248087,24 @@
},
"type": "chat"
},
+ {
+ "id": "tencent/Hunyuan-A13B-Instruct",
+ "name": "tencent/Hunyuan-A13B-Instruct",
+ "display_name": "tencent/Hunyuan-A13B-Instruct",
+ "limit": {
+ "context": 8192,
+ "output": 8192
+ },
+ "tool_call": false,
+ "reasoning": {
+ "supported": false
+ },
+ "cost": {
+ "input": 0.14,
+ "output": 0.56
+ },
+ "type": "chat"
+ },
{
"id": "unsloth/gemma-3-27b-it",
"name": "unsloth/gemma-3-27b-it",
@@ -247644,24 +248298,6 @@
},
"type": "chat"
},
- {
- "id": "tencent/Hunyuan-MT-7B",
- "name": "tencent/Hunyuan-MT-7B",
- "display_name": "tencent/Hunyuan-MT-7B",
- "limit": {
- "context": 8192,
- "output": 8192
- },
- "tool_call": false,
- "reasoning": {
- "supported": false
- },
- "cost": {
- "input": 0.2,
- "output": 0.2
- },
- "type": "chat"
- },
{
"id": "BAAI/bge-large-en-v1.5",
"name": "BAAI/bge-large-en-v1.5",
@@ -247734,6 +248370,24 @@
},
"type": "rerank"
},
+ {
+ "id": "tencent/Hunyuan-MT-7B",
+ "name": "tencent/Hunyuan-MT-7B",
+ "display_name": "tencent/Hunyuan-MT-7B",
+ "limit": {
+ "context": 8192,
+ "output": 8192
+ },
+ "tool_call": false,
+ "reasoning": {
+ "supported": false
+ },
+ "cost": {
+ "input": 0.2,
+ "output": 0.2
+ },
+ "type": "chat"
+ },
{
"id": "V3",
"name": "V3",
@@ -253994,9 +254648,14 @@
"type": "chat"
},
{
- "id": "text-ada-001",
- "name": "text-ada-001",
- "display_name": "text-ada-001",
+ "id": "tts-1-hd-1106",
+ "name": "tts-1-hd-1106",
+ "display_name": "tts-1-hd-1106",
+ "modalities": {
+ "input": [
+ "audio"
+ ]
+ },
"limit": {
"context": 8192,
"output": 8192
@@ -254006,15 +254665,14 @@
"supported": false
},
"cost": {
- "input": 0.4,
- "output": 0.4
- },
- "type": "chat"
+ "input": 30,
+ "output": 30
+ }
},
{
- "id": "tts-1",
- "name": "tts-1",
- "display_name": "tts-1",
+ "id": "tts-1-hd",
+ "name": "tts-1-hd",
+ "display_name": "tts-1-hd",
"modalities": {
"input": [
"audio"
@@ -254029,14 +254687,19 @@
"supported": false
},
"cost": {
- "input": 15,
- "output": 15
+ "input": 30,
+ "output": 30
}
},
{
- "id": "text-search-ada-doc-001",
- "name": "text-search-ada-doc-001",
- "display_name": "text-search-ada-doc-001",
+ "id": "tts-1-1106",
+ "name": "tts-1-1106",
+ "display_name": "tts-1-1106",
+ "modalities": {
+ "input": [
+ "audio"
+ ]
+ },
"limit": {
"context": 8192,
"output": 8192
@@ -254046,15 +254709,14 @@
"supported": false
},
"cost": {
- "input": 20,
- "output": 20
- },
- "type": "chat"
+ "input": 15,
+ "output": 15
+ }
},
{
- "id": "tts-1-hd-1106",
- "name": "tts-1-hd-1106",
- "display_name": "tts-1-hd-1106",
+ "id": "tts-1",
+ "name": "tts-1",
+ "display_name": "tts-1",
"modalities": {
"input": [
"audio"
@@ -254069,14 +254731,14 @@
"supported": false
},
"cost": {
- "input": 30,
- "output": 30
+ "input": 15,
+ "output": 15
}
},
{
- "id": "text-moderation-stable",
- "name": "text-moderation-stable",
- "display_name": "text-moderation-stable",
+ "id": "text-search-ada-doc-001",
+ "name": "text-search-ada-doc-001",
+ "display_name": "text-search-ada-doc-001",
"limit": {
"context": 8192,
"output": 8192
@@ -254086,15 +254748,15 @@
"supported": false
},
"cost": {
- "input": 0.2,
- "output": 0.2
+ "input": 20,
+ "output": 20
},
"type": "chat"
},
{
- "id": "text-moderation-latest",
- "name": "text-moderation-latest",
- "display_name": "text-moderation-latest",
+ "id": "text-moderation-007",
+ "name": "text-moderation-007",
+ "display_name": "text-moderation-007",
"limit": {
"context": 8192,
"output": 8192
@@ -254110,9 +254772,14 @@
"type": "chat"
},
{
- "id": "text-moderation-007",
- "name": "text-moderation-007",
- "display_name": "text-moderation-007",
+ "id": "text-embedding-ada-002",
+ "name": "text-embedding-ada-002",
+ "display_name": "text-embedding-ada-002",
+ "modalities": {
+ "input": [
+ "text"
+ ]
+ },
"limit": {
"context": 8192,
"output": 8192
@@ -254122,18 +254789,18 @@
"supported": false
},
"cost": {
- "input": 0.2,
- "output": 0.2
+ "input": 0.1,
+ "output": 0.1
},
- "type": "chat"
+ "type": "embedding"
},
{
- "id": "tts-1-hd",
- "name": "tts-1-hd",
- "display_name": "tts-1-hd",
+ "id": "text-embedding-3-small",
+ "name": "text-embedding-3-small",
+ "display_name": "text-embedding-3-small",
"modalities": {
"input": [
- "audio"
+ "text"
]
},
"limit": {
@@ -254145,14 +254812,15 @@
"supported": false
},
"cost": {
- "input": 30,
- "output": 30
- }
+ "input": 0.02,
+ "output": 0.02
+ },
+ "type": "embedding"
},
{
- "id": "text-embedding-v1",
- "name": "text-embedding-v1",
- "display_name": "text-embedding-v1",
+ "id": "text-embedding-3-large",
+ "name": "text-embedding-3-large",
+ "display_name": "text-embedding-3-large",
"modalities": {
"input": [
"text"
@@ -254167,20 +254835,15 @@
"supported": false
},
"cost": {
- "input": 0.1,
- "output": 0.1
+ "input": 0.13,
+ "output": 0.13
},
"type": "embedding"
},
{
- "id": "text-embedding-ada-002",
- "name": "text-embedding-ada-002",
- "display_name": "text-embedding-ada-002",
- "modalities": {
- "input": [
- "text"
- ]
- },
+ "id": "text-moderation-stable",
+ "name": "text-moderation-stable",
+ "display_name": "text-moderation-stable",
"limit": {
"context": 8192,
"output": 8192
@@ -254190,20 +254853,15 @@
"supported": false
},
"cost": {
- "input": 0.1,
- "output": 0.1
+ "input": 0.2,
+ "output": 0.2
},
- "type": "embedding"
+ "type": "chat"
},
{
- "id": "text-embedding-3-small",
- "name": "text-embedding-3-small",
- "display_name": "text-embedding-3-small",
- "modalities": {
- "input": [
- "text"
- ]
- },
+ "id": "text-davinci-edit-001",
+ "name": "text-davinci-edit-001",
+ "display_name": "text-davinci-edit-001",
"limit": {
"context": 8192,
"output": 8192
@@ -254213,10 +254871,10 @@
"supported": false
},
"cost": {
- "input": 0.02,
- "output": 0.02
+ "input": 20,
+ "output": 20
},
- "type": "embedding"
+ "type": "chat"
},
{
"id": "whisper-1",
@@ -254288,14 +254946,9 @@
"type": "chat"
},
{
- "id": "text-embedding-3-large",
- "name": "text-embedding-3-large",
- "display_name": "text-embedding-3-large",
- "modalities": {
- "input": [
- "text"
- ]
- },
+ "id": "text-davinci-003",
+ "name": "text-davinci-003",
+ "display_name": "text-davinci-003",
"limit": {
"context": 8192,
"output": 8192
@@ -254305,20 +254958,15 @@
"supported": false
},
"cost": {
- "input": 0.13,
- "output": 0.13
+ "input": 20,
+ "output": 20
},
- "type": "embedding"
+ "type": "chat"
},
{
- "id": "tts-1-1106",
- "name": "tts-1-1106",
- "display_name": "tts-1-1106",
- "modalities": {
- "input": [
- "audio"
- ]
- },
+ "id": "text-davinci-002",
+ "name": "text-davinci-002",
+ "display_name": "text-davinci-002",
"limit": {
"context": 8192,
"output": 8192
@@ -254328,14 +254976,15 @@
"supported": false
},
"cost": {
- "input": 15,
- "output": 15
- }
+ "input": 20,
+ "output": 20
+ },
+ "type": "chat"
},
{
- "id": "text-davinci-edit-001",
- "name": "text-davinci-edit-001",
- "display_name": "text-davinci-edit-001",
+ "id": "text-curie-001",
+ "name": "text-curie-001",
+ "display_name": "text-curie-001",
"limit": {
"context": 8192,
"output": 8192
@@ -254345,15 +254994,15 @@
"supported": false
},
"cost": {
- "input": 20,
- "output": 20
+ "input": 2,
+ "output": 2
},
"type": "chat"
},
{
- "id": "text-davinci-003",
- "name": "text-davinci-003",
- "display_name": "text-davinci-003",
+ "id": "text-babbage-001",
+ "name": "text-babbage-001",
+ "display_name": "text-babbage-001",
"limit": {
"context": 8192,
"output": 8192
@@ -254363,15 +255012,15 @@
"supported": false
},
"cost": {
- "input": 20,
- "output": 20
+ "input": 0.5,
+ "output": 0.5
},
"type": "chat"
},
{
- "id": "text-davinci-002",
- "name": "text-davinci-002",
- "display_name": "text-davinci-002",
+ "id": "text-ada-001",
+ "name": "text-ada-001",
+ "display_name": "text-ada-001",
"limit": {
"context": 8192,
"output": 8192
@@ -254381,15 +255030,15 @@
"supported": false
},
"cost": {
- "input": 20,
- "output": 20
+ "input": 0.4,
+ "output": 0.4
},
"type": "chat"
},
{
- "id": "text-curie-001",
- "name": "text-curie-001",
- "display_name": "text-curie-001",
+ "id": "text-moderation-latest",
+ "name": "text-moderation-latest",
+ "display_name": "text-moderation-latest",
"limit": {
"context": 8192,
"output": 8192
@@ -254399,8 +255048,8 @@
"supported": false
},
"cost": {
- "input": 2,
- "output": 2
+ "input": 0.2,
+ "output": 0.2
},
"type": "chat"
},
@@ -254513,9 +255162,14 @@
"type": "chat"
},
{
- "id": "text-babbage-001",
- "name": "text-babbage-001",
- "display_name": "text-babbage-001",
+ "id": "text-embedding-v1",
+ "name": "text-embedding-v1",
+ "display_name": "text-embedding-v1",
+ "modalities": {
+ "input": [
+ "text"
+ ]
+ },
"limit": {
"context": 8192,
"output": 8192
@@ -254525,10 +255179,10 @@
"supported": false
},
"cost": {
- "input": 0.5,
- "output": 0.5
+ "input": 0.1,
+ "output": 0.1
},
- "type": "chat"
+ "type": "embedding"
},
{
"id": "meta-llama-3-70b",
@@ -257185,8 +257839,8 @@
]
},
"limit": {
- "context": 131072,
- "output": 131072
+ "context": 110000,
+ "output": 110000
},
"tool_call": true,
"reasoning": {
@@ -257782,8 +258436,8 @@
]
},
"limit": {
- "context": 131072,
- "output": 131072
+ "context": 80000,
+ "output": 80000
},
"tool_call": false,
"reasoning": {
@@ -257926,6 +258580,33 @@
},
"type": "imageGeneration"
},
+ {
+ "id": "meta/muse-spark-1.1",
+ "name": "Meta: Muse Spark 1.1",
+ "display_name": "Meta: Muse Spark 1.1",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "video",
+ "audio"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 1048576
+ },
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "attachment": true,
+ "type": "imageGeneration"
+ },
{
"id": "microsoft/phi-4",
"name": "Microsoft: Phi 4",
@@ -258139,7 +258820,7 @@
]
},
"limit": {
- "context": 204800,
+ "context": 196608,
"output": 131072
},
"temperature": true,
@@ -258821,6 +259502,35 @@
},
"type": "imageGeneration"
},
+ {
+ "id": "moonshotai/kimi-k3",
+ "name": "MoonshotAI: Kimi K3",
+ "display_name": "MoonshotAI: Kimi K3",
+ "modalities": {
+ "input": [
+ "text",
+ "image"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 1048576
+ },
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "type": "imageGeneration"
+ },
{
"id": "morph/morph-v3-fast",
"name": "Morph: Morph V3 Fast",
@@ -264548,6 +265258,36 @@
},
"type": "chat"
},
+ {
+ "id": "moonshotai/kimi-k3",
+ "name": "Kimi K3",
+ "display_name": "Kimi K3",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "video"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1048576,
+ "output": 1048576
+ },
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "type": "chat"
+ },
{
"id": "gpt-5.6-terra",
"name": "gpt-5.6-terra",
@@ -272599,9 +273339,9 @@
"release_date": "2026-06-12",
"last_updated": "2026-06-12",
"cost": {
- "input": 0.719,
- "output": 3.49,
- "cache_read": 0.149,
+ "input": 0.75,
+ "output": 3.5,
+ "cache_read": 0.16,
"cache_write": 0
},
"type": "chat"
@@ -272652,6 +273392,46 @@
},
"type": "chat"
},
+ {
+ "id": "moonshotai/kimi-k3",
+ "name": "MoonshotAI: Kimi K3",
+ "display_name": "MoonshotAI: Kimi K3",
+ "modalities": {
+ "input": [
+ "text",
+ "image",
+ "pdf"
+ ],
+ "output": [
+ "text"
+ ]
+ },
+ "limit": {
+ "context": 1000000,
+ "output": 131072
+ },
+ "temperature": true,
+ "tool_call": true,
+ "reasoning": {
+ "supported": true,
+ "default": true
+ },
+ "extra_capabilities": {
+ "reasoning": {
+ "supported": true
+ }
+ },
+ "attachment": true,
+ "open_weights": false,
+ "release_date": "2026-07-16",
+ "last_updated": "2026-07-16",
+ "cost": {
+ "input": 3,
+ "output": 15,
+ "cache_read": 0.3
+ },
+ "type": "chat"
+ },
{
"id": "openai/chat-latest",
"name": "OpenAI: Chat Latest (GPT-5.5 Instant)",
@@ -274976,9 +275756,9 @@
"release_date": "2026-05-29",
"last_updated": "2026-05-29",
"cost": {
- "input": 0.2,
- "output": 1.15,
- "cache_read": 0.04,
+ "input": 0.19,
+ "output": 1.14,
+ "cache_read": 0.03,
"cache_write": 0
},
"type": "chat"
@@ -275013,9 +275793,9 @@
"release_date": "2026-05-29",
"last_updated": "2026-05-29",
"cost": {
- "input": 0.2,
- "output": 1.15,
- "cache_read": 0.04,
+ "input": 0.19,
+ "output": 1.14,
+ "cache_read": 0.03,
"cache_write": 0
},
"type": "chat"
diff --git a/src/main/agent/deepchat/runtime/dispatch.ts b/src/main/agent/deepchat/runtime/dispatch.ts
index 9d41f7cf85..efc2d715ee 100644
--- a/src/main/agent/deepchat/runtime/dispatch.ts
+++ b/src/main/agent/deepchat/runtime/dispatch.ts
@@ -1345,6 +1345,7 @@ async function runToolCall(params: {
}
const enabledMcpServerIds = controls?.getEnabledMcpServerIds?.()
const result = await toolExecution.execute(toolCall, {
+ runId: io.requestId,
onProgress: applyProgressUpdate,
signal: io.abortSignal,
permissionMode: toolPermissionMode,
diff --git a/src/main/desktop/browser/BrowserProfileImportService.ts b/src/main/desktop/browser/BrowserProfileImportService.ts
new file mode 100644
index 0000000000..f17a4ec2ee
--- /dev/null
+++ b/src/main/desktop/browser/BrowserProfileImportService.ts
@@ -0,0 +1,484 @@
+import { createDecipheriv, createHash, pbkdf2Sync } from 'crypto'
+import { execFile } from 'child_process'
+import { chmod, mkdtemp, readFile, readdir, rm, stat } from 'fs/promises'
+import { homedir, tmpdir } from 'os'
+import { join } from 'path'
+import { promisify } from 'util'
+import type { CookiesSetDetails, Session } from 'electron'
+import Database from 'better-sqlite3-multiple-ciphers'
+import { nanoid } from 'nanoid'
+import type {
+ BrowserImportApplyResult,
+ BrowserImportPreview,
+ BrowserImportProfile,
+ BrowserImportScanResult
+} from '@shared/types/browser'
+
+const execFileAsync = promisify(execFile)
+const STAGE_TTL_MS = 5 * 60 * 1000
+const CHROME_EPOCH_OFFSET_SECONDS = 11_644_473_600
+
+type BrowserSource = {
+ id: BrowserImportProfile['browser']
+ name: string
+ userDataDirectory: string
+ keychainService: string
+}
+
+const BROWSER_SOURCES: BrowserSource[] = [
+ {
+ id: 'chrome',
+ name: 'Google Chrome',
+ userDataDirectory: join(homedir(), 'Library', 'Application Support', 'Google', 'Chrome'),
+ keychainService: 'Chrome Safe Storage'
+ },
+ {
+ id: 'arc',
+ name: 'Arc',
+ userDataDirectory: join(homedir(), 'Library', 'Application Support', 'Arc', 'User Data'),
+ keychainService: 'Arc Safe Storage'
+ }
+]
+
+type ChromeCookieRow = {
+ host_key: string
+ top_frame_site_key: string
+ name: string
+ value: string
+ encrypted_value: Buffer
+ path: string
+ expires_utc: number
+ is_secure: number
+ is_httponly: number
+ samesite: number
+}
+
+type DiscoveredProfile = BrowserImportProfile & {
+ source: BrowserSource
+ directoryName: string
+ cookiePath: string
+}
+
+type StagedImport = {
+ createdAt: number
+ profile: DiscoveredProfile
+ sourceSize: number
+ sourceMtimeMs: number
+ cookies: CookiesSetDetails[]
+ skippedExpired: number
+ skippedPartitioned: number
+}
+
+export class BrowserProfileImportService {
+ private readonly stagedImports = new Map()
+ private readonly stageExpiryTimers = new Map()
+ private applying = false
+
+ constructor(
+ private readonly getTargetSession: () => Session,
+ private readonly getTargetUnpartitionedCookies: () => Promise,
+ private readonly platform: NodeJS.Platform = process.platform
+ ) {}
+
+ async scan(): Promise {
+ if (this.platform !== 'darwin') {
+ return {
+ platformSupported: false,
+ profiles: [],
+ reason: 'platform_unsupported'
+ }
+ }
+
+ const profiles = await this.discoverChromeProfiles()
+ return {
+ platformSupported: true,
+ profiles: profiles.map(this.toPublicProfile),
+ ...(profiles.length === 0 ? { reason: 'browser_not_found' as const } : {})
+ }
+ }
+
+ async preview(profileId: string): Promise {
+ if (this.platform !== 'darwin') {
+ throw new Error('browser_import_platform_unsupported')
+ }
+ this.removeExpiredStages()
+ const profile = (await this.discoverChromeProfiles()).find((item) => item.id === profileId)
+ if (!profile || !profile.supported) {
+ throw new Error('browser_import_profile_unavailable')
+ }
+
+ const sourceStat = await stat(profile.cookiePath)
+ const password = await this.readSafeStoragePassword(profile.source.keychainService)
+ const temporaryDirectory = await mkdtemp(join(tmpdir(), 'deepchat-browser-import-'))
+ await chmod(temporaryDirectory, 0o700)
+ const snapshotPath = join(temporaryDirectory, 'Cookies')
+
+ try {
+ const sourceDatabase = new Database(profile.cookiePath, {
+ readonly: true,
+ fileMustExist: true
+ })
+ try {
+ await sourceDatabase.backup(snapshotPath)
+ } finally {
+ sourceDatabase.close()
+ }
+
+ const decoded = this.readCookieSnapshot(snapshotPath, password)
+ const token = nanoid(24)
+ this.stagedImports.set(token, {
+ createdAt: Date.now(),
+ profile,
+ sourceSize: sourceStat.size,
+ sourceMtimeMs: sourceStat.mtimeMs,
+ cookies: decoded.cookies,
+ skippedExpired: decoded.skippedExpired,
+ skippedPartitioned: decoded.skippedPartitioned
+ })
+ const expiryTimer = setTimeout(() => this.deleteStage(token), STAGE_TTL_MS)
+ expiryTimer.unref()
+ this.stageExpiryTimers.set(token, expiryTimer)
+
+ return {
+ token,
+ profile: this.toPublicProfile(profile),
+ cookieCount: decoded.cookies.length,
+ skippedExpired: decoded.skippedExpired,
+ skippedPartitioned: decoded.skippedPartitioned
+ }
+ } finally {
+ password.fill(0)
+ await rm(temporaryDirectory, { recursive: true, force: true })
+ }
+ }
+
+ async apply(token: string): Promise {
+ if (this.applying) {
+ throw new Error('browser_import_already_running')
+ }
+
+ this.removeExpiredStages()
+ const staged = this.stagedImports.get(token)
+ if (!staged) {
+ throw new Error('browser_import_preview_expired')
+ }
+
+ const sourceStat = await stat(staged.profile.cookiePath)
+ if (sourceStat.size !== staged.sourceSize || sourceStat.mtimeMs !== staged.sourceMtimeMs) {
+ this.deleteStage(token)
+ throw new Error('browser_import_source_changed')
+ }
+
+ this.applying = true
+ try {
+ const target = this.getTargetSession()
+ const rollbackCookies = await this.getTargetUnpartitionedCookies()
+
+ try {
+ await this.removeCookies(target, rollbackCookies)
+ await this.setCookies(target, staged.cookies)
+ await target.cookies.flushStore()
+ await this.verifyCookies(staged.cookies)
+ } catch (error) {
+ await this.removeCookies(target, await this.getTargetUnpartitionedCookies())
+ await this.setCookies(target, rollbackCookies)
+ await target.cookies.flushStore()
+ throw error
+ }
+ } finally {
+ this.deleteStage(token)
+ this.applying = false
+ }
+
+ return {
+ importedCookies: staged.cookies.length,
+ skippedExpired: staged.skippedExpired,
+ skippedPartitioned: staged.skippedPartitioned,
+ syncedAt: Date.now()
+ }
+ }
+
+ private async discoverChromeProfiles(): Promise {
+ const profiles: DiscoveredProfile[] = []
+ for (const source of BROWSER_SOURCES) {
+ let entries: Array<{ name: string; isDirectory(): boolean }>
+ try {
+ entries = await readdir(source.userDataDirectory, { withFileTypes: true })
+ } catch {
+ continue
+ }
+
+ const profileNames = await this.readProfileNames(source)
+ for (const entry of entries) {
+ if (!entry.isDirectory() || !/^(Default|Profile \d+)$/.test(entry.name)) {
+ continue
+ }
+
+ const profileDirectory = join(source.userDataDirectory, entry.name)
+ const networkCookiePath = join(profileDirectory, 'Network', 'Cookies')
+ const legacyCookiePath = join(profileDirectory, 'Cookies')
+ const cookiePath = await this.firstExistingPath([networkCookiePath, legacyCookiePath])
+ if (!cookiePath) {
+ continue
+ }
+
+ profiles.push({
+ id: `${source.id}:${entry.name}`,
+ browser: source.id,
+ browserName: source.name,
+ profileName: profileNames.get(entry.name) || entry.name,
+ supported: true,
+ source,
+ directoryName: entry.name,
+ cookiePath
+ })
+ }
+ }
+
+ return profiles.sort((left, right) => left.id.localeCompare(right.id))
+ }
+
+ private async readProfileNames(source: BrowserSource): Promise