我给我的 agent 装了双手:零依赖浏览器操控插件开发记

159 阅读2分钟

我给我的 agent 装了双手:零依赖浏览器操控插件开发记

起因

我在 DeepSeek Harness 里跑的是纯文本模型。让它"上网查个资料",web_fetch 能应付静态页;让它"打开登录页、填表单、点提交、把结果读出来"——没戏。市面上的方案要么是 Playwright 全家桶(几十个依赖),要么需要 API key 接视觉模型烧 token。

设计:文本优先 + 按编号交互

pilot 的核心想法只有两条:

  1. 给盲人装导盲杖而不是眼镜。页面被转成结构化文本:标题、URL、正文、链接、以及一个编号元素列表。点击/输入直接用编号——pilot_click {ref: 14},不猜选择器。快照差异检测(pilot_diff)回答 agent 最常问的问题:"我刚点的那一下,生效了吗?"
  2. 零依赖。Node ≥ 22 自带 WebSocket,CDP 协议直接原生实现,浏览器用机器上现成的 Edge/Chrome headless。整个插件运行时依赖为零。

架构

  • 宿主:CDP 客户端 + 每会话一个浏览器实例的 PilotPool(LRU 上限 8)
  • GUI:可拖拽驾驶舱面板,实时截图 + 操作日志,人类随时接管
  • 13 个工具:open/snapshot/diff/click/type/press/back/reload/wait/screenshot/download/eval/close

开发中抓到自己的三个真 bug

  1. inject 时序:ctx.get() 在服务未激活时返回 undefined,插件"优雅地"什么都没注册。改成声明硬依赖 inject: ['webServer', 'tools'],让 Cordis 等就绪再激活。
  2. load 事件竞态:点击后页面加载完成得比监听器注册还快,导致永远等不到 load 事件。修复:先注册监听、后触发动作。
  3. 一个 BOM 事故:用 PowerShell 写 package.json 带上了 UTF-8 BOM,直接把 dsh 启动搞崩。从此 JSON 一律 node 写。

验收方式

用自己写的 pilot_click 去点自己写的面板按钮,跑真实 headless Edge 的 29 项冒烟测试,GitHub Actions CI 全绿。已收录进 awesome-dsh-plugin 精选列表和 dsh-web-ui 社区索引。

仓库:github.com/guo6x/dsh-p… (MIT,双语 README,欢迎 star/issue)