Repository navigation
Conversation
◈ PR Lens
Architecture 10 components touched across 3 lanes. Play the interactive walkthrough Inside the changed components — 2 viewsComponent view — Browser Agent Bridge In-tab registry and RPC sync bridge forwarding page functions to Devframe Component view — Client Agent Manager Node session manager tracking tabs, focus state, and routing tool calls Data flow
Follow each request, response and payload The other flows — 1 sequence
View
Tip Click the link under each diagram to open it on a canvas you can zoom, pan and step through 🪧 More tips
Thanks for using PR Lens! It's built by Coldtea, free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
fc6a624 to
ff554f0
Compare
…per tab Forward agent-flagged in-page channel functions to the node MCP endpoint (ports the bridge from #376 onto 0.10), and make each connected browser tab visible and addressable: a built-in devframe:agent:list-clients tool, a reserved client_id argument on forwarded tools, and focus-aware default routing so an unaddressed call follows the tab the user looked at last. devframe connect nests the tab list under mcp.clients per instance. Closes #394
ff554f0 to
0077dd9
Compare
|
👁️🗨️ Review this pull request with grouped, summarized diffs at: raw result💭 analyzed by {
"headSha": "0077dd9a2b93aec9cac65f010e5b15e869a98f92",
"result": {
"overallSummary": "Ports the browser-agent/in-page-tools bridge to the current RPC stack and extends it so multiple open tabs of the same app are distinguishable and individually addressable: each tab now reports an id plus URL/title/visibility/focus, the node exposes a `devframe:agent:list-clients` tool and dedupes forwarded tool ids across tabs, calls can target one tab via a reserved `client_id` (with a new DF0082 error for unknown ids), and `devframe connect` surfaces the same tab list under `mcp.clients`.",
"groups": [
{
"key": "client-agent-routing",
"label": "Per-tab client agent routing",
"summary": "Core of the feature: each browser tab now reports its own manifest plus visibility/focus/URL/title info over RPC; the node tracks one entry per tab, dedupes tool ids across tabs, exposes a built-in `devframe:agent:list-clients` tool, and routes forwarded tool calls to a specific tab via a reserved `client_id` argument (falling back to focused → visible → last-synced), with a new DF0082 diagnostic for an unknown/missing id.",
"category": "core",
"filePaths": [
"packages/devframe/src/node/client-agent.ts",
"packages/devframe/src/node/diagnostics.ts",
"packages/devframe/src/node/rpc/agent-sync-client-tools.ts",
"packages/devframe/src/node/rpc/index.ts",
"packages/devframe/src/types/rpc-augments.ts",
"packages/devframe/src/internal/index.ts",
"packages/devframe/src/client/browser-agent.ts",
"packages/devframe/src/client/browser-agent-rpc.ts"
],
"critical": true,
"fileNotes": [
{
"path": "packages/devframe/src/node/client-agent.ts",
"text": "Holds the targeting/ranking logic (`pickTarget`), the `client_id` schema injection/stripping, and the dedup across tabs sharing tool ids — the riskiest and most central piece of this PR.",
"critical": true
},
{
"path": "packages/devframe/src/client/browser-agent-rpc.ts",
"text": "Adds focus/blur/visibilitychange listeners that re-sync the tab's info without necessarily republishing the tool list."
}
]
},
{
"key": "connect-cli-clients",
"label": "devframe connect: list clients",
"summary": "Extends `devframe connect`'s `list-instances` to nest connected browser tabs under `mcp.clients` (by calling the new `list-clients` tool in the same MCP session) and documents `client_id` for `call-tool`.",
"category": "cli",
"filePaths": [
"packages/agentic/src/connect/index.ts"
],
"fileNotes": [
{
"path": "packages/agentic/src/connect/index.ts",
"text": "`indexInstanceMcp` now also calls the built-in `list-clients` tool when present, reading its result from `structuredContent`, which is typed only via a cast (the tool's output schema is the real source of truth)."
}
]
},
{
"key": "tests",
"label": "Routing and integration tests",
"summary": "Unit tests for the tab-targeting rules (focus → visible → last synced, addressed/missing `client_id`, no re-publish on focus-only sync) plus a live WS + real MCP client integration test exercising dedup, `list-clients`, and routed calls end to end.",
"category": "tests",
"filePaths": [
"packages/devframe/src/node/__tests__/client-agent.test.ts",
"packages/devframe/src/client/browser-agent-rpc.test.ts",
"packages/agentic/src/mcp/__tests__/mcp-client-tools.test.ts"
],
"fileNotes": [
{
"path": "packages/agentic/src/mcp/__tests__/mcp-client-tools.test.ts",
"text": "Spins up a real dev server and two WS-connected fake tabs, then drives the public MCP endpoint, so it's a good smoke test to run if the core routing logic is touched."
}
]
},
{
"key": "docs",
"label": "Docs for in-page tools over MCP",
"summary": "Documents the new 'in-page tools over MCP' flow, the `client_id` routing contract, `devframe:agent:list-clients`, and the new DF0082 error.",
"category": "docs",
"filePaths": [
"docs/content/1.guide/12.in-page-channel.md",
"docs/content/1.guide/15.agent-native.md",
"docs/content/6.errors/DF0082.md",
"docs/content/6.errors/index.md"
]
},
{
"key": "generated-snapshots",
"label": "Generated API snapshots",
"summary": "Auto-generated public API snapshots updated to reflect the new `BrowserAgentClientInfo` parameter, `ConnectedClient` type, `LIST_CLIENTS_TOOL` export and DF0082 diagnostic.",
"category": "other",
"filePaths": [
"tests/__snapshots__/tsnapi/devframe/index.snapshot.d.ts",
"tests/__snapshots__/tsnapi/devframe/internal.snapshot.d.ts",
"tests/__snapshots__/tsnapi/devframe/internal.snapshot.js"
]
}
],
"schemaVersion": 1,
"source": "llm",
"generatedAt": "2026-10-21T01:49:52.145Z",
"model": "vercel-ai-gateway/anthropic/claude-sonnet-5",
"locale": "en"
}
} |
Closes #394. MVP of the plan discussed there.
What changes
With several tabs of the same app open, the MCP surface behaved as if there were one client:
devframe connectlists instances per port, and in-page tools (from #376) were silently owned by whichever tab synced last.@devframes/agenticera):agent-flagged in-page channel functions register in a per-document browser-agent registry and sync to the node over the page's RPC connection; the node exposes them as MCP tools and relays calls back. Not yet on main, so it lands here as the foundation.sessionStorage-backed instance id, so it survives reloads), URL, title,visible,focused. Re-synced on connect, tool changes, andfocus/blur/visibilitychange.devframe:agent:list-clients(wiredevframe_agent_list-clients): built-in tool listing the connected tabs and the tool ids each exposes. Appears once a tab is connected, so a devframe with no agent surface of its own doesn't flip MCP auto-mount.tools/liststays deduped (one entry per tool id). Forwarded tools take a reservedclient_idargument; an unknown id fails with the newDF0081listing the live ids. Withoutclient_id, the call goes to the most recently focused visible tab, falling back to the last-synced one — which is what medula's vendored patch approximated with "last sync wins".devframe connect:list-instancesnestsmcp.clientsper instance (fetched in the same MCP session it already opens to list tools);call-toolpassesclient_idthrough.DF0080(the feat: eagerly expose in-page tools to browser agents #376jsonSerializableguard, renumbered sinceDF0078is taken on main) andDF0081pages.Verification
client_idtargeting/stripping, missing id, no re-publish on focus-only re-sync).tools/listdedup + injectedclient_idschema,list-clientsoutput, addressed/unaddressed/missing-id calls, focus follow.pnpm lint && pnpm knip && pnpm test && pnpm typecheck && pnpm buildgreen (knip's remaining items are the pre-existing unbuilt-starter hints).Known limits (MVP)
sessionStorage, so two tabs can briefly share an id; targeting then picks the better-ranked one.Supersedes the in-page-tools part of #376 (ported and extended here).
This PR was created with the help of an agent.