## 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>
9.0 KiB
9.0 KiB
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分钟
问题: updateMemoryStats 使用 camelCase 参数,但 Rust 后端期望 snake_case
修改位置: 第 989-1011 行
// 修改前
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
问题: 记忆统计仅在启动时同步一次,之后数据可能陈旧
修改位置: 第 213 行后(heartbeat.start 之后)
// 添加周期性同步(每 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
问题: 当缓存为空时,检查函数直接跳过,无告警
修改: 在 check_pending_tasks 和 check_memory_health 中添加缓存缺失告警
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分钟
问题: 前端使用 totalEntries,后端返回 total_memories
修改: 更新接口定义以匹配后端
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 中的转换函数
Fix 2.2: 增强提案审批错误处理 ⚡ 10分钟
文件: IdentityChangeProposal.tsx
添加错误解析函数:
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
添加最后交互时间追踪:
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 命令:
#[tauri::command]
pub async fn heartbeat_record_interaction(agent_id: String) -> Result<(), String>
Phase 3: 修复 LOW 优先级问题(可选)
Fix 3.1: localStorage fallback 存储大小计算
// 在 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 | API 参数命名、类型转换、存储大小计算 |
| App.tsx | 周期性记忆统计同步 |
| heartbeat.rs | 缓存容错、空闲问候 |
| intelligence-backend.ts | 类型定义统一 |
| IdentityChangeProposal.tsx | 错误处理增强 |
| lib.rs | 注册新 Tauri 命令(如实现 Fix 2.3) |
验证方法
Fix 1.1 验证
# 启动应用,检查控制台
pnpm start:dev
# 观察 Tauri invoke 调用参数是否正确
Fix 1.2 验证
# 启动后等待 5 分钟,检查控制台
# 应看到 "[App] Memory stats synced (periodic)" 日志
Fix 1.3 验证
# 清除缓存后触发心跳
# 应看到 "记忆统计未同步" 告警
全量验证
# TypeScript 类型检查
pnpm tsc --noEmit
# 运行测试
pnpm vitest run
# 启动开发环境
pnpm start:dev
人工验证清单
- 应用启动无错误
- 心跳引擎正常初始化
- 记忆统计同步正常(启动 + 周期)
- 提案审批流程正常
- 错误信息清晰可读