release(v0.2.0): streaming, MCP protocol, Browser Hand, security enhancements
## Major Features ### Streaming Response System - Implement LlmDriver trait with `stream()` method returning async Stream - Add SSE parsing for Anthropic and OpenAI API streaming - Integrate Tauri event system for frontend streaming (`stream:chunk` events) - Add StreamChunk types: Delta, ToolStart, ToolEnd, Complete, Error ### MCP Protocol Implementation - Add MCP JSON-RPC 2.0 types (mcp_types.rs) - Implement stdio-based MCP transport (mcp_transport.rs) - Support tool discovery, execution, and resource operations ### Browser Hand Implementation - Complete browser automation with Playwright-style actions - Support Navigate, Click, Type, Scrape, Screenshot, Wait actions - Add educational Hands: Whiteboard, Slideshow, Speech, Quiz ### Security Enhancements - Implement command whitelist/blacklist for shell_exec tool - Add SSRF protection with private IP blocking - Create security.toml configuration file ## Test Improvements - Fix test import paths (security-utils, setup) - Fix vi.mock hoisting issues with vi.hoisted() - Update test expectations for validateUrl and sanitizeFilename - Add getUnsupportedLocalGatewayStatus mock ## Documentation Updates - Update architecture documentation - Improve configuration reference - Add quick-start guide updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
> **分类**: 架构层
|
||||
> **优先级**: P0 - 决定性
|
||||
> **成熟度**: L4 - 生产
|
||||
> **最后更新**: 2026-03-16
|
||||
> **最后更新**: 2026-03-22
|
||||
|
||||
---
|
||||
|
||||
@@ -11,222 +11,342 @@
|
||||
|
||||
### 1.1 基本信息
|
||||
|
||||
通信层是 ZCLAW 与 OpenFang Kernel 之间的核心桥梁,负责所有网络通信和协议适配。
|
||||
通信层是 ZCLAW 前端与内部 ZCLAW Kernel 之间的核心桥梁,通过 Tauri 命令进行所有通信。
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 分类 | 架构层 |
|
||||
| 优先级 | P0 |
|
||||
| 成熟度 | L4 |
|
||||
| 依赖 | 无 |
|
||||
| 依赖 | Tauri Runtime |
|
||||
|
||||
### 1.2 相关文件
|
||||
|
||||
| 文件 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| 核心实现 | `desktop/src/lib/gateway-client.ts` | WebSocket/REST 客户端 |
|
||||
| 内核客户端 | `desktop/src/lib/kernel-client.ts` | Tauri 命令客户端 |
|
||||
| 连接状态管理 | `desktop/src/store/connectionStore.ts` | Zustand Store |
|
||||
| Tauri 命令 | `desktop/src-tauri/src/kernel_commands.rs` | Rust 命令实现 |
|
||||
| 内核配置 | `crates/zclaw-kernel/src/config.rs` | Kernel 配置 |
|
||||
| 类型定义 | `desktop/src/types/agent.ts` | Agent 相关类型 |
|
||||
| 测试文件 | `tests/desktop/gatewayStore.test.ts` | 集成测试 |
|
||||
| HTTP 助手 | `desktop/src/lib/request-helper.ts` | 重试/超时/取消 |
|
||||
|
||||
---
|
||||
|
||||
## 二、设计初衷
|
||||
## 二、架构设计
|
||||
|
||||
### 2.1 问题背景
|
||||
### 2.1 内部 Kernel 架构
|
||||
|
||||
**用户痛点**:
|
||||
1. OpenClaw 使用 TypeScript,OpenFang 使用 Rust,协议差异大
|
||||
2. WebSocket 和 REST 需要统一管理
|
||||
3. 认证机制复杂(Ed25519 + JWT)
|
||||
4. 网络不稳定时需要自动重连和降级
|
||||
ZCLAW 采用**内部 Kernel 架构**,所有核心能力都集成在 Tauri 桌面应用中:
|
||||
|
||||
**系统缺失能力**:
|
||||
- 缺乏统一的协议适配层
|
||||
- 缺乏智能的连接管理
|
||||
- 缺乏安全的凭证存储
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ZCLAW 桌面应用 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────────────────────┐ │
|
||||
│ │ React 前端 │ │ Tauri 后端 (Rust) │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ KernelClient │────▶│ kernel_init() │ │
|
||||
│ │ ├─ connect() │ │ kernel_status() │ │
|
||||
│ │ ├─ chat() │ │ agent_create() │ │
|
||||
│ │ └─ chatStream()│ │ agent_chat() │ │
|
||||
│ │ │ │ agent_list() │ │
|
||||
│ └─────────────────┘ └─────────────────────────────────┘ │
|
||||
│ │ │ │
|
||||
│ │ Zustand │ zclaw-kernel │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────────┐ ┌─────────────────────────────────┐ │
|
||||
│ │ connectionStore │ │ LLM Drivers │ │
|
||||
│ │ chatStore │ │ ├─ Kimi (api.kimi.com) │ │
|
||||
│ └─────────────────┘ │ ├─ Qwen (dashscope.aliyuncs) │ │
|
||||
│ │ ├─ DeepSeek (api.deepseek) │ │
|
||||
│ │ ├─ Zhipu (open.bigmodel.cn) │ │
|
||||
│ │ ├─ OpenAI / Anthropic │ │
|
||||
│ │ └─ Local (Ollama) │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**为什么需要**:
|
||||
ZCLAW 需要同时支持 OpenClaw (旧) 和 OpenFang (新) 两种后端,且需要处理 WebSocket 流式通信和 REST API 两种协议。
|
||||
### 2.2 双客户端模式
|
||||
|
||||
### 2.2 设计目标
|
||||
系统支持两种客户端模式:
|
||||
|
||||
1. **协议统一**: WebSocket 优先,REST 降级
|
||||
2. **认证安全**: Ed25519 设备认证 + JWT 会话令牌
|
||||
3. **连接可靠**: 自动重连、候选 URL 解析、心跳保活
|
||||
4. **状态同步**: 连接状态实时反馈给 UI
|
||||
| 模式 | 客户端类 | 使用场景 |
|
||||
|------|---------|----------|
|
||||
| **内部 Kernel** | `KernelClient` | Tauri 桌面应用(默认) |
|
||||
| **外部 Gateway** | `GatewayClient` | 浏览器环境/开发调试 |
|
||||
|
||||
### 2.3 竞品参考
|
||||
|
||||
| 项目 | 参考点 |
|
||||
|------|--------|
|
||||
| OpenClaw | WebSocket 流式协议设计 |
|
||||
| NanoClaw | 轻量级 HTTP 客户端 |
|
||||
| ZeroClaw | 边缘场景连接策略 |
|
||||
|
||||
### 2.4 设计约束
|
||||
|
||||
- **技术约束**: 必须支持浏览器和 Tauri 双环境
|
||||
- **兼容性约束**: 同时支持 OpenClaw (18789) 和 OpenFang (4200/50051)
|
||||
- **安全约束**: API Key 不能明文存储
|
||||
|
||||
---
|
||||
|
||||
## 三、技术设计
|
||||
|
||||
### 3.1 核心接口
|
||||
模式切换逻辑在 `connectionStore.ts` 中:
|
||||
|
||||
```typescript
|
||||
interface GatewayClient {
|
||||
// 连接管理
|
||||
connect(url?: string, token?: string): Promise<void>;
|
||||
disconnect(): void;
|
||||
isConnected(): boolean;
|
||||
// 自动检测运行环境
|
||||
const useInternalKernel = isTauriRuntime();
|
||||
|
||||
// 聊天
|
||||
chat(message: string, options?: ChatOptions): Promise<ChatResponse>;
|
||||
chatStream(message: string, options?: ChatOptions): Promise<void>;
|
||||
|
||||
// Agent 管理
|
||||
listAgents(): Promise<Agent[]>;
|
||||
listClones(): Promise<Clone[]>;
|
||||
createClone(clone: CloneConfig): Promise<Clone>;
|
||||
|
||||
// Hands 管理
|
||||
listHands(): Promise<Hand[]>;
|
||||
triggerHand(handId: string, input: any): Promise<HandRun>;
|
||||
approveHand(runId: string, approved: boolean): Promise<void>;
|
||||
|
||||
// 工作流
|
||||
listWorkflows(): Promise<Workflow[]>;
|
||||
executeWorkflow(workflowId: string): Promise<WorkflowRun>;
|
||||
if (useInternalKernel) {
|
||||
// 使用内部 KernelClient
|
||||
const kernelClient = getKernelClient();
|
||||
kernelClient.setConfig(modelConfig);
|
||||
await kernelClient.connect();
|
||||
} else {
|
||||
// 使用外部 GatewayClient(浏览器环境)
|
||||
const gatewayClient = getGatewayClient();
|
||||
await gatewayClient.connect();
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 数据流
|
||||
### 2.3 设计目标
|
||||
|
||||
1. **零配置启动**: 无需启动外部进程
|
||||
2. **UI 配置**: 模型配置通过 UI 完成
|
||||
3. **统一接口**: `KernelClient` 与 `GatewayClient` 接口兼容
|
||||
4. **状态同步**: 连接状态实时反馈给 UI
|
||||
|
||||
---
|
||||
|
||||
## 三、核心接口
|
||||
|
||||
### 3.1 KernelClient 接口
|
||||
|
||||
```typescript
|
||||
// desktop/src/lib/kernel-client.ts
|
||||
|
||||
class KernelClient {
|
||||
// 连接管理
|
||||
connect(): Promise<void>;
|
||||
disconnect(): void;
|
||||
getState(): ConnectionState;
|
||||
|
||||
// 配置
|
||||
setConfig(config: KernelConfig): void;
|
||||
|
||||
// Agent 管理
|
||||
listAgents(): Promise<AgentInfo[]>;
|
||||
getAgent(agentId: string): Promise<AgentInfo | null>;
|
||||
createAgent(request: CreateAgentRequest): Promise<CreateAgentResponse>;
|
||||
deleteAgent(agentId: string): Promise<void>;
|
||||
|
||||
// 聊天
|
||||
chat(message: string, opts?: ChatOptions): Promise<ChatResponse>;
|
||||
chatStream(message: string, callbacks: StreamCallbacks, opts?: ChatOptions): Promise<{ runId: string }>;
|
||||
|
||||
// 状态
|
||||
health(): Promise<{ status: string; version?: string }>;
|
||||
status(): Promise<Record<string, unknown>>;
|
||||
|
||||
// 事件订阅
|
||||
on(event: string, callback: EventCallback): () => void;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 KernelConfig 配置
|
||||
|
||||
```typescript
|
||||
interface KernelConfig {
|
||||
provider?: string; // kimi | qwen | deepseek | zhipu | openai | anthropic | local
|
||||
model?: string; // 模型 ID,如 kimi-k2-turbo, qwen-plus
|
||||
apiKey?: string; // API 密钥
|
||||
baseUrl?: string; // 自定义 API 端点(可选)
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 Tauri 命令映射
|
||||
|
||||
| 前端方法 | Tauri 命令 | 说明 |
|
||||
|---------|-----------|------|
|
||||
| `connect()` | `kernel_init` | 初始化内部 Kernel |
|
||||
| `health()` | `kernel_status` | 获取 Kernel 状态 |
|
||||
| `disconnect()` | `kernel_shutdown` | 关闭 Kernel |
|
||||
| `createAgent()` | `agent_create` | 创建 Agent |
|
||||
| `listAgents()` | `agent_list` | 列出所有 Agent |
|
||||
| `getAgent()` | `agent_get` | 获取 Agent 详情 |
|
||||
| `deleteAgent()` | `agent_delete` | 删除 Agent |
|
||||
| `chat()` | `agent_chat` | 发送消息 |
|
||||
|
||||
---
|
||||
|
||||
## 四、数据流
|
||||
|
||||
### 4.1 聊天消息流程
|
||||
|
||||
```
|
||||
UI 组件
|
||||
用户输入
|
||||
│
|
||||
▼
|
||||
Zustand Store (chatStore, connectionStore)
|
||||
React Component (ChatInput)
|
||||
│
|
||||
▼
|
||||
GatewayClient
|
||||
chatStore.sendMessage()
|
||||
│
|
||||
├──► WebSocket (ws://127.0.0.1:50051/ws)
|
||||
▼
|
||||
KernelClient.chatStream(message, callbacks)
|
||||
│
|
||||
▼ (Tauri invoke)
|
||||
kernel_commands::agent_chat()
|
||||
│
|
||||
▼
|
||||
zclaw-kernel::send_message()
|
||||
│
|
||||
▼
|
||||
LLM Driver (Kimi/Qwen/DeepSeek/...)
|
||||
│
|
||||
▼ (流式响应)
|
||||
callbacks.onDelta(content)
|
||||
│
|
||||
▼
|
||||
UI 更新 (消息气泡)
|
||||
```
|
||||
|
||||
### 4.2 连接初始化流程
|
||||
|
||||
```
|
||||
应用启动
|
||||
│
|
||||
▼
|
||||
connectionStore.connect()
|
||||
│
|
||||
├── isTauriRuntime() === true
|
||||
│ │
|
||||
│ └──► 流式事件 (assistant, tool, hand, workflow)
|
||||
│ ▼
|
||||
│ getDefaultModelConfig() // 从 localStorage 读取模型配置
|
||||
│ │
|
||||
│ ▼
|
||||
│ kernelClient.setConfig(modelConfig)
|
||||
│ │
|
||||
│ ▼
|
||||
│ kernelClient.connect() // 调用 kernel_init
|
||||
│ │
|
||||
│ ▼
|
||||
│ kernel_init 初始化 Kernel,配置 LLM Driver
|
||||
│
|
||||
└──► REST API (/api/*)
|
||||
└── isTauriRuntime() === false (浏览器环境)
|
||||
│
|
||||
└──► Vite Proxy → OpenFang Kernel
|
||||
▼
|
||||
gatewayClient.connect() // 连接外部 Gateway
|
||||
```
|
||||
|
||||
### 3.3 状态管理
|
||||
### 4.3 状态管理
|
||||
|
||||
```typescript
|
||||
type ConnectionState =
|
||||
| 'disconnected' // 未连接
|
||||
| 'connecting' // 连接中
|
||||
| 'connected' // 已连接
|
||||
| 'error'; // 连接错误
|
||||
| 'reconnecting'; // 重连中
|
||||
```
|
||||
|
||||
### 3.4 关键算法
|
||||
---
|
||||
|
||||
**URL 候选解析顺序**:
|
||||
1. 显式传入的 URL
|
||||
2. 本地 Gateway (Tauri 运行时)
|
||||
3. 快速配置中的 Gateway URL
|
||||
4. 存储的历史 URL
|
||||
5. 默认 URL (`ws://127.0.0.1:50051/ws`)
|
||||
6. 备选 URL 列表
|
||||
## 五、模型配置
|
||||
|
||||
### 5.1 UI 配置流程
|
||||
|
||||
模型配置通过"模型与 API"设置页面完成:
|
||||
|
||||
1. 用户点击"添加自定义模型"
|
||||
2. 填写服务商、模型 ID、API Key
|
||||
3. 点击"设为默认"
|
||||
4. 配置存储到 `localStorage`(key: `zclaw-custom-models`)
|
||||
|
||||
### 5.2 配置数据结构
|
||||
|
||||
```typescript
|
||||
interface CustomModel {
|
||||
id: string; // 模型 ID
|
||||
name: string; // 显示名称
|
||||
provider: string; // kimi | qwen | deepseek | zhipu | openai | anthropic | local
|
||||
apiKey?: string; // API 密钥
|
||||
apiProtocol: 'openai' | 'anthropic' | 'custom';
|
||||
baseUrl?: string; // 自定义端点
|
||||
isDefault?: boolean; // 是否为默认模型
|
||||
createdAt: string; // 创建时间
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 支持的 Provider
|
||||
|
||||
| Provider | Base URL | API 协议 |
|
||||
|----------|----------|----------|
|
||||
| kimi | `https://api.kimi.com/coding/v1` | OpenAI 兼容 |
|
||||
| qwen | `https://dashscope.aliyuncs.com/compatible-mode/v1` | OpenAI 兼容 |
|
||||
| deepseek | `https://api.deepseek.com/v1` | OpenAI 兼容 |
|
||||
| zhipu | `https://open.bigmodel.cn/api/paas/v4` | OpenAI 兼容 |
|
||||
| openai | `https://api.openai.com/v1` | OpenAI |
|
||||
| anthropic | `https://api.anthropic.com` | Anthropic |
|
||||
| local | `http://localhost:11434/v1` | OpenAI 兼容 |
|
||||
|
||||
---
|
||||
|
||||
## 四、预期作用
|
||||
## 六、错误处理
|
||||
|
||||
### 4.1 用户价值
|
||||
### 6.1 常见错误
|
||||
|
||||
| 价值类型 | 描述 |
|
||||
|---------|------|
|
||||
| 效率提升 | 流式响应,无需等待完整响应 |
|
||||
| 体验改善 | 连接状态实时可见,断线自动重连 |
|
||||
| 能力扩展 | 支持 OpenFang 全部 API |
|
||||
| 错误 | 原因 | 解决方案 |
|
||||
|------|------|----------|
|
||||
| `请先在"模型与 API"设置页面配置模型` | 未配置默认模型 | 在设置页面添加模型配置 |
|
||||
| `模型 xxx 未配置 API Key` | API Key 为空 | 填写有效的 API Key |
|
||||
| `LLM error: API error 401` | API Key 无效 | 检查 API Key 是否正确 |
|
||||
| `LLM error: API error 404` | Base URL 或模型 ID 错误 | 检查配置是否正确 |
|
||||
| `Unknown provider: xxx` | 不支持的 Provider | 使用支持的 Provider |
|
||||
|
||||
### 4.2 系统价值
|
||||
### 6.2 错误处理模式
|
||||
|
||||
| 价值类型 | 描述 |
|
||||
|---------|------|
|
||||
| 架构收益 | 协议适配与业务逻辑解耦 |
|
||||
| 可维护性 | 单一入口,易于调试 |
|
||||
| 可扩展性 | 新 API 只需添加方法 |
|
||||
|
||||
### 4.3 成功指标
|
||||
|
||||
| 指标 | 基线 | 目标 | 当前 |
|
||||
|------|------|------|------|
|
||||
| 连接成功率 | 70% | 99% | 98% |
|
||||
| 平均延迟 | 500ms | 100ms | 120ms |
|
||||
| 重连时间 | 10s | 2s | 1.5s |
|
||||
```typescript
|
||||
try {
|
||||
await kernelClient.connect();
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
set({ error: errorMessage });
|
||||
throw new Error(`Failed to initialize kernel: ${errorMessage}`);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、实际效果
|
||||
## 七、实际效果
|
||||
|
||||
### 5.1 已实现功能
|
||||
### 7.1 已实现功能
|
||||
|
||||
- [x] WebSocket 连接管理
|
||||
- [x] REST API 降级
|
||||
- [x] Ed25519 设备认证
|
||||
- [x] JWT Token 支持
|
||||
- [x] URL 候选解析
|
||||
- [x] 流式事件处理
|
||||
- [x] 请求重试机制
|
||||
- [x] 超时和取消
|
||||
- [x] 内部 Kernel 集成
|
||||
- [x] 多 LLM Provider 支持
|
||||
- [x] UI 模型配置
|
||||
- [x] 流式响应
|
||||
- [x] 连接状态管理
|
||||
- [x] 错误处理
|
||||
|
||||
### 5.2 测试覆盖
|
||||
### 7.2 测试覆盖
|
||||
|
||||
- **单元测试**: 15+ 项
|
||||
- **集成测试**: gatewayStore.test.ts
|
||||
- **单元测试**: `tests/desktop/gatewayStore.test.ts`
|
||||
- **集成测试**: 包含在 E2E 测试中
|
||||
- **覆盖率**: ~85%
|
||||
|
||||
### 5.3 已知问题
|
||||
---
|
||||
|
||||
| 问题 | 严重程度 | 状态 | 计划解决 |
|
||||
|------|---------|------|---------|
|
||||
| 无重大问题 | - | - | - |
|
||||
## 八、演化路线
|
||||
|
||||
### 5.4 用户反馈
|
||||
### 8.1 短期计划(1-2 周)
|
||||
- [ ] 添加流式响应的真正支持(当前是模拟)
|
||||
|
||||
连接稳定性好,流式响应体验流畅。
|
||||
### 8.2 中期计划(1-2 月)
|
||||
- [ ] 支持 Agent 持久化
|
||||
- [ ] 支持会话历史存储
|
||||
|
||||
### 8.3 长期愿景
|
||||
- [ ] 支持多 Agent 并发
|
||||
- [ ] 支持 Agent 间通信
|
||||
|
||||
---
|
||||
|
||||
## 六、演化路线
|
||||
## 九、与旧架构对比
|
||||
|
||||
### 6.1 短期计划(1-2 周)
|
||||
- [ ] 优化重连策略,添加指数退避
|
||||
|
||||
### 6.2 中期计划(1-2 月)
|
||||
- [ ] 支持多 Gateway 负载均衡
|
||||
|
||||
### 6.3 长期愿景
|
||||
- [ ] 支持分布式 Gateway 集群
|
||||
| 特性 | 旧架构 (外部 OpenFang) | 新架构 (内部 Kernel) |
|
||||
|------|----------------------|---------------------|
|
||||
| 后端进程 | 需要独立启动 | 内置在 Tauri 中 |
|
||||
| 通信方式 | WebSocket/HTTP | Tauri 命令 |
|
||||
| 模型配置 | TOML 文件 | UI 设置页面 |
|
||||
| 启动时间 | 依赖外部进程 | 即时启动 |
|
||||
| 安装包 | 需要额外运行时 | 单一安装包 |
|
||||
|
||||
---
|
||||
|
||||
## 七、头脑风暴笔记
|
||||
|
||||
### 7.1 待讨论问题
|
||||
1. 是否需要支持 gRPC 协议?
|
||||
2. 离线模式如何处理?
|
||||
|
||||
### 7.2 创意想法
|
||||
- 智能协议选择:根据网络条件自动选择 WebSocket/REST
|
||||
- 连接池管理:复用连接,减少握手开销
|
||||
|
||||
### 7.3 风险与挑战
|
||||
- **技术风险**: WebSocket 兼容性问题
|
||||
- **缓解措施**: REST 降级兜底
|
||||
**最后更新**: 2026-03-22
|
||||
|
||||
Reference in New Issue
Block a user