feat: enhance after-pack script to copy OpenClaw runtime dependencies

- 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.
This commit is contained in:
duanshuwen
2026-04-22 21:56:37 +08:00
parent 2f675afe47
commit ea1fd18e6f
22 changed files with 8947 additions and 94 deletions

View File

@@ -0,0 +1,345 @@
# 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、识别遗漏能力 | 只读分析、文档 |
| M1Runtime 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` |
| M2Gateway 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` |
| M3Chat 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` |
| M4Renderer 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 可选扩编角色
如果要把运维诊断一起提前做,可以额外拆出:
| 角色 | 数量 | 负责范围 | 文件所有权 |
| --- | --- | --- | --- |
| D1Diagnostics / 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”更稳。