feat(desktop): add browser tabs and Chromium diagnostics - #44838
Merged
Merged
Conversation
6 tasks
Hona
force-pushed
the
browser-experimental
branch
4 times, most recently
from
September 1, 2026 02:40
b128bf7 to
0926215
Compare
Member
Author
|
The desktop dev-tooling fixes are now in #46523. They have been removed from this branch so this PR stays focused on the browser feature. |
Hona
force-pushed
the
browser-experimental
branch
from
September 1, 2026 03:36
4f0fb9e to
47350e0
Compare
Hona
marked this pull request as ready for review
September 1, 2026 03:37
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces an experimental desktop-hosted browser pane integrated into the desktop session UI and wired through desktop IPC so agents can drive navigation and interactions via the browser tool while keeping execution inside the desktop client.
Changes:
- Adds a Desktop IPC RPC + event surface for a “browser pane” (register/layout/command/close) and a main-process implementation backed by a sandboxed Chromium
WebContentsView. - Adds an App session-side browser model + UI pane (toolbar + address bar) and session layout updates to accommodate the browser alongside existing panels.
- Adds an experimental setting toggle and English i18n strings for UI/permissions copy.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/desktop/src/shared/ipc-rpc/events.ts | Adds BrowserPaneEvent and includes it in the desktop event stream + RPC group. |
| packages/desktop/src/shared/ipc-rpc/browser.ts | Defines the BrowserPane IPC request/event schemas and BrowserPane RPC. |
| packages/desktop/src/renderer/platform/index.ts | Exposes platform.browserPane registration API backed by desktop IPC calls. |
| packages/desktop/src/renderer/api.ts | Adds renderer-side IPC bindings for BrowserPane request/send/event listening. |
| packages/desktop/src/renderer/api-types.ts | Extends the Electron API types to include BrowserPane request/event types. |
| packages/desktop/src/main/ipc-handlers/events.ts | Wires BrowserPane RPC into the main-process handler and owns lifecycle disposal. |
| packages/desktop/src/main/browser-pane.ts | Implements BrowserPane ownership, OpenCode RPC bridging, and request execution lifecycle. |
| packages/desktop/src/main/browser-pane-policy.test.ts | Adds a focused policy test for allowed/blocked navigation destinations. |
| packages/desktop/src/main/browser-chromium.ts | Implements sandboxed Chromium page driver: navigation, snapshotting, input, screenshots. |
| packages/desktop/package.json | Adds workspace deps needed for browser RPC + schema usage in Desktop. |
| packages/app/src/settings/model.tsx | Adds general.experimentalBrowser setting with default + setters. |
| packages/app/src/settings/general/general.tsx | Adds UI toggle row for the experimental browser pane (desktop-only). |
| packages/app/src/session/session-panel-layout.ts | Extends panel layout logic to consider browser panel visibility/stacking. |
| packages/app/src/session/session-panel-layout.test.ts | Updates tests to cover new browser panel layout behavior. |
| packages/app/src/session/screen.tsx | Integrates session browser model and conditionally renders browser pane vs review pane. |
| packages/app/src/session/screen-layout.ts | Updates screen layout sizing/resizability to account for the browser panel. |
| packages/app/src/session/header/session-header.tsx | Adds browser toggle wiring into the session header actions model. |
| packages/app/src/session/header/session-header-actions.tsx | Adds a browser toggle button (ARIA-wired) to header actions. |
| packages/app/src/session/browser/pane.tsx | Adds the browser pane UI (controls + address input) and layout reporting to desktop host. |
| packages/app/src/session/browser/model.ts | Adds session browser state/model: availability, registration, open/close, command dispatch. |
| packages/app/src/runtime/platform/platform.tsx | Extends the platform type to optionally provide a browserPane capability. |
| packages/app/src/runtime/platform/browser-pane.ts | Adds shared platform-side BrowserPane types used by App. |
| packages/app/src/runtime/i18n/en.ts | Adds English strings for browser toggle, pane UI labels, settings row, permission descriptions. |
| packages/app/src/desktop.ts | Re-exports BrowserPane platform types from the desktop entrypoint. |
| packages/app/package.json | Adds @opencode-ai/browser dependency for shared Browser RPC types in App. |
| bun.lock | Locks workspace dependency additions for the new browser package usage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Hona
force-pushed
the
browser-experimental
branch
from
September 1, 2026 04:07
744f2a9 to
b264265
Compare
Hona
force-pushed
the
browser-experimental
branch
from
September 1, 2026 23:12
b264265 to
bb610d7
Compare
Hona
force-pushed
the
browser-experimental
branch
from
September 1, 2026 23:30
bb610d7 to
b09774b
Compare
Hona
force-pushed
the
browser-experimental
branch
from
September 2, 2026 04:56
b09774b to
3376a88
Compare
Hona
force-pushed
the
browser-experimental
branch
from
September 2, 2026 08:37
808dc9b to
b4ac905
Compare
Hona
force-pushed
the
browser-experimental
branch
2 times, most recently
from
September 2, 2026 09:34
e89a3f6 to
07370ba
Compare
Hona
force-pushed
the
browser-experimental
branch
from
September 2, 2026 22:51
0281da0 to
c507eea
Compare
Hona
force-pushed
the
browser-experimental
branch
from
September 7, 2026 07:16
5d22078 to
ec93d00
Compare
…ransport for browser attachments
…ctly, and keep upload names
1 task
jinhuang712
pushed a commit
to jinhuang712/opencode
that referenced
this pull request
Sep 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Browser tabs and Chromium tools
+menu.Review pane controls
Actual application UI in an isolated test instance. These crops show the tab strip and address controls; native page content is outside the crop.
Depends on the browser plugin in #46531.
Review follow-ups
Each item notes whether the change fixes the root cause or patches a symptom.
Root fixes
BrowserAttachmentsProviderowns registration, retry, and replacement per server + session. It closes when the shell session tab closes or the setting turns off, so Settings and session switches keep native pages, files, and agent work.SessionModeland the side panel now read the sameattachedflag; browser keys flow throughpanelTabs()in layout order.<For>. Browser tabs now render throughSortableTabintabs().all()order, so reordering and persistence come for free.SidecarCredentials.authorization), so the renderer never sees the password and Node requests no longer bypass the header injection.press("Enter")/press("Space"): named keys resolve to their character data before dispatch.sessionFor(frameID)walks to the nearest ancestor with a CDP target instead of requiring one per frame.getBoundingClientRect / offsetWidthscale, including width and height.*ExtraInfonetwork events: onebegin/requestHeaders/responseInfo/finishpath handles renderer and network-stack events in either arrival order.edge_countsum equals the edge array, everyto_nodeis a real node offset) instead of trusting the file during traversal.attach's outcome decides the close reason.ensuringno longer aborts the signal, so a real retrieval failure stops the attachment as intended.browser/policy.ts, Electron-free.Contained patches
waitdeadline: eachcheck()races the remaining time; cancellation is still bounded by the deadline rather than interrupting a hung check.blob:/data:: the http(s)-only guard applies to the main frame only.dispose()reason argument,navigatein the retained set,0o700/0o600capture files, dead i18n keys,puppeteer-coreas a devDependency.CIis set; it needs a display.Left as-is, on purpose
Review follow-ups, round two
Root fixes
tabKey, so returning from a child session to its parent, or hydration finishing after the route mounted, no longer closes the attachment.attach()refreshes the retained connection when the same server key arrives as a new connection, andregister()reads it per attempt.session.createdsubscription runs under the provider owner, so leaving an optimistic session before creation finishes can no longer orphan itsliveentry.rpc.stateretries with exponential backoff and clearslastStateon failure, so a temporarily unreachable server still learns about every tab.set-cookie/location.Contained patches
rpc.commandretrieval failures no longerstop()the attachment; a cancelled-before-retrieval request or an unknown operation fails only that request.durationMs: 0, andwebSocketClosedfails a still-pending socket.cookie,set-cookie,authorization, andproxy-authorizationvalues are redacted innetwork.get; the names remain so the model knows they were sent.SortableTabresolves custom children once withchildren().New native assertions cover the 503-then-retry state path, the two-hop redirect, the refused WebSocket, and redaction.
Review follow-ups, round three
Root fixes
unavailable). There is no exhaustion state to resynchronise from: results queued behind a state never name a tab the server lacks, and the renderer publishes locally only once the server has the inventory. The native suite now rejects five publications in a row, beyond the previous budget.ctx.sdk.url) at each attempt, so a background session follows a restarted sidecar's port without any route being mounted. The route-drivenexisting.serverrefresh is gone.redirectHasExtraInfo/hasExtraInfoflags, so a cached 301's successor keeps its own wire headers and status. Native fixture: a cacheable301 → 201chain fetched twice records301, 201, 301, 201, and the cached hop carries none of the target's headers.Contained patches
unsupportedfailure result immediately instead of waiting out the server's timeout; a vanished (already cancelled) request still needs nothing.Left as is
Review follow-ups, round four
Root fixes
executereceives a run-scoped signal,fill_formchecks it between fields, andfillchecks it after focusing and before inserting, so achangevalidation alert on one field leaves the next one untouched after dismissal.navigateis exempt so abeforeunloaddialog can still be answered and the load proceed.input/changeevents, the way Playwright fills them; a value the control rejects restores the previous one and fails with the required format.File.namematches the server file. Per-file directories already prevent collisions.Contained patches
Log.enableper instrumented session; Chromium-generated entries (CSP refusals, failed resource loads, deprecations) join the bounded console buffer with their source URL.retainers; they remain visible as references from their owner.Native assertions cover the interrupted
fill_form, date/time values and the rejected malformed value, the preservedQuarter 1 日本語.csvupload name, and the 404 log entry; unit tests cover the sanitizer and the weak edge.