Skip to content

feat(agent): 补齐 Browser/Computer Use 动作契约并对齐 a11y 协议(P0) - #1328

Open
sheepbox8646 wants to merge 2 commits into
mainfrom
feat/computer-browser-p0
Open

sheepbox8646 wants to merge 2 commits into
mainfrom
feat/computer-browser-p0

Conversation

@sheepbox8646

Copy link
Copy Markdown
Member

Author

  • Human
  • Agent

Type

  • bug
  • feat
  • test

Summary

实施 docs/computer-browser-capability-completion-plan.mdP0 阶段(修复现有协议和动作错误),计划文档本身也随本 PR 入库并勾选 P0 项;P1–P5 未在本 PR 中实施。

问题

  • a11y-cli 输出的 lines 是数组、几何字段是 x/y/width/height,而 Go 侧按字符串 linescenter 解码:真实 helper 的快照在 Go 侧解码失败,ref 中心坐标也永远拿不到(C07/C08)。
  • 六个已实现的 browser action(keyboard_typekeyboard_inserttextkeydownkeyupdblclickscrollintoview)没有进入 schema 枚举,严格 schema 调用无法表达(C01)。
  • schema 只要求 action/observe,错误的参数组合要到执行时才失败,部分输入被静默忽略(C02)。
  • Browser 鼠标固定左键、一次或两次;Computer 按 ref 点击忽略 button,AX 双击只调一次默认动作(C03/C04)。
  • fill 的 RFB 回退只输入不清空,两侧都拒绝空文本,替换/清空语义不成立(C05)。
  • timeout 默认值与执行分支不一致,导航就绪失败被 _ = 吞掉(C10)。
  • 实施中发现:GTK 未布局的表格单元通过 AT-SPI 报告 -2147483648,-2147483648 的坐标,原实现会把它当成指针目标——实测双击落到了桌面左上角的 Applications 菜单(见截图 00)。

改动

  • 协议crates/a11y-cli 输出带 protocol_version(2)、helper_versionlimittruncated、数组 lines、逐项几何与 states;Go 侧 computer_a11y.go 先校验版本再解码,旧 helper 或不认识 locate/--limit 的 helper 返回「重建工作区镜像」错误。诊断计数返回给模型,总线地址只进日志。
  • a11y-cli locate --ref eN:从持久化索引取几何信息,不重扫、不重新编号;ref 的双击/三击/中键/右键据此回放真实指针事件(AT-SPI 默认动作只触发一次且没有按钮)。中心不在 0–32767 范围内的元素视为无几何,指针类动作明确报错。
  • 动作契约 internal/agent/tool/gui_contract.go(定义在 browser_contract.go / computer_contract.go):一份规范同时生成五个工具的 schema、action 参数说明和执行前校验。不属于该动作的参数、未知枚举值、越界数字、ref+selector、元素+坐标、半个坐标对、timeout+duration_msdouble_click 冲突的 click_count 都在任何副作用之前被拒绝。
  • 动作行为:Browser click/double_click/hover/drag 支持 buttonclick_count 与视口坐标;fill 两侧接受空字符串清空(Browser 端同时校验元素可编辑并返回实际值,Computer 端 RFB 回退先 Select All + BackSpace);select 校验选项存在;timeout 只用于就绪等待(默认 30000),duration_ms 用于固定等待,旧的 Computer wait.amount / Browser 无目标 wait.timeout 仍单独接受;导航、刷新、历史的就绪失败改为返回错误;RFB 多次点击与滚轮步在一个批次内发送。
  • 文档docs/agent-runtime.md 补充契约与协议说明。

Related Issues

无。

Validation

自动化

  • cargo test -p a11y-cli:37 项通过。
  • go test ./internal/agent/... ./internal/display/... ./internal/handlers/...:34 个包通过(新增契约校验、a11y 协议解码/版本拒绝、schema 枚举完整性等测试)。
  • golangci-lint run ./...(仓库全量):无问题。
  • go test ./...(仓库全量):156 个包通过,0 失败。
  • 说明:提交时 husky pre-commit 钩子因新 worktree 里钩子文件不可执行而被 git 跳过,因此上面两项是手动按 .husky/check-go.husky/check-go-test 的内容执行的;本 PR 不含 web 文件,lint-staged 无需运行。scripts/check-ui-contract.mjs 报告 apps/web/src/pages/home/components/tool-call-diff-panel.vue 有一个 hand-spun loader,该文件在 main 上已存在且本 PR 未触碰,与本改动无关。

