0878535cb8
主要变更: - Capability Evolver 技能大幅升级 - 新增 LLM 审查、叙事记忆、反思机制模块 - 改进 Agent 间通信协议和技能搜索 - 整合 Git 备份到 evolver-run.sh - Agent 配置与日志更新 - dev-assist/haonan/main 认证和会话配置 - 5 个 agent 的 AGENTS.md 文档更新 - haonan 的 MEMORY.md 和 SOUL.md 更新 - 新增功能目录 - hooks/self-improvement 自我改进钩子 - memory/evolution 进化记忆状态 - workspace/.learnings/ 学习记录 - 清理 - 删除 scripts/git-auto-sync.sh(已整合到 evolver) - 删除旧的 _meta.json 配置 - 忽略临时工作空间目录
128 lines
4.2 KiB
JavaScript
128 lines
4.2 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { getReflectionLogPath, getEvolutionDir } = require('./paths');
|
|
|
|
const REFLECTION_INTERVAL_CYCLES = 5;
|
|
const REFLECTION_COOLDOWN_MS = 30 * 60 * 1000;
|
|
|
|
function ensureDir(dir) {
|
|
try { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); } catch (_) {}
|
|
}
|
|
|
|
function shouldReflect({ cycleCount, recentEvents }) {
|
|
if (!Number.isFinite(cycleCount) || cycleCount < REFLECTION_INTERVAL_CYCLES) return false;
|
|
if (cycleCount % REFLECTION_INTERVAL_CYCLES !== 0) return false;
|
|
|
|
const logPath = getReflectionLogPath();
|
|
try {
|
|
if (fs.existsSync(logPath)) {
|
|
const stat = fs.statSync(logPath);
|
|
if (Date.now() - stat.mtimeMs < REFLECTION_COOLDOWN_MS) return false;
|
|
}
|
|
} catch (_) {}
|
|
|
|
return true;
|
|
}
|
|
|
|
function buildReflectionContext({ recentEvents, signals, memoryAdvice, narrative }) {
|
|
const parts = ['You are performing a strategic reflection on recent evolution cycles.'];
|
|
parts.push('Analyze the patterns below and provide concise strategic guidance.');
|
|
parts.push('');
|
|
|
|
if (Array.isArray(recentEvents) && recentEvents.length > 0) {
|
|
const last10 = recentEvents.slice(-10);
|
|
const successCount = last10.filter(e => e && e.outcome && e.outcome.status === 'success').length;
|
|
const failCount = last10.filter(e => e && e.outcome && e.outcome.status === 'failed').length;
|
|
const intents = {};
|
|
last10.forEach(e => {
|
|
const i = e && e.intent ? e.intent : 'unknown';
|
|
intents[i] = (intents[i] || 0) + 1;
|
|
});
|
|
const genes = {};
|
|
last10.forEach(e => {
|
|
const g = e && Array.isArray(e.genes_used) && e.genes_used[0] ? e.genes_used[0] : 'unknown';
|
|
genes[g] = (genes[g] || 0) + 1;
|
|
});
|
|
|
|
parts.push('## Recent Cycle Statistics (last 10)');
|
|
parts.push(`- Success: ${successCount}, Failed: ${failCount}`);
|
|
parts.push(`- Intent distribution: ${JSON.stringify(intents)}`);
|
|
parts.push(`- Gene usage: ${JSON.stringify(genes)}`);
|
|
parts.push('');
|
|
}
|
|
|
|
if (Array.isArray(signals) && signals.length > 0) {
|
|
parts.push('## Current Signals');
|
|
parts.push(signals.slice(0, 20).join(', '));
|
|
parts.push('');
|
|
}
|
|
|
|
if (memoryAdvice) {
|
|
parts.push('## Memory Graph Advice');
|
|
if (memoryAdvice.preferredGeneId) {
|
|
parts.push(`- Preferred gene: ${memoryAdvice.preferredGeneId}`);
|
|
}
|
|
if (Array.isArray(memoryAdvice.bannedGeneIds) && memoryAdvice.bannedGeneIds.length > 0) {
|
|
parts.push(`- Banned genes: ${memoryAdvice.bannedGeneIds.join(', ')}`);
|
|
}
|
|
if (memoryAdvice.explanation) {
|
|
parts.push(`- Explanation: ${memoryAdvice.explanation}`);
|
|
}
|
|
parts.push('');
|
|
}
|
|
|
|
if (narrative) {
|
|
parts.push('## Recent Evolution Narrative');
|
|
parts.push(String(narrative).slice(0, 3000));
|
|
parts.push('');
|
|
}
|
|
|
|
parts.push('## Questions to Answer');
|
|
parts.push('1. Are there persistent signals being ignored?');
|
|
parts.push('2. Is the gene selection strategy optimal, or are we stuck in a local maximum?');
|
|
parts.push('3. Should the balance between repair/optimize/innovate shift?');
|
|
parts.push('4. Are there capability gaps that no current gene addresses?');
|
|
parts.push('5. What single strategic adjustment would have the highest impact?');
|
|
parts.push('');
|
|
parts.push('Respond with a JSON object: { "insights": [...], "strategy_adjustment": "...", "priority_signals": [...] }');
|
|
|
|
return parts.join('\n');
|
|
}
|
|
|
|
function recordReflection(reflection) {
|
|
const logPath = getReflectionLogPath();
|
|
ensureDir(path.dirname(logPath));
|
|
|
|
const entry = JSON.stringify({
|
|
ts: new Date().toISOString(),
|
|
type: 'reflection',
|
|
...reflection,
|
|
}) + '\n';
|
|
|
|
fs.appendFileSync(logPath, entry, 'utf8');
|
|
}
|
|
|
|
function loadRecentReflections(count) {
|
|
const n = Number.isFinite(count) ? count : 3;
|
|
const logPath = getReflectionLogPath();
|
|
try {
|
|
if (!fs.existsSync(logPath)) return [];
|
|
const lines = fs.readFileSync(logPath, 'utf8').trim().split('\n').filter(Boolean);
|
|
return lines.slice(-n).map(line => {
|
|
try { return JSON.parse(line); } catch (_) { return null; }
|
|
}).filter(Boolean);
|
|
} catch (_) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
shouldReflect,
|
|
buildReflectionContext,
|
|
recordReflection,
|
|
loadRecentReflections,
|
|
REFLECTION_INTERVAL_CYCLES,
|
|
};
|