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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user