Web Use 实施与验证记录

本页只记录 Web Use 目标设计 的实施任务、验证命令和 review 结论,不修改概念设计。第一项任务交付内置浏览器 Browser Agent 的低成本 baseline。

任务 1 · 已完成 任务 2 · 已完成 任务 3 · 已完成 / APP 端到端验收通过 任务 4–5 · 已完成 / APP 端到端验收通过 任务 6 · 已完成 / 公共 API WEB_USE

任务 1:DOM-first Browser Agent baseline

批准的设计:docs/reference/design/integrations/web-use.html。

基线:717d4e17。实现从隔离 worktree 和分支 codex/browser-agent-20260814 开始。

生产文件:openprogram/programs/workflow/browser/__init__.py、openprogram/programs/_registry.py、openprogram/programs/__init__.py、openprogram/agent/authority.py。

测试文件:tests/component/programs/browser/test_browser_agent.py。

行为契约

公开入口 RED

python -m pytest -q tests/component/programs/browser/test_browser_agent.py 必须先证明以下缺口:

安全、取消、错误与并发边界

明确排除

桌面级 Computer Use、GUI Harness 视觉 pipeline、权限卡片新 UI、永久 origin grant、tab lease、多窗口路由重构、Windows、OS keychain/keyring、浏览器 profile 迁移均不属于任务 1。

完整检查清单

安装版 E2E 验证

测试对象:/Applications/OpenProgram.app 0.6.1。测试没有用 Electron 源码启动;桌面进程和 18101 worker 均来自应用包,worker Python 为 Contents/Resources/runtime/python/cpython-3.12.10-macos-aarch64-none/bin/python3.12。

隔离方式:使用 profile browser-agent-installed-20260814 和端口 18101,避免影响同时运行的其他 OpenProgram worker。模型配置来自该 profile 的本地副本。

场景运行证据结论
DOM-first 表单会话 local_38e090f085;输入 browser-agent-installed-final,点击 pushState,url_contains ?p=1 通过;2 次页面写动作,0 次 screenshot,0 个 tool error。PASS
单图视觉输入会话 local_7a8021f999;tool trace 为 observe → screenshot → verify;恰好 1 次 screenshot,返回 ImageContent 与 mime_type='image/png',无 validation error。PASS
模型原生 vision 判断模型基于该 screenshot 判断当前 viewport 含浅色紫色渐变区域。该项是模型语义判断,不是 DOM assertion。已获得视觉结果
确定性完成判定同一视觉 session 的 title_contains Desktop Transfer Acceptance 返回 passed=true,Runtime 因此输出 status=succeeded、reason_code=verified。该 assertion 只验证标题,不单独证明渐变判断正确。PASS,证据范围受限

安装版缺陷闭环

缺陷修复验证
ToolReturn 用 media_type 构造 provider 图片,截图调用触发缺少 mime_type 的 Pydantic validation error。3c850a91 改为 provider 类型要求的 mime_type;screenshot 未传 frame ID 时复用最新 observation,并继续限制同一 frame 只截图一次。Browser/tool runtime 相关测试 74 passed;安装版视觉 trace 中 PNG image block 成功到达模型。
自动检测到 provider.json 提供的 minimax-cn-coding-plan 后,create_runtime() 仍直接索引六项内置表,抛出 KeyError。2acf630b 将动态 provider 路由到通用 API Runtime,并规范化带 provider 前缀的 model。Provider routing 6 passed;安装版 session 成功创建 minimax-cn-coding-plan:MiniMax-M3 Runtime。
桌面内嵌 runtime 只安装基础 wheel,没有 Playwright Python 包,CDP session 无法创建。334d0abc 让桌面 runtime 安装 wheel 的 [browser] extra,并在构建时导入检查 playwright.sync_api;不下载 Playwright Chromium。发布回归测试、Bash 语法和 Ruff 通过;安装包内嵌 Python 导入通过;DOM 与视觉 E2E 均通过。

本地 macOS 构建未签名。依赖安装同时报告 Web 依赖 8 个 high severity、Desktop 依赖 2 个 moderate 与 5 个 high severity;本任务未执行会改写依赖树的 npm audit fix。

任务账本

项目证据状态
基准提交717d4e17记录完成
REDpython -m pytest -q tests/component/programs/browser/test_browser_agent.py:9 failed,缺失公开模块与全部约束。记录完成
GREEN / 受影响检查聚焦 browser/browser-control 分组:51 项通过;registry/tool-selection 分组:25 项通过。通过
规格审查独立只读 review 对实现提交 37b2c37c 逐项核对 8 条行为契约与安全边界;zero remaining findings。PASS
质量审查首轮 CHANGES_REQUIRED 的取消、URL scheme、cleanup 三项已由 af33c608 修复。Fresh review 对候选 d0996f7b 复核全部 changed boundary,确认此前 KeyboardInterrupt 结论为误判;zero remaining findings。PASS
完整检查审查候选:browser/browser-control 58 项通过;registry/tool-selection 25 项通过;Ruff 通过;文档 0 死链;diff 检查通过。通过

任务 2:Turn-scoped Surface Awareness 与绑定式 Web Use

实现范围:chat turn 自动携带当前 split web surface;模型首轮上下文包含有界 DOM/ARIA preview;仅在有效 surface 存在时提供 web_use;读取和动作固定到 originating WebSocket 的 window_id + tab_id + target_id。

前台要求:没有。Electron 直接读取绑定 WebContents 并返回其 CDP target;activateView 不调用 BrowserWindow.focus() 或其他 OS focus API。目标 pane 不需要拥有键盘焦点,普通 DOM/ARIA action 不使用桌面坐标和 screenshot。

运行对象:默认 profile ~/.openprogram、端口 18100、/Applications/OpenProgram.app。没有从 Electron 源码启动第二个桌面进程或第二个可见 worker。

任务 2 实现分层

步骤实现边界
1. 轮次界面引用composer 从当前 compound group 生成 version/window/tab/region/access/focused/title/url 引用,并随 chat command 提交;region 按实际 pane 顺序区分 left、right 与 center,surface chip 显示当前绑定目标和位置。关闭访问时只保留 disabled descriptor,不提供 preview 或执行工具。
2. 精确预览服务端只向发起 chat 的 WebSocket 请求 preview,并校验 exact window/tab/target;Electron 从当前 viewport 的 DOM、ARIA landmarks、title 与 URL 生成结果。文本最多 2,000 字符,landmark 最多 12 项且 name 最多 160 字符;URL 只保留 origin,不包含 query value;不发送 screenshot。
3. 模型上下文与工具 schemadispatcher 在首个模型调用前注入 Surface Context。web_use 是 resident tool,但仅在 surface binding 有效时进入 provider tool array;没有 surface 时主动移除。模型不能提交 window/tab/CDP target,只能使用当前 turn 的 surface alias。
4. 绑定执行binding registry 保存 originating WebSocket、window、tab、target 与 expiry。聊天直接调用的 web_use 保留 runtime card,但在持有 renderer WebSocket 与 WebSession registry 的 worker 主进程执行;只有 GUI Agent Harness 的长循环使用 subprocess bridge。Browser Agent 继续使用 DOM/ARIA refs 和 post-action observation。不使用 OS 输入、桌面坐标、app window focus 或默认 active tab;binding 缺失、过期或 identity 不匹配时失败。
5. 审批与验证用户发送带 exact surface 的 turn 后,外层 web_use 不请求第二次通用 approval;hard constraints、authority 和显式 deny/ask rules仍先执行。Plan mode 不提供 web_use。父 turn 的 permission rules 以纯数据快照传入 agentic 子进程;内部 browser_page 只在该绑定调用期间使用 scoped bypass,结束后恢复。Runtime assertion 决定终态。高风险 action 规则仍可 ask/deny;写动作继续要求新鲜 DOM frame。动态页面的 verification 读取同一 bound target 的当前 DOM,不因无关 mutation 永久 stale。
6. 清理归属chat query 从 surface capture 开始进入 try/finally;dispatcher 为当前 session + assistant turn 生成稳定 Web Use owner,并在正常返回、重试、取消或异常 teardown 时释放该 owner 的全部 WebSession、Page lease 与 binding,不依赖模型显式调用 close。prepare_turn、TurnBindings.bind 或 provider 初始化失败,以及模型没有调用 close 时,Page 都不能残留为 page_in_use。

任务 2 安装版验收

场景证据结论
首轮页面感知安装版 chat command 包含 exact surface;服务端向同一 originating WebSocket 发出 preview,provider 在首个回复前获得 Bilibili title、origin、DOM excerpt、ARIA landmarks 和 web_use schema。PASS,无 screenshot
绑定页面点击会话 local_340bc50ccd2c4eafb1fc12378e0489ab;模型调用 web_use,内部以 DOM ref 点击首页导航“番剧”。命令记录同时包含 exact window/tab 的 preview 和 activate。PASS
确定性结果目标变为 https://www.bilibili.com/anime/?spm_id_from=333.1007.0.0;title_contains=番剧 在 frame_6_a628e0d2 返回 passed=true。外层工具结果为 status=succeeded、reason_code=verified。PASS
窗口状态不参与执行test_web_use_background_app.py 自行创建临时 Page 后立即切回原 tab,使目标 Page 成为 visible=false 的后台 WebContents。随后执行 list_pages → observe → viewport screenshot → DOM ref click → observe → verify → close;每个 Agent 动作后都要求原 tab 仍然可见。截图由 exact Page 的 CDP session 直接生成;Web Use 不读取系统屏幕,也不查询或改变系统窗口的层级、位置、遮挡、最小化或置顶状态,不调用 browser.close()、bringToFront()、窗口 focus、整屏截图或 OS input。独立后台 Page 自动化 E2E

