# dsh-browser 通信方式设计 本文描述 v0.2 的生产与开发通信路径。协议类型的唯一源码是 [`packages/browser/src/types.ts`](../packages/browser/src/types.ts)。 ## 1. 生产架构 ```text DeepSeek Harness process browser_* tools | v ctx.browser / BrowserBridge | | authenticated ws://127.0.0.1: v Native Messaging host process | | 4-byte little-endian length + UTF-8 JSON v Chromium MV3 extension service worker | | chrome.tabs / chrome.scripting / scoped chrome.debugger v HTTP/HTTPS browser tab ``` Native Messaging 是生产传输。浏览器清单把 `com.deepseek.dsh_browser` 绑定到安装器拥有的本地可执行文件,并用 `allowed_origins` 限制可启动它的扩展 ID。扩展建立原生消息通道后,Native host 再连接 Harness bridge。 Direct 开发模式省略 Native host,由扩展直接连接 bridge。两种模式共享同一命令协议、错误语义和 HTTP/HTTPS 目标检查。 ## 2. Harness 包责任 | 包 | 责任 | |---|---| | `@dsh-browser/browser` | `ctx.browser` Service Definition、协议版本、命令、回复和错误相关类型。 | | `@dsh-browser/bridge` | 回环 WebSocket 服务端、握手认证、请求关联、取消、心跳和静止卸载。 | | `@dsh-browser/browser-policy` | 根据当前 permission preset 为修改型 `browser_*` 工具返回审批或直接委托。 | | `@dsh-browser/tool-browser` | 模型工具、参数与结果 schema、模型渲染和 UI render intent。 | | `@dsh-browser/native-host` | Chrome 原生消息 framing、扩展身份检查、token 注入和 WebSocket 转发。 | | `@dsh-browser/browser-bundle` | 工作区内组装和测试 bridge、policy、tools 与 Web 设置卡片。 | `@dsh-browser/browser` 是类型与 Service Definition 依赖,不单独挂载。公开发行包 `dsh-browser` 把工作区运行时代码打包为自包含入口,并暴露四个名称明确的 loader 行: | Loader id | 包名 | 作用 | |---|---|---| | `browser-bridge` | `dsh-browser/browser-bridge` | 监听回环连接、认证扩展并提供 `ctx.browser`。 | | `browser-policy` | `dsh-browser/browser-policy` | 对修改型浏览器工具贡献 Harness 审批决定。 | | `browser-tools` | `dsh-browser/browser-tools` | 向 Agent 注册或移除完整的 `browser_*` 工具集。 | | `browser-settings` | `dsh-browser` | 在 DSH Web 中提供组件开关以及 bridge、Edge 扩展连接状态。 | ## 3. 连接与握手 扩展连接状态依次为 `disconnected -> connecting -> awaiting_hello -> ready`。只有成功收到 `hello_ack` 后才能处理命令。 `hello` 包含: - `protocolVersion`:当前协议版本;不匹配返回 `PROTOCOL_MISMATCH`。 - `client`:稳定安装 ID、显示名称、版本和 `direct`/`native-host` 传输类型。 - `authToken`:Direct 开发模式由扩展内部诊断消息配置;Native 模式由 host 从私有配置注入。 - `capabilities`:客户端实现的命令能力;未知能力拒绝握手。 bridge 还校验 WebSocket Origin。Direct 模式必须来自 `chrome-extension://`,Native 模式由 host 使用 `dsh-native-host://com.deepseek.dsh_browser`。token 使用定时安全比较。 一条尚未认证的新连接不能替换当前 ready 连接。认证成功的新连接成为唯一当前客户端,并以 `CONNECTION_REPLACED` 结算旧连接拥有的全部请求。 ## 4. Native host 转发 Chrome 把扩展 origin 作为 Native host 进程参数传入。host 先把尾部 `/` 规范化,再与私有配置中的 `allowedExtensionOrigins` 精确比较;不匹配时不连接 bridge。 扩展发出的 `hello` 不携带 bridge token。host 验证消息属于 `native-host` 传输后写入安装 token,并把客户端传输固定为 `native-host`。bridge 返回的 `maxMessageBytes` 还会受 Native Messaging framing 上限约束。 Native host 保持浏览器 stdio 通道,并在 bridge 暂时不可用时按有界退避重连。重新连接需要新的握手;旧请求不跨连接重放。 ## 5. 请求协议 bridge 发送 `{ type: 'request', id, command }`,扩展返回同 id 的成功或错误 `reply`。Agent 工具命令还携带内部 `controlOwnerId`,用于跨连续工具调用保留页面控制指示。调用方取消或 bridge 超时时,bridge 删除 pending 项并发送 `{ type: 'cancel', id }`;Agent 进入 idle 或被销毁时,bridge 发送 `{ type: 'control_release', ownerId }`。该释放消息不参与请求结算。 扩展为请求维护 AbortController。无法取消的 Chrome API 可以自然结束,但其晚到结果不能再次结算请求或继续后续步骤。 入站 JSON、消息类型、字段和每种命令的回复值都在进程边界校验。违反协议的客户端收到错误或被关闭,未验证的值不进入 `ctx.browser`。 ## 6. 浏览器命令 | 命令 | 结果 | |---|---| | `tabs.list` | HTTP/HTTPS 标签页列表。 | | `tabs.create` | 后台新建的 HTTP/HTTPS 标签页。 | | `page.snapshot` | 可见文本、交互元素和截断状态。 | | `page.navigate` | 导航完成后的页面快照。 | | `page.back` / `page.forward` / `page.reload` | 历史操作后的页面快照。 | | `page.wait` | 条件满足时的新页面快照。 | | `dom.click` / `dom.type` | 元素操作结果和当前 `documentId`。 | | `dom.scroll` / `dom.key` | 页面或元素操作结果和当前 `documentId`。 | | `page.evaluate` | CDP `Runtime.evaluate` 返回的有界 JSON 值;默认注册,可由 Harness profile 显式移除。 | 省略 `tabId` 时,扩展优先使用用户最近激活的可操控标签页,再查询当前前台窗口的活动标签页。协议不提供标签页激活命令,`tabs.create` 固定在后台创建,其他命令也不会聚焦浏览器窗口。 `page.evaluate` 是唯一使用 `chrome.debugger` 的命令。扩展确认标签页使用 HTTP/HTTPS URL 并临时附加 CDP 1.3,再为主 frame 创建隔离 execution context。固定的 origin 探针和调用方表达式使用同一个 `executionContextId`;导航会销毁该 context,使表达式失败而不是转移到新文档。扩展等待 Promise,通过固定 `Runtime.callFunctionOn` 序列化器限制递归深度、条目数、单个字符串长度和总字符数,在 `finally` 中 detach,并且不向 Harness 暴露任意 CDP 方法。 ## 7. 快照与元素引用 一次快照产生一个 `documentId` 和若干 `ref`。`ref` 只在同一标签页、同一文档代际内有效。导航、刷新或文档替换后使用旧引用返回 `STALE_REF`。 有限快照不会清空同一文档仍连接在 DOM 中的旧引用,因此模型可以在截断快照之后继续使用先前完整快照的元素。已经脱离 DOM 的元素会失效。 快照分别报告 `textTruncated` 和 `elementsTruncated`,并用 `truncated` 表示任一部分不完整。 ## 8. 等待、超时与恢复 `page.wait` 支持 load、URL 包含、可见文本包含,以及元素 attached/visible/hidden 条件。命令等待超时返回 `WAIT_TIMEOUT`;bridge 等不到任何回复返回 `REQUEST_TIMEOUT`,两者含义不同。 bridge 使用 WebSocket ping/pong 检测失活连接。扩展 service worker 加载后自动连接 Native host,生产 Popup 不提供连接配置或启停操作;`chrome.alarms` 会唤醒 worker 并恢复持久化传输。Native host 或 bridge 重启后重新握手;任何未确认修改操作都不自动重试,调用方重新观察页面后再决定下一步。Chrome debugger 命令本身不可取消;取消后扩展丢弃结果并完成 detach。 ## 9. 部署配置 bridge 只允许绑定 `127.0.0.1`。Native host 安装器把端口和 token 写入权限为 `0600` 的 `$DSH_HOME/browser-native-host.env`;启动 Harness 前必须把该文件导入启动进程环境,bundle 才能通过 `DSH_BROWSER_PORT` 和 `DSH_BROWSER_AUTH_TOKEN` 读取。正式 DSH 不从 `$DSH_HOME/.env` 加载影响启动的 `DSH_*` 变量。 `requestTimeoutMs`、`handshakeTimeoutMs`、`heartbeatMs`、`maxMessageBytes` 和允许的 Origin 前缀属于 bridge 配置。修改 profile 中的 `browser-bridge` 行时,Harness patch 会替换整段 `config`,因此覆盖层必须重述需要保留的全部字段。 browser-policy 的 `askFor` 配置拥有修改工具集合,`allowWithoutApprovalIn` 拥有无需交互审批的 permission preset 名称,默认值为 `danger-full-access`。无 agent 的调用无法解析 session preset,因此仍返回 `ask` 并由 ToolRuntime 按缺少可审计 agent 的规则拒绝。