## 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>
304 lines
9.0 KiB
Markdown
304 lines
9.0 KiB
Markdown
# ZCLAW 自我进化系统审查与修复计划
|
||
|
||
## 背景
|
||
|
||
自我进化系统是 ZCLAW 的核心能力,包括四个组件:
|
||
- **心跳引擎** - 定期主动检查
|
||
- **反思引擎** - 分析模式并生成改进建议
|
||
- **身份管理** - 管理人格文件和变更提案
|
||
- **记忆存储** - 持久化对话和经验
|
||
|
||
---
|
||
|
||
## 审查结果摘要
|
||
|
||
### 实现状态
|
||
|
||
| 组件 | 函数/功能 | 状态 |
|
||
|------|----------|------|
|
||
| **心跳引擎** | check_pending_tasks | ✅ 完整 |
|
||
| | check_memory_health | ✅ 完整 |
|
||
| | check_correction_patterns | ✅ 完整 |
|
||
| | check_learning_opportunities | ✅ 完整 |
|
||
| | check_idle_greeting | ⚠️ 占位符 |
|
||
| **反思引擎** | analyze_patterns | ✅ 完整 |
|
||
| | generate_improvements | ✅ 完整 |
|
||
| | propose_identity_changes | ✅ 完整 |
|
||
| **身份管理** | 提案处理 | ✅ 完整 |
|
||
| | 持久化 | ✅ 完整 |
|
||
| **前端** | Intelligence Client | ✅ 完整 |
|
||
| | IdentityChangeProposal UI | ✅ 完整 |
|
||
| | 提案通知系统 | ✅ 存在 |
|
||
|
||
### 发现的问题
|
||
|
||
| 优先级 | 问题 | 影响 |
|
||
|--------|------|------|
|
||
| HIGH | MemoryStatsCache 同步问题 | 心跳检查依赖前端主动更新,可能跳过检查 |
|
||
| HIGH | API 命名不一致 | `updateMemoryStats` 参数名不匹配(camelCase vs snake_case) |
|
||
| MEDIUM | check_idle_greeting 占位符 | 空闲问候功能不可用 |
|
||
| MEDIUM | 类型定义不一致 | `totalEntries` vs `total_memories` 命名不统一 |
|
||
| MEDIUM | 提案审批错误处理 | 缺少详细的错误反馈 |
|
||
| LOW | storageSizeBytes fallback 为 0 | localStorage 模式下无法计算 |
|
||
| LOW | 硬编码配置值 | 历史限制、快照数量不可配置 |
|
||
|
||
---
|
||
|
||
## 修复计划
|
||
|
||
### Phase 1: 修复 HIGH 优先级问题
|
||
|
||
#### Fix 1.1: API 参数命名修正 ⚡ 5分钟
|
||
|
||
**文件**: [intelligence-client.ts](desktop/src/lib/intelligence-client.ts)
|
||
|
||
**问题**: `updateMemoryStats` 使用 camelCase 参数,但 Rust 后端期望 snake_case
|
||
|
||
**修改位置**: 第 989-1011 行
|
||
|
||
```typescript
|
||
// 修改前
|
||
await invoke('heartbeat_update_memory_stats', {
|
||
agentId,
|
||
taskCount,
|
||
totalEntries,
|
||
storageSizeBytes,
|
||
});
|
||
|
||
// 修改后
|
||
await invoke('heartbeat_update_memory_stats', {
|
||
agent_id: agentId,
|
||
task_count: taskCount,
|
||
total_entries: totalEntries,
|
||
storage_size_bytes: storageSizeBytes,
|
||
});
|
||
```
|
||
|
||
#### Fix 1.2: 添加周期性记忆统计同步 ⚡ 15分钟
|
||
|
||
**文件**: [App.tsx](desktop/src/App.tsx)
|
||
|
||
**问题**: 记忆统计仅在启动时同步一次,之后数据可能陈旧
|
||
|
||
**修改位置**: 第 213 行后(heartbeat.start 之后)
|
||
|
||
```typescript
|
||
// 添加周期性同步(每 5 分钟)
|
||
const MEMORY_STATS_SYNC_INTERVAL = 5 * 60 * 1000;
|
||
const statsSyncInterval = setInterval(async () => {
|
||
try {
|
||
const stats = await intelligenceClient.memory.stats();
|
||
const taskCount = stats.byType?.['task'] || 0;
|
||
await intelligenceClient.heartbeat.updateMemoryStats(
|
||
defaultAgentId,
|
||
taskCount,
|
||
stats.totalEntries,
|
||
stats.storageSizeBytes
|
||
);
|
||
console.log('[App] Memory stats synced (periodic)');
|
||
} catch (err) {
|
||
console.warn('[App] Periodic memory stats sync failed:', err);
|
||
}
|
||
}, MEMORY_STATS_SYNC_INTERVAL);
|
||
```
|
||
|
||
#### Fix 1.3: 心跳检查容错处理 ⚡ 20分钟
|
||
|
||
**文件**: [heartbeat.rs](desktop/src-tauri/src/intelligence/heartbeat.rs)
|
||
|
||
**问题**: 当缓存为空时,检查函数直接跳过,无告警
|
||
|
||
**修改**: 在 `check_pending_tasks` 和 `check_memory_health` 中添加缓存缺失告警
|
||
|
||
```rust
|
||
fn check_pending_tasks(agent_id: &str) -> Option<HeartbeatAlert> {
|
||
match get_cached_memory_stats(agent_id) {
|
||
Some(stats) if stats.task_count >= 5 => { /* 现有逻辑 */ },
|
||
Some(_) => None,
|
||
None => Some(HeartbeatAlert {
|
||
title: "记忆统计未同步".to_string(),
|
||
content: "心跳引擎未能获取记忆统计信息,部分检查被跳过".to_string(),
|
||
urgency: Urgency::Low,
|
||
source: "pending-tasks".to_string(),
|
||
timestamp: chrono::Utc::now().to_rfc3339(),
|
||
}),
|
||
}
|
||
}
|
||
```
|
||
|
||
### Phase 2: 修复 MEDIUM 优先级问题
|
||
|
||
#### Fix 2.1: 统一类型定义命名 ⚡ 10分钟
|
||
|
||
**文件**: [intelligence-backend.ts](desktop/src/lib/intelligence-backend.ts)
|
||
|
||
**问题**: 前端使用 `totalEntries`,后端返回 `total_memories`
|
||
|
||
**修改**: 更新接口定义以匹配后端
|
||
|
||
```typescript
|
||
export interface MemoryStats {
|
||
total_entries: number; // 匹配后端
|
||
by_type: Record<string, number>;
|
||
by_agent: Record<string, number>;
|
||
oldest_entry: string | null;
|
||
newest_entry: string | null;
|
||
storage_size_bytes: number;
|
||
}
|
||
```
|
||
|
||
**同时更新** [intelligence-client.ts](desktop/src/lib/intelligence-client.ts) 中的转换函数
|
||
|
||
#### Fix 2.2: 增强提案审批错误处理 ⚡ 10分钟
|
||
|
||
**文件**: [IdentityChangeProposal.tsx](desktop/src/components/IdentityChangeProposal.tsx)
|
||
|
||
**添加错误解析函数**:
|
||
|
||
```typescript
|
||
function parseProposalError(err: unknown, operation: 'approval' | 'rejection' | 'restore'): string {
|
||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||
|
||
if (errorMessage.includes('not found')) {
|
||
return `提案不存在或已被处理`;
|
||
}
|
||
if (errorMessage.includes('not pending')) {
|
||
return '该提案已被处理,请刷新页面';
|
||
}
|
||
if (errorMessage.includes('network') || errorMessage.includes('fetch')) {
|
||
return '网络连接失败,请检查网络后重试';
|
||
}
|
||
|
||
return `${operation === 'approval' ? '审批' : operation === 'rejection' ? '拒绝' : '恢复'}失败: ${errorMessage}`;
|
||
}
|
||
```
|
||
|
||
#### Fix 2.3: 实现 check_idle_greeting(可选)⚡ 30分钟
|
||
|
||
**文件**: [heartbeat.rs](desktop/src-tauri/src/intelligence/heartbeat.rs)
|
||
|
||
**添加最后交互时间追踪**:
|
||
|
||
```rust
|
||
static LAST_INTERACTION: OnceLock<RwLock<StdHashMap<String, String>>> = OnceLock::new();
|
||
|
||
pub fn record_interaction(agent_id: &str) {
|
||
let map = get_last_interaction_map();
|
||
if let Ok(mut map) = map.write() {
|
||
map.insert(agent_id.to_string(), chrono::Utc::now().to_rfc3339());
|
||
}
|
||
}
|
||
|
||
fn check_idle_greeting(agent_id: &str) -> Option<HeartbeatAlert> {
|
||
let map = get_last_interaction_map();
|
||
let last_interaction = map.read().ok()?.get(agent_id).cloned()?;
|
||
|
||
let last_time = chrono::DateTime::parse_from_rfc3339(&last_interaction).ok()?;
|
||
let idle_hours = (chrono::Utc::now() - last_time).num_hours();
|
||
|
||
if idle_hours >= 24 {
|
||
Some(HeartbeatAlert {
|
||
title: "用户长时间未互动".to_string(),
|
||
content: format!("距离上次互动已过去 {} 小时", idle_hours),
|
||
urgency: Urgency::Low,
|
||
source: "idle-greeting".to_string(),
|
||
timestamp: chrono::Utc::now().to_rfc3339(),
|
||
})
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
```
|
||
|
||
**同时添加 Tauri 命令**:
|
||
```rust
|
||
#[tauri::command]
|
||
pub async fn heartbeat_record_interaction(agent_id: String) -> Result<(), String>
|
||
```
|
||
|
||
### Phase 3: 修复 LOW 优先级问题(可选)
|
||
|
||
#### Fix 3.1: localStorage fallback 存储大小计算
|
||
|
||
**文件**: [intelligence-client.ts](desktop/src/lib/intelligence-client.ts)
|
||
|
||
```typescript
|
||
// 在 fallbackMemory.stats() 中添加
|
||
let storageSizeBytes = 0;
|
||
try {
|
||
const serialized = JSON.stringify(store.memories);
|
||
storageSizeBytes = new Blob([serialized]).size;
|
||
} catch { /* ignore */ }
|
||
```
|
||
|
||
---
|
||
|
||
## 实现顺序
|
||
|
||
| 顺序 | 修复项 | 优先级 | 预估时间 |
|
||
|------|--------|--------|----------|
|
||
| 1 | Fix 1.1 - API 参数命名 | HIGH | 5 分钟 |
|
||
| 2 | Fix 1.2 - 周期性同步 | HIGH | 15 分钟 |
|
||
| 3 | Fix 1.3 - 心跳容错 | HIGH | 20 分钟 |
|
||
| 4 | Fix 2.1 - 类型统一 | MEDIUM | 10 分钟 |
|
||
| 5 | Fix 2.2 - 错误处理 | MEDIUM | 10 分钟 |
|
||
| 6 | Fix 2.3 - 空闲问候 | MEDIUM | 30 分钟 |
|
||
| 7 | Fix 3.1 - 存储大小 | LOW | 5 分钟 |
|
||
|
||
**总计**: 约 1.5 小时(不含可选项)
|
||
|
||
---
|
||
|
||
## 关键文件
|
||
|
||
| 文件 | 修改内容 |
|
||
|------|----------|
|
||
| [intelligence-client.ts](desktop/src/lib/intelligence-client.ts) | API 参数命名、类型转换、存储大小计算 |
|
||
| [App.tsx](desktop/src/App.tsx) | 周期性记忆统计同步 |
|
||
| [heartbeat.rs](desktop/src-tauri/src/intelligence/heartbeat.rs) | 缓存容错、空闲问候 |
|
||
| [intelligence-backend.ts](desktop/src/lib/intelligence-backend.ts) | 类型定义统一 |
|
||
| [IdentityChangeProposal.tsx](desktop/src/components/IdentityChangeProposal.tsx) | 错误处理增强 |
|
||
| [lib.rs](desktop/src-tauri/src/lib.rs) | 注册新 Tauri 命令(如实现 Fix 2.3) |
|
||
|
||
---
|
||
|
||
## 验证方法
|
||
|
||
### Fix 1.1 验证
|
||
```bash
|
||
# 启动应用,检查控制台
|
||
pnpm start:dev
|
||
# 观察 Tauri invoke 调用参数是否正确
|
||
```
|
||
|
||
### Fix 1.2 验证
|
||
```bash
|
||
# 启动后等待 5 分钟,检查控制台
|
||
# 应看到 "[App] Memory stats synced (periodic)" 日志
|
||
```
|
||
|
||
### Fix 1.3 验证
|
||
```bash
|
||
# 清除缓存后触发心跳
|
||
# 应看到 "记忆统计未同步" 告警
|
||
```
|
||
|
||
### 全量验证
|
||
```bash
|
||
# TypeScript 类型检查
|
||
pnpm tsc --noEmit
|
||
|
||
# 运行测试
|
||
pnpm vitest run
|
||
|
||
# 启动开发环境
|
||
pnpm start:dev
|
||
```
|
||
|
||
### 人工验证清单
|
||
- [ ] 应用启动无错误
|
||
- [ ] 心跳引擎正常初始化
|
||
- [ ] 记忆统计同步正常(启动 + 周期)
|
||
- [ ] 提案审批流程正常
|
||
- [ ] 错误信息清晰可读
|