# ClawX 浏览器自动化能力迁移规划 ## 1. 背景与结论 - 现象:在 `ClawX` 中发送“打开:http://www.baidu.com”,模型可以真实驱动浏览器打开页面;在 `zn-ai` 中发送同样内容,当前不会真实操作浏览器。 - 结论:问题不在“模型名”或“prompt”本身,而在聊天请求最终是否进入了真正的 `OpenClaw runtime / gateway / tool execution loop`。 - `ClawX` 目前走的是完整的 `OpenClaw Gateway` 链路,且会在启动前把 `~/.openclaw/openclaw.json` 的 `browser.enabled` 等配置补齐。 - `zn-ai` 当前聊天主链路仍是 `in-process provider.chat(...)`,没有真实 `OpenClaw` 子进程、没有 browser config sync、没有 tool execution protocol,所以模型只能生成文本,不能真实调用浏览器工具。 - `zn-ai` 已经有 `playwright`、`browser-use-sdk` 依赖,但它们并没有接入当前聊天主链路,因此现在并不构成功能闭环。 这份文档是对 [OpenClaw-Chat-Alignment-Plan.md](./OpenClaw-Chat-Alignment-Plan.md) 的浏览器自动化专题补充,重点回答: 1. 为什么 `ClawX` 能打开浏览器而 `zn-ai` 不能。 2. `zn-ai` 还缺哪些关键文件/能力。 3. 下一步迁移应该按什么顺序做。 ## 2. 两个项目的真实执行链路对比 ### 2.1 ClawX `ClawX` 的对话会进入真实 Gateway/Runtime: 1. Renderer 发消息: `ClawX/src/stores/chat/runtime-send-actions.ts:192-218` 通过 `invokeIpc('gateway:rpc', 'chat.send', ...)` 或 `chat:sendWithMedia` 发起调用。 2. Main IPC 转发: `ClawX/electron/main/ipc-handlers.ts:1209-1216` `ClawX/electron/main/ipc-handlers.ts:1298-1368` 3. Gateway Manager 托管 OpenClaw 子进程、WebSocket、重连、ready 状态: `ClawX/electron/gateway/manager.ts:1-205` `ClawX/electron/gateway/process-launcher.ts:91-144` 4. 启动前同步 `openclaw.json`: `ClawX/electron/gateway/config-sync.ts:251-323` `ClawX/electron/utils/openclaw-auth.ts:1169-1321` 5. `OpenClaw` runtime 真正执行 `tool_use / tool_result`,包括浏览器工具。 6. Renderer 可以展示 thinking、tool card、tool result: `ClawX/src/pages/Chat/message-utils.ts:153-201` `ClawX/src/stores/chat.ts:1886-2015` `ClawX/src/pages/Chat/ChatMessage.tsx:1-220` ### 2.2 zn-ai `zn-ai` 当前对话仍停留在“直接调用模型”: 1. Renderer 发消息: `zn-ai/src/stores/chat.ts:271-294` 通过 `gatewayRpc('chat.send', ...)` 进入本地 gateway。 2. Main IPC 只做本地转发: `zn-ai/electron/main.ts:94-97` 3. Gateway Manager 仍是 in-process 模式: `zn-ai/electron/gateway/manager.ts:53-62` 4. Chat handler 直接取 provider account 后调用: `zn-ai/electron/gateway/handlers/chat.ts:48-49` `zn-ai/electron/gateway/handlers/chat.ts:134-161` 5. 当前事件协议只有 `chat:delta/final/error/aborted`: `zn-ai/electron/gateway/types.ts:10-47` 6. 当前消息 UI 只展示普通文本/附件,不展示 tool/thinking 执行过程: `zn-ai/src/components/chat/ChatMessageList.tsx:23-90` `zn-ai/src/components/chat/types.ts:15-24` 因此,`zn-ai` 现在收到“打开百度”时,并没有一个真正的浏览器工具执行器可以被模型调用。 ## 3. 为什么 ClawX 能打开浏览器 `ClawX` 能成功,不是因为“它装了 Playwright”这么简单,而是它把下面这几层都打通了: ### 3.1 有真实 OpenClaw Runtime - `ClawX/electron/gateway/process-launcher.ts` 会通过 `utilityProcess.fork(...)` 启动 Gateway 子进程。 - `ClawX/package.json:39-42,123` 已经引入 `openclaw` 与配套 bundling 脚本。 - `ClawX/electron-builder.yml:16-31` 会把 `build/openclaw/` 打进安装包。 ### 3.2 启动前会把浏览器能力写进 openclaw.json - `ClawX/electron/utils/openclaw-auth.ts:1181-1194` 会确保: - `browser.enabled = true` - `browser.defaultProfile = 'openclaw'` - `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork = true` - `ClawX/electron/gateway/config-sync.ts:317-320` 会在 Gateway 启动前统一执行这类配置同步。 ### 3.3 聊天调用的是 Gateway,不是裸模型 - `ClawX` 的聊天发送不是直接 `provider.chat(...)`,而是先进入 `gateway:rpc -> chat.send`。 - 这样模型在运行时可以发出 `tool_use`,再由 runtime 真正执行浏览器操作。 ### 3.4 前端能消费工具执行过程 - `ClawX` 的消息解析和 UI 会识别 `tool_use` / `tool_result`,所以不仅能执行,也能在界面上看到执行轨迹。 ## 4. 为什么 zn-ai 现在不能打开浏览器 ### 4.1 当前没有真实 OpenClaw 子进程接入聊天链路 - `zn-ai/electron/gateway/manager.ts` 明确返回 `mode: 'in-process'`。 - `zn-ai/electron/gateway/openclaw-process-owner.ts` 目前只是占位实现: - `prepare()` 只创建目录 - `start()` 只把状态切到 `running` - 没有真正 `fork` 进程 - 也没有 WebSocket / JSON-RPC / ready 检测 ### 4.2 当前聊天处理器直接打模型 - `zn-ai/electron/gateway/handlers/chat.ts` 里核心执行是: - 取 `provider account` - 拼消息历史 - `createProvider(accountId)` - `provider.chat(messages, model, { signal })` 这条链路天然不会触发 OpenClaw 的浏览器工具。 ### 4.3 当前没有 browser config sync - `zn-ai` 虽然已经有 `electron/utils/paths.ts` 和 `openclaw-process-owner.ts` 这些雏形, 但没有对应 `ClawX/electron/utils/openclaw-auth.ts` 与 `ClawX/electron/gateway/config-sync.ts` 那一整套启动前配置同步逻辑。 - 即使未来把 `openclaw` 包带进来,如果不写入 `browser.enabled`,浏览器能力仍可能不会生效。 ### 4.4 当前协议和 UI 也没有完整 tool 语义 - `zn-ai/electron/gateway/types.ts` 目前没有面向 tool execution 的 richer event protocol。 - `zn-ai/src/components/chat/ChatMessageList.tsx` 目前也没有对应 `tool card / thinking / tool result` 的展示结构。 ## 5. 缺少哪些文件 这里分成两类:`P0 必需缺失文件` 和 `已有但需要重构的文件`。 ### 5.1 P0 必需缺失文件 这些文件是让“聊天真正能调用浏览器工具”最关键的一批,建议优先迁: | 能力 | ClawX 参考文件 | zn-ai 当前状态 | 结论 | | --- | --- | --- | --- | | OpenClaw 子进程启动 | `ClawX/electron/gateway/process-launcher.ts` | 缺失 | 必需补 | | Gateway 启动前配置同步 | `ClawX/electron/gateway/config-sync.ts` | 缺失 | 必需补 | | browser/config 写入 | `ClawX/electron/utils/openclaw-auth.ts` | 缺失 | 必需补 | | Gateway WebSocket/ready | `ClawX/electron/gateway/ws-client.ts` | 缺失 | 必需补 | | Gateway 协议定义 | `ClawX/electron/gateway/protocol.ts` | 缺失 | 必需补 | | Gateway request 跟踪 | `ClawX/electron/gateway/request-store.ts` | 缺失 | 建议补 | | 启动/重连/生命周期控制 | `ClawX/electron/gateway/lifecycle-controller.ts` `restart-controller.ts` `connection-monitor.ts` | 缺失 | 建议补 | | 进程守护与诊断 | `ClawX/electron/gateway/supervisor.ts` `startup-orchestrator.ts` `startup-stderr.ts` | 缺失 | 建议补 | | openclaw 打包脚本 | `ClawX/scripts/bundle-openclaw.mjs` | 缺失 | 必需补 | | openclaw 插件打包 | `ClawX/scripts/bundle-openclaw-plugins.mjs` | 缺失 | 浏览器最小闭环非必需,但后续强相关 | | openclaw 安装包资源声明 | `ClawX/electron-builder.yml` 中 `build/openclaw -> openclaw` | `zn-ai/electron-builder.yml` 未配置 | 必需补 | ### 5.2 已有但需要重构的文件 这些文件在 `zn-ai` 里已经存在,但当前实现还是过渡态: | zn-ai 文件 | 当前问题 | 改造方向 | | --- | --- | --- | | `electron/gateway/manager.ts` | 仍是 in-process manager | 改成真实 OpenClaw gateway manager,负责 start/stop/restart/status/rpc | | `electron/gateway/openclaw-process-owner.ts` | 只是状态占位,没有真实进程 | 接入 `utilityProcess.fork`、ready 检测、退出处理 | | `electron/gateway/handlers/chat.ts` | 直接 `provider.chat(...)` | 改成调用真实 Gateway RPC,不再直接驱动 provider | | `electron/main.ts` | 只初始化本地 gateway bridge | 增加 OpenClaw runtime 启动、配置同步、事件注册 | | `electron/utils/paths.ts` | 已有路径层,但没接 runtime bundling | 继续沿用,作为 runtime/package path 基础设施 | | `package.json` | 没有 `openclaw` 依赖和 bundling 脚本 | 对齐 `ClawX` 的 runtime 打包入口 | | `electron-builder.yml` | 没有 `openclaw` extraResources | 把 runtime 资源打进安装包 | | `scripts/after-pack.cjs` | 只处理 `playwright/chromium-bidi/bytenode` | 增加 openclaw/node_modules/plugins 复制逻辑 | | `src/stores/chat.ts` | 只消费简化事件 | 增加 tool/thinking/tool_result 流式状态处理 | | `src/components/chat/ChatMessageList.tsx` | 只渲染简单消息卡片 | 对齐 `ClawX` 的工具执行展示能力 | | `src/components/chat/types.ts` | message shape 过于简单 | 增加 tool execution 相关 UI 数据结构 | ### 5.3 可后置但建议保留参考的文件 这批不是“打开网址”的最小闭环必需,但如果目标是后续继续向 `ClawX` 对齐,建议一起纳入规划: - `ClawX/electron/utils/openclaw-proxy.ts` - `ClawX/electron/utils/openclaw-control-ui.ts` - `ClawX/electron/utils/openclaw-cli.ts` - `ClawX/electron/utils/openclaw-doctor.ts` - `ClawX/electron/gateway/reload-policy.ts` - `ClawX/electron/gateway/process-policy.ts` - `ClawX/electron/gateway/restart-governor.ts` - `ClawX/src/pages/Chat/message-utils.ts` - `ClawX/src/pages/Chat/ChatMessage.tsx` ## 6. 推荐迁移顺序 ### Phase 1:先打通最小运行闭环 目标:让 `zn-ai` 的聊天可以真正进入 OpenClaw runtime。 建议优先完成: 1. `package.json` 引入 `openclaw`,补 `bundle-openclaw.mjs`。 2. `electron-builder.yml` 和 `scripts/after-pack.cjs` 补 runtime 打包。 3. 基于 `electron/utils/paths.ts` 实现真实 `process-launcher + process-owner`。 4. 增加 `config-sync.ts + openclaw-auth.ts`,确保 browser 配置被写入 `openclaw.json`。 完成标准: - 开发态和打包态都能找到 `openclaw` 入口。 - `GatewayManager` 能拉起真实 Gateway 子进程。 - `~/.openclaw/openclaw.json` 中出现有效的 `browser.enabled` 配置。 ### Phase 2:替换聊天执行面 目标:让对话不再直接 `provider.chat(...)`,而是走真实 Gateway。 建议改造: 1. `electron/gateway/manager.ts` 2. `electron/gateway/handlers/chat.ts` 3. `electron/main.ts` 完成标准: - “打开:http://www.baidu.com” 时,请求进入真实 Gateway,而不是本地 provider adapter。 - 聊天不再依赖 `provider.chat(...)` 直接生成最终文本。 ### Phase 3:补齐 tool 事件与前端可视化 目标:不仅能执行,还能在 UI 看见执行过程。 建议改造: 1. `src/stores/chat.ts` 2. `src/components/chat/types.ts` 3. `src/components/chat/ChatMessageList.tsx` 4. 参考 `ClawX/src/pages/Chat/message-utils.ts` 和 `ChatMessage.tsx` 完成标准: - UI 能显示 `thinking / tool_use / tool_result`。 - 浏览器执行失败时,前端能展示明确错误,而不是只有空白或文本兜底。 ### Phase 4:补诊断与运维能力 目标:减少“本地能跑、打包后失效”。 建议纳入: 1. `openclaw doctor` 2. Control UI URL 3. restart / health / ready / diagnostics 4. proxy 同步与 reload policy ## 7. sub-agent 数量估算 ### 7.1 推荐编制 - 分析 sub-agent:`1` - 迁移开发 sub-agent:`4` - 集成验收 sub-agent:`1` - 推荐总数:`6` ### 7.2 峰值编制 - 如果希望把 `Phase 4` 的 diagnostics / doctor / control UI 也并行推进,可以临时再拆出 `1` 个运维诊断 sub-agent。 - 峰值总数:`7` ### 7.3 最小可行编制 - 主控 Codex 兼任分析与最终验收 - 保留 `3` 个开发 sub-agent + `1` 个集成角色 - 最小总数:`4` ### 7.4 为什么推荐 6 个 - 这次迁移至少横跨 `Runtime Packaging`、`Gateway Process & Config Sync`、`Chat Execution`、`Renderer Tool UI` 四条主要开发线。 - 这四条线的写集可以基本拆开,适合并行推进。 - 如果开发角色少于 `4`,很容易出现“runtime 已经能拉起,但 chat path 还没切完”或者“后端已经有 tool 事件,但前端完全看不见”的串行阻塞。 ## 8. sub-agent 分工与推进安排 ### 8.1 推荐分工 | 角色 | 数量 | 负责范围 | 文件所有权 | | --- | --- | --- | --- | | A1:浏览器自动化契约分析 | 1 | 持续对照 `ClawX`,冻结最小闭环契约、补验收 checklist、识别遗漏能力 | 只读分析、文档 | | M1:Runtime Packaging / Paths | 1 | 引入 `openclaw`、补 bundling、after-pack、resources 布局、运行时路径管理 | `package.json` `electron-builder.yml` `scripts/bundle-openclaw.mjs` `scripts/after-pack.cjs` `electron/utils/paths.ts` | | M2:Gateway Process / Config Sync | 1 | 实现真实进程拉起、ready 检测、WebSocket 通信、启动前同步 `openclaw.json` 浏览器配置 | `electron/gateway/process-launcher.ts` `electron/gateway/ws-client.ts` `electron/gateway/config-sync.ts` `electron/gateway/openclaw-process-owner.ts` `electron/utils/openclaw-auth.ts` | | M3:Chat Execution / IPC 集成 | 1 | 把 `chat.send` 从本地 `provider.chat(...)` 切到真实 Gateway,补主进程生命周期与状态接口 | `electron/gateway/manager.ts` `electron/gateway/handlers/chat.ts` `electron/gateway/types.ts` `electron/main.ts` `electron/api/routes/gateway.ts` | | M4:Renderer Tool Events / UI | 1 | 接 tool/thinking/tool_result 事件,补消息结构、流式状态与工具执行可视化 | `src/stores/chat.ts` `src/components/chat/types.ts` `src/components/chat/ChatMessageList.tsx` `src/pages/Home/index.tsx` | | I1:联调验收 / 回归收口 | 1 | 维护 smoke checklist、验证开发态/打包态、补文档与测试基线 | 测试、文档、回归记录 | ### 8.2 可选扩编角色 如果要把运维诊断一起提前做,可以额外拆出: | 角色 | 数量 | 负责范围 | 文件所有权 | | --- | --- | --- | --- | | D1:Diagnostics / Control UI / Doctor | 1 | 补 OpenClaw 诊断入口、Control UI URL、health diagnostics 展示 | `electron/utils/openclaw-control-ui.ts` `electron/utils/openclaw-cli.ts` `electron/utils/openclaw-doctor.ts` `electron/api/routes/*` 设置/诊断相关前端 | 这个角色建议只在 `M3` 把基础 gateway status 契约稳定后再启动,避免和 `gateway/manager.ts` 产生写冲突。 ### 8.3 建议并行波次 | 波次 | 并行角色 | 目标 | | --- | --- | --- | | Wave 1 | A1 + M1 | 冻结最小闭环契约,先把 `openclaw` 资源打包和路径层打通 | | Wave 2 | M2 + M3 | 一边实现真实 Gateway 进程与 config sync,一边切换聊天执行面到 Gateway | | Wave 3 | M4 + I1 | 对接 tool 事件与 UI 展示,同时开始做 smoke 与回归清单 | | Wave 4 | D1 + 主控 Codex | 可选补 diagnostics / doctor / control UI,并做最终跨层收口 | ### 8.4 开工顺序建议 1. 先开 `M1` - 这是最靠前的阻塞项,因为没有 runtime bundling 和路径层,后面的真实 Gateway 无法稳定拉起。 2. 紧接着开 `M2` - 它负责把 `openclaw` 真正跑起来,并把 `browser.enabled` 等关键配置写入 `openclaw.json`。 3. `M3` 与 `M2` 并行 - `M3` 可以先把 `manager/chat/main` 的调用面改成“面向真实 Gateway”的接口,再等待 `M2` 落地真实进程。 4. `M4` 在 `M3` 暴露稳定事件后接入 - 避免前端先写死一套后端并不会发出的事件结构。 5. `I1` 从 `Wave 2` 就开始 - 不要等所有人写完再验,因为开发态和打包态的差异很可能会在中途暴露。 ### 8.5 文件冲突规避 - `M1` 不要改 `electron/gateway/manager.ts` - `M2` 不要改 `src/*` - `M3` 尽量只拥有 `manager/chat/main/routes`,不要接管 `process-launcher/config-sync` - `M4` 不要改 `electron/*` - `I1` 不直接改生产实现,除非主控明确分配 这样拆分后,主要写冲突只会集中在接口边界,而不会集中在同一个文件。 ## 9. 最小验收清单 当下面这些都满足时,才算“浏览器自动化已迁成功”: - 在 `zn-ai` 中发送“打开:http://www.baidu.com”时,真实浏览器会打开对应页面。 - 聊天链路里能看到 `tool_use` 或等价工具执行痕迹,而不是只有纯文本回复。 - `GatewayManager` 状态不再只是 `mode: 'in-process'`。 - 打包后的应用也能执行同样操作,不仅是开发环境可用。 - provider/account 切换后,浏览器能力不需要手动改 `openclaw.json` 才能生效。 ## 10. 风险与注意点 - 不建议只尝试“把 Playwright 接到某个单独 service”来修这件事。这样也许能做出一个临时浏览器工具,但会绕开 `OpenClaw` 的 tool protocol、会话、history、tool_result、diagnostics,后续维护成本更高。 - `zn-ai` 已有的 `openclaw-process-owner.ts` 和 `paths.ts` 可以继续复用,不需要完全推翻。 - 如果短期目标只是先实现“打开网址”,可以先不迁全部插件/Control UI,但 `process-launcher + config-sync + browser.enabled + real gateway rpc` 这四块不能省。 ## 11. 结论 `zn-ai` 现在不能像 `ClawX` 一样准确打开浏览器,核心原因不是缺某一个浏览器脚本,而是聊天主链路还没有接到真正的 `OpenClaw runtime`。 最关键的迁移入口是四块: 1. 引入并打包 `openclaw runtime` 2. 用真实 Gateway 子进程替换当前 in-process chat execution 3. 启动前同步 `openclaw.json` 的 browser 配置 4. 前端补齐 tool execution 的事件消费和展示 按这个顺序推进,推荐以 `6` 个 sub-agent 为常态编制;如果把 diagnostics / doctor 也一起并行推进,峰值可以短时扩到 `7` 个。这样后续浏览器、文件、搜索等工具能力都会比“单点硬接 Playwright”更稳。