@cogmem/engram 0.2.1 → 0.3.1
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 +45 -25
- package/SKILL.md +120 -0
- package/drizzle/meta/0000_snapshot.json +17 -50
- package/drizzle/meta/_journal.json +1 -1
- package/package.json +30 -28
- package/src/cli/commands/encode.ts +15 -6
- package/src/cli/commands/focus.ts +38 -11
- package/src/cli/commands/health.ts +47 -13
- package/src/cli/commands/inspect.ts +7 -2
- package/src/cli/commands/install.ts +122 -0
- package/src/cli/commands/list.ts +3 -1
- package/src/cli/commands/recall.ts +4 -2
- package/src/cli/commands/sleep.ts +31 -11
- package/src/cli/commands/stats.ts +38 -15
- package/src/cli/format.ts +3 -2
- package/src/cli/index.ts +6 -3
- package/src/cli/providers/claude.ts +100 -0
- package/src/cli/providers/index.ts +12 -0
- package/src/cli/providers/types.ts +20 -0
- package/src/config/defaults.ts +5 -2
- package/src/core/activation.ts +43 -11
- package/src/core/associations.ts +22 -19
- package/src/core/chunking.ts +14 -4
- package/src/core/consolidation.ts +21 -6
- package/src/core/encoder.ts +3 -3
- package/src/core/engine.ts +3 -2
- package/src/core/forgetting.ts +11 -4
- package/src/core/memory.ts +2 -1
- package/src/core/procedural-store.ts +1 -1
- package/src/core/recall.ts +32 -19
- package/src/core/reconsolidation.ts +5 -2
- package/src/core/working-memory.ts +8 -4
- package/src/mcp/server.ts +53 -15
- package/src/mcp/tools.ts +108 -45
- package/src/storage/schema.ts +1 -0
- package/src/storage/sqlite.ts +22 -7
package/src/mcp/tools.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { CognitiveConfig } from "../config/defaults.ts";
|
|
2
|
-
import
|
|
2
|
+
import { discoverChunks } from "../core/chunking.ts";
|
|
3
|
+
import { consolidate } from "../core/consolidation.ts";
|
|
4
|
+
import { isValidEmotion } from "../core/emotional-tag.ts";
|
|
5
|
+
import { encode } from "../core/encoder.ts";
|
|
3
6
|
import type { EngramEngine } from "../core/engine.ts";
|
|
7
|
+
import { refreshActivations } from "../core/forgetting.ts";
|
|
4
8
|
import { isValidMemoryType, MemoryType, Emotion } from "../core/memory.ts";
|
|
5
|
-
import { encode } from "../core/encoder.ts";
|
|
6
9
|
import { recall } from "../core/recall.ts";
|
|
10
|
+
import {
|
|
11
|
+
reconsolidate,
|
|
12
|
+
type ReconsolidationContext,
|
|
13
|
+
} from "../core/reconsolidation.ts";
|
|
7
14
|
import {
|
|
8
15
|
pushFocus,
|
|
9
16
|
popFocus,
|
|
@@ -11,11 +18,7 @@ import {
|
|
|
11
18
|
clearFocus,
|
|
12
19
|
focusUtilization,
|
|
13
20
|
} from "../core/working-memory.ts";
|
|
14
|
-
import {
|
|
15
|
-
import { discoverChunks } from "../core/chunking.ts";
|
|
16
|
-
import { refreshActivations } from "../core/forgetting.ts";
|
|
17
|
-
import { reconsolidate, type ReconsolidationContext } from "../core/reconsolidation.ts";
|
|
18
|
-
import { isValidEmotion } from "../core/emotional-tag.ts";
|
|
21
|
+
import type { EngramStorage } from "../storage/sqlite.ts";
|
|
19
22
|
|
|
20
23
|
export interface ToolResult {
|
|
21
24
|
[key: string]: unknown;
|
|
@@ -33,13 +36,23 @@ function errorResult(text: string): ToolResult {
|
|
|
33
36
|
|
|
34
37
|
export function handleStore(
|
|
35
38
|
engine: EngramEngine,
|
|
36
|
-
args: { action: string; [key: string]: unknown }
|
|
39
|
+
args: { action: string; [key: string]: unknown }
|
|
37
40
|
): ToolResult {
|
|
38
41
|
switch (args.action) {
|
|
39
42
|
case "encode":
|
|
40
|
-
return handleEncode(
|
|
43
|
+
return handleEncode(
|
|
44
|
+
engine.storage,
|
|
45
|
+
engine.config,
|
|
46
|
+
args as any,
|
|
47
|
+
engine.projectContext
|
|
48
|
+
);
|
|
41
49
|
case "encode_batch":
|
|
42
|
-
return handleEncodeBatch(
|
|
50
|
+
return handleEncodeBatch(
|
|
51
|
+
engine.storage,
|
|
52
|
+
engine.config,
|
|
53
|
+
args as any,
|
|
54
|
+
engine.projectContext
|
|
55
|
+
);
|
|
43
56
|
case "reconsolidate":
|
|
44
57
|
return handleReconsolidate(engine.storage, engine.config, args as any);
|
|
45
58
|
default:
|
|
@@ -49,12 +62,17 @@ export function handleStore(
|
|
|
49
62
|
|
|
50
63
|
export function handleRecall(
|
|
51
64
|
engine: EngramEngine,
|
|
52
|
-
args: { action?: string; [key: string]: unknown }
|
|
65
|
+
args: { action?: string; [key: string]: unknown }
|
|
53
66
|
): ToolResult {
|
|
54
67
|
const action = args.action ?? "recall";
|
|
55
68
|
switch (action) {
|
|
56
69
|
case "recall":
|
|
57
|
-
return handleRecallQuery(
|
|
70
|
+
return handleRecallQuery(
|
|
71
|
+
engine.storage,
|
|
72
|
+
engine.config,
|
|
73
|
+
args as any,
|
|
74
|
+
engine.projectContext
|
|
75
|
+
);
|
|
58
76
|
case "inspect":
|
|
59
77
|
return handleInspect(engine.storage, args as any);
|
|
60
78
|
case "list":
|
|
@@ -68,7 +86,7 @@ export function handleRecall(
|
|
|
68
86
|
|
|
69
87
|
export function handleManage(
|
|
70
88
|
engine: EngramEngine,
|
|
71
|
-
args: { action: string; [key: string]: unknown }
|
|
89
|
+
args: { action: string; [key: string]: unknown }
|
|
72
90
|
): ToolResult {
|
|
73
91
|
switch (args.action) {
|
|
74
92
|
case "consolidate":
|
|
@@ -82,7 +100,12 @@ export function handleManage(
|
|
|
82
100
|
case "focus_clear":
|
|
83
101
|
return handleFocusClear(engine.storage);
|
|
84
102
|
case "recall_to_focus":
|
|
85
|
-
return handleRecallToFocus(
|
|
103
|
+
return handleRecallToFocus(
|
|
104
|
+
engine.storage,
|
|
105
|
+
engine.config,
|
|
106
|
+
args as any,
|
|
107
|
+
engine.projectContext
|
|
108
|
+
);
|
|
86
109
|
default:
|
|
87
110
|
return errorResult(`Unknown manage action: ${args.action}`);
|
|
88
111
|
}
|
|
@@ -98,16 +121,24 @@ function handleEncode(
|
|
|
98
121
|
emotionWeight?: number;
|
|
99
122
|
context?: string;
|
|
100
123
|
},
|
|
101
|
-
defaultContext?: string | null
|
|
124
|
+
defaultContext?: string | null
|
|
102
125
|
): ToolResult {
|
|
103
126
|
const typeStr = args.type ?? "semantic";
|
|
104
127
|
if (!isValidMemoryType(typeStr)) {
|
|
105
|
-
return errorResult(
|
|
128
|
+
return errorResult(
|
|
129
|
+
`Invalid type '${typeStr}'. Valid: ${Object.values(MemoryType).join(
|
|
130
|
+
", "
|
|
131
|
+
)}`
|
|
132
|
+
);
|
|
106
133
|
}
|
|
107
134
|
|
|
108
135
|
const emotionStr = args.emotion ?? "neutral";
|
|
109
136
|
if (!isValidEmotion(emotionStr)) {
|
|
110
|
-
return errorResult(
|
|
137
|
+
return errorResult(
|
|
138
|
+
`Invalid emotion '${emotionStr}'. Valid: ${Object.values(Emotion).join(
|
|
139
|
+
", "
|
|
140
|
+
)}`
|
|
141
|
+
);
|
|
111
142
|
}
|
|
112
143
|
|
|
113
144
|
const memory = encode(
|
|
@@ -119,7 +150,7 @@ function handleEncode(
|
|
|
119
150
|
emotionWeight: args.emotionWeight,
|
|
120
151
|
context: args.context ?? defaultContext ?? undefined,
|
|
121
152
|
},
|
|
122
|
-
config
|
|
153
|
+
config
|
|
123
154
|
);
|
|
124
155
|
|
|
125
156
|
return textResult(JSON.stringify({ id: memory.id }));
|
|
@@ -137,7 +168,7 @@ function handleEncodeBatch(
|
|
|
137
168
|
context?: string;
|
|
138
169
|
}>;
|
|
139
170
|
},
|
|
140
|
-
defaultContext?: string | null
|
|
171
|
+
defaultContext?: string | null
|
|
141
172
|
): ToolResult {
|
|
142
173
|
const ids: string[] = [];
|
|
143
174
|
const errors: string[] = [];
|
|
@@ -164,7 +195,7 @@ function handleEncodeBatch(
|
|
|
164
195
|
emotionWeight: m.emotionWeight,
|
|
165
196
|
context: m.context ?? defaultContext ?? undefined,
|
|
166
197
|
},
|
|
167
|
-
config
|
|
198
|
+
config
|
|
168
199
|
);
|
|
169
200
|
ids.push(memory.id);
|
|
170
201
|
}
|
|
@@ -188,9 +219,10 @@ function handleRecallQuery(
|
|
|
188
219
|
verbose?: boolean;
|
|
189
220
|
format?: "full" | "content" | "ids";
|
|
190
221
|
},
|
|
191
|
-
defaultContext?: string | null
|
|
222
|
+
defaultContext?: string | null
|
|
192
223
|
): ToolResult {
|
|
193
|
-
const typeFilter =
|
|
224
|
+
const typeFilter =
|
|
225
|
+
args.type && isValidMemoryType(args.type) ? args.type : undefined;
|
|
194
226
|
|
|
195
227
|
const results = recall(storage, args.cue, config, {
|
|
196
228
|
limit: args.limit ?? 5,
|
|
@@ -244,11 +276,12 @@ function handleList(
|
|
|
244
276
|
offset?: number;
|
|
245
277
|
format?: "full" | "content" | "ids";
|
|
246
278
|
},
|
|
247
|
-
defaultContext?: string | null
|
|
279
|
+
defaultContext?: string | null
|
|
248
280
|
): ToolResult {
|
|
249
281
|
const limit = args.limit ?? 20;
|
|
250
282
|
const offset = args.offset ?? 0;
|
|
251
|
-
const typeFilter =
|
|
283
|
+
const typeFilter =
|
|
284
|
+
args.type && isValidMemoryType(args.type) ? args.type : undefined;
|
|
252
285
|
const context = args.context ?? defaultContext ?? undefined;
|
|
253
286
|
|
|
254
287
|
let results;
|
|
@@ -280,15 +313,15 @@ function handleList(
|
|
|
280
313
|
type: m.type,
|
|
281
314
|
context: m.context,
|
|
282
315
|
activation: m.activation,
|
|
283
|
-
}))
|
|
284
|
-
)
|
|
316
|
+
}))
|
|
317
|
+
)
|
|
285
318
|
);
|
|
286
319
|
}
|
|
287
320
|
|
|
288
321
|
function handleFocusPush(
|
|
289
322
|
storage: EngramStorage,
|
|
290
323
|
config: CognitiveConfig,
|
|
291
|
-
args: { content: string; memoryRef?: string }
|
|
324
|
+
args: { content: string; memoryRef?: string }
|
|
292
325
|
): ToolResult {
|
|
293
326
|
const { slot, evicted } = pushFocus(storage, args.content, config, {
|
|
294
327
|
memoryRef: args.memoryRef,
|
|
@@ -298,8 +331,10 @@ function handleFocusPush(
|
|
|
298
331
|
JSON.stringify({
|
|
299
332
|
slot: slot.slot,
|
|
300
333
|
content: slot.content,
|
|
301
|
-
evicted: evicted
|
|
302
|
-
|
|
334
|
+
evicted: evicted
|
|
335
|
+
? { slot: evicted.slot, content: evicted.content }
|
|
336
|
+
: null,
|
|
337
|
+
})
|
|
303
338
|
);
|
|
304
339
|
}
|
|
305
340
|
|
|
@@ -308,10 +343,15 @@ function handleFocusPop(storage: EngramStorage): ToolResult {
|
|
|
308
343
|
if (!popped) {
|
|
309
344
|
return textResult("Working memory is empty.");
|
|
310
345
|
}
|
|
311
|
-
return textResult(
|
|
346
|
+
return textResult(
|
|
347
|
+
JSON.stringify({ slot: popped.slot, content: popped.content })
|
|
348
|
+
);
|
|
312
349
|
}
|
|
313
350
|
|
|
314
|
-
function handleFocusGet(
|
|
351
|
+
function handleFocusGet(
|
|
352
|
+
storage: EngramStorage,
|
|
353
|
+
config: CognitiveConfig
|
|
354
|
+
): ToolResult {
|
|
315
355
|
const slots = getFocus(storage);
|
|
316
356
|
const { used, capacity } = focusUtilization(storage, config);
|
|
317
357
|
|
|
@@ -319,8 +359,12 @@ function handleFocusGet(storage: EngramStorage, config: CognitiveConfig): ToolRe
|
|
|
319
359
|
JSON.stringify({
|
|
320
360
|
used,
|
|
321
361
|
capacity,
|
|
322
|
-
slots: slots.map((s) => ({
|
|
323
|
-
|
|
362
|
+
slots: slots.map((s) => ({
|
|
363
|
+
slot: s.slot,
|
|
364
|
+
content: s.content,
|
|
365
|
+
memoryRef: s.memoryRef,
|
|
366
|
+
})),
|
|
367
|
+
})
|
|
324
368
|
);
|
|
325
369
|
}
|
|
326
370
|
|
|
@@ -333,9 +377,10 @@ function handleRecallToFocus(
|
|
|
333
377
|
storage: EngramStorage,
|
|
334
378
|
config: CognitiveConfig,
|
|
335
379
|
args: { cue: string; limit?: number; type?: string; context?: string },
|
|
336
|
-
defaultContext?: string | null
|
|
380
|
+
defaultContext?: string | null
|
|
337
381
|
): ToolResult {
|
|
338
|
-
const typeFilter =
|
|
382
|
+
const typeFilter =
|
|
383
|
+
args.type && isValidMemoryType(args.type) ? args.type : undefined;
|
|
339
384
|
const limit = args.limit ?? 3;
|
|
340
385
|
|
|
341
386
|
const results = recall(storage, args.cue, config, {
|
|
@@ -357,7 +402,10 @@ function handleRecallToFocus(
|
|
|
357
402
|
return textResult(JSON.stringify({ loaded, focus: { used, capacity } }));
|
|
358
403
|
}
|
|
359
404
|
|
|
360
|
-
function handleConsolidate(
|
|
405
|
+
function handleConsolidate(
|
|
406
|
+
storage: EngramStorage,
|
|
407
|
+
config: CognitiveConfig
|
|
408
|
+
): ToolResult {
|
|
361
409
|
const result = consolidate(storage, config);
|
|
362
410
|
const chunks = discoverChunks(storage, config);
|
|
363
411
|
|
|
@@ -370,11 +418,14 @@ function handleConsolidate(storage: EngramStorage, config: CognitiveConfig): Too
|
|
|
370
418
|
chunksFormed: chunks.length,
|
|
371
419
|
extractedFacts: result.extractedFacts,
|
|
372
420
|
prunedIds: result.prunedIds,
|
|
373
|
-
})
|
|
421
|
+
})
|
|
374
422
|
);
|
|
375
423
|
}
|
|
376
424
|
|
|
377
|
-
function handleStats(
|
|
425
|
+
function handleStats(
|
|
426
|
+
storage: EngramStorage,
|
|
427
|
+
config: CognitiveConfig
|
|
428
|
+
): ToolResult {
|
|
378
429
|
const { atRisk } = refreshActivations(storage, config);
|
|
379
430
|
const { used, capacity } = focusUtilization(storage, config);
|
|
380
431
|
const lastConsolidation = storage.getLastConsolidation();
|
|
@@ -394,13 +445,18 @@ function handleStats(storage: EngramStorage, config: CognitiveConfig): ToolResul
|
|
|
394
445
|
memoriesPruned: lastConsolidation.memoriesPruned,
|
|
395
446
|
}
|
|
396
447
|
: null,
|
|
397
|
-
})
|
|
448
|
+
})
|
|
398
449
|
);
|
|
399
450
|
}
|
|
400
451
|
|
|
401
|
-
function handleInspect(
|
|
452
|
+
function handleInspect(
|
|
453
|
+
storage: EngramStorage,
|
|
454
|
+
args: { id: string }
|
|
455
|
+
): ToolResult {
|
|
402
456
|
const allMemories = storage.getAllMemories();
|
|
403
|
-
const match = allMemories.find(
|
|
457
|
+
const match = allMemories.find(
|
|
458
|
+
(m) => m.id === args.id || m.id.startsWith(args.id)
|
|
459
|
+
);
|
|
404
460
|
|
|
405
461
|
if (!match) {
|
|
406
462
|
return errorResult(`No memory found matching "${args.id}".`);
|
|
@@ -431,14 +487,19 @@ function handleInspect(storage: EngramStorage, args: { id: string }): ToolResult
|
|
|
431
487
|
strength: a.strength,
|
|
432
488
|
type: a.type,
|
|
433
489
|
})),
|
|
434
|
-
})
|
|
490
|
+
})
|
|
435
491
|
);
|
|
436
492
|
}
|
|
437
493
|
|
|
438
494
|
function handleReconsolidate(
|
|
439
495
|
storage: EngramStorage,
|
|
440
496
|
config: CognitiveConfig,
|
|
441
|
-
args: {
|
|
497
|
+
args: {
|
|
498
|
+
id: string;
|
|
499
|
+
newContext?: string;
|
|
500
|
+
currentEmotion?: string;
|
|
501
|
+
currentEmotionWeight?: number;
|
|
502
|
+
}
|
|
442
503
|
): ToolResult {
|
|
443
504
|
const memory = storage.getMemory(args.id);
|
|
444
505
|
if (!memory) {
|
|
@@ -446,7 +507,9 @@ function handleReconsolidate(
|
|
|
446
507
|
}
|
|
447
508
|
|
|
448
509
|
const validEmotion =
|
|
449
|
-
args.currentEmotion && isValidEmotion(args.currentEmotion)
|
|
510
|
+
args.currentEmotion && isValidEmotion(args.currentEmotion)
|
|
511
|
+
? args.currentEmotion
|
|
512
|
+
: undefined;
|
|
450
513
|
|
|
451
514
|
const context: ReconsolidationContext = {
|
|
452
515
|
newContext: args.newContext,
|
|
@@ -461,6 +524,6 @@ function handleReconsolidate(
|
|
|
461
524
|
id: updated.id,
|
|
462
525
|
context: updated.context,
|
|
463
526
|
reconsolidationCount: updated.reconsolidationCount,
|
|
464
|
-
})
|
|
527
|
+
})
|
|
465
528
|
);
|
|
466
529
|
}
|
package/src/storage/schema.ts
CHANGED
package/src/storage/sqlite.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
|
+
import { mkdirSync, existsSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { eq, and, gt, lt, or, desc, asc, count, sql } from "drizzle-orm";
|
|
2
6
|
import { drizzle, type BunSQLiteDatabase } from "drizzle-orm/bun-sqlite";
|
|
3
7
|
import { migrate } from "drizzle-orm/bun-sqlite/migrator";
|
|
4
|
-
|
|
5
|
-
import {
|
|
8
|
+
|
|
9
|
+
import { resolveDbPath } from "../config/defaults.ts";
|
|
6
10
|
import type { MemoryType, AccessType } from "../core/memory.ts";
|
|
11
|
+
import { generateId } from "../core/memory.ts";
|
|
12
|
+
import { memories, accessLog, associations, workingMemory, consolidationLog } from "./schema.ts";
|
|
7
13
|
import type {
|
|
8
14
|
Memory,
|
|
9
15
|
AccessLogEntry,
|
|
@@ -11,11 +17,6 @@ import type {
|
|
|
11
17
|
WorkingMemorySlot,
|
|
12
18
|
ConsolidationLog,
|
|
13
19
|
} from "./schema.ts";
|
|
14
|
-
import { generateId } from "../core/memory.ts";
|
|
15
|
-
import { resolveDbPath } from "../config/defaults.ts";
|
|
16
|
-
import { mkdirSync, existsSync } from "node:fs";
|
|
17
|
-
import { dirname, resolve } from "node:path";
|
|
18
|
-
|
|
19
20
|
import * as schema from "./schema.ts";
|
|
20
21
|
|
|
21
22
|
export class EngramStorage {
|
|
@@ -153,6 +154,20 @@ export class EngramStorage {
|
|
|
153
154
|
.all();
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
getTopMemoriesByActivation(limit: number, type?: MemoryType, contextPrefix?: string): Memory[] {
|
|
158
|
+
const conditions = [];
|
|
159
|
+
if (type) conditions.push(eq(memories.type, type));
|
|
160
|
+
if (contextPrefix) conditions.push(sql`${memories.context} LIKE ${contextPrefix + "%"}`);
|
|
161
|
+
|
|
162
|
+
return this.db
|
|
163
|
+
.select()
|
|
164
|
+
.from(memories)
|
|
165
|
+
.where(conditions.length ? and(...conditions) : undefined)
|
|
166
|
+
.orderBy(desc(memories.activation))
|
|
167
|
+
.limit(limit)
|
|
168
|
+
.all();
|
|
169
|
+
}
|
|
170
|
+
|
|
156
171
|
getMemoriesBelowActivation(threshold: number): Memory[] {
|
|
157
172
|
return this.db
|
|
158
173
|
.select()
|