# ZClaw 项目深度分析与改进计划 ## 一、现状分析 ### 1.1 核心发现 基于 `docs/openclaw-deep-dive.md` 的目标与实际代码的对比: | 模块 | 目标状态 | 实际状态 | 差距程度 | |------|----------|----------|----------| | **Gateway 连接** | 设备认证 + Challenge 签名 | ✅ 完整实现 | 无差距 | | **分身系统** | 映射到 OpenClaw `agents.list` | ⚠️ 独立存储在 `zclaw-data.json` | **严重** | | **设置页** | OpenClaw Runtime 配置面板 | ⚠️ 大部分是前端本地状态 | **严重** | | **右侧面板** | 真实 Agent 身份与状态 | ⚠️ 混合真实数据与硬编码值 | **中等** | ### 1.2 关键差距详解 #### 差距 1:分身与 Agent 断层(最严重) ``` 当前架构: ┌─────────────────────────────────────────────────────────────┐ │ ZClaw 分身系统 (zclaw-data.json) │ │ clone_1: { name: "程序员", workspaceDir: "...", ... } │ │ clone_2: { name: "设计师", workspaceDir: "...", ... } │ └────────────────────────┬────────────────────────────────────┘ │ ❌ 无同步 ▼ ┌─────────────────────────────────────────────────────────────┐ │ OpenClaw agents.list (openclaw.json) │ │ 只有: [{ id: "main", groupChat: {...} }] │ └─────────────────────────────────────────────────────────────┘ ``` **后果**: - 所有分身实际共用同一个 `main` Agent - 聊天时不传递 `agentId`,OpenClaw 不知道当前是哪个分身 - Bootstrap 文件(IDENTITY.md, SOUL.md 等)生成了但未被运行时使用 #### 差距 2:设置页是"假状态" | 设置页 | 当前实现 | 应该实现 | |--------|----------|----------| | 模型选择 | 存在 `chatStore.currentModel`(前端状态) | 调用 `config.patch` 修改 OpenClaw 配置 | | MCP 服务 | 存 `quickConfig`,部分同步到 Gateway | 管理 `plugins.load.paths` | | 技能目录 | 存 `quickConfig` | 管理 `skills.load.extraDirs` | | IM 频道 | 存 `quickConfig`,只显示状态 | 管理 `channels.*` 配置 | | 工作区 | 存 `quickConfig` | 管理 `agents.defaults.workspace` | | 隐私 | 存 `quickConfig` | 管理 telemetry/优化计划 | **缺失的 RPC 方法**: - `config.get` - 读取 OpenClaw 配置 - `config.patch` - 修改配置 - `config.apply` - 热更新配置 #### 差距 3:右侧面板数据不真实 ```typescript // 硬编码的默认值(RightPanel.tsx) const credits = 2268; // 完全假数据 const defaultUserName = '用户7141'; // 假用户名 ``` --- ## 二、根因分析 ### 2.1 架构层面的偏差 **文档期望**: > ZClaw 应该是 OpenClaw Runtime 的控制界面 **实际实现**: > ZClaw 是一个有自己数据模型的前端应用,与 OpenClaw 是松耦合 ### 2.2 数据模型的分裂 ``` OpenClaw 数据模型: openclaw.json → agents.list → Agent workspace → Bootstrap files ZClaw 数据模型: zclaw-data.json → clones[] → (独立的) workspace 路径 ``` 两套数据模型没有桥接,导致: 1. 分身不能路由到正确的 Agent 2. 设置不能影响 OpenClaw 行为 3. Bootstrap 文件与运行时脱节 --- ## 三、头脑风暴:改进方案 ### 3.1 方案 A:完全对齐 OpenClaw(推荐) **核心思路**:让 ZClaw 分身直接映射到 OpenClaw Agent ``` 改进后架构: ┌─────────────────────────────────────────────────────────────┐ │ ZClaw 分身 = OpenClaw Agent │ │ │ │ clone_1 ↔ agents.list[0] (id: "programmer") │ │ clone_2 ↔ agents.list[1] (id: "designer") │ │ │ │ 分身 CRUD → 同步修改 agents.list │ │ 聊天时 → 传递 agentId 到 Gateway │ └─────────────────────────────────────────────────────────────┘ ``` **优点**: - 符合 `openclaw-deep-dive.md` 的设计哲学 - 分身真正有独立人格、记忆、工具权限 - 设置页可以直接操作 OpenClaw 配置 **缺点**: - 改动较大,需要修改多个模块 - 需要处理数据迁移 ### 3.2 方案 B:保持独立,增强桥接 **核心思路**:保持 `zclaw-data.json`,但增加同步逻辑 ``` 改进后架构: ┌─────────────────────────────────────────────────────────────┐ │ ZClaw 分身系统 (主) │ │ zclaw-data.json → clones[] │ │ │ │ │ ▼ (单向同步) │ │ openclaw.json → agents.list (从分身生成) │ └─────────────────────────────────────────────────────────────┘ ``` **优点**: - 改动较小 - 保持现有分身管理逻辑 **缺点**: - 数据冗余,需要维护同步 - 不符合 OpenClaw 的设计哲学 ### 3.3 方案 C:混合模式 **核心思路**: - 简单分身:共用 `main` Agent,通过 Bootstrap 文件区分 - 高级分身:映射到独立 OpenClaw Agent --- ## 四、推荐实施路线(方案 A) ### P0:让分身真正工作(最小可行) **目标**:创建分身时同步到 OpenClaw `agents.list`,聊天时传递 `agentId` **关键修改**: 1. **`plugins/zclaw-ui/index.ts`** - `createClone` 时调用 OpenClaw API 添加到 `agents.list` - `deleteClone` 时从 `agents.list` 移除 - 新增 `zclaw.agents.sync` 方法 2. **`desktop/src/lib/gateway-client.ts`** - `chat()` 方法增加 `agentId` 参数 ```typescript async chat(message: string, opts?: { agentId?: string; sessionKey?: string }): Promise<...> ``` 3. **`desktop/src/store/chatStore.ts`** - `sendMessage` 时传递 `currentAgent.id` 作为 `agentId` 4. **新增 Gateway RPC** - `zclaw.config.get` - 读取 OpenClaw 配置 - `zclaw.config.patch` - 修改配置 **验收标准**: - [ ] 创建分身后,`openclaw.json` 的 `agents.list` 包含新 Agent - [ ] 切换分身后,聊天请求携带正确的 `agentId` - [ ] 每个分身有独立的对话上下文 ### P1:设置页 Runtime 化 **目标**:设置修改直接影响 OpenClaw Runtime **关键修改**: 1. **`desktop/src/lib/gateway-client.ts`** - 实现 `configGet()`、`configPatch()`、`configApply()` 方法 2. **各设置页改造** - **模型与 API**:调用 `config.patch` 修改 `agents.defaults.model` - **MCP 服务**:管理 `plugins.load.paths` - **技能目录**:管理 `skills.load.extraDirs` - **工作区**:管理 `agents.defaults.workspace` - **隐私**:管理 telemetry 相关配置 3. **UI 反馈** - 显示配置保存状态 - 配置变更后显示"需要重启"提示(如需要) **验收标准**: - [ ] 模型选择后,`openclaw.json` 的 `agents.defaults.model` 更新 - [ ] 添加技能目录后,`skills.load.extraDirs` 更新 - [ ] Gateway 重启后配置生效 ### P2:完整的 Agent 管理系统 **目标**:分身管理 = Agent 全生命周期管理 **功能扩展**: 1. 分身绑定渠道(飞书账号、微信群等) 2. 分身 Heartbeat 配置 3. 分身工具权限/沙箱配置 4. 分身间路由规则 **UI 改进**: - 右侧面板显示真实 Agent 状态(非硬编码) - 分身详情页增加完整配置选项 ### P3:产品化封装 **目标**:开箱即用的桌面体验 **功能**: 1. Tauri sidecar 管理 Gateway 进程 2. 首次安装配置向导 3. 错误诊断与自动修复 4. 一键更新 --- ## 五、关键文件清单 | 文件 | 修改内容 | |------|----------| | `plugins/zclaw-ui/index.ts` | 分身 CRUD 同步到 agents.list | | `desktop/src/lib/gateway-client.ts` | 增加 agentId 参数、config RPC | | `desktop/src/store/chatStore.ts` | sendMessage 传递 agentId | | `desktop/src/store/gatewayStore.ts` | 管理 Agent 配置状态 | | `desktop/src/components/CloneManager.tsx` | 显示同步状态 | | `desktop/src/components/RightPanel.tsx` | 显示真实 Agent 数据 | | `desktop/src/components/Settings/*.tsx` | 改造为 Runtime 配置面板 | | `config/openclaw.default.json` | 更新默认 Agent 模板 | --- ## 六、风险与缓解 | 风险 | 缓解措施 | |------|----------| | 数据迁移复杂 | 提供迁移脚本,保留 `zclaw-data.json` 作为备份 | | OpenClaw 版本兼容 | 检测 OpenClaw 版本,低版本降级到兼容模式 | | 破坏现有功能 | 灰度发布,支持回滚 | | 性能下降 | 懒加载 Agent 配置,缓存 RPC 结果 | --- ## 七、确认的方案 **选择:方案 A - 完全对齐 OpenClaw** 理由: 1. 符合 `openclaw-deep-dive.md` 的设计哲学 2. 分身真正有独立人格、记忆、工具权限 3. 设置页可以直接操作 OpenClaw 配置 4. 长期维护成本最低 --- ## 八、下一步行动(P0 详细任务) ### Task 1: 修改 `zclaw-ui` 插件 - 分身同步到 agents.list **文件**: `plugins/zclaw-ui/index.ts` **修改点**: 1. `createClone` 方法增加: - 调用 OpenClaw 内部 API 将分身添加到 `agents.list` - 设置 `agentId` 字段关联分身与 Agent 2. `deleteClone` 方法增加: - 从 `agents.list` 移除对应 Agent 3. `updateClone` 方法增加: - 同步更新 Agent 配置 4. 新增 `zclaw.agents.sync` 方法: - 读取当前 `agents.list` - 与 `zclaw-data.json` 比对 - 修复不一致 ### Task 2: 修改 GatewayClient - 支持 agentId **文件**: `desktop/src/lib/gateway-client.ts` **修改点**: 1. `chat()` 方法签名改为: ```typescript async chat(message: string, opts?: { agentId?: string; // 新增 sessionKey?: string; model?: string; }): Promise<{ runId: string; acceptedAt: string }> ``` 2. `request('agent', ...)` 时传递 `agentId` ### Task 3: 修改 chatStore - 传递 agentId **文件**: `desktop/src/store/chatStore.ts` **修改点**: 1. `sendMessage` 方法调用 `client.chat()` 时传递 `currentAgent.id` ### Task 4: 新增配置 RPC 方法 **文件**: `desktop/src/lib/gateway-client.ts` + `plugins/zclaw-ui/index.ts` **新增方法**: - `zclaw.config.get` - 读取 OpenClaw 配置 - `zclaw.config.patch` - 修改配置(不重启) - `zclaw.config.apply` - 热更新配置(如需重启) ### Task 5: 数据迁移脚本 **创建**: `scripts/migrate-clones-to-agents.ts` **功能**: 1. 读取现有 `zclaw-data.json` 中的分身 2. 为每个分身在 `agents.list` 创建对应条目 3. 更新分身的 `agentId` 字段 4. 备份原始文件 --- ## 九、验收标准 ### P0 完成标准 - [ ] 创建分身后,`~/.openclaw/openclaw.json` 的 `agents.list` 包含新 Agent - [ ] 删除分身后,对应 Agent 从 `agents.list` 移除 - [ ] 切换分身后,聊天请求携带正确的 `agentId` - [ ] 每个分身有独立的对话上下文(不串聊) - [ ] 现有分身数据成功迁移,无数据丢失 - [ ] 单元测试覆盖新增逻辑 ≥ 80%