任务 2 验证命令

任务 2 当前范围与剩余项

当前实现支持 turn-scoped exact Page binding、server-owned connection/Page/access monotonic revision、renderer-owned monotonic geometry revision、基于 Page revision canonical key 的 WebSession 排他 lease,以及显式 screenshot 的单张当前 viewport 原生视觉输入。session 内 action、verify、observe 与 close 串行执行;首次 observe 以及后续每次 observe、act 和 verify 都在 backend 前重新验证 exact binding。Page capability 保存 page/access/geometry revision,agentic 子进程把期望值经父子进程 bridge 传回父 worker;父 worker 比较 Page/access revision,exact renderer 在 native preview/activate 前以及异步完成后复核应用内 pane 状态与 geometry revision。任一不一致即返回 page_context_stale,不进入 backend;异步完成后的过期结果不包含 preview 或 target。pane bounds 或应用内可见性变化只使旧 WebSession 失效,不重建 Page identity;后台 Page 通过 resolve 直接取得 exact target。macOS 窗口层级、遮挡、位置和最小化状态不进入 binding 或 screenshot 判断。close、首次 observe 失败、owner disconnect 或进程清理完成前 lease 不会提前释放。target replacement 会撤销旧 Page identity;owner WebSocket disconnect 会立即撤销该连接的全部 binding 并唤醒 pending exact-socket request。两个 connection、48 个 binding 的 component 并发验证确认命令只发送到 originating connection,断开其中一个不影响另一个。安装版双窗口 transfer/rollback、截图 artifact 临时保留策略与三个 backend 的统一 parity suite 已完成。专用 permission card 属于 UI 后续项,不在本次仅实现功能的范围内。

任务 2 审查记录

审查发现与处理结论
规格审查首轮发现目标设计仍保留旧的“Surface Awareness 未实现”和“完整 registry 完成前不得向 provider 注入”表述。已改为当前 turn-scoped baseline 与后续完整架构分别记录;复核未发现新矛盾。通过,0 项问题
质量审查复核确认跨进程 revision 字段完整传递,并发现自定义一参数 binding_validator 的兼容回归。Runtime 现在只对默认生产 validator 传 revision 关键字,自定义 validator 继续使用原一参数契约;legacy 与 revision-aware 路径均有回归测试。通过,0 项问题
几何规格审查对 47fad4a5、33dd8f75、d77a17c3、9c826f0c、4ac96a21 与 2b3dda2e 复核首次 observe、二次 attach、preview/activate Promise、revision 0 与真实 hide 生命周期;最终未发现剩余规格偏差。PASS
几何质量审查独立复核先后复现激活期间 geometry 变化、首次 observe 缺少校验、preview 缓存旧 revision、revision 0 兼容偏差与应用内 pane 可见性误判;对应回归全部加入后 fresh review 通过。PASS
视觉 artifact review截图只进入紧邻的一次 provider request;Runtime/DAG 文本仅保留 frame、viewport 与已附图标记。正常返回、provider error、timeout 与 cancel 都清除原始 image block、ToolReturn.images 和坐标权限。Specification 与 Quality 均 PASS

任务 3:统一 command API 与三个 backend

