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.
Files changed (79) hide show
  1. package/README.md +335 -0
  2. package/VERSION +1 -0
  3. package/bin/cli.js +12 -0
  4. package/dist/agent/context.js +78 -0
  5. package/dist/agent/index.js +6 -0
  6. package/dist/agent/runtime.js +195 -0
  7. package/dist/agent/task-graph.js +209 -0
  8. package/dist/agent/types.js +1 -0
  9. package/dist/cli/index.js +206 -0
  10. package/dist/core/cognition/active-inference.js +296 -0
  11. package/dist/core/cognition/cognitive-architecture.js +263 -0
  12. package/dist/core/cognition/dual-process.js +102 -0
  13. package/dist/core/cognition/index.js +13 -0
  14. package/dist/core/cognition/learning-from-failure.js +184 -0
  15. package/dist/core/cognition/meta-agent.js +407 -0
  16. package/dist/core/cognition/metacognition.js +322 -0
  17. package/dist/core/cognition/react.js +177 -0
  18. package/dist/core/cognition/retrieval-anchor.js +99 -0
  19. package/dist/core/cognition/self-evolution.js +294 -0
  20. package/dist/core/cognition/self-verification.js +190 -0
  21. package/dist/core/cognition/thought-graph.js +495 -0
  22. package/dist/core/cognition/tool-augmented-llm.js +188 -0
  23. package/dist/core/cognition/tool-execution-verifier.js +204 -0
  24. package/dist/core/collaboration/agentic-loop.js +165 -0
  25. package/dist/core/collaboration/index.js +3 -0
  26. package/dist/core/collaboration/multi-agent-system.js +186 -0
  27. package/dist/core/collaboration/multi-agent.js +110 -0
  28. package/dist/core/consciousness/emotion-engine.js +101 -0
  29. package/dist/core/consciousness/flow-machine.js +121 -0
  30. package/dist/core/consciousness/index.js +4 -0
  31. package/dist/core/consciousness/personality.js +103 -0
  32. package/dist/core/consciousness/types.js +1 -0
  33. package/dist/core/emotional-protocol.js +54 -0
  34. package/dist/core/evolution/engine.js +194 -0
  35. package/dist/core/evolution/goal-engine.js +153 -0
  36. package/dist/core/evolution/index.js +6 -0
  37. package/dist/core/evolution/meta-learning.js +172 -0
  38. package/dist/core/evolution/reflection.js +158 -0
  39. package/dist/core/evolution/self-healer.js +139 -0
  40. package/dist/core/evolution/types.js +1 -0
  41. package/dist/core/healing-rl.js +266 -0
  42. package/dist/core/heartbeat.js +408 -0
  43. package/dist/core/identity/index.js +3 -0
  44. package/dist/core/identity/reflexion.js +165 -0
  45. package/dist/core/identity/self-model.js +274 -0
  46. package/dist/core/identity/self-verifier.js +158 -0
  47. package/dist/core/identity/types.js +12 -0
  48. package/dist/core/lesson-bank.js +301 -0
  49. package/dist/core/memory/adaptive-rag.js +440 -0
  50. package/dist/core/memory/archive-store.js +187 -0
  51. package/dist/core/memory/dream-consolidation.js +366 -0
  52. package/dist/core/memory/embedder.js +130 -0
  53. package/dist/core/memory/hopfield-network.js +128 -0
  54. package/dist/core/memory/index.js +9 -0
  55. package/dist/core/memory/knowledge-graph.js +151 -0
  56. package/dist/core/memory/spaced-repetition.js +113 -0
  57. package/dist/core/memory/store.js +404 -0
  58. package/dist/core/memory/types.js +1 -0
  59. package/dist/core/psychology/analysis.js +456 -0
  60. package/dist/core/psychology/index.js +1 -0
  61. package/dist/core/rollback-manager.js +191 -0
  62. package/dist/core/security/index.js +1 -0
  63. package/dist/core/security/privacy.js +132 -0
  64. package/dist/core/truth-teller.js +253 -0
  65. package/dist/core/truthfulness.js +99 -0
  66. package/dist/core/types.js +2 -0
  67. package/dist/event/bus.js +47 -0
  68. package/dist/index.js +8 -0
  69. package/dist/skills/dag.js +181 -0
  70. package/dist/skills/index.js +5 -0
  71. package/dist/skills/registry.js +40 -0
  72. package/dist/skills/types.js +1 -0
  73. package/dist/storage/archive.js +77 -0
  74. package/dist/storage/checkpoint.js +119 -0
  75. package/dist/storage/types.js +1 -0
  76. package/dist/utils/config.js +81 -0
  77. package/dist/utils/logger.js +49 -0
  78. package/dist/version.js +1 -0
  79. 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';