Files
zclaw_openfang/plans/abstract-finding-forest-agent-a5bc2d4e73e72fb27.md
iven ce562e8bfc feat: complete Phase 1-3 architecture optimization
Phase 1 - Security:
- Add AES-GCM encryption for localStorage fallback
- Enforce WSS protocol for non-localhost WebSocket connections
- Add URL sanitization to prevent XSS in markdown links

Phase 2 - Domain Reorganization:
- Create Intelligence Domain with Valtio store and caching
- Add unified intelligence-client for Rust backend integration
- Migrate from legacy agent-memory, heartbeat, reflection modules

Phase 3 - Core Optimization:
- Add virtual scrolling for ChatArea with react-window
- Implement LRU cache with TTL for intelligence operations
- Add message virtualization utilities

Additional:
- Add OpenFang compatibility test suite
- Update E2E test fixtures
- Add audit logging infrastructure
- Update project documentation and plans

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 22:11:50 +08:00

367 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ZCLAW 智能层统一实现方案
## 概述
本方案旨在消除前后端智能层代码重复,统一使用 Rust 后端 + TypeScript 适配器 (`intelligence-backend.ts`)。
## 现状分析
### 已有的 Rust 后端命令(通过 `intelligence-backend.ts` 封装)
| 模块 | 命令 | 状态 |
|------|------|------|
| Memory | memory_init, memory_store, memory_get, memory_search, memory_delete, memory_delete_all, memory_stats, memory_export, memory_import, memory_db_path | 完整 |
| Heartbeat | heartbeat_init, heartbeat_start, heartbeat_stop, heartbeat_tick, heartbeat_get_config, heartbeat_update_config, heartbeat_get_history | 完整 |
| Compactor | compactor_estimate_tokens, compactor_estimate_messages_tokens, compactor_check_threshold, compactor_compact | 完整 |
| Reflection | reflection_init, reflection_record_conversation, reflection_should_reflect, reflection_reflect, reflection_get_history, reflection_get_state | 完整 |
| Identity | identity_get, identity_get_file, identity_build_prompt, identity_update_user_profile, identity_append_user_profile, identity_propose_change, identity_approve_proposal, identity_reject_proposal, identity_get_pending_proposals, identity_update_file, identity_get_snapshots, identity_restore_snapshot, identity_list_agents, identity_delete_agent | 完整 |
### 需要迁移的前端 TS 实现
| 文件 | 代码行数 | 引用位置 |
|------|----------|----------|
| `agent-memory.ts` | ~487行 | chatStore, memoryGraphStore, MemoryPanel, memory-extractor, agent-swarm, skill-discovery |
| `agent-identity.ts` | ~351行 | chatStore, reflection-engine, memory-extractor, ReflectionLog |
| `reflection-engine.ts` | ~678行 | chatStore, ReflectionLog |
| `heartbeat-engine.ts` | ~347行 | HeartbeatConfig |
| `context-compactor.ts` | ~443行 | chatStore |
### 类型差异分析
前端 TS 和 Rust 后端的类型有细微差异,需要创建适配层:
```
前端 MemoryEntry.importance: number (0-10)
后端 PersistentMemory.importance: number (相同)
前端 MemoryEntry.type: MemoryType ('fact' | 'preference' | ...)
后端 PersistentMemory.memory_type: string
前端 MemoryEntry.tags: string[]
后端 PersistentMemory.tags: string (JSON 序列化)
```
---
## 实施计划
### Phase 0: 准备工作(环境检测 + 降级策略)
**目标**: 创建环境检测机制,支持 Tauri/浏览器双环境
**修改文件**:
- 新建 `desktop/src/lib/intelligence-client.ts`
**实现内容**:
```typescript
// intelligence-client.ts
import { intelligence } from './intelligence-backend';
// 检测是否在 Tauri 环境中
const isTauriEnv = typeof window !== 'undefined' && '__TAURI__' in window;
// 降级策略:非 Tauri 环境使用 localStorage 模拟
const fallbackMemory = {
store: async (entry) => { /* localStorage 模拟 */ },
search: async (options) => { /* localStorage 模拟 */ },
// ... 其他方法
};
export const intelligenceClient = {
memory: isTauriEnv ? intelligence.memory : fallbackMemory,
heartbeat: isTauriEnv ? intelligence.heartbeat : fallbackHeartbeat,
compactor: isTauriEnv ? intelligence.compactor : fallbackCompactor,
reflection: isTauriEnv ? intelligence.reflection : fallbackReflection,
identity: isTauriEnv ? intelligence.identity : fallbackIdentity,
};
```
**验证方法**:
- 在 Tauri 桌面端启动,确认 `isTauriEnv === true`
- 在浏览器中访问 Vite dev server确认降级逻辑生效
---
### Phase 1: 迁移 Memory 模块(最关键)
**优先级**: 最高(其他模块都依赖 Memory
**修改文件**:
| 文件 | 修改内容 |
|------|----------|
| `chatStore.ts` | 将 `getMemoryManager()` 替换为 `intelligenceClient.memory` |
| `memoryGraphStore.ts` | 将 `getMemoryManager()` 替换为 `intelligenceClient.memory` |
| `MemoryPanel.tsx` | 将 `getMemoryManager()` 替换为 `intelligenceClient.memory` |
| `memory-extractor.ts` | 将 `getMemoryManager()` 替换为 `intelligenceClient.memory` |
| `agent-swarm.ts` | 将 `getMemoryManager()` 替换为 `intelligenceClient.memory` |
| `skill-discovery.ts` | 将 `getMemoryManager()` 替换为 `intelligenceClient.memory` |
**详细修改示例** (chatStore.ts):
```typescript
// 修改前
import { getMemoryManager } from '../lib/agent-memory';
// 在 sendMessage 中
const memoryMgr = getMemoryManager();
const relevantMemories = await memoryMgr.search(content, {
agentId,
limit: 8,
minImportance: 3,
});
// 修改后
import { intelligenceClient } from '../lib/intelligence-client';
// 在 sendMessage 中
const relevantMemories = await intelligenceClient.memory.search({
agent_id: agentId,
query: content,
limit: 8,
min_importance: 3,
});
```
**类型适配**:
```typescript
// 创建类型转换函数
function toFrontendMemory(backend: PersistentMemory): MemoryEntry {
return {
id: backend.id,
agentId: backend.agent_id,
content: backend.content,
type: backend.memory_type as MemoryType,
importance: backend.importance,
source: backend.source as MemorySource,
tags: JSON.parse(backend.tags || '[]'),
createdAt: backend.created_at,
lastAccessedAt: backend.last_accessed_at,
accessCount: backend.access_count,
conversationId: backend.conversation_id || undefined,
};
}
function toBackendMemoryInput(frontend: Omit<MemoryEntry, 'id' | 'createdAt' | 'lastAccessedAt' | 'accessCount'>): MemoryEntryInput {
return {
agent_id: frontend.agentId,
memory_type: frontend.type,
content: frontend.content,
importance: frontend.importance,
source: frontend.source,
tags: frontend.tags,
conversation_id: frontend.conversationId,
};
}
```
**验证方法**:
1. 启动桌面端,发送消息
2. 检查记忆是否正确存储到 SQLite
3. 搜索记忆是否返回正确结果
4. MemoryPanel 组件是否正确显示记忆列表
**回滚方案**:
- 保留 `agent-memory.ts` 文件
- 通过 feature flag 切换新旧实现
---
### Phase 2: 迁移 Compactor 模块
**优先级**: 高(依赖 Memory但影响范围较小
**修改文件**:
| 文件 | 修改内容 |
|------|----------|
| `chatStore.ts` | 将 `getContextCompactor()` 替换为 `intelligenceClient.compactor` |
**详细修改**:
```typescript
// 修改前
import { getContextCompactor } from '../lib/context-compactor';
const compactor = getContextCompactor();
const check = compactor.checkThreshold(messages);
// 修改后
import { intelligenceClient } from '../lib/intelligence-client';
const check = await intelligenceClient.compactor.checkThreshold(
messages.map(m => ({ role: m.role, content: m.content }))
);
```
**验证方法**:
1. 发送大量消息触发 compaction 阈值
2. 检查是否正确压缩上下文
3. 验证压缩后消息正常显示
---
### Phase 3: 迁移 Reflection + Identity 模块
**优先级**: 中(关联紧密,需要一起迁移)
**修改文件**:
| 文件 | 修改内容 |
|------|----------|
| `chatStore.ts` | 将 `getReflectionEngine()` 替换为 `intelligenceClient.reflection` |
| `ReflectionLog.tsx` | 将 `ReflectionEngine``getAgentIdentityManager()` 替换为 intelligenceClient |
| `memory-extractor.ts` | 将 `getAgentIdentityManager()` 替换为 `intelligenceClient.identity` |
**详细修改**:
```typescript
// 修改前 (chatStore.ts)
import { getReflectionEngine } from '../lib/reflection-engine';
const reflectionEngine = getReflectionEngine();
reflectionEngine.recordConversation();
if (reflectionEngine.shouldReflect()) {
reflectionEngine.reflect(agentId);
}
// 修改后
import { intelligenceClient } from '../lib/intelligence-client';
await intelligenceClient.reflection.recordConversation();
if (await intelligenceClient.reflection.shouldReflect()) {
const memories = await intelligenceClient.memory.search({ agent_id: agentId, limit: 100 });
await intelligenceClient.reflection.reflect(agentId, memories.map(m => ({
memory_type: m.memory_type,
content: m.content,
importance: m.importance,
access_count: m.access_count,
tags: JSON.parse(m.tags || '[]'),
})));
}
```
**验证方法**:
1. 完成多轮对话后检查 reflection 是否触发
2. 检查 ReflectionLog 组件是否正确显示反思历史
3. 验证身份变更提案的审批流程
---
### Phase 4: 迁移 Heartbeat 模块
**优先级**: 低(独立模块,无依赖)
**修改文件**:
| 文件 | 修改内容 |
|------|----------|
| `HeartbeatConfig.tsx` | 将 `HeartbeatEngine` 替换为 `intelligenceClient.heartbeat` |
| `SettingsLayout.tsx` | 如有引用,同样替换 |
**详细修改**:
```typescript
// 修改前
import { HeartbeatEngine, DEFAULT_HEARTBEAT_CONFIG } from '../lib/heartbeat-engine';
const engine = new HeartbeatEngine(agentId, config);
engine.start();
// 修改后
import { intelligenceClient } from '../lib/intelligence-client';
import type { HeartbeatConfig } from '../lib/intelligence-backend';
await intelligenceClient.heartbeat.init(agentId, config);
await intelligenceClient.heartbeat.start(agentId);
```
**验证方法**:
1. 在 HeartbeatConfig 面板中启用心跳
2. 等待心跳触发,检查是否生成 alert
3. 验证配置更新是否正确持久化
---
### Phase 5: 清理遗留代码
**优先级**: 最低(在所有迁移验证完成后)
**删除文件**:
- `desktop/src/lib/agent-memory.ts`
- `desktop/src/lib/agent-identity.ts`
- `desktop/src/lib/reflection-engine.ts`
- `desktop/src/lib/heartbeat-engine.ts`
- `desktop/src/lib/context-compactor.ts`
- `desktop/src/lib/memory-index.ts` (agent-memory 的依赖)
**更新文档**:
- 更新 `CLAUDE.md` 中的架构说明
- 更新相关组件的注释
---
## 风险与缓解措施
| 风险 | 缓解措施 |
|------|----------|
| Tauri invoke 失败 | 实现完整的降级策略fallback 到 localStorage |
| 类型不匹配 | 创建类型转换层,隔离前后端类型差异 |
| 性能差异 | Rust 后端应该更快,但需要测试 SQLite 查询性能 |
| 数据迁移 | 提供 localStorage -> SQLite 迁移工具 |
| 回滚困难 | 使用 feature flag可快速切换回旧实现 |
---
## 测试检查清单
### 每个阶段必须验证
- [ ] TypeScript 编译通过 (`pnpm tsc --noEmit`)
- [ ] 相关单元测试通过 (`pnpm vitest run`)
- [ ] 桌面端启动正常
- [ ] 聊天功能正常
- [ ] 记忆存储/搜索正常
- [ ] 无控制台错误
### Phase 1 额外验证
- [ ] MemoryPanel 正确显示记忆列表
- [ ] 记忆图谱正确渲染
- [ ] skill-discovery 推荐功能正常
### Phase 3 额外验证
- [ ] ReflectionLog 正确显示反思历史
- [ ] 身份变更提案审批流程正常
- [ ] USER.md 自动更新正常
---
## 时间估算
| 阶段 | 预计时间 | 累计 |
|------|----------|------|
| Phase 0 | 2h | 2h |
| Phase 1 | 4h | 6h |
| Phase 2 | 1h | 7h |
| Phase 3 | 3h | 10h |
| Phase 4 | 1h | 11h |
| Phase 5 | 1h | 12h |
| 测试与修复 | 3h | 15h |
**总计**: 约 2 个工作日
---
## 执行顺序建议
1. **先完成 Phase 0** - 这是所有后续工作的基础
2. **然后 Phase 1** - Memory 是核心依赖
3. **接着 Phase 2** - Compactor 依赖 Memory
4. **然后 Phase 3** - Reflection + Identity 关联紧密
5. **然后 Phase 4** - Heartbeat 独立,可最后处理
6. **最后 Phase 5** - 确认一切正常后再删除旧代码
每个阶段完成后都应该进行完整的功能验证,确保没有引入 bug。