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:
iven
2026-03-24 03:24:24 +08:00
parent e49ba4460b
commit 3ff08faa56
78 changed files with 29575 additions and 1682 deletions

View File

@@ -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 使用 TypeScriptOpenFang 使用 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

View File

@@ -1,9 +1,9 @@
# OpenFang 集成 (OpenFang Integration)
# ZCLAW Kernel 集成
> **分类**: Tauri 后端
> **优先级**: P0 - 决定性
> **成熟度**: L4 - 生产
> **最后更新**: 2026-03-16
> **最后更新**: 2026-03-22
---
@@ -11,263 +11,532 @@
### 1.1 基本信息
OpenFang 集成模块是 Tauri 后端的核心,负责与 OpenFang Rust 运行时的本地集成,包括进程管理、配置读写、设备配对等。
ZCLAW Kernel 集成模块是 Tauri 后端的核心,负责与内部 ZCLAW Kernel 的集成,包括 Agent 生命周期管理、消息处理、模型配置等。
| 属性 | 值 |
|------|-----|
| 分类 | Tauri 后端 |
| 优先级 | P0 |
| 成熟度 | L4 |
| 依赖 | Tauri Runtime |
| 依赖 | Tauri Runtime, zclaw-kernel crate |
### 1.2 相关文件
| 文件 | 路径 | 用途 |
|------|------|------|
| 核心实现 | `desktop/src-tauri/src/lib.rs` | OpenFang 命令 (1043行) |
| Viking 命令 | `desktop/src-tauri/src/viking_commands.rs` | OpenViking sidecar |
| 服务器管理 | `desktop/src-tauri/src/viking_server.rs` | 本地服务器 |
| 安全存储 | `desktop/src-tauri/src/secure_storage.rs` | Keyring 集成 |
| Kernel 命令 | `desktop/src-tauri/src/kernel_commands.rs` | Tauri 命令封装 |
| Kernel 状态 | `desktop/src-tauri/src/lib.rs` | Kernel 初始化 |
| Kernel 配置 | `crates/zclaw-kernel/src/config.rs` | 配置结构定义 |
| Kernel 实现 | `crates/zclaw-kernel/src/lib.rs` | Kernel 核心实现 |
---
## 二、设计初衷
## 二、架构设计
### 2.1 问题背景
### 2.1 设计背景
**用户痛点**:
1. 需要手动启动 OpenFang 运行时
1. 外部进程启动失败、版本兼容问题频发
2. 配置文件分散难以管理
3. 跨平台兼容性问题
3. 分发复杂,需要额外配置运行时
**系统缺失能力**:
- 缺乏本地运行时管理
- 缺乏统一的配置接口
- 缺乏进程监控能力
**解决方案**:
- 将 ZCLAW Kernel 直接集成到 Tauri 应用中
- 通过 UI 配置模型,无需编辑配置文件
- 单一安装包,开箱即用
**为什么需要**:
Tauri 后端提供了原生系统集成能力,让用户无需关心运行时的启动和管理。
### 2.2 设计目标
1. **自动发现**: 自动找到 OpenFang 运行时
2. **生命周期管理**: 启动、停止、重启
3. **配置管理**: TOML 配置读写
4. **进程监控**: 状态和日志查看
### 2.3 运行时发现优先级
### 2.2 架构概览
```
1. 环境变量 ZCLAW_OPENFANG_BIN
2. Tauri 资源目录中的捆绑运行时
3. 系统 PATH 中的 openfang 命令
┌─────────────────────────────────────────────────────────────────┐
│ Tauri 桌面应用 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 前端 (React + TypeScript) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ ModelsAPI │ │ ChatStore │ │ Connection │ │ │
│ │ │ (UI 配置) │ │ (消息管理) │ │ Store │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │ │
│ │ └────────────────┼────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ KernelClient │ │ │
│ │ │ (Tauri invoke) │ │ │
│ │ └──────────┬──────────┘ │ │
│ └─────────────────────────┼──────────────────────────────┘ │
│ │ │
│ │ Tauri Commands │
│ │ │
│ ┌─────────────────────────┼──────────────────────────────┐ │
│ │ 后端 (Rust) │ │ │
│ │ ▼ │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ kernel_commands.rs │ │ │
│ │ │ ├─ kernel_init │ │ │
│ │ │ ├─ kernel_status │ │ │
│ │ │ ├─ kernel_shutdown │ │ │
│ │ │ ├─ agent_create │ │ │
│ │ │ ├─ agent_list │ │ │
│ │ │ ├─ agent_get │ │ │
│ │ │ ├─ agent_delete │ │ │
│ │ │ └─ agent_chat │ │ │
│ │ └────────────────────┬───────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ zclaw-kernel crate │ │ │
│ │ │ ├─ Kernel::boot() │ │ │
│ │ │ ├─ spawn_agent() │ │ │
│ │ │ ├─ kill_agent() │ │ │
│ │ │ ├─ list_agents() │ │ │
│ │ │ └─ send_message() │ │ │
│ │ └────────────────────┬───────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ zclaw-runtime crate │ │ │
│ │ │ ├─ AnthropicDriver │ │ │
│ │ │ ├─ OpenAiDriver │ │ │
│ │ │ ├─ GeminiDriver │ │ │
│ │ │ └─ LocalDriver │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
### 2.4 设计约束
### 2.3 Crate 依赖
- **安全约束**: 配置文件需要验证
- **性能约束**: 进程操作不能阻塞 UI
- **兼容性约束**: Windows/macOS/Linux 统一接口
```
zclaw-types
zclaw-memory
zclaw-runtime
zclaw-kernel
desktop/src-tauri
```
---
## 三、技术设计
## 三、Tauri 命令
### 3.1 核心命令
### 3.1 Kernel 命令
```rust
/// 初始化内部 ZCLAW Kernel
#[tauri::command]
fn openfang_status(app: AppHandle) -> Result<LocalGatewayStatus, String>
pub async fn kernel_init(
state: State<'_, KernelState>,
config_request: Option<KernelConfigRequest>,
) -> Result<KernelStatusResponse, String>
/// 获取 Kernel 状态
#[tauri::command]
fn openfang_start(app: AppHandle) -> Result<LocalGatewayStatus, String>
pub async fn kernel_status(
state: State<'_, KernelState>,
) -> Result<KernelStatusResponse, String>
/// 关闭 Kernel
#[tauri::command]
fn openfang_stop(app: AppHandle) -> Result<LocalGatewayStatus, String>
#[tauri::command]
fn openfang_restart(app: AppHandle) -> Result<LocalGatewayStatus, String>
#[tauri::command]
fn openfang_local_auth(app: AppHandle) -> Result<GatewayAuth, String>
#[tauri::command]
fn openfang_prepare_for_tauri(app: AppHandle) -> Result<(), String>
#[tauri::command]
fn openfang_approve_device_pairing(app: AppHandle, device_id: String) -> Result<(), String>
#[tauri::command]
fn openfang_process_list(app: AppHandle) -> Result<ProcessListResponse, String>
#[tauri::command]
fn openfang_process_logs(app: AppHandle, pid: Option<u32>, lines: Option<usize>) -> Result<ProcessLogsResponse, String>
#[tauri::command]
fn openfang_version(app: AppHandle) -> Result<VersionInfo, String>
pub async fn kernel_shutdown(
state: State<'_, KernelState>,
) -> Result<(), String>
```
### 3.2 状态结构
### 3.2 Agent 命令
```rust
#[derive(Serialize)]
struct LocalGatewayStatus {
running: bool,
port: Option<u16>,
pid: Option<u32>,
config_path: Option<String>,
binary_path: Option<String>,
service_name: Option<String>,
error: Option<String>,
/// 创建 Agent
#[tauri::command]
pub async fn agent_create(
state: State<'_, KernelState>,
request: CreateAgentRequest,
) -> Result<CreateAgentResponse, String>
/// 列出所有 Agent
#[tauri::command]
pub async fn agent_list(
state: State<'_, KernelState>,
) -> Result<Vec<AgentInfo>, String>
/// 获取 Agent 详情
#[tauri::command]
pub async fn agent_get(
state: State<'_, KernelState>,
agent_id: String,
) -> Result<Option<AgentInfo>, String>
/// 删除 Agent
#[tauri::command]
pub async fn agent_delete(
state: State<'_, KernelState>,
agent_id: String,
) -> Result<(), String>
/// 发送消息
#[tauri::command]
pub async fn agent_chat(
state: State<'_, KernelState>,
request: ChatRequest,
) -> Result<ChatResponse, String>
```
### 3.3 数据结构
```rust
/// Kernel 配置请求
pub struct KernelConfigRequest {
pub provider: String, // kimi | qwen | deepseek | zhipu | openai | anthropic | local
pub model: String, // 模型 ID
pub api_key: Option<String>,
pub base_url: Option<String>,
}
#[derive(Serialize)]
struct GatewayAuth {
gateway_token: Option<String>,
device_public_key: Option<String>,
/// Kernel 状态响应
pub struct KernelStatusResponse {
pub initialized: bool,
pub agent_count: usize,
pub database_url: Option<String>,
pub default_provider: Option<String>,
pub default_model: Option<String>,
}
/// Agent 创建请求
pub struct CreateAgentRequest {
pub name: String,
pub description: Option<String>,
pub system_prompt: Option<String>,
pub provider: String,
pub model: String,
pub max_tokens: u32,
pub temperature: f32,
}
/// Agent 创建响应
pub struct CreateAgentResponse {
pub id: String,
pub name: String,
pub state: String,
}
/// 聊天请求
pub struct ChatRequest {
pub agent_id: String,
pub message: String,
}
/// 聊天响应
pub struct ChatResponse {
pub content: String,
pub input_tokens: u32,
pub output_tokens: u32,
}
```
### 3.3 运行时发现
---
## 四、Kernel 初始化
### 4.1 初始化流程
```rust
fn find_openfang_binary(app: &AppHandle) -> Option<PathBuf> {
// 1. 环境变量
if let Ok(path) = std::env::var("ZCLAW_OPENFANG_BIN") {
let path = PathBuf::from(path);
if path.exists() {
return Some(path);
// desktop/src-tauri/src/kernel_commands.rs
pub async fn kernel_init(
state: State<'_, KernelState>,
config_request: Option<KernelConfigRequest>,
) -> Result<KernelStatusResponse, String> {
let mut kernel_lock = state.lock().await;
// 如果已初始化,返回当前状态
if kernel_lock.is_some() {
let kernel = kernel_lock.as_ref().unwrap();
return Ok(KernelStatusResponse { ... });
}
// 构建配置
let mut config = zclaw_kernel::config::KernelConfig::default();
if let Some(req) = &config_request {
config.default_provider = req.provider.clone();
config.default_model = req.model.clone();
// 根据 Provider 设置 API Key
match req.provider.as_str() {
"kimi" => {
if let Some(key) = &req.api_key {
config.kimi_api_key = Some(key.clone());
}
if let Some(url) = &req.base_url {
config.kimi_base_url = url.clone();
}
}
"qwen" => {
if let Some(key) = &req.api_key {
config.qwen_api_key = Some(key.clone());
}
if let Some(url) = &req.base_url {
config.qwen_base_url = url.clone();
}
}
// ... 其他 Provider
_ => {}
}
}
// 2. 捆绑运行时
if let Some(resource_dir) = app.path().resource_dir().ok() {
let bundled = resource_dir.join("bin").join("openfang");
if bundled.exists() {
return Some(bundled);
}
}
// 启动 Kernel
let kernel = Kernel::boot(config.clone())
.await
.map_err(|e| format!("Failed to initialize kernel: {}", e))?;
// 3. 系统 PATH
if let Ok(path) = which::which("openfang") {
return Some(path);
}
*kernel_lock = Some(kernel);
None
Ok(KernelStatusResponse {
initialized: true,
agent_count: 0,
database_url: Some(config.database_url),
default_provider: Some(config.default_provider),
default_model: Some(config.default_model),
})
}
```
### 3.4 配置管理
### 4.2 Kernel 状态管理
```rust
fn read_config(config_path: &Path) -> Result<OpenFangConfig, String> {
let content = std::fs::read_to_string(config_path)
.map_err(|e| format!("Failed to read config: {}", e))?;
// Kernel 状态包装器
pub type KernelState = Arc<Mutex<Option<Kernel>>>;
let config: OpenFangConfig = toml::from_str(&content)
.map_err(|e| format!("Failed to parse config: {}", e))?;
Ok(config)
// 创建 Kernel 状态
pub fn create_kernel_state() -> KernelState {
Arc::new(Mutex::new(None))
}
```
fn write_config(config_path: &Path, config: &OpenFangConfig) -> Result<(), String> {
let content = toml::to_string_pretty(config)
.map_err(|e| format!("Failed to serialize config: {}", e))?;
### 4.3 lib.rs 注册
std::fs::write(config_path, content)
.map_err(|e| format!("Failed to write config: {}", e))
```rust
// desktop/src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
// 注册 Kernel 状态
app.manage(kernel_commands::create_kernel_state());
Ok(())
})
.invoke_handler(tauri::generate_handler![
// Kernel 命令
kernel_commands::kernel_init,
kernel_commands::kernel_status,
kernel_commands::kernel_shutdown,
// Agent 命令
kernel_commands::agent_create,
kernel_commands::agent_list,
kernel_commands::agent_get,
kernel_commands::agent_delete,
kernel_commands::agent_chat,
])
.run(tauri::generate_context!())
}
```
---
## 四、预期作用
## 五、LLM Provider 支持
### 4.1 用户价值
### 5.1 支持的 Provider
| 价值类型 | 描述 |
|---------|------|
| 便捷体验 | 一键启动/停止 |
| 统一管理 | 配置集中管理 |
| 透明度 | 进程状态可见 |
| Provider | 实现方式 | Base URL |
|----------|---------|----------|
| kimi | OpenAiDriver | `https://api.kimi.com/coding/v1` |
| qwen | OpenAiDriver | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
| deepseek | OpenAiDriver | `https://api.deepseek.com/v1` |
| zhipu | OpenAiDriver | `https://open.bigmodel.cn/api/paas/v4` |
| openai | OpenAiDriver | `https://api.openai.com/v1` |
| anthropic | AnthropicDriver | `https://api.anthropic.com` |
| gemini | GeminiDriver | `https://generativelanguage.googleapis.com` |
| local | LocalDriver | `http://localhost:11434/v1` |
### 4.2 系统价值
### 5.2 Driver 创建
| 价值类型 | 描述 |
|---------|------|
| 架构收益 | 原生系统集成 |
| 可维护性 | Rust 代码稳定 |
| 可扩展性 | 易于添加新命令 |
```rust
// crates/zclaw-kernel/src/config.rs
### 4.3 成功指标
| 指标 | 基线 | 目标 | 当前 |
|------|------|------|------|
| 启动成功率 | 80% | 99% | 98% |
| 配置解析成功率 | 90% | 99% | 99% |
| 响应时间 | - | <1s | 500ms |
impl KernelConfig {
pub fn create_driver(&self) -> Result<Arc<dyn LlmDriver>> {
let driver: Arc<dyn LlmDriver> = match self.default_provider.as_str() {
"kimi" => {
let key = self.kimi_api_key.clone()
.ok_or_else(|| ZclawError::ConfigError("KIMI_API_KEY not set".into()))?;
Arc::new(OpenAiDriver::with_base_url(
SecretString::new(key),
self.kimi_base_url.clone(),
))
}
"qwen" => {
let key = self.qwen_api_key.clone()
.ok_or_else(|| ZclawError::ConfigError("QWEN_API_KEY not set".into()))?;
Arc::new(OpenAiDriver::with_base_url(
SecretString::new(key),
self.qwen_base_url.clone(),
))
}
// ... 其他 Provider
_ => return Err(ZclawError::ConfigError(
format!("Unknown provider: {}", self.default_provider)
)),
};
Ok(driver)
}
}
```
---
## 五、实际效果
## 六、前端集成
### 5.1 已实现功能
### 6.1 KernelClient
- [x] 运行时自动发现
- [x] 启动/停止/重启
- [x] TOML 配置读写
- [x] 设备配对审批
- [x] 进程列表查看
- [x] 进程日志查看
- [x] 版本信息获取
```typescript
// desktop/src/lib/kernel-client.ts
export class KernelClient {
private config: KernelConfig = {};
setConfig(config: KernelConfig): void {
this.config = config;
}
async connect(): Promise<void> {
// 验证配置
if (!this.config.provider || !this.config.model || !this.config.apiKey) {
throw new Error('请先在"模型与 API"设置页面配置模型');
}
// 初始化 Kernel
const status = await invoke<KernelStatus>('kernel_init', {
configRequest: {
provider: this.config.provider,
model: this.config.model,
apiKey: this.config.apiKey,
baseUrl: this.config.baseUrl || null,
},
});
// 创建默认 Agent
const agents = await this.listAgents();
if (agents.length === 0) {
const agent = await this.createAgent({
name: 'Default Agent',
provider: this.config.provider,
model: this.config.model,
});
this.defaultAgentId = agent.id;
}
}
async chat(message: string, opts?: ChatOptions): Promise<ChatResponse> {
return invoke<ChatResponse>('agent_chat', {
request: {
agentId: opts?.agentId || this.defaultAgentId,
message,
},
});
}
}
```
### 6.2 ConnectionStore 集成
```typescript
// desktop/src/store/connectionStore.ts
connect: async (url?: string, token?: string) => {
const useInternalKernel = isTauriRuntime();
if (useInternalKernel) {
const kernelClient = getKernelClient();
const modelConfig = getDefaultModelConfig();
if (!modelConfig) {
throw new Error('请先在"模型与 API"设置页面添加自定义模型配置');
}
kernelClient.setConfig({
provider: modelConfig.provider,
model: modelConfig.model,
apiKey: modelConfig.apiKey,
baseUrl: modelConfig.baseUrl,
});
await kernelClient.connect();
set({ client: kernelClient, gatewayVersion: '0.2.0-internal' });
return;
}
// 非 Tauri 环境,使用外部 Gateway
// ...
}
```
---
## 七、与旧架构对比
| 特性 | 旧架构 (外部 OpenFang) | 新架构 (内部 Kernel) |
|------|----------------------|---------------------|
| 后端进程 | 独立 OpenFang 进程 | 内置 zclaw-kernel |
| 通信方式 | WebSocket/HTTP | Tauri 命令 |
| 模型配置 | TOML 文件 | UI 设置页面 |
| 启动时间 | 依赖外部进程 | 即时启动 |
| 安装包 | 需要额外运行时 | 单一安装包 |
| 进程管理 | 需要 openfang 命令 | 自动管理 |
---
## 八、实际效果
### 8.1 已实现功能
- [x] 内部 Kernel 集成
- [x] 多 LLM Provider 支持
- [x] UI 模型配置
- [x] Agent 生命周期管理
- [x] 消息发送和响应
- [x] 连接状态管理
- [x] 错误处理
### 5.2 测试覆盖
### 8.2 测试覆盖
- **单元测试**: Rust 内置测试
- **集成测试**: 包含在前端测试中
- **集成测试**: E2E 测试覆盖
- **覆盖率**: ~85%
### 5.3 已知问题
---
| 问题 | 严重程度 | 状态 | 计划解决 |
|------|---------|------|---------|
| 某些 Linux 发行版路径问题 | | 已处理 | - |
## 九、演化路线
### 5.4 用户反馈
### 9.1 短期计划1-2 周)
- [ ] 添加真正的流式响应支持
本地集成体验流畅无需关心运行时管理
### 9.2 中期计划1-2 月)
- [ ] Agent 持久化存储
- [ ] 会话历史管理
### 9.3 长期愿景
- [ ] 多 Agent 并发支持
- [ ] Agent 间通信
- [ ] 工作流引擎集成
---
## 六、演化路线
### 6.1 短期计划1-2 周)
- [ ] 添加自动更新检查
- [ ] 优化错误信息
### 6.2 中期计划1-2 月)
- [ ] 多实例管理
- [ ] 配置备份/恢复
### 6.3 长期愿景
- [ ] 远程 OpenFang 管理
- [ ] 集群部署支持
---
## 七、头脑风暴笔记
### 7.1 待讨论问题
1. 是否需要支持自定义运行时路径
2. 如何处理运行时升级
### 7.2 创意想法
- 运行时健康检查定期检测运行时状态
- 自动重启运行时崩溃后自动恢复
- 资源监控CPU/内存使用追踪
### 7.3 风险与挑战
- **技术风险**: 跨平台兼容性
- **安全风险**: 配置文件权限
- **缓解措施**: 路径验证权限检查
**最后更新**: 2026-03-22