Repository navigation
Conversation
|
Thanks for working on this! I’m exploring a related browser use case and would appreciate some guidance. I run OpenCode on a Linux machine and connect through Two questions before exploring an implementation:
I’d be interested in contributing and want to understand how this could complement the desktop browser work. |
|
Just posting as encouragement. This direction seems fine and avoids proxying, and hopefully keeps everything on desktop app (to be decided, from what I see). We need a top level browser in OpenCode Desktop. EDIT: Maybe that project was spun up from this PR. Not sure. Plausible? |
|
I hadn't seen that, thank you for the tip. That looks like it will do everything I want, just not quite with the UX I'm looking for: that is a tab in a regular browser, and I was hoping for a tab right in OpenCode itself next to the session transcript, so it's all visually together. I wonder if this browse tool and a remote window viewer (VNC?) embedded in OpenCode might work well together. |
|
Uhm. I don't think VNC is the way (unless you have specific needs?), just rework the embedding as stated in this PR should come out as more polished and persistent Browser. As a general rule of thumb, I spent my saturday to look at OpenCode UX / polish, and I think it needs a month of intense hammering to become as smooth as more famous competitors |
Draft to look at the shape of the code. The in-app browser now registers its tools the way James's client MCP does (#57502–#57506): the desktop hosts an MCP server called
browserover/api/experimental/client-mcp, and the server has no browser code at all.@opencode/plugin-browseris deleted.Before / after
flowchart LR subgraph Before direction LR A1[Agent] --> T1[plugin-browser tools<br/>server] T1 --> C1[connection.ts<br/>pending map, grants, state copy] C1 -- "event: control {requestID}" --> D1[Desktop pane] D1 -- "rpc.command(requestID)" --> C1 D1 -- "rpc.result(outcome)" --> C1 D1 -- "rpc.state(inventory)" --> C1 D1 <-- "rpc.tunnel.*" --> C1 end subgraph After direction LR A2[Agent] --> M2[core MCP<br/>attached client 'browser'] M2 -- "tools/call + _meta.sessionID" --> D2[Desktop pane] D2 -- "result + structuredContent" --> M2 endpackages/plugin-browser(connection, tools, skill, tunnel, proxy, files)attach,state,command,result,tunnel.*+ control eventsBrowser.Operations, exported as JSON Schema by the desktopbrowserskillinstructionstools.browser.tabs.opentools.browser.tabs_openbrowser_tabs_openbrowser_tabs_open(same)The whole desktop side
packages/gui-plugins/src/browser/pane.tsserves one connection per server and directory and routes each call by session:packages/gui-plugins/src/browser/mcp.tsturnsBrowser.Operationsinto tools: it decodes the input, runs the page, checks the output against the operation's schema, and returnsstructuredContent. Screenshots go back asimageparts. Other captures go back asresourceblobs, which the server saves to a file.What the SDK and core needed
connectClientMcp(packages/client/src/mcp.ts):instructionsoption.outputSchema.structuredContentandresourceparts in results.ctx.signal, which aborts onnotifications/cancelledor when the socket closes.Mcp.instructions()includes the instructions of the attached client that serves each name, so the browser skill becomes server instructions.McpToolcontent: textual resources over 32 KiB are saved to a file instead of inlined, so a Lighthouse JSON report or a.cpuprofiledoes not flood the context.Behavior changes to decide on
localhostis the user's machine, not the server. The tunnel/proxy is gone, so a remote server's dev ports are no longer reachable.browser_*. A session with no pane gets[browser.disconnected]. Before, a deny rule hid the tools until a pane attached to that exact session.browser_<tool>), not thebrowseraction.GET /api/fs/read. Absolute server paths are no longer accepted.browser.tabs.list({}); Code Mode now usesbrowser.tabs_list.