Files
zclaw_openfang/plans/nifty-inventing-valiant.md
iven aa6a9cbd84
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
feat: 新增技能编排引擎和工作流构建器组件
refactor: 统一Hands系统常量到单个源文件
refactor: 更新Hands中文名称和描述

fix: 修复技能市场在连接状态变化时重新加载
fix: 修复身份变更提案的错误处理逻辑

docs: 更新多个功能文档的验证状态和实现位置
docs: 更新Hands系统文档

test: 添加测试文件验证工作区路径
2026-03-25 08:27:25 +08:00

12 KiB
Raw Permalink Blame History

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

问题: 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_taskscheck_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分钟

文件: intelligence-backend.ts

问题: 前端使用 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 存储大小计算

文件: intelligence-client.ts

// 在 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

人工验证清单

  • 应用启动无错误
  • 心跳引擎正常初始化
  • 记忆统计同步正常(启动 + 周期)
  • 提案审批流程正常
  • 错误信息清晰可读

深度复验报告 (2026-03-24)

前端修复验证

修复项 文件 状态 说明
Fix 1.1 intelligence-client.ts 已正确实现 updateMemoryStatsrecordCorrection 使用 snake_case
Fix 1.2 App.tsx 已正确实现 5分钟周期同步 + 清理逻辑完整
Fix 2.1 intelligence-backend.ts 已正确实现 MemoryStats 使用 total_entries
Fix 2.1 intelligence-client.ts 已正确实现 toFrontendStats 正确映射字段
Fix 2.2 IdentityChangeProposal.tsx 已正确实现 parseProposalError 函数 + 3处调用
Fix 3.1 intelligence-client.ts 已正确实现 fallbackMemory.stats() 计算 storageSizeBytes

前端修复验证结果: 全部 6/6 通过

后端修复验证

修复项 文件 状态 说明
Fix 1.3 heartbeat.rs:451-480 已正确实现 check_pending_tasks 缓存为空时返回告警
Fix 1.3 heartbeat.rs:484-521 ⚠️ 设计偏差 check_memory_health 缓存为空时返回 None避免重复告警
Fix 2.3 heartbeat.rs:347 已正确实现 LAST_INTERACTION 静态变量
Fix 2.3 heartbeat.rs:366-368 已正确实现 get_last_interaction_map() 函数
Fix 2.3 heartbeat.rs:371-376 已正确实现 record_interaction() 函数
Fix 2.3 heartbeat.rs:524-559 已正确实现 check_idle_greeting 完整实现24小时阈值
Fix 2.3 heartbeat.rs:736-741 已正确实现 heartbeat_record_interaction Tauri 命令
命令注册 lib.rs:1432 已正确注册 heartbeat_record_interaction 已注册

后端修复验证结果: 7/8 完全通过1/8 设计偏差(合理)

设计偏差说明

check_memory_health 缓存为空时返回 None

原计划要求:返回告警 实际实现:返回 None

设计理由(代码注释):

Cache is empty - skip check (already reported in check_pending_tasks)

评估: 这是合理的设计决策,避免在缓存为空时产生重复告警。check_pending_tasks 已经报告了缓存未同步的问题,check_memory_health 无需再次告警。

复验结论

类别 结果
前端修复 6/6 通过
后端修复 7/8 通过
设计偏差 1 ⚠️ 合理(不视为问题)
总体评估 全部修复已正确实现

编译验证:

  • TypeScript 类型检查: 通过
  • Rust 编译: 通过(仅有预先存在的警告)