真实运行环境

  • 独立开发环境 memoh-cuadevenv/docker-compose.yml + 项目名/端口 override):Server http://localhost:19880,Web http://localhost:19882,工作区镜像用 scripts/prepare-dev-workspace-image.sh 从本分支重建(含新版 a11y-cli),server 重启后重新导入并重建 Bot 工作区,GET /bots/{id}/container/display 返回 a11y_available: true
  • 模型说明:本机没有可用的真实模型密钥,验证使用一个脚本化的 OpenAI 兼容模型服务(按对话状态返回下一步工具调用),驱动的是真实的 Memoh Web 聊天 → Agent 运行时 → 工具执行 → 工作区浏览器/桌面链路;工具调用、结果和截图均为真实执行产物。这不构成 Human QA。
  • 通过 Web UI 的聊天页发送四条消息,各触发一个场景:
    1. 参数校验:9 次调用,前 8 个是故意的错误组合(ref+selectortimeout 90000、double_clickclick_count 3、navigatetexttimeout+duration_msamount+duration_ms、无定位的 click、空 texttype),全部在执行前被拒绝并返回明确错误;最后一个合法 wait 正常完成。
    2. 浏览器:navigate 到测试表单 → snapshot → fill 写入「新名字 Memoh 🚀」(evaluate 读回一致,页面收到 input 事件)→ fill 空串清空(读回 "")→ double_click 触发页面 dblclick(detail 2)→ button: right 触发 mousedown(button 2)contextmenu → 视口坐标 click_count: 3get_content 与 screenshot。
    3. 桌面exec 启动 xfce4-appfinder → snapshot(helper_version 0.1.0、诊断计数)→ fill 输入框「term」(via a11y,列表被过滤)→ button: right → 后续 snapshot 出现 menuCut/Copy/Paste/Delete/Select All/Insert Emoji 菜单项 → Escape → fill 空串清空(via a11y)→ 再过滤并 double_click 可见的「Terminal Emulator」行(via rfb)→ snapshot 出现 frame "Terminal -"terminal "Terminal" (focused),桌面上打开了 Xfce Terminal。
    4. 受控报错:对 AT-SPI 报告 i32::MIN 坐标的列表单元执行 double_click 与右键 click,两次都返回「ref … has no on-screen box …」错误,随后 snapshot 与之前一致,桌面未被误操作。
  • 未做:P1–P5 的能力(computer_context、稳定 ref/generation、paste/select_text 等)不在本 PR;uploadpdftab_* 路径只做了契约校验测试,未在真实 UI 中逐一触发。

Screenshots / Recordings

截图托管在分支 computer-p0/assetsshots/)。

截图 说明
validation 参数校验场景:聊天里每个错误调用都在执行前被拒绝并给出原因;右侧桌面面板由 UI 自动打开
browser chat 浏览器场景在聊天页中的 11 步工具调用记录
browser page 工具保存的工作区浏览器截图:Name 已被清空,状态区依次记录 fill 的 input 事件、双击(detail 2)、右键(button 2)与 contextmenu
appfinder fill 桌面场景:fill 通过 AT-SPI 把「term」写进应用查找器输入框,列表被过滤
context menu 按 ref 右键(通过 locate 取中心后回放 RFB)弹出 GTK 上下文菜单
terminal 按 ref 双击可见的「Terminal Emulator」行,Xfce Terminal 被启动
desktop chat 桌面场景的聊天记录与右侧实时桌面(终端已打开)
guarded 受控报错场景:对无几何单元的双击/右键被拒绝,桌面未变化
before fix 修复前的对照:同样的双击落到了左上角 Applications 菜单

Human QA

  • Human QA passed

🤖 Generated with Claude Code

按 docs/computer-browser-capability-completion-plan.md 的 P0 阶段实施:

- a11y-cli 与 Go 之间改为带 protocol_version 的 JSON 契约:lines 为数组、
  逐项 x/y/width/height 与 states、helper_version/limit/truncated 与诊断计数;
  旧 helper 或版本不匹配时返回「重建工作区镜像」错误而不是空树。
- 新增 a11y-cli locate 子命令,按 ref 从持久化索引取几何信息而不重扫;
  ref 的双击/三击/中键/右键据此回放真实指针事件。
- 一份动作规范同时生成 browser_action/browser_observe/computer_action/
  computer_observe/browser_remote_session 的 schema、参数说明与执行前校验:
  六个遗漏 action 进入枚举,别名归一化;不属于该动作的参数、冲突定位、
  timeout 与 duration_ms 并存、double_click 冲突 click_count 等在副作用前拒绝。
- Browser click/double_click/hover/drag 支持 button、click_count 与视口坐标;
  fill 两侧接受空字符串清空,Computer 的 RFB 回退先 Select All + BackSpace;
  导航/刷新/历史的就绪失败改为返回错误。
- 修复 GTK 未布局表格单元报告 i32::MIN 坐标时被当成指针目标的问题。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@sheepbox8646
sheepbox8646 requested review from a team as code owners September 18, 2026 14:29
@github-actions github-actions Bot added change:server Changes backend code, configuration, or API contracts feat Adds or improves functionality size:L PR size uses the larger of added or deleted lines, excluding generated files labels Sep 18, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:server Changes backend code, configuration, or API contracts feat Adds or improves functionality size:L PR size uses the larger of added or deleted lines, excluding generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant