fix: open browser popup links in managed tabs
Links requesting a new window were silently blocked. Open them in managed browser tabs with the existing session restrictions, clean up script-closed tabs, and follow click-created tabs in subsequent direct and MCP browser tools. Validation: 232 targeted tests and Windows Electron E2E passed; typecheck and lint passed. The full suite retains six failures outside the popup path. Release note: Browser links that open a new page now open in a managed tab, and AI browser actions follow the new page after a click.
This commit is contained in:
@@ -153,9 +153,38 @@ Conversation 归属,不新建租约或把页面重新归属到子级对话。
|
||||
单次工具取消信号、Tab 使用租约信号和请求信号,取消一次工具调用不终止后续调用。
|
||||
|
||||
该阶段 MCP transport、endpoint 和 token 生命周期不变,只扩展服务端 capability 内容和内部
|
||||
路由。工具调用使用当前请求绑定的 Tab,只有上述显式导航恢复会更换绑定。
|
||||
路由。工具调用使用当前请求绑定的 Tab;显式导航恢复和下述点击开窗会更换绑定。
|
||||
|
||||
### 6.2 Agent 多 Tab 阶段
|
||||
### 6.2 Page-created tabs
|
||||
|
||||
`target="_blank"` and `window.open` create managed `WebContentsView` tabs through Electron's
|
||||
`setWindowOpenHandler.createWindow`. Chromium retains the original request and opener relationship,
|
||||
including a blank window followed by a script-assigned location. These tabs share the Conversation
|
||||
partition, proxy and permission restrictions. HTTP(S) URL checks remain in the session and filtering
|
||||
proxy; `about:blank` is permitted only as the initial empty popup. Unsupported URL schemes remain denied.
|
||||
|
||||
BrowserService reserves capacity before creating the native view, assigns a new Tab/workbar identity,
|
||||
and owns initialization, the Driver and cleanup. Initialization failure or Conversation disposal releases
|
||||
the popup. Closing the opener leaves an already created popup alive. A popup's `window.close()` releases
|
||||
its service slot and usage leases; Renderer removes its workbar instance and returns to the opener when
|
||||
it is still available. No separate unmanaged BrowserWindow is created.
|
||||
|
||||
Live state includes `openerTabId`. A popup from the visible browser is selected even when the active chat
|
||||
has switched to a different Conversation. Other workbar panels and viewport occlusion rules retain their
|
||||
existing behavior. The existing workbar capacity notification still applies when all 32 slots are occupied.
|
||||
|
||||
During `browser_click`, the service collects popup registrations from that Tab and waits for their
|
||||
initialization. The result identifies the last created popup. BrowserModelTools binds subsequent tools to
|
||||
that Tab and asks the model to obtain new references with `browser_snapshot`; the MCP gateway also replaces
|
||||
its capability binding and usage lease. Switching visible tabs does not alter this binding. Closing the
|
||||
popup retains the existing explicit `browser_navigate` recovery behavior. A page may still be loading
|
||||
when the click returns. Popups requested asynchronously after the click has completed are displayed as
|
||||
managed tabs, but are not attributed to that completed tool call.
|
||||
|
||||
The remote ACP Runtime exposes its separately scoped image MCP server, not this desktop browser gateway;
|
||||
this change does not add browser access to the deployed GoodBuddy Agent.
|
||||
|
||||
### 6.3 Agent 多 Tab 阶段
|
||||
|
||||
只有明确需要 Agent 管理多个页面时,才增加:
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ Runtime
|
||||
从当前聊天右栏迁移时,Task Center 和工作区作为默认打开、单实例且不可关闭的基础应用保留;
|
||||
浏览器保留一个默认打开实例,但注册为可关闭的多实例应用;成果保持默认打开、单实例且可
|
||||
关闭;终端不默认打开,由用户通过“+”创建,并从首期开始支持多实例。Tab 必须单行横向滚动,
|
||||
不能自动隐藏或缩写到不可辨认,“+”不能随滚动消失。Task Center 继续作为 Task 的现有
|
||||
不能自动隐藏或缩写到不可辨认,“+”紧随最后一个 Tab 并随标签滚动,溢出时两端提供固定滚动箭头。Task Center 继续作为 Task 的现有
|
||||
入口;审批定位到所属 Task 或 Runtime。智能心跳不作为工作栏页签,其报告、建议、历史和
|
||||
完整配置统一归属“智能心跳”菜单入口。当前阶段不新增独立自动化中心。
|
||||
|
||||
@@ -457,6 +457,12 @@ Renderer 不接收任意系统 PID 控制能力。控制动作引用 Main 签发
|
||||
|
||||
### 7.7 浏览器
|
||||
|
||||
Page requests made with `target="_blank"` or `window.open` open managed browser tabs in the same
|
||||
Conversation. A popup from the visible page becomes visible in the workbar; closing it from page script
|
||||
removes that popup tab. When an Agent click opens a new tab, subsequent browser tools follow that page
|
||||
and obtain fresh element references. Detailed lifecycle and routing rules are defined in
|
||||
[Page-created tabs](./browser-tabs-technical-design.md#62-page-created-tabs).
|
||||
|
||||
浏览器是可关闭的多实例应用。升级后的默认布局保留一个浏览器实例;用户从“+”目录选择
|
||||
浏览器时每次创建新的 Browser Tab。每个实例必须显示可区分的标题和绑定 Conversation,
|
||||
不能让多个工作栏 Tab 只是同一页面的重复控制入口。
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
# 工作栏实现与验证进度
|
||||
|
||||
## 2026-09-15 Managed browser popups
|
||||
|
||||
Implemented [page-created tabs](./browser-tabs-technical-design.md#62-page-created-tabs): native
|
||||
Electron popup creation now registers a managed Tab, and click results update direct-tool and MCP
|
||||
bindings. Renderer selects a visible opener's popup across chat switches and removes script-closed
|
||||
popup instances. Existing worktree changes were retained.
|
||||
|
||||
Validation against the current source:
|
||||
|
||||
- `npx vitest run src/main/browser src/main/agent/knowledge-mcp-gateway.test.ts src/main/agent/model-tool-provider.test.ts src/renderer/src/RightAssistantSidebar.resize.test.tsx src/shared/contracts.test.ts`: 10 files, 232 tests passed.
|
||||
- `node build/run-browser-tabs-electron-e2e.cjs`: passed twice after making the test wait for the shown
|
||||
native view's animation frames before sending mouse input. Real Chromium verified `target=_blank`,
|
||||
`window.open(url)`, blank-then-location, script close, opener close, shared partition, unsupported URL
|
||||
denial, and subsequent direct/MCP snapshots on the popup. No fixed click delay was added to production.
|
||||
- `npm run typecheck` and `npm run lint`: passed. `git diff --check`: no whitespace errors.
|
||||
- `npm test`: 4319 passed, 67 skipped, 6 failed across 5 files. Failures were Agent offline dependency
|
||||
installation timeout, local Runtime reuse timeout, diagnostic-log writer expectations, two heartbeat
|
||||
migration fixtures with `duplicate column name: pinned`, and an App external knowledge binding test
|
||||
missing the `Remote handbook` heading. The full suite was not green; none of these failures exercise
|
||||
the popup registration or binding path.
|
||||
|
||||
The Electron test uses production BrowserService, CDP and MCP with a local HTTP fixture; the workbar
|
||||
selection/removal path is covered by the actual Renderer component test. A complete installed-App
|
||||
visual test and macOS/Linux native popup checks were not run. No external model calls were made for
|
||||
the popup validation. Remote ACP exposes only its scoped image MCP server (`imageMcpServers`), so the
|
||||
deployed Agent has no separate affected browser implementation and no remote Host change was needed.
|
||||
|
||||
## 2026-09-15 会话置顶与浮动操作菜单
|
||||
|
||||
已核对当前源码差异:置顶经专用 IPC 写入 SQLite,schema 36 迁移保留已有会话;会话操作
|
||||
|
||||
Reference in New Issue
Block a user