Web Use 实施与验证记录

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

TASK 1 · COMPLETE TASK 2 · COMPLETE TASK 3 · COMPLETE / APP E2E PASSED TASK 4–5 · COMPLETE / APP E2E PASSED TASK 6 · COMPLETE / PUBLIC API WEB_USE

任务 1:DOM-first Browser Agent baseline

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

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

生产文件:openprogram/programs/agentic_functions/browser_agent/__init__.pyopenprogram/programs/_registry.pyopenprogram/programs/__init__.pyopenprogram/agent/authority.py

测试文件:tests/unit/test_browser_agent.py

行为契约

Public-entry RED

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

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

明确排除

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

Full gate manifest

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

安装版缺陷闭环

缺陷修复验证
ToolReturnmedia_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() 仍直接索引六项内置表,抛出 KeyError2acf630b 将动态 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

任务账本

项目证据状态
Base commit717d4e17记录完成
REDpython -m pytest -q tests/unit/test_browser_agent.py:9 failed,缺失公开模块与全部约束。记录完成
GREEN / affectedFocused browser/browser-control group:51 passed;registry/tool-selection group:25 passed。通过
Specification review独立只读 review 对实现提交 37b2c37c 逐项核对 8 条行为契约与安全边界;zero remaining findings。PASS
Quality review首轮 CHANGES_REQUIRED 的取消、URL scheme、cleanup 三项已由 af33c608 修复。Fresh review 对候选 d0996f7b 复核全部 changed boundary,确认此前 KeyboardInterrupt 结论为误判;zero remaining findings。PASS
Full gateReviewed candidate:browser/browser-control 58 passed;registry/tool-selection 25 passed;Ruff passed;docs 0 broken links;diff check passed。通过

任务 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. Turn surface referencecomposer 从当前 compound group 生成 version/window/tab/region/access/focused/title/url 引用,并随 chat command 提交;region 按实际 pane 顺序区分 left、right 与 center,surface chip 显示当前绑定目标和位置。关闭访问时只保留 disabled descriptor,不提供 preview 或执行工具。
2. Exact preview服务端只向发起 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. Model context and tool schemadispatcher 在首个模型调用前注入 Surface Context。web_use 是 resident tool,但仅在 surface binding 有效时进入 provider tool array;没有 surface 时主动移除。模型不能提交 window/tab/CDP target,只能使用当前 turn 的 surface alias。
4. Bound executionbinding registry 保存 originating WebSocket、window、tab、target 与 expiry;subprocess bridge 只允许 exact binding 的 activate。Browser Agent 继续使用 DOM/ARIA refs 和 post-action observation。不使用 OS 输入、桌面坐标、app window focus 或默认 active tab;binding 缺失、过期或 identity 不匹配时失败。
5. Approval and verification用户发送带 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. Cleanup ownershipchat query 从 surface capture 开始进入 try/finally,直接 owner 无条件幂等释放 binding;正常 dispatcher teardown 也执行相同释放。prepare_turnTurnBindings.bind 或 provider 初始化在 context 建立前失败时,binding 不继续持有 originating WebSocket。

任务 2 安装版验收

场景证据结论
首轮页面感知安装版 chat command 包含 exact surface;服务端向同一 originating WebSocket 发出 preview,provider 在首个回复前获得 Bilibili title、origin、DOM excerpt、ARIA landmarks 和 web_use schema。PASS,无 screenshot
绑定页面点击Session local_340bc50ccd2c4eafb1fc12378e0489ab;模型调用 web_use,内部以 DOM ref 点击首页导航“番剧”。命令记录同时包含 exact window/tab 的 previewactivatePASS
确定性结果目标变为 https://www.bilibili.com/anime/?spm_id_from=333.1007.0.0title_contains=番剧frame_6_a628e0d2 返回 passed=true。外层工具结果为 status=succeededreason_code=verifiedPASS
窗口状态不参与执行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 审查记录

审查发现与处理结论
Specification review首轮发现目标设计仍保留旧的“Surface Awareness 未实现”和“完整 registry 完成前不得向 provider 注入”表述。已改为当前 turn-scoped baseline 与后续完整架构分别记录;复核未发现新矛盾。PASS,zero findings
Quality review复核确认跨进程 revision 字段完整传递,并发现自定义一参数 binding_validator 的兼容回归。Runtime 现在只对默认生产 validator 传 revision 关键字,自定义 validator 继续使用原一参数契约;legacy 与 revision-aware 路径均有回归测试。PASS,zero findings
Geometry specification review47fad4a533dd8f75d77a17c39c826f0c4ac96a212b3dda2e 复核首次 observe、二次 attach、preview/activate Promise、revision 0 与真实 hide 生命周期;最终未发现剩余规格偏差。PASS
Geometry quality review独立复核先后复现激活期间 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 同名第一方工具。完成
Session selectorobserve 选择 playwright_mcpchrome_devtools_mcpopen_claude_chrome;当前 session 禁止切换和自动 fallback。完成
Exact PagePlaywright 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 通过
Direct MCP单一桌面控制连接时可获取当前 in-app Page;多个连接直接拒绝,不随机选择窗口。component 通过
Backend parity真实 OfficialMCPPageBackendControllerBackend 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

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

生产文件:desktop/main.jsdesktop/preload.jsweb/lib/desktop-bridge.tsweb/lib/state/center-tabs-store.tsopenprogram/webui/ws_actions/webtab.pyopenprogram/agent/surface_context.pyagentic_functions/browser_agent/__init__.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 撤销能力。Gate:相关 Python tests、desktop navigation check、Web split/compound checks、TypeScript、生产 Web build、docs build/links、安装版 18100 E2E、diff/status。

状态证据
IMPLEMENTED · INSTALLED E2E PASSfe35dddf 实现同窗口 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。旧安装包已删除。
GROUP-AWARE INVENTORY · INSTALLED E2E PASSbrowserPageInventory()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。

状态证据
IMPLEMENTED · INSTALLED E2E PASSd2e9baa2 定义跨窗口数据模型;348e07f3 实现 Desktop window_id 登记和聚合;67e6ed09window_id + tab_id 标记 GUI Agent 当前 Page;833c23141699fb03 保持窗口独立生命周期和 primary fail-closed;26c662e9d4c4337e 以 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_useweb_session_id;模型工具列表不再公开 computer_use

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

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

交付直接证据状态
Runtime 与 sessionweb_use_runtime.pyWebUseSessionRegistryweb_session_id;三个 browser backend 和 exact Page 生命周期保持不变。完成
Agent / GUI HarnessChat Agent 可直接调用 web_usegui_agent 通过同一 Web Use adapter 使用相同命令和 session contract。完成
MCP / HTTPMCP tools/listtools/call 只公开 web_use;canonical route 为 /api/web-use完成
取消与连接清理3a2e6baf 在 MCP 调用取消后关闭延迟返回的 WebSession;cbc24778 精确撤销取消的 list_pages 所签发且未消费的 Page capability,不清理同 owner 的其他 session 或 capability。完成
自动验证与复核test_web_use_runtime.pytest_web_use_backend_parity.pytest_web_use_backend_threading.pytest_web_use_surface.pytest_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 PASS · PAGE E2E NOT RUN