交付直接证据状态
统一入口web_use(list_pages / observe / act / verify / close);OpenProgram MCP 同名第一方工具。完成
会话选择器observe 选择 playwright_mcp、chrome_devtools_mcp 或 open_claude_chrome;当前 session 禁止切换和自动 fallback。完成
精确页面Playwright MCP 通过官方 createConnection(contextGetter) 获得只含 exact target 的 BrowserContext 视图;Chrome DevTools MCP 使用一次性 marker 解析 pageId。Runtime 在首次 observe 及后续每次 observe、act 和 verify 前重新验证原绑定 target 的可见性、identity 与 Page/access/geometry revision;controller 的 app attach 继续携带同一 revision。revision、identity 或真实可见性变化时先清理 session,不进入 backend。三个 backend 均不选择或置前 tab。component 通过
直接 MCP单一桌面控制连接时可获取当前 in-app Page;多个连接直接拒绝,不随机选择窗口。component 通过
后端一致性真实 OfficialMCPPageBackend 与 ControllerBackend adapter 通过公共 WebUseSessionRegistry.execute() 运行同一矩阵;覆盖 observe、7 个 allowlisted action、stale/unsupported、backend error、内建及 Playwright timeout、verify、PNG screenshot 与 close。每个写动作只到达所选 backend 一次,失败不触发 fallback。Specification 与 Quality 均 PASS
验证Surface、permission、跨进程 bridge、Backend parity、Runtime、threading、Browser Agent、MCP contract 与 route 相关测试 312 passed;完整 Web check、TypeScript、生产 build、WebTab navigation/zoom 与安装版 transfer client 检查通过。通过
安装版ba665053 已刷新到 /Applications/OpenProgram.app,只使用默认 ~/.openprogram 与 18100 worker。三个 backend 依次绑定同一当前可见内置 Page,完成 list_pages → observe → scroll → observe → text_contains verify → close;每条路径只执行一次写动作并返回 passed=true。三个 backend 又各自返回恰好一张带 viewport 元数据的有效 PNG,验收过程不保存图片。真实双窗口 transfer/rollback 同时确认目标 renderer 已 stage、源状态未变化、目标窗口销毁且存储无残留。PASS

任务 4:浏览器多 Page 与 popup handoff

基准:54c466e9。范围:当前 OpenProgram window 的 web Page inventory、background exact target、popup opener 归属,以及 browser_agent/gui_agent 的显式 Page 切换。

生产文件:apps/desktop/main.js、apps/desktop/preload.js、apps/web/lib/desktop/desktop-bridge.ts、apps/web/lib/tabs/center-tabs-store.ts、apps/server/openprogram_server/_webui/ws_actions/webtab.py、openprogram/agent/surface_context.py、openprogram/programs/gui_browser_agent.py。排除:桌面软件控制、跨窗口 inventory、OCR/YOLO/memory、自动 backend fallback。

RED:同窗口 A/B/popup C inventory;C 保存 opener=A;token 绑定 exact target;background B observe/act 不改变 visible/active/focus;GUI Agent 写动作后发现 C 并以 token 切换;没有已挂载 native Page 时返回空 inventory;close/target replacement/disconnect 撤销能力。检查:相关 Python tests、desktop navigation check、Web split/compound checks、TypeScript、生产 Web build、docs build/links、安装版 18100 E2E、diff/status。

状态证据
已实现 · 已安装版本端到端验收通过fe35dddf 实现同窗口 Page inventory、background exact binding、popup opener 与 GUI Agent 显式切换;67a65e2a 让 inventory 从 native WebContents 读取实时 URL/title,后台导航后不再返回旧 tab metadata;没有已挂载 native Page 时返回 ok: true, pages: [],不再转换成 HTTP 500。
自动验证Browser Agent、Web Use Runtime、backend parity/threading、Page binding 与 HTTP route 相关测试 123 passed;WebTab navigation、Web split/compound、TypeScript 与生产 Web build 通过。行为测试确认 resolve/inspect background Page 不调用 show、focus 或 bringToFront()。
安装版验证只使用默认 ~/.openprogram、18100 与 /Applications/OpenProgram.app。inventory 同时返回前台 Grammarly 与后台 Example;open_claude_chrome 在后台 Example 上执行 observe → click Learn more → observe → close,真实 Page 进入 IANA,前台始终保持 Grammarly;下一次 inventory 实时返回后台 Example Domains / https://www.iana.org。旧安装包已删除。
分组感知清单 · 已安装版本端到端验收通过browserPageInventory() 与 list_pages 现在返回 tab_entries + pages、active/focused identity、pane placement 和单调 inventory_revision。pane 顺序跟随实际 visibleIds;Page capability 独立释放,关闭一个 session 不影响同一 inventory 中的其他 Page。自动测试覆盖 3 个 tab entry、4 个 Page、成员重排、并发 revision 和 sibling session 生命周期;安装版在真实 split entry 的 left Page 完成 list_pages → observe → click → observe → restore → close,点击 Example 的 Learn more 后进入 IANA,再恢复原页。
保留范围跨窗口 inventory 已在任务 5 实现。桌面软件控制、OCR/YOLO/memory 与自动 backend fallback 不属于 Web Use。popup opener、token handoff 与 stale/close 撤销已有 component 覆盖,尚未增加公开网站 popup 的安装版 fixture。

任务 5:跨窗口 Page inventory

范围:登记每个 Desktop renderer 的 window_id,让 list_pages 聚合所有已登记窗口,同时保留原 connection/window/tab/target binding。截图继续直接捕获 exact Page 的当前 viewport,不置前窗口,不读取桌面画面。

兼容:保留现有顶层 primary-window 字段;新增 windows[] 与 Page 级 window_id。不增加配置 ID、权限 UI、OCR、桌面控制或自动 backend fallback。

状态证据
已实现 · 已安装版本端到端验收通过d2e9baa2 定义跨窗口数据模型;348e07f3 实现 Desktop window_id 登记和聚合;67e6ed09 以 window_id + tab_id 标记 GUI Agent 当前 Page;833c2314、1699fb03 保持窗口独立生命周期和 primary fail-closed;26c662e9、d4c4337e 以 connection revision CAS 拒绝断线后的延迟 binding。
自动验证与复核Browser Agent、Web Use Runtime、Page surface 和 process bridge 相关测试 123 passed;Ruff、Web split/compound/WS action、TypeScript 与生产 Web build 通过。Specification 与 Quality 独立复核均为 PASS,覆盖未登记客户端、跨窗口同名 tab_id、origin disconnect/timeout、materialization race 和 direct preview/active late result。
安装版验证只使用默认 ~/.openprogram、18100 与当前主分支重新生成的 /Applications/OpenProgram.app。真实 list_pages 返回 main 和 detached window 两个 snapshot;选择 detached window 的 Microsoft Edge Add-ons Page 执行 observe → screenshot → close,得到一张 exact Page 的 image/png 当前 viewport。执行路径没有窗口 focus、bringToFront()、整屏截图或 OS input。

任务 6:公开名称与边界迁移

公开能力:Agent registry、GUI Agent Harness、OpenProgram MCP 与 canonical HTTP API 统一使用 web_use 和 web_session_id;模型工具列表不再公开 computer_use。

兼容边界:/api/computer-use 与旧请求字段 computer_session_id 只作为隐藏 HTTP 兼容入口保留,映射到同一个 Web Use Runtime,且不出现在 OpenAPI、Agent 或 MCP 工具列表中。

未来边界:Computer Use 名称只保留给未来桌面应用、应用窗口或整屏截图及 OS 输入能力;本次不增加桌面 adapter、配置或后台进程。

Agent 光标任务

BrowserPageController 已在 exact Page 上实现 click-only 内部 overlay,官方 MCP adapter 在 click 调用期间复用同一 arming contract。component 验收覆盖 DOM ref click、viewport coordinate click、用户点击不显示、反馈失败不改变 action 结果以及三个 backend;106 项相关回归通过。安装版后台 Page E2E 在目标 visible=false 且原 tab 不变时完成 ref click,页面 click handler 记录 cursor=true。范围不包含系统鼠标、窗口 focus、hover/type 动画、配置项、依赖或常驻进程。

交付直接证据状态
Runtime 与 sessionweb_use_contract.py 为 Chat Agent 与 MCP 提供同一份 command-conditioned schema;空的旧版可选字段按未指定处理,act、verify 与 close 各自强制要求所需 session/frame/arguments。web_use_runtime.py、WebUseSessionRegistry、三个 browser backend 和 exact Page 生命周期保持不变;Runtime 对缺失 action 字段返回完整 missing_arguments,不进入 backend,也不清除仍有效的 observation。完成
Agent / GUI HarnessChat Agent 可直接调用 web_use;gui_agent 通过同一 Web Use adapter 使用相同命令和 session contract。完成
MCP / HTTPMCP tools/list 与 tools/call 只公开 web_use;canonical route 为 /api/web-use。完成
取消与连接清理3a2e6baf 在 MCP 调用取消后关闭延迟返回的 WebSession;cbc24778 精确撤销取消的 list_pages 所签发且未消费的 Page capability,不清理同 owner 的其他 session 或 capability。完成
自动验证与复核test_web_use_runtime.py、test_web_use_backend_parity.py、test_web_use_backend_threading.py、test_web_use_surface.py、test_web_use_route.py 与 MCP/Agent 相关组共 453 passed;Specification 与 Quality 独立复核均为 PASS。通过
当前安装版使用默认 ~/.openprogram、18100 和 /Applications/OpenProgram.app 验证:Agent registry 只返回 web_use;OpenAPI 公开 /api/web-use,隐藏 legacy /api/computer-use 与内部 capability release route;真实 list_pages 成功返回一个 window snapshot。验收时没有已登记 Page,因此本轮没有执行 observe 或网页动作,也没有为验收切换前台窗口。API 通过 · 页面端到端验收未执行