feat(hands): restructure Hands UI with Chinese localization

Major changes:
- Add HandList.tsx component for left sidebar
- Add HandTaskPanel.tsx for middle content area
- Restructure Sidebar tabs: 分身/HANDS/Workflow
- Remove Hands tab from RightPanel
- Localize all UI text to Chinese
- Archive legacy OpenClaw documentation
- Add Hands integration lessons document
- Update feature checklist with new components

UI improvements:
- Left sidebar now shows Hands list with status icons
- Middle area shows selected Hand's tasks and results
- Consistent styling with Tailwind CSS
- Chinese status labels and buttons

Documentation:
- Create docs/archive/openclaw-legacy/ for old docs
- Add docs/knowledge-base/hands-integration-lessons.md
- Update docs/knowledge-base/feature-checklist.md
- Update docs/knowledge-base/README.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-14 23:16:32 +08:00
parent 67e1da635d
commit 07079293f4
126 changed files with 36229 additions and 1035 deletions

View File

@@ -0,0 +1,958 @@
# OpenClaw 线上知识库
**版本**: 1.0.0
**最后更新**: 2026-03-12
**目的**: 为 ZClaw 项目提供全面、结构化的 OpenClaw 抷术参考
---
## 目录
1. [核心概念](#核心概念)
2. [系统架构](#系统架构)
3. [Gateway 协议](#gateway-协议)
4. [配置系统](#配置系统)
5. [Skills 与 Tools](#skills-与-tools)
6. [插件开发](#插件开发)
7. [多 Agent 路由](#多-agent-路由)
8. [安全与沙箱](#安全与沙箱)
9. [Heartbeat 机制](#heartbeat-机制)
10. [Channels 通道系统](#channels-通道系统)
11. [最佳实践](#最佳实践)
12. [ZClaw 映射指南](#zclaw-映射指南)
---
## 核心概念
### OpenClaw 是什么?
OpenClaw 是一个 **自托管的 AI Agent 硴关**,不是简单的"聊天 UI + 模型接入器"。
**核心定位**
- **自托管**: 运行在你自己的硬件上,你的规则
- **多通道**: 一个 Gateway 同时服务 WhatsApp、Telegram、Discord、飞书等多个渠道
- **Agent 原生**: 为编码 Agent 构建,支持工具调用、会话、记忆、多 Agent 路由
- **开源**: MIT 许可,社区驱动
**关键洞察** OpenClaw 的核心价值是 **执行 + 持续性 + 可控性**
- **执行**: 能真正读写文件、跑命令、控浏览器、发消息
- **持续性**: 不只是一次性问答,而是可长期运转的 Agent
- **可控性**: 用户能看到配置、文本指令、工作区与约束,而不是黑盒
### Agent 的真正含义
在 OpenClaw 中,一个 Agent 包含:
- 一个 `agentId`
- 一个独立 workspace / agentDir
- 一组 bootstrap 文件 (`AGENTS.md``SOUL.md``USER.md``IDENTITY.md`)
- 一套工具与 sandbox 规则
- 一套 session 历史
- 一组可能的 channel bindings
- 一种人格 / 工作方式 / 角色定位
### Bootstrap 文件职责
| 文件 | 职责 | 内容示例 |
|------|------|----------|
| `AGENTS.md` | 操作规范与行为准则 | 会话启动 checklist、安全规范、工具使用规则 |
| `SOUL.md` | 身份、气质、边界 | Core Truths、Boundaries、Vibe、Continuity |
| `USER.md` | 关于用户的信息 | 用户习惯、上下文、沟通偏好、时区 |
| `IDENTITY.md` | Agent 外显身份 | Name、Emoji、Avatar、Vibe |
| `HEARTBEAT.md` | 心跳任务指令 | 定时检查任务、触发条件、投递目标 |
---
## 系统架构
### 四层架构
```
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (Application) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │WhatsApp │ │Telegram │ │ Discord │ │ 飞书 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ └────────────┴────────────┴────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Gateway (中枢) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ WebSocket │ │ HTTP API │ │ Config │ │ │
│ │ │ Server │ │ Server │ │ Manager │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Agent Runtime │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Skills │ │ Tools │ │ Memory │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ LLM Providers │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │ Claude │ │ GPT-4 │ │ GLM │ │ Qwen │ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### Gateway 职责
Gateway 是 OpenClaw 的真正控制面板:
- WebSocket 协议握手与会话维持
- Agent 运行时管理
- Session/stream 事件分发
- Channels 消息收发
- 配置热加载与配置 RPC
- Skills / Tools / Plugins / Heartbeat 协调
- Device auth / pairing / scopes
### Workspace 结构
```
~/.openclaw/
├── openclaw.json # 主配置文件
├── .env # 环境变量
├── workspace/ # 默认工作区
│ ├── AGENTS.md
│ ├── SOUL.md
│ ├── USER.md
│ ├── IDENTITY.md
│ ├── memory.md
│ └── memory/
│ └── YYYY-MM-DD.md
├── agents/ # 多 Agent 状态目录
│ └── <agentId>/
│ ├── agent/
│ │ └── auth-profiles.json
│ └── sessions/
│ └── <sessionKey>.jsonl
└── skills/ # 托管技能目录
```
---
## Gateway 协议
### WebSocket 帧类型
```typescript
// 请求帧
interface GatewayRequest {
type: 'req';
id: string;
method: string;
params?: Record<string, any>;
}
// 响应帧
interface GatewayResponse {
type: 'res';
id: string;
ok: boolean;
payload?: any;
error?: any;
}
// 事件帧
interface GatewayEvent {
type: 'event';
event: string;
payload?: any;
seq?: number;
}
```
### 握手流程
```
客户端 Gateway
│ │
│────── WebSocket Connect ────▶│
│ │
│◀───── connect.challenge ─────│ (包含 nonce)
│ │
│────── connect request ──────▶│ (包含 device 签名)
│ │
│◀───── connect response ──────│ (成功/失败)
│ │
│◀═══════ 事件流 ═══════════════│ (agent, chat, etc.)
│ │
```
### Device 认证
```typescript
// 签名载荷格式 (v2)
const payload = [
'v2',
deviceId,
clientId,
clientMode,
role,
scopes.join(','),
String(signedAt),
token || '',
nonce,
].join('|');
// 使用 Ed25519 签名
const signature = nacl.sign.detached(messageBytes, secretKey);
```
### 连接参数
```typescript
interface ConnectParams {
minProtocol: 3;
maxProtocol: 3;
client: {
id: string; // 客户端标识
version: string; // 客户端版本
platform: string; // Win32/Darwin/Linux
mode: 'operator' | 'node';
};
role: 'operator' | 'node';
scopes: string[]; // ['operator.read', 'operator.write']
auth?: { token?: string };
device: {
id: string; // 设备 ID (公钥指纹)
publicKey: string; // Base64 编码的公钥
signature: string; // 签名
signedAt: number; // 签名时间戳
nonce: string; // 服务器提供的 nonce
};
}
```
### 核心 RPC 方法
| 方法 | 描述 | 参数 |
|------|------|------|
| `agent` | 发送消息给 Agent | `message`, `sessionKey?`, `model?` |
| `health` | 获取健康状态 | - |
| `status` | 获取 Gateway 状态 | - |
| `config.get` | 获取配置 | `path` |
| `config.patch` | 更新配置 | `path`, `value` |
| `send` | 通过渠道发送消息 | `channel`, `chatId`, `text` |
### Agent 流事件
```typescript
interface AgentStreamEvent {
stream: 'assistant' | 'tool' | 'lifecycle';
delta?: string; // 增量文本
content?: string; // 完整内容
tool?: string; // 工具名称
phase?: 'start' | 'end' | 'error';
runId?: string; // 运行 ID
error?: string; // 错误信息
}
```
---
## 配置系统
### 配置文件位置
```
~/.openclaw/openclaw.json # 主配置
~/.openclaw/.env # 环境变量
```
### 配置层级与优先级
```
agents.defaults.* # 全局默认
↓ 覆盖
agents.list[].* # 每个 Agent 的覆盖
↓ 覆盖
channels.defaults.* # 全渠道默认
↓ 覆盖
channels.<channel>.* # 单渠道覆盖
↓ 覆盖
channels.<channel>.accounts.<id>.* # 账号级覆盖
```
### 热加载模式
| 模式 | 行为 |
|------|------|
| `hybrid` (默认) | 安全更改即时生效,关键更改自动重启 |
| `hot` | 只热应用安全更改,需重启时记录警告 |
| `restart` | 任何更改都重启 Gateway |
| `off` | 禁用文件监控,手动重启生效 |
### CLI 配置命令
```bash
# 查看配置
openclaw config get agents.defaults.workspace
# 设置配置
openclaw config set agents.defaults.heartbeat.every "2h"
# 删除配置
openclaw config unset tools.web.search.apiKey
# 配置向导
openclaw configure
# 完整设置向导
openclaw onboard
```
### 环境变量引用
```json
{
"gateway": {
"auth": {
"token": "${OPENCLAW_GATEWAY_TOKEN}"
}
},
"models": {
"providers": {
"openai": {
"apiKey": "${OPENAI_API_KEY}"
}
}
}
}
```
---
## Skills 与 Tools
### Skills 加载位置与优先级
1. **Bundled skills**: 安装包自带
2. **Managed/local skills**: `~/.openclaw/skills`
3. **Workspace skills**: `<workspace>/skills`
4. **Extra dirs**: `skills.load.extraDirs` 配置
**优先级**: workspace > managed > bundled > extraDirs
### SKILL.md 格式
```markdown
---
name: my-skill
description: 技能描述
homepage: https://example.com
user-invocable: true
disable-model-invocation: false
---
# 技能标题
技能说明内容...
Use {baseDir} to reference skill folder path.
```
### Skills vs Tools 区别
| 概念 | 描述 | 示例 |
|------|------|------|
| **Skills** | 任务说明 + 规则 + 可选脚本的组合 | 代码审查、文档生成 |
| **Tools** | 类型化的可执行能力 | `exec`, `read`, `write`, `browser` |
### 内置 Tools
```json
{
"tools": {
"exec": { "shell": true },
"web": {
"search": { "enabled": true }
},
"browser": { "enabled": true },
"read": {},
"write": {},
"edit": {}
}
}
```
### MCP 支持
OpenClaw 原生支持 MCP (Model Context Protocol):
- 给 Agent 扩展新的上下文来源与工具面
- 让技能可以调用标准化外部能力
- 让模型在不写死工具的情况下复用第三方协议能力
---
## 插件开发
### 插件结构
```
my-plugin/
├── openclaw.plugin.json # 必需: 插件清单
├── index.ts # 入口文件
├── package.json
└── dist/
```
### openclaw.plugin.json
```json
{
"id": "my-plugin",
"name": "My Plugin",
"version": "1.0.0",
"description": "Plugin description",
"main": "dist/index.js",
"skills": ["./skills"],
"config": {
"enabled": {
"type": "boolean",
"default": true
}
}
}
```
### 插件 API
```typescript
interface PluginAPI {
config: Record<string, any>;
// 注册 Gateway RPC 方法
registerGatewayMethod(
method: string,
handler: (ctx: RpcContext) => void
): void;
// 注册钩子
registerHook(
event: string,
handler: (...args: any[]) => any,
meta?: Record<string, any>
): void;
}
interface RpcContext {
params: Record<string, any>;
respond(ok: boolean, payload: any): void;
}
```
### ZClaw 插件示例
```typescript
// plugins/zclaw-ui/index.ts
export default function register(api: PluginAPI) {
// 注册自定义 RPC 方法
api.registerGatewayMethod('zclaw.clones.list', ({ respond }) => {
const data = readZclawData();
respond(true, { clones: data.clones });
});
// 注册启动钩子
api.registerHook('gateway:startup', async () => {
console.log('[ZCLAW] Plugin loaded');
});
}
```
---
## 多 Agent 路由
### 路由规则 (按优先级)
1. `peer` 精确匹配 (DM/group/channel id)
2. `parentPeer` 继承匹配 (thread 继承)
3. `guildId + roles` (Discord 角色路由)
4. `guildId` (Discord)
5. `teamId` (Slack)
6. `accountId` 规则
7. channel-level 匹配 (`accountId: "*"`)
8. fallback 到默认 Agent
### Binding 配置
```json
{
"bindings": [
{
"agentId": "work",
"match": {
"channel": "whatsapp",
"accountId": "personal",
"peer": { "kind": "direct", "id": "+15551234567" }
}
},
{
"agentId": "main",
"match": { "channel": "whatsapp" }
}
]
}
```
### 多 Agent 配置示例
```json
{
"agents": {
"list": [
{
"id": "home",
"default": true,
"workspace": "~/.openclaw/workspace-home"
},
{
"id": "work",
"workspace": "~/.openclaw/workspace-work",
"model": "anthropic/claude-opus-4-6"
}
]
},
"bindings": [
{ "agentId": "home", "match": { "channel": "whatsapp", "accountId": "personal" } },
{ "agentId": "work", "match": { "channel": "whatsapp", "accountId": "biz" } }
]
}
```
---
## 安全与沙箱
### 沙箱模式
| 模式 | 描述 |
|------|------|
| `off` | 无沙箱,直接执行 |
| `write` | 只沙箱写操作 |
| `all` | 所有操作都在沙箱中执行 |
### 工具策略
```json
{
"agents": {
"list": [
{
"id": "family",
"sandbox": { "mode": "all" },
"tools": {
"allow": ["read", "exec"],
"deny": ["write", "browser"]
}
}
]
}
}
```
### 安全检查清单
- [ ] 无硬编码密钥 (使用 env 引用)
- [ ] DM 访问控制已配置
- [ ] 群聊 mention 规则已设置
- [ ] 工具权限最小化
- [ ] 沙箱模式适当
- [ ] Gateway 端口不对外暴露
---
## Heartbeat 机制
### 概念
Heartbeat 不是简单的 cron而是 **定期触发一个完整 Agent turn**
- 默认读取 `HEARTBEAT.md`
- 如果没事做,返回 `HEARTBEAT_OK`
- 可以配置投递目标 (`none``last` 或具体渠道)
- 可以设置 active hours
- 支持 per-agent 覆盖
### 配置
```json
{
"agents": {
"defaults": {
"heartbeat": {
"every": "1h",
"activeHours": { "start": "09:00", "end": "18:00" },
"deliverTo": "last"
}
}
}
}
```
### HEARTBEAT.md 示例
```markdown
# 心跳任务
每小时检查:
1. 是否有待处理的提醒
2. 是否需要发送日报
3. 日历事件提醒
如果无事可做,回复 HEARTBEAT_OK
```
---
## Channels 通道系统
### 支持的通道
| 通道 | 多账号 | 描述 |
|------|--------|------|
| WhatsApp | ✅ | 通过 Web WhatsApp |
| Telegram | ✅ | Bot API |
| Discord | ✅ | Bot + Guild |
| 飞书 | ✅ | 企业自建应用 |
| Slack | ✅ | Bot + Workspace |
| iMessage | ❌ | macOS only |
| Signal | ✅ | 通过 signald |
### 通道配置结构
```json
{
"channels": {
"whatsapp": {
"enabled": true,
"dmPolicy": "pairing",
"allowFrom": ["+15555550123"],
"accounts": {
"personal": {
"authDir": "~/.openclaw/credentials/whatsapp/personal"
},
"biz": {
"authDir": "~/.openclaw/credentials/whatsapp/biz"
}
}
}
}
}
```
### 访问控制
```json
{
"channels": {
"whatsapp": {
"dmPolicy": "allowlist",
"allowFrom": ["+15555550123"],
"groups": {
"*": { "requireMention": true }
}
}
},
"messages": {
"groupChat": {
"mentionPatterns": ["@openclaw", "小龙虾"]
}
}
}
```
---
## 最佳实践
### 1. 配置管理
```bash
# 使用 CLI 而非直接编辑 JSON
openclaw config set agents.defaults.model "anthropic/claude-sonnet-4-6"
# 验证配置
openclaw doctor
# 查看日志
openclaw logs --follow
```
### 2. Agent 隔离
- 每个 Agent 使用独立 workspace
- 不共享 `agentDir` (会导致 auth/session 冲突)
- 敏感 Agent 启用沙箱
### 3. 密钥管理
```json
// 使用环境变量引用
{
"models": {
"providers": {
"openai": {
"apiKey": "${OPENAI_API_KEY}"
}
}
}
}
```
### 4. 错误处理
- Gateway 连接是协议适配工程,不是简单的 ws 连接
- 实现指数退避重连
- 正确处理 `connect.challenge`
---
## ZClaw 映射指南
### 设置页面对应关系
| ZClaw 页面 | OpenClaw 子系统 | 真实目标 |
|-----------|-----------------|----------|
| 通用 | 系统级设置 | 控制连接状态、系统级行为开关 |
| 模型与 API | providers / model defaults | 管理 provider 配置、主模型与 fallback |
| MCP 服务 | Tools / MCP | 定义 Agent 可接入的外部能力 |
| 技能 | Skills | 管理 Agent 可调用的工作流知识库 |
| IM 频道 | Channels | 管理消息来源和路由规则 |
| 工作区 | Workspace / Sandbox | 确定 Agent 执行边界 |
| 数据与隐私 | Data / Telemetry | 明确数据存储位置和隐私设置 |
| 分身/快速配置 | Agents / Bindings | 创建/配置新的 Agent 实例 |
### ZClaw 自定义 RPC 方法
```typescript
// plugins/zclaw-ui 注册的方法
client.listClones() // zclaw.clones.list
client.createClone(opts) // zclaw.clones.create
client.updateClone(id, opts) // zclaw.clones.update
client.deleteClone(id) // zclaw.clones.delete
client.getUsageStats() // zclaw.stats.usage
client.getSessionStats() // zclaw.stats.sessions
client.getWorkspaceInfo() // zclaw.workspace.info
client.getPluginStatus() // zclaw.plugins.status
client.getQuickConfig() // zclaw.config.quick
client.listSkills() // zclaw.skills.list
```
### 分身 (Clone) = Agent 实例
```typescript
interface CloneConfig {
id: string;
name: string;
role?: string;
nickname?: string;
scenarios?: string[];
model?: string;
workspaceDir?: string;
workspaceResolvedPath?: string;
restrictFiles?: boolean;
privacyOptIn?: boolean;
userName?: string;
userRole?: string;
bootstrapReady?: boolean;
bootstrapFiles?: Array<{ name: string; path: string; exists: boolean }>;
}
```
### 判断标准
> 如果一个页面改动之后,没有改变 OpenClaw Runtime 的真实行为、真实配置、真实路由、真实工作区或真实 Agent 上下文,那它大概率还只是"演示 UI",不是系统能力。
---
## ZCLAW 桌面 Gateway 握手排障案例2026-03
### 症状演进
1. 初始表现为桌面端长时间停留在“握手中...”
2. 修正握手客户端身份后,错误表象变成 `WebSocket connection failed`
3. 修复候选地址 fallback 的错误覆盖后,暴露出真实错误 `origin not allowed`
4. 自动补齐 `gateway.controlUi.allowedOrigins` 后,错误继续推进为 `pairing required`
### 已确认的排查结论
- `gateway.auth.token` 已正确从 `openclaw.json` 读取并注入桌面端连接
- Tauri 调试版实际运行的是 `target/debug/resources/openclaw-runtime`
- Gateway WebSocket 握手客户端身份需满足当前 schema
- `client.id=cli`
- `client.mode=cli`
- `role=operator`
- 浏览器 / WebView 环境与 Node 探针的关键差异是会附带 `Origin`
- Tauri WebView 需要被加入:
- `gateway.controlUi.allowedOrigins`
- `http://tauri.localhost`
- `tauri://localhost`
-`origin not allowed` 被解决后Gateway 会继续要求对当前设备完成 pairing
### 有效的排障方法
#### 1. 先分离“网络失败”和“协议失败”
如果 UI 只显示 `WebSocket connection failed`,先检查连接代码是否在多个候选地址之间 fallback并把更早的握手错误覆盖掉。
ZCLAW 的处理方式是:
- 仅对以下错误继续尝试下一个候选地址:
- `WebSocket connection failed`
- `Gateway handshake timed out`
- `WebSocket closed before handshake completed`
- 对握手 / 鉴权 / schema 错误立即停止 fallback原样暴露给 UI
#### 2. 用独立协议探针验证 Gateway 真正接受的握手参数
在本案例中Node 探针证明了:
- `cli/cli/operator` 是可接受的客户端身份
- 设备 `deviceId` 必须和 `publicKey` 的派生规则一致
- 仅靠终端探针成功并不能证明 Tauri WebView 一定能连通,因为 WebView 会额外带 `Origin`
#### 3. 优先检查本地 Gateway 的 pending / paired devices
可用命令:
```powershell
openclaw devices list --json
```
本案例中,`pairing required` 发生时,`devices list` 已能看到当前桌面端的 pending 请求,说明:
- 连接已到达 Gateway
- 当前缺的是“批准这台设备”,不是 token 或网络
### ZCLAW 当前修复策略
#### A. 连接前自动准备本地 Gateway
桌面端在 Tauri 运行时连接前,先调用本地准备逻辑:
- 确保 `gateway.controlUi.allowedOrigins` 包含:
- `http://tauri.localhost`
- `tauri://localhost`
- 如果配置被修改且 Gateway 正在运行,自动重启 Gateway 使配置生效
#### B. 握手遇到 `pairing required` 时自动批准本机桌面设备
当前策略只在**本地 loopback Gateway** 下启用:
- 仅匹配 `ws://127.0.0.1:*``ws://localhost:*`
- 前端读取当前桌面端持久化的 `deviceId/publicKey`
- Tauri 侧调用:
```powershell
openclaw devices list --json
openclaw devices approve <requestId> --json --token <token> --url <url>
```
- 只批准同时匹配以下条件的 pending request
- `deviceId`
- `publicKey`
- 批准成功后立即重试连接
### 后续遇到同类问题时的最短排障顺序
1. 确认当前运行的是目标 `desktop.exe`
2. 确认 `openclaw.json` 中有 `gateway.auth.token`
3. 确认 WebView localStorage 已持久化 `zclaw_gateway_url` / `zclaw_gateway_token`
4. 把握手错误原样暴露,不要让 fallback 覆盖
5. 若报 `origin not allowed`
- 检查 `gateway.controlUi.allowedOrigins`
6. 若报 `pairing required`
- 检查 `openclaw devices list --json`
- 看当前桌面设备是否进入 `pending`
7. 如果 pending 存在,优先做“只批准本机当前设备”的自动化,而不是直接放宽所有设备
---
## ZCLAW 桌面聊天 / 模型配置协议错配案例2026-03
### 症状
- 桌面端显示 Gateway 已连接,但发送消息立即失败
- 常见错误文案为:
- `invalid agent params: must have required property 'idempotencyKey'`
- `invalid agent params: must NOT have additional properties: model`
- 模型与 API 页面可以切换本地显示值,但不会改变 Gateway 的真实默认模型
### 根因
- ZCLAW 桌面端此前仍按旧协议调用 `agent`
- 发送了顶层 `model`
- 没有发送必填 `idempotencyKey`
- 当前 OpenClaw runtime 的 `agent` schema 已变更为:
- `message` 必填
- `idempotencyKey` 必填
- `model` 不是允许的顶层字段
- 桌面端“模型切换”之前只是本地 Zustand 状态,没有写回 Gateway 配置,因此不会影响真实运行时行为
### 有效排查方法
1. 不要只看仓库里的旧 client 封装,要直接核对当前实际 runtime 的 schema
2. 如果仓库源码里搜不到新字段(如 `idempotencyKey`),优先检查打包后的 `openclaw-runtime`
3. 在本案例中,真实约束来自 runtime 中的 `AgentParamsSchema`
- `message: NonEmptyString`
- `idempotencyKey: NonEmptyString`
- `agentId/sessionKey/...` 可选
- `additionalProperties: false`
4. 对模型配置,不要只改前端本地状态;应优先确认 runtime 是否已暴露:
- `models.list`
- `config.get`
- `config.apply`
### ZCLAW 当前修复策略
- `desktop/src/lib/gateway-client.ts`
- `chat()` 改为发送 `idempotencyKey`
- 停止发送非法顶层 `model`
- 新增 `models.list` / `config.get` / `config.apply` 客户端接口
- `desktop/src/store/chatStore.ts`
- 发送消息时不再把本地 `clone_*` 直接当作 runtime `agentId`
- 继续保留前端会话与分身关联信息,避免 UI 上下文丢失
- `desktop/src/components/Settings/ModelsAPI.tsx`
- 改为基于真实 Gateway 配置读写默认模型与中文模型插件 Provider 配置
- `desktop/src/components/ChatArea.tsx`
- 聊天输入区模型下拉改为通过 `config.apply` 更新 Gateway 默认模型,而不是只切本地显示
### 当前结论
- 如果错误同时出现 `missing idempotencyKey``unexpected property model`,优先判断为“桌面端协议版本落后于当前 runtime”
- 如果模型切换只改变 UI 文案、不会改变新会话的实际模型,说明它仍是“演示态”,应改为落到 `config.get/config.apply`
---
## 参考资料
### 官方文档
- [OpenClaw 官方文档](https://docs.openclaw.ai/)
- [Gateway 配置参考](https://docs.openclaw.ai/gateway/configuration)
- [Multi-Agent 路由](https://docs.openclaw.ai/concepts/multi-agent)
- [Skills 文档](https://docs.openclaw.ai/tools/skills)
- [Heartbeat 文档](https://docs.openclaw.ai/gateway/heartbeat)
### 社区资源
- [OpenClaw 中文指南](https://yeasy.gitbook.io/openclaw_guide/)
- [awesome-openclaw-skills](https://github.com/VoltAgent/awesome-openclaw-skills)
- [OpenClaw 源码解析](https://www.ququ123.top/2026/03/openclaw-gateway-startup/)
### ZClaw 内部参考
- `docs/openclaw-deep-dive.md` - 深度分析
- `config/openclaw.default.json` - 默认配置
- `plugins/zclaw-ui/index.ts` - 插件实现
- `desktop/src/lib/gateway-client.ts` - 客户端实现