#!/usr/bin/env node /** * Memory System Phase 3 — 集成测试 * * 测试: * 1. autoReflect: 高复杂度对话自动触发反思 * 2. consolidateMemory: 过期 short-term 合并到 long-term * 3. generateDailyReport: 日报生成 */ const http = require('http'); const fs = require('fs'); const path = require('path'); const BASE = 'http://localhost:3000'; const AGENT = 'ceo'; const AGENT_DIR = path.resolve(__dirname, '../../data/agents', AGENT); const MEMORY_DIR = path.join(AGENT_DIR, 'memory'); let passed = 0, failed = 0; function assert(condition, msg) { if (condition) { passed++; console.log(` ✅ ${msg}`); } else { failed++; console.log(` ❌ ${msg}`); } } function post(url, body) { return new Promise((resolve, reject) => { const data = JSON.stringify(body); const u = new URL(url); const req = http.request({ hostname: u.hostname, port: u.port, path: u.pathname, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } }, res => { let buf = ''; res.on('data', c => buf += c); res.on('end', () => { try { resolve(JSON.parse(buf)); } catch { resolve(buf); } }); }); req.on('error', reject); req.write(data); req.end(); }); } function sleep(ms) { return new Promise(r => setTimeout(r, ms)); } async function main() { console.log('\n🧪 Memory System Phase 3 — 集成测试\n'); console.log('═'.repeat(50)); // ── Test 1: 直接调用 autoReflect (模拟高复杂度对话) ── console.log('\n📋 Test 1: autoReflect 引擎'); const { autoReflect } = require('../../server/services/memory-service'); // 模拟一个 5-tool-call 的成功对话 const mockMeta = { status: 'completed', stats: { toolCallCount: 6, messageCount: 3 }, createdAt: new Date(Date.now() - 120000).toISOString(), updatedAt: new Date().toISOString(), title: '创建新的 Marketing Agent 并配置所有技能文件', }; const mockOutput = `创建完成!以下是步骤: 1. 创建 data/agents/marketing 目录结构 2. 编写 agent.md 和 soul.md 3. 配置 identity.md (名称: Marketing Agent) 4. 编写 SKILL.md 主技能 5. 更新 config.json 6. 验证 Agent 列表 文件已写入: - data/agents/marketing/agent.md - data/agents/marketing/soul.md - data/agents/marketing/.claude/skills/main_skill/SKILL.md Agent 已成功创建并加入系统。`; const reflection = autoReflect(AGENT, 'test-reflect-001', mockMeta, mockOutput); assert(reflection !== null, 'autoReflect 返回了结果'); assert(reflection.patterns.length >= 1, `提取了 ${reflection.patterns.length} 个模式`); assert(reflection.plan !== null, '自动固化了方案到小脑'); // 验证反思日志 const reflectDir = path.join(MEMORY_DIR, 'reflections'); const reflectFiles = fs.existsSync(reflectDir) ? fs.readdirSync(reflectDir).filter(f => f.startsWith('reflect-')) : []; assert(reflectFiles.length >= 1, `reflections/ 有 ${reflectFiles.length} 个日志文件`); // 验证 memory.md 更新 const memContent = fs.readFileSync(path.join(MEMORY_DIR, 'memory.md'), 'utf-8'); assert(!memContent.includes('已验证的模式\n(尚无记录)'), 'memory.md "已验证模式" 段有内容'); // 验证小脑方案 const cerebellumFiles = fs.readdirSync(path.join(MEMORY_DIR, 'cerebellum')); assert(cerebellumFiles.length >= 3, `cerebellum/ 有 ${cerebellumFiles.length} 个方案 (含自动固化的)`); // ── Test 2: autoReflect 对简单对话不触发 ── console.log('\n📋 Test 2: 简单对话不触发反思'); const simpleMeta = { status: 'completed', stats: { toolCallCount: 1, messageCount: 1 }, createdAt: new Date(Date.now() - 10000).toISOString(), updatedAt: new Date().toISOString(), title: '回答一个简单问题', }; const simpleResult = autoReflect(AGENT, 'test-simple', simpleMeta, '这是一个简单回答'); assert(simpleResult === null, '简单对话 (1 tool, 10s) 不触发反思'); // ── Test 3: autoReflect 对失败对话提取教训 ── console.log('\n📋 Test 3: 失败对话提取教训'); const failMeta = { status: 'failed', stats: { toolCallCount: 3, messageCount: 2 }, createdAt: new Date(Date.now() - 90000).toISOString(), updatedAt: new Date().toISOString(), title: '部署服务到生产环境', }; const failOutput = 'error: Connection refused to database. Error: ECONNREFUSED 127.0.0.1:5432'; const failReflect = autoReflect(AGENT, 'test-fail', failMeta, failOutput); assert(failReflect !== null, '失败对话触发了反思'); assert(failReflect.lessons.length >= 1, `提取了 ${failReflect.lessons.length} 个教训`); // ── Test 4: consolidateMemory ── console.log('\n📋 Test 4: 记忆合并'); // 创建一些"过期"的 short-term 文件 (时间戳 = 8天前) const shortDir = path.join(MEMORY_DIR, 'short-term'); const eightDaysAgo = Date.now() - 8 * 24 * 60 * 60 * 1000; for (let i = 0; i < 3; i++) { const ts = eightDaysAgo + i * 1000; fs.writeFileSync(path.join(shortDir, `session-${ts}.md`), `# Session 摘要\n\n- **时间**: 2026-03-17 10:${i}0:00\n\n## 任务\n测试任务${i}\n\n## 结果\n测试结果${i}\n`, 'utf-8'); } const consolidateResult = await post(`${BASE}/api/agent/${AGENT}/memory/consolidate`, {}); assert(consolidateResult.merged === 3, `合并了 ${consolidateResult.merged} 个过期 session (期望 3)`); // 验证 long-term 目录有文件 const longTermDir = path.join(MEMORY_DIR, 'long-term'); const ltFiles = fs.existsSync(longTermDir) ? fs.readdirSync(longTermDir).filter(f => f.startsWith('consolidate-')) : []; assert(ltFiles.length >= 1, `long-term/ 有 ${ltFiles.length} 个合并记录`); // 验证过期文件已删除 const remainingShort = fs.readdirSync(shortDir).filter(f => { const ts = parseInt(f.replace('session-', '').replace('.md', '')); return !isNaN(ts) && ts < eightDaysAgo + 5000; }); assert(remainingShort.length === 0, '过期的 short-term 文件已删除'); // ── Test 5: generateDailyReport ── console.log('\n📋 Test 5: 日报生成'); const reportResult = await post(`${BASE}/api/agent/${AGENT}/memory/daily-report`, {}); assert(reportResult.success, '日报生成成功'); const today = new Date().toISOString().substring(0, 10); const dailyFile = path.join(MEMORY_DIR, 'daily', `${today}.md`); assert(fs.existsSync(dailyFile), `daily/${today}.md 文件存在`); if (fs.existsSync(dailyFile)) { const dailyContent = fs.readFileSync(dailyFile, 'utf-8'); assert(dailyContent.includes('# 日报'), '日报包含标题'); assert(dailyContent.includes('对话数'), '日报包含统计'); } // ── 结果 ── console.log('\n' + '═'.repeat(50)); console.log(`\n🏁 测试结果: ${passed} 通过, ${failed} 失败\n`); if (failed > 0) process.exit(1); } main().catch(err => { console.error('❌ 测试崩溃:', err); process.exit(1); });