- Added a new script `bundle-openclaw.mjs` to bundle OpenClaw runtime dependencies. - Updated `after-pack.cjs` to copy bundled OpenClaw runtime and its node_modules. - Improved cleanup of unnecessary development files in node_modules. - Adjusted paths for resources in the packaging process. style: update loading indicator styles in ChatHistoryPanel - Changed the border radius and padding for the loading indicator in ChatHistoryPanel. fix: improve ProvidersSection to handle provider account syncing - Added logic to sync model configuration to provider accounts. - Introduced error handling and loading states during the sync process. - Enhanced vendor resolution and account management logic. fix: fallback session handling in chat store - Implemented fallback session logic in loadSessions to ensure a valid session is always available on error.
346 lines
18 KiB
Markdown
346 lines
18 KiB
Markdown
# 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”更稳。
|