Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | /** * Phase 6.1 — LongTermMemory * - Append snapshots (from Phase 5 via toSnapshot/createSnapshot) * - Compute rolling metrics: stability, adaptationRate, evolutionScore * - Persist to JSON (storage/phase6_long_term_memory.json) * * Also acts as the backing store for the alias "MemoryKernel" (see memory_kernel.ts). */ import fs from 'node:fs'; import { Snapshot, LongTermState, LongTermMetrics } from '../../types/core'; import { Phase6Config } from '../../config/phase6.config'; /** ---------- load / save ---------- */ function loadState(): LongTermState { if (!fs.existsSync(Phase6Config.storagePath)) { return { snapshots: [], metrics: null }; } try { const parsed = JSON.parse(fs.readFileSync(Phase6Config.storagePath, 'utf-8')); return { snapshots: Array.isArray(parsed?.snapshots) ? parsed.snapshots : [], metrics: parsed?.metrics ?? null, }; } catch { return { snapshots: [], metrics: null }; } } function saveState(state: LongTermState) { fs.mkdirSync('./storage', { recursive: true }); fs.writeFileSync(Phase6Config.storagePath, JSON.stringify(state, null, 2)); } /** ---------- metrics ---------- */ function computeMetrics(snapshots: Snapshot[]): LongTermMetrics { const win = Phase6Config.metricsWindow; const recent = snapshots.slice(-win); // stability = variance of all outcome scores in the recent window (lower is better) const scores = recent.flatMap((s) => s.outcomes.map((o) => o.score)); const mean = avg(scores); const variance = avg(scores.map((x) => (x - mean) ** 2)); const stability = variance || 0; // adaptationRate = mean(delta of average snapshot score) across the recent window const deltas: number[] = []; for (let i = 1; i < recent.length; i++) { const prev = snapshotMean(recent[i - 1]); const curr = snapshotMean(recent[i]); deltas.push(curr - prev); } const adaptationRate = avg(deltas) || 0; // evolutionScore = improvement discounted by instability const evolutionScore = Math.max(0, adaptationRate - stability); return { stability, adaptationRate, evolutionScore }; } function snapshotMean(s: Snapshot) { const vals = s.outcomes.map((o) => o.score); return avg(vals); } const avg = (arr: number[]) => (arr.length ? arr.reduce((a, b) => a + b, 0) / arr.length : 0); /** ---------- public API ---------- */ export const LongTermMemory = { /** * Append a snapshot, trim to rolling window, recompute metrics, persist. */ appendSnapshot(snapshot: Snapshot) { const state = loadState(); state.snapshots.push(snapshot); if (state.snapshots.length > Phase6Config.maxSnapshots) { state.snapshots = state.snapshots.slice(-Phase6Config.maxSnapshots); } state.metrics = computeMetrics(state.snapshots); saveState(state); return state; }, /** * Load in-memory state (snapshots + metrics) from disk. */ getState(): LongTermState { return loadState(); }, }; |