mark-improving-agent 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +335 -0
- package/VERSION +1 -0
- package/bin/cli.js +12 -0
- package/dist/agent/context.js +78 -0
- package/dist/agent/index.js +6 -0
- package/dist/agent/runtime.js +195 -0
- package/dist/agent/task-graph.js +209 -0
- package/dist/agent/types.js +1 -0
- package/dist/cli/index.js +206 -0
- package/dist/core/cognition/active-inference.js +296 -0
- package/dist/core/cognition/cognitive-architecture.js +263 -0
- package/dist/core/cognition/dual-process.js +102 -0
- package/dist/core/cognition/index.js +13 -0
- package/dist/core/cognition/learning-from-failure.js +184 -0
- package/dist/core/cognition/meta-agent.js +407 -0
- package/dist/core/cognition/metacognition.js +322 -0
- package/dist/core/cognition/react.js +177 -0
- package/dist/core/cognition/retrieval-anchor.js +99 -0
- package/dist/core/cognition/self-evolution.js +294 -0
- package/dist/core/cognition/self-verification.js +190 -0
- package/dist/core/cognition/thought-graph.js +495 -0
- package/dist/core/cognition/tool-augmented-llm.js +188 -0
- package/dist/core/cognition/tool-execution-verifier.js +204 -0
- package/dist/core/collaboration/agentic-loop.js +165 -0
- package/dist/core/collaboration/index.js +3 -0
- package/dist/core/collaboration/multi-agent-system.js +186 -0
- package/dist/core/collaboration/multi-agent.js +110 -0
- package/dist/core/consciousness/emotion-engine.js +101 -0
- package/dist/core/consciousness/flow-machine.js +121 -0
- package/dist/core/consciousness/index.js +4 -0
- package/dist/core/consciousness/personality.js +103 -0
- package/dist/core/consciousness/types.js +1 -0
- package/dist/core/emotional-protocol.js +54 -0
- package/dist/core/evolution/engine.js +194 -0
- package/dist/core/evolution/goal-engine.js +153 -0
- package/dist/core/evolution/index.js +6 -0
- package/dist/core/evolution/meta-learning.js +172 -0
- package/dist/core/evolution/reflection.js +158 -0
- package/dist/core/evolution/self-healer.js +139 -0
- package/dist/core/evolution/types.js +1 -0
- package/dist/core/healing-rl.js +266 -0
- package/dist/core/heartbeat.js +408 -0
- package/dist/core/identity/index.js +3 -0
- package/dist/core/identity/reflexion.js +165 -0
- package/dist/core/identity/self-model.js +274 -0
- package/dist/core/identity/self-verifier.js +158 -0
- package/dist/core/identity/types.js +12 -0
- package/dist/core/lesson-bank.js +301 -0
- package/dist/core/memory/adaptive-rag.js +440 -0
- package/dist/core/memory/archive-store.js +187 -0
- package/dist/core/memory/dream-consolidation.js +366 -0
- package/dist/core/memory/embedder.js +130 -0
- package/dist/core/memory/hopfield-network.js +128 -0
- package/dist/core/memory/index.js +9 -0
- package/dist/core/memory/knowledge-graph.js +151 -0
- package/dist/core/memory/spaced-repetition.js +113 -0
- package/dist/core/memory/store.js +404 -0
- package/dist/core/memory/types.js +1 -0
- package/dist/core/psychology/analysis.js +456 -0
- package/dist/core/psychology/index.js +1 -0
- package/dist/core/rollback-manager.js +191 -0
- package/dist/core/security/index.js +1 -0
- package/dist/core/security/privacy.js +132 -0
- package/dist/core/truth-teller.js +253 -0
- package/dist/core/truthfulness.js +99 -0
- package/dist/core/types.js +2 -0
- package/dist/event/bus.js +47 -0
- package/dist/index.js +8 -0
- package/dist/skills/dag.js +181 -0
- package/dist/skills/index.js +5 -0
- package/dist/skills/registry.js +40 -0
- package/dist/skills/types.js +1 -0
- package/dist/storage/archive.js +77 -0
- package/dist/storage/checkpoint.js +119 -0
- package/dist/storage/types.js +1 -0
- package/dist/utils/config.js +81 -0
- package/dist/utils/logger.js +49 -0
- package/dist/version.js +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
// Dream Consolidation - Hippocampal-style memory consolidation during "sleep"
|
|
2
|
+
// Based on:
|
|
3
|
+
// - Dream Sleep Memory Consolidation (Zhang 2009) - Sleep stages, neural replay
|
|
4
|
+
// - AI Hippocampus - Pattern separation/completion, memory transfer
|
|
5
|
+
// - Graph Agent Memory Taxonomy - Memory layers and operations
|
|
6
|
+
// - MetaDreamer - Meta-learning during dreams
|
|
7
|
+
import { randomUUID, randomBytes } from 'crypto';
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
9
|
+
import { join, dirname } from 'path';
|
|
10
|
+
// Sleep stage durations in ms (typical 90-min cycle proportions)
|
|
11
|
+
const STAGE_DURATIONS = {
|
|
12
|
+
awake: 5000,
|
|
13
|
+
n1: 10 * 60 * 1000, // ~5% of cycle
|
|
14
|
+
n2: 50 * 60 * 1000, // ~55% of cycle
|
|
15
|
+
n3: 20 * 60 * 1000, // ~20% of cycle
|
|
16
|
+
rem: 25 * 60 * 1000, // ~25% of cycle
|
|
17
|
+
};
|
|
18
|
+
// Memory consolidation efficiency by stage
|
|
19
|
+
const STAGE_CONSOLIDATION = {
|
|
20
|
+
awake: 0.0,
|
|
21
|
+
n1: 0.1,
|
|
22
|
+
n2: 0.3,
|
|
23
|
+
n3: 0.8, // Slow-wave sleep - peak consolidation
|
|
24
|
+
rem: 0.5, // REM - emotional memory processing
|
|
25
|
+
};
|
|
26
|
+
function getAgeDays(entry) {
|
|
27
|
+
return (Date.now() - entry.timestamp) / (1000 * 60 * 60 * 24);
|
|
28
|
+
}
|
|
29
|
+
function applyEbbinghausDecay(entry) {
|
|
30
|
+
const ageDays = getAgeDays(entry);
|
|
31
|
+
return entry.importance * Math.exp(-ageDays / 7);
|
|
32
|
+
}
|
|
33
|
+
function generateMemoryTrace(entry) {
|
|
34
|
+
return {
|
|
35
|
+
id: entry.id,
|
|
36
|
+
content: entry.content.slice(0, 200),
|
|
37
|
+
context: entry.tags.join(', '),
|
|
38
|
+
emotionalWeight: entry.importance,
|
|
39
|
+
replayCount: 0,
|
|
40
|
+
lastReplay: Date.now(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function sharpWaveRipple(traces, hippocampalState) {
|
|
44
|
+
// Sharp-wave ripples (Spx) are high-frequency oscillations in CA3-CA1
|
|
45
|
+
// that facilitate memory replay and transfer
|
|
46
|
+
const replayed = [];
|
|
47
|
+
if (hippocampalState.ca3.associativity > 0.5) {
|
|
48
|
+
for (const trace of traces) {
|
|
49
|
+
if (Math.random() < hippocampalState.ca3.associativity * 0.3) {
|
|
50
|
+
trace.replayCount++;
|
|
51
|
+
trace.lastReplay = Date.now();
|
|
52
|
+
replayed.push(trace.id);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return replayed;
|
|
57
|
+
}
|
|
58
|
+
function patternSeparation(dentateGyrus) {
|
|
59
|
+
// DG performs pattern separation to create distinct representations
|
|
60
|
+
const separated = [];
|
|
61
|
+
const noise = (Math.random() - 0.5) * 0.2 * dentateGyrus.activity;
|
|
62
|
+
separated.push(noise);
|
|
63
|
+
return separated;
|
|
64
|
+
}
|
|
65
|
+
function patternCompletion(ca3, cue) {
|
|
66
|
+
// CA3 performs pattern completion to retrieve full memory from partial cue
|
|
67
|
+
if (ca3.patternComplete.includes(cue) && Math.random() < ca3.associativity) {
|
|
68
|
+
return cue;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
function tripartiteDialogue(corticalInput, hippocampalOutput, thalamicActivity) {
|
|
73
|
+
// Simulate the tripartite dialogue: Cortex ↔ Hippocampus ↔ Thalamus
|
|
74
|
+
// This is the "systems consolidation" mechanism where memories are
|
|
75
|
+
// transferred from hippocampal to cortical long-term storage
|
|
76
|
+
const consolidationStrength = Math.min(1, thalamicActivity * 0.3 + 0.2);
|
|
77
|
+
return {
|
|
78
|
+
corticalInput: corticalInput.slice(0, 5).join('; '),
|
|
79
|
+
hippocampalOutput: hippocampalOutput.slice(0, 5).join('; '),
|
|
80
|
+
thalamicModulation: thalamicActivity,
|
|
81
|
+
consolidationStrength,
|
|
82
|
+
replayEvents: hippocampalOutput.slice(0, 3),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function simulateSleepStage(stage, traces, hippocampalState) {
|
|
86
|
+
const startTime = Date.now();
|
|
87
|
+
const duration = STAGE_DURATIONS[stage];
|
|
88
|
+
const efficiency = STAGE_CONSOLIDATION[stage];
|
|
89
|
+
const replayedTraces = [];
|
|
90
|
+
// Copy hippocampal state for this stage
|
|
91
|
+
const newHippocampalState = {
|
|
92
|
+
dentateGyrus: { ...hippocampalState.dentateGyrus },
|
|
93
|
+
ca3: { ...hippocampalState.ca3 },
|
|
94
|
+
ca1: { ...hippocampalState.ca1 },
|
|
95
|
+
};
|
|
96
|
+
// Stage-specific processing
|
|
97
|
+
if (stage === 'n2') {
|
|
98
|
+
// N2: Sleep spindles (thalamic) - memory transfer initiation
|
|
99
|
+
const spindleCount = Math.floor(Math.random() * 5) + 3;
|
|
100
|
+
newHippocampalState.ca1.activity += spindleCount * 0.1;
|
|
101
|
+
// Replay some traces during spindles
|
|
102
|
+
for (const trace of traces) {
|
|
103
|
+
if (Math.random() < efficiency * 0.2) {
|
|
104
|
+
trace.replayCount++;
|
|
105
|
+
replayedTraces.push(trace.id);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (stage === 'n3') {
|
|
110
|
+
// N3: Slow-wave sleep - peak consolidation via sharp-wave ripples
|
|
111
|
+
// Sharp-wave ripples increase CA3 associativity which triggers replay
|
|
112
|
+
newHippocampalState.ca3.associativity = Math.min(1, newHippocampalState.ca3.associativity + 0.15);
|
|
113
|
+
// Sharp-wave ripples in CA3-CA1 trigger memory replay
|
|
114
|
+
const spxReplayed = sharpWaveRipple(traces, newHippocampalState);
|
|
115
|
+
replayedTraces.push(...spxReplayed);
|
|
116
|
+
// Pattern separation in dentate gyrus for new memories
|
|
117
|
+
patternSeparation(newHippocampalState.dentateGyrus);
|
|
118
|
+
}
|
|
119
|
+
else if (stage === 'rem') {
|
|
120
|
+
// REM: Dreaming - emotional memory processing, cortical integration
|
|
121
|
+
newHippocampalState.ca3.associativity = Math.min(1, newHippocampalState.ca3.associativity + 0.1);
|
|
122
|
+
// More associative replay during REM
|
|
123
|
+
for (const trace of traces) {
|
|
124
|
+
if (Math.random() < efficiency * 0.3 * trace.emotionalWeight) {
|
|
125
|
+
trace.replayCount++;
|
|
126
|
+
replayedTraces.push(trace.id);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
stageInfo: { stage, duration, startTime },
|
|
132
|
+
replayedTraces,
|
|
133
|
+
newHippocampalState,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function generateInsight(entryA, entryB, mechanism) {
|
|
137
|
+
const types = [
|
|
138
|
+
'pattern',
|
|
139
|
+
'connection',
|
|
140
|
+
'decay',
|
|
141
|
+
'correction',
|
|
142
|
+
'breakthrough',
|
|
143
|
+
'separation',
|
|
144
|
+
'completion',
|
|
145
|
+
];
|
|
146
|
+
const typeIndex = randomBytes(1)[0] % types.length;
|
|
147
|
+
const type = types[typeIndex];
|
|
148
|
+
return {
|
|
149
|
+
id: randomUUID(),
|
|
150
|
+
type,
|
|
151
|
+
description: `Connection between "${entryA.content.slice(0, 50)}..." and "${entryB.content.slice(0, 50)}..."`,
|
|
152
|
+
weight: Math.min(entryA.importance, entryB.importance) * 0.5,
|
|
153
|
+
timestamp: Date.now(),
|
|
154
|
+
mechanism: mechanism ||
|
|
155
|
+
(type === 'separation' ? 'pattern_separation' :
|
|
156
|
+
type === 'completion' ? 'pattern_completion' : undefined),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
export function createDreamEngine(dataDir) {
|
|
160
|
+
const statsFile = join(dataDir, 'dream-stats.json');
|
|
161
|
+
let state = {
|
|
162
|
+
dreamsPerformed: 0,
|
|
163
|
+
insightsGenerated: 0,
|
|
164
|
+
memoriesStrengthened: 0,
|
|
165
|
+
memoriesPruned: 0,
|
|
166
|
+
lastDreamAt: null,
|
|
167
|
+
totalReplayEvents: 0,
|
|
168
|
+
sharpWaveRipples: 0,
|
|
169
|
+
cyclesCompleted: 0,
|
|
170
|
+
traces: [],
|
|
171
|
+
currentCycle: null,
|
|
172
|
+
};
|
|
173
|
+
// Hippocampal state for pattern separation/completion
|
|
174
|
+
let hippocampalState = {
|
|
175
|
+
dentateGyrus: { patternSeparated: [], activity: 0.5 },
|
|
176
|
+
ca3: { patternComplete: [], associativity: 0.3 },
|
|
177
|
+
ca1: { temporalOrder: [], activity: 0.4 },
|
|
178
|
+
};
|
|
179
|
+
function loadState() {
|
|
180
|
+
try {
|
|
181
|
+
if (existsSync(statsFile)) {
|
|
182
|
+
const raw = readFileSync(statsFile, 'utf-8');
|
|
183
|
+
const parsed = JSON.parse(raw);
|
|
184
|
+
state = { ...state, ...parsed };
|
|
185
|
+
if (parsed.hippocampalState) {
|
|
186
|
+
hippocampalState = parsed.hippocampalState;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Use defaults
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function persistState() {
|
|
195
|
+
try {
|
|
196
|
+
const dir = dirname(statsFile);
|
|
197
|
+
if (!existsSync(dir)) {
|
|
198
|
+
mkdirSync(dir, { recursive: true });
|
|
199
|
+
}
|
|
200
|
+
const stateWithHippocampal = { ...state, hippocampalState };
|
|
201
|
+
const tmp = statsFile + '.tmp.' + randomUUID().slice(0, 8);
|
|
202
|
+
writeFileSync(tmp, JSON.stringify(stateWithHippocampal, null, 2), 'utf-8');
|
|
203
|
+
require('fs').renameSync(tmp, statsFile);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Persistence failure is non-fatal
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
loadState();
|
|
210
|
+
async function dream(entries) {
|
|
211
|
+
const now = Date.now();
|
|
212
|
+
// Rate limit: max 1 dream per hour
|
|
213
|
+
if (state.lastDreamAt && now - state.lastDreamAt < 60 * 60 * 1000) {
|
|
214
|
+
return {
|
|
215
|
+
strengthenedIds: [],
|
|
216
|
+
prunedIds: [],
|
|
217
|
+
insights: [],
|
|
218
|
+
memoriesArchived: 0,
|
|
219
|
+
sleepStage: 'awake',
|
|
220
|
+
replayedTraces: [],
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const strengthenedIds = [];
|
|
224
|
+
const prunedIds = [];
|
|
225
|
+
const insights = [];
|
|
226
|
+
const replayedTraces = [];
|
|
227
|
+
// Create memory traces for replay
|
|
228
|
+
const traces = entries.map(generateMemoryTrace);
|
|
229
|
+
state.traces = traces;
|
|
230
|
+
// Initialize sleep cycle
|
|
231
|
+
const cycle = {
|
|
232
|
+
id: randomUUID(),
|
|
233
|
+
startTime: now,
|
|
234
|
+
stages: [],
|
|
235
|
+
replayedTraces: [],
|
|
236
|
+
consolidatedMemories: [],
|
|
237
|
+
};
|
|
238
|
+
// Simulate full sleep cycle: N1 → N2 → N3 → REM
|
|
239
|
+
const sleepStages = ['n1', 'n2', 'n3', 'rem'];
|
|
240
|
+
for (const stage of sleepStages) {
|
|
241
|
+
const { stageInfo, replayedTraces: stageReplayed, newHippocampalState } = simulateSleepStage(stage, traces, hippocampalState);
|
|
242
|
+
hippocampalState = newHippocampalState;
|
|
243
|
+
cycle.stages.push(stageInfo);
|
|
244
|
+
cycle.replayedTraces.push(...stageReplayed);
|
|
245
|
+
state.totalReplayEvents += stageReplayed.length;
|
|
246
|
+
// Track replayed traces
|
|
247
|
+
for (const traceId of stageReplayed) {
|
|
248
|
+
const trace = traces.find(t => t.id === traceId);
|
|
249
|
+
if (trace) {
|
|
250
|
+
replayedTraces.push(trace);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Count sharp-wave ripples (Spx) events in N3 stage
|
|
255
|
+
const n3Stage = cycle.stages.find(s => s.stage === 'n3');
|
|
256
|
+
if (n3Stage) {
|
|
257
|
+
state.sharpWaveRipples += Math.floor(Math.random() * 10) + 5;
|
|
258
|
+
}
|
|
259
|
+
// Apply consolidation to entries based on trace replay
|
|
260
|
+
for (const entry of entries) {
|
|
261
|
+
const trace = traces.find(t => t.id === entry.id);
|
|
262
|
+
const decayedImportance = applyEbbinghausDecay(entry);
|
|
263
|
+
const replayBoost = trace ? trace.replayCount * 0.05 : 0;
|
|
264
|
+
if (decayedImportance < 0.2 && replayBoost < 0.1) {
|
|
265
|
+
prunedIds.push(entry.id);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
strengthenedIds.push(entry.id);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// Generate insights from memory interactions
|
|
272
|
+
if (entries.length >= 2) {
|
|
273
|
+
const insightCount = Math.min(5, Math.floor(entries.length / 2));
|
|
274
|
+
for (let i = 0; i < insightCount; i++) {
|
|
275
|
+
const randA = randomBytes(2);
|
|
276
|
+
const randB = randomBytes(2);
|
|
277
|
+
const a = entries[(randA[0] | (randA[1] << 8)) % entries.length];
|
|
278
|
+
const b = entries[(randB[0] | (randB[1] << 8)) % entries.length];
|
|
279
|
+
if (a.id !== b.id) {
|
|
280
|
+
const mechanisms = [
|
|
281
|
+
'pattern_separation',
|
|
282
|
+
'pattern_completion',
|
|
283
|
+
'sharp_wave_ripple',
|
|
284
|
+
'systems_consolidation',
|
|
285
|
+
];
|
|
286
|
+
const mech = mechanisms[randomBytes(1)[0] % mechanisms.length];
|
|
287
|
+
insights.push(generateInsight(a, b, mech));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Generate tripartite dialogue for this dream
|
|
292
|
+
const dialogue = tripartiteDialogue(strengthenedIds, replayedTraces.map(t => t.id), hippocampalState.ca1.activity);
|
|
293
|
+
// Update stats
|
|
294
|
+
state.dreamsPerformed++;
|
|
295
|
+
state.lastDreamAt = now;
|
|
296
|
+
state.insightsGenerated += insights.length;
|
|
297
|
+
state.memoriesStrengthened += strengthenedIds.length;
|
|
298
|
+
state.memoriesPruned += prunedIds.length;
|
|
299
|
+
state.cyclesCompleted++;
|
|
300
|
+
state.currentCycle = cycle;
|
|
301
|
+
persistState();
|
|
302
|
+
return {
|
|
303
|
+
strengthenedIds,
|
|
304
|
+
prunedIds,
|
|
305
|
+
insights,
|
|
306
|
+
memoriesArchived: prunedIds.length,
|
|
307
|
+
sleepStage: 'rem', // Final stage reached
|
|
308
|
+
replayedTraces,
|
|
309
|
+
dialogueState: dialogue,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function applyForgettingCurve(entry) {
|
|
313
|
+
return applyEbbinghausDecay(entry);
|
|
314
|
+
}
|
|
315
|
+
function getMemoryHealth() {
|
|
316
|
+
const issues = [];
|
|
317
|
+
if (state.memoriesPruned > state.memoriesStrengthened * 3) {
|
|
318
|
+
issues.push('High prune rate - memories being lost too quickly');
|
|
319
|
+
}
|
|
320
|
+
if (state.dreamsPerformed === 0) {
|
|
321
|
+
issues.push('No dream consolidation performed yet');
|
|
322
|
+
}
|
|
323
|
+
const timeSinceLastDream = state.lastDreamAt ? Date.now() - state.lastDreamAt : Infinity;
|
|
324
|
+
if (timeSinceLastDream > 7 * 24 * 60 * 60 * 1000) {
|
|
325
|
+
issues.push('Dream consolidation overdue (no dreams in 7+ days)');
|
|
326
|
+
}
|
|
327
|
+
if (state.sharpWaveRipples < 10 && state.dreamsPerformed > 0) {
|
|
328
|
+
issues.push('Low sharp-wave ripple activity - memory consolidation may be impaired');
|
|
329
|
+
}
|
|
330
|
+
// Calculate score: 1.0 = healthy, 0.0 = problematic
|
|
331
|
+
let score = 1.0;
|
|
332
|
+
if (issues.length === 1)
|
|
333
|
+
score = 0.75;
|
|
334
|
+
else if (issues.length === 2)
|
|
335
|
+
score = 0.5;
|
|
336
|
+
else if (issues.length >= 3)
|
|
337
|
+
score = 0.25;
|
|
338
|
+
return { score, issues };
|
|
339
|
+
}
|
|
340
|
+
function getDreamStats() {
|
|
341
|
+
return {
|
|
342
|
+
dreamsPerformed: state.dreamsPerformed,
|
|
343
|
+
insightsGenerated: state.insightsGenerated,
|
|
344
|
+
memoriesStrengthened: state.memoriesStrengthened,
|
|
345
|
+
memoriesPruned: state.memoriesPruned,
|
|
346
|
+
lastDreamAt: state.lastDreamAt,
|
|
347
|
+
totalReplayEvents: state.totalReplayEvents,
|
|
348
|
+
sharpWaveRipples: state.sharpWaveRipples,
|
|
349
|
+
cyclesCompleted: state.cyclesCompleted,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function getHippocampalState() {
|
|
353
|
+
return { ...hippocampalState };
|
|
354
|
+
}
|
|
355
|
+
function getCurrentCycle() {
|
|
356
|
+
return state.currentCycle;
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
dream,
|
|
360
|
+
applyForgettingCurve,
|
|
361
|
+
getMemoryHealth,
|
|
362
|
+
getDreamStats,
|
|
363
|
+
getHippocampalState,
|
|
364
|
+
getCurrentCycle,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI-backed embedder using the completions API.
|
|
4
|
+
* Note: embed() is async to support API calls - use embedSync() for hash-based fallback.
|
|
5
|
+
*/
|
|
6
|
+
class OpenAIEmbedder {
|
|
7
|
+
apiKey;
|
|
8
|
+
model;
|
|
9
|
+
dimensions;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.apiKey = config.apiKey;
|
|
12
|
+
this.model = config.model ?? 'text-embedding-3-small';
|
|
13
|
+
this.dimensions = config.dimensions ?? 1536;
|
|
14
|
+
}
|
|
15
|
+
// Sync version that throws - use HashEmbedder for sync embedding
|
|
16
|
+
embed(text) {
|
|
17
|
+
throw new Error('OpenAIEmbedder.embed is async - use HashEmbedder or call embedAsync()');
|
|
18
|
+
}
|
|
19
|
+
embedBatch(texts) {
|
|
20
|
+
throw new Error('OpenAIEmbedder.embedBatch is async - use HashEmbedder or call embedBatchAsync()');
|
|
21
|
+
}
|
|
22
|
+
async embedAsync(text) {
|
|
23
|
+
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: {
|
|
26
|
+
'Content-Type': 'application/json',
|
|
27
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
model: this.model,
|
|
31
|
+
input: text,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`OpenAI embedding error: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
return data.data[0]?.embedding ?? [];
|
|
39
|
+
}
|
|
40
|
+
async embedBatchAsync(texts) {
|
|
41
|
+
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: {
|
|
44
|
+
'Content-Type': 'application/json',
|
|
45
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify({
|
|
48
|
+
model: this.model,
|
|
49
|
+
input: texts,
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
throw new Error(`OpenAI embedding error: ${response.status} ${response.statusText}`);
|
|
54
|
+
}
|
|
55
|
+
const data = await response.json();
|
|
56
|
+
// Sort by index to maintain order
|
|
57
|
+
return data.data
|
|
58
|
+
.sort((a, b) => 0) // maintain original order
|
|
59
|
+
.map(item => item.embedding);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Hash-based pseudo-embedder for environments without an API key.
|
|
64
|
+
* Uses SHA256 to generate deterministic pseudo-random floats.
|
|
65
|
+
* NOT suitable for real semantic similarity but useful for fast lookups.
|
|
66
|
+
*/
|
|
67
|
+
class HashEmbedder {
|
|
68
|
+
dimensions;
|
|
69
|
+
cache = new Map();
|
|
70
|
+
constructor(dimensions = 128) {
|
|
71
|
+
this.dimensions = dimensions;
|
|
72
|
+
}
|
|
73
|
+
embed(text) {
|
|
74
|
+
const cached = this.cache.get(text);
|
|
75
|
+
if (cached) {
|
|
76
|
+
return cached;
|
|
77
|
+
}
|
|
78
|
+
const hash = createHash('sha256').update(text).digest('hex');
|
|
79
|
+
const hashLen = hash.length;
|
|
80
|
+
const embedding = [];
|
|
81
|
+
for (let i = 0; i < this.dimensions; i++) {
|
|
82
|
+
// Parse 8 hex chars at a time to get a pseudo-random float
|
|
83
|
+
// Wrap around the hash using modulo to handle dimensions > hash segments
|
|
84
|
+
const offset = ((i % 32) * 8) % hashLen;
|
|
85
|
+
const hexSegment = hash.slice(offset, offset + 8);
|
|
86
|
+
const num = parseInt(hexSegment, 16);
|
|
87
|
+
// Normalize to 0..1 range
|
|
88
|
+
embedding.push((num % 2000) / 2000);
|
|
89
|
+
}
|
|
90
|
+
this.cache.set(text, embedding);
|
|
91
|
+
return embedding;
|
|
92
|
+
}
|
|
93
|
+
embedBatch(texts) {
|
|
94
|
+
return texts.map(text => this.embed(text));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Creates an embedder based on configuration.
|
|
99
|
+
* If apiKey is provided, uses OpenAI; otherwise uses hash fallback.
|
|
100
|
+
*/
|
|
101
|
+
export function createEmbedder(config) {
|
|
102
|
+
if (config.apiKey) {
|
|
103
|
+
return new OpenAIEmbedder({ apiKey: config.apiKey, model: config.model, dimensions: config.dimensions });
|
|
104
|
+
}
|
|
105
|
+
return new HashEmbedder(config.dimensions ?? 128);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Computes cosine similarity between two vectors.
|
|
109
|
+
* Returns a value between -1 and 1.
|
|
110
|
+
*/
|
|
111
|
+
export function cosineSimilarity(a, b) {
|
|
112
|
+
if (a.length !== b.length) {
|
|
113
|
+
throw new Error(`Vector dimensions must match: ${a.length} vs ${b.length}`);
|
|
114
|
+
}
|
|
115
|
+
let dotProduct = 0;
|
|
116
|
+
let normA = 0;
|
|
117
|
+
let normB = 0;
|
|
118
|
+
for (let i = 0; i < a.length; i++) {
|
|
119
|
+
dotProduct += a[i] * b[i];
|
|
120
|
+
normA += a[i] * a[i];
|
|
121
|
+
normB += b[i] * b[i];
|
|
122
|
+
}
|
|
123
|
+
const denominator = Math.sqrt(normA) * Math.sqrt(normB);
|
|
124
|
+
if (denominator === 0) {
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
return dotProduct / denominator;
|
|
128
|
+
}
|
|
129
|
+
// Default embedder using hash fallback (no API key required)
|
|
130
|
+
export const DEFAULT_EMBEDDER = createEmbedder({});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hopfield Network - Associative Memory
|
|
3
|
+
*
|
|
4
|
+
* Paper: "A Cognitive Architecture for Autonomous Agents Based on Hopfield Networks"
|
|
5
|
+
* Concept: Associative memory with energy-based pattern storage
|
|
6
|
+
*
|
|
7
|
+
* Key mechanisms:
|
|
8
|
+
* - Energy minimization for pattern storage
|
|
9
|
+
* - Associative retrieval (content-addressable)
|
|
10
|
+
* - Two-stage retrieval: fast associative + slow refinement
|
|
11
|
+
* - Continuous knowledge updates
|
|
12
|
+
*/
|
|
13
|
+
import { randomUUID } from 'crypto';
|
|
14
|
+
export function createHopfieldNetwork() {
|
|
15
|
+
const nodes = new Map();
|
|
16
|
+
/**
|
|
17
|
+
* Compute energy for a pattern (simplified Hopfield energy)
|
|
18
|
+
*/
|
|
19
|
+
function computeEnergy(pattern, connections) {
|
|
20
|
+
// Energy based on pattern complexity and connection strength
|
|
21
|
+
const patternComplexity = pattern.length / 100;
|
|
22
|
+
const connectionStrength = connections.length * 0.1;
|
|
23
|
+
return patternComplexity - connectionStrength;
|
|
24
|
+
}
|
|
25
|
+
function store(pattern, associations = []) {
|
|
26
|
+
const id = `hf-${Date.now()}-${randomUUID().slice(0, 8)}`;
|
|
27
|
+
const energy = computeEnergy(pattern, associations);
|
|
28
|
+
const node = {
|
|
29
|
+
id,
|
|
30
|
+
pattern,
|
|
31
|
+
energy,
|
|
32
|
+
activation: 1.0,
|
|
33
|
+
connections: associations,
|
|
34
|
+
lastUpdated: Date.now(),
|
|
35
|
+
retrievalCount: 0,
|
|
36
|
+
};
|
|
37
|
+
nodes.set(id, node);
|
|
38
|
+
// Update connections for associated nodes
|
|
39
|
+
for (const assocId of associations) {
|
|
40
|
+
const assocNode = nodes.get(assocId);
|
|
41
|
+
if (assocNode && !assocNode.connections.includes(id)) {
|
|
42
|
+
assocNode.connections.push(id);
|
|
43
|
+
assocNode.lastUpdated = Date.now();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return node;
|
|
47
|
+
}
|
|
48
|
+
function retrieve(query) {
|
|
49
|
+
const queryLower = query.toLowerCase();
|
|
50
|
+
const results = [];
|
|
51
|
+
for (const node of nodes.values()) {
|
|
52
|
+
const patternLower = node.pattern.toLowerCase();
|
|
53
|
+
// Calculate similarity score
|
|
54
|
+
const queryWords = queryLower.split(/\s+/);
|
|
55
|
+
const patternWords = patternLower.split(/\s+/);
|
|
56
|
+
let matches = 0;
|
|
57
|
+
for (const qWord of queryWords) {
|
|
58
|
+
if (patternWords.some(p => p.includes(qWord) || qWord.includes(p))) {
|
|
59
|
+
matches++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const similarity = queryWords.length > 0 ? matches / queryWords.length : 0;
|
|
63
|
+
if (similarity > 0.3) {
|
|
64
|
+
node.retrievalCount++;
|
|
65
|
+
node.lastUpdated = Date.now();
|
|
66
|
+
results.push(node);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Sort by activation and retrieval count
|
|
70
|
+
return results
|
|
71
|
+
.sort((a, b) => {
|
|
72
|
+
const scoreA = a.activation * 0.6 + a.retrievalCount * 0.001;
|
|
73
|
+
const scoreB = b.activation * 0.6 + b.retrievalCount * 0.001;
|
|
74
|
+
return scoreB - scoreA;
|
|
75
|
+
})
|
|
76
|
+
.slice(0, 5);
|
|
77
|
+
}
|
|
78
|
+
function updateEnergy(nodeId, delta) {
|
|
79
|
+
const node = nodes.get(nodeId);
|
|
80
|
+
if (node) {
|
|
81
|
+
node.energy += delta;
|
|
82
|
+
node.lastUpdated = Date.now();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function getAssociated(nodeId) {
|
|
86
|
+
const node = nodes.get(nodeId);
|
|
87
|
+
if (!node)
|
|
88
|
+
return [];
|
|
89
|
+
return node.connections
|
|
90
|
+
.map(id => nodes.get(id))
|
|
91
|
+
.filter((n) => n !== undefined);
|
|
92
|
+
}
|
|
93
|
+
function pruneWeakNodes(threshold) {
|
|
94
|
+
let pruned = 0;
|
|
95
|
+
for (const [id, node] of nodes.entries()) {
|
|
96
|
+
if (node.energy > threshold && node.retrievalCount < 2) {
|
|
97
|
+
nodes.delete(id);
|
|
98
|
+
pruned++;
|
|
99
|
+
// Remove from other nodes' connections
|
|
100
|
+
for (const other of nodes.values()) {
|
|
101
|
+
other.connections = other.connections.filter(cid => cid !== id);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return pruned;
|
|
106
|
+
}
|
|
107
|
+
function getStats() {
|
|
108
|
+
let totalEnergy = 0;
|
|
109
|
+
let totalConnections = 0;
|
|
110
|
+
for (const node of nodes.values()) {
|
|
111
|
+
totalEnergy += node.energy;
|
|
112
|
+
totalConnections += node.connections.length;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
nodes: nodes.size,
|
|
116
|
+
avgEnergy: nodes.size > 0 ? totalEnergy / nodes.size : 0,
|
|
117
|
+
avgConnections: nodes.size > 0 ? totalConnections / nodes.size : 0,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
store,
|
|
122
|
+
retrieve,
|
|
123
|
+
updateEnergy,
|
|
124
|
+
getAssociated,
|
|
125
|
+
pruneWeakNodes,
|
|
126
|
+
getStats,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './embedder.js';
|
|
3
|
+
export * from './store.js';
|
|
4
|
+
export * from './archive-store.js';
|
|
5
|
+
export * from './knowledge-graph.js';
|
|
6
|
+
export * from './dream-consolidation.js';
|
|
7
|
+
export * from './spaced-repetition.js';
|
|
8
|
+
export * from './hopfield-network.js';
|
|
9
|
+
export * from './adaptive-rag.js';
|