@cogmem/engram 0.0.0 → 0.1.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 +1 -1
- package/package.json +1 -1
- package/src/core/recall.ts +7 -0
- package/src/mcp/server.ts +35 -19
- package/src/mcp/tools.ts +149 -17
package/README.md
CHANGED
package/package.json
CHANGED
package/src/core/recall.ts
CHANGED
|
@@ -31,6 +31,13 @@ export function recall(
|
|
|
31
31
|
candidateMap.set(m.id, m);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
if (options?.context) {
|
|
35
|
+
const contextMatches = storage.getMemoriesByContext(options.context, options?.type, limit * 2);
|
|
36
|
+
for (const m of contextMatches) {
|
|
37
|
+
candidateMap.set(m.id, m);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
34
41
|
const allCandidates = options?.type
|
|
35
42
|
? storage.getAllMemories(options.type)
|
|
36
43
|
: storage.getAllMemories();
|
package/src/mcp/server.ts
CHANGED
|
@@ -17,11 +17,7 @@ server.registerTool(
|
|
|
17
17
|
"memory_store",
|
|
18
18
|
{
|
|
19
19
|
title: "Store Memory",
|
|
20
|
-
description: `
|
|
21
|
-
|
|
22
|
-
Actions:
|
|
23
|
-
- action:"encode" — Create a new memory. Params: content (required), type? (semantic|episodic|procedural, default semantic), emotion? (neutral|curiosity|surprise|anxiety|satisfaction|frustration|confusion|excitement|calm|urgency), emotionWeight? (0-1), context? (e.g. "project:acme")
|
|
24
|
-
- action:"reconsolidate" — Update an existing memory during recall. Params: id (required), newContext?, currentEmotion?, currentEmotionWeight?`,
|
|
20
|
+
description: `Actions: encode(content) — store memory | encode_batch(memories[]) — store multiple | reconsolidate(id) — update during recall. Optional: type, emotion, emotionWeight, context.`,
|
|
25
21
|
inputSchema: z.discriminatedUnion("action", [
|
|
26
22
|
z.object({
|
|
27
23
|
action: z.literal("encode"),
|
|
@@ -31,6 +27,22 @@ Actions:
|
|
|
31
27
|
emotionWeight: z.number().min(0).max(1).optional().describe("Emotion intensity 0-1"),
|
|
32
28
|
context: z.string().optional().describe("Context tag (e.g. project:acme)"),
|
|
33
29
|
}),
|
|
30
|
+
z.object({
|
|
31
|
+
action: z.literal("encode_batch"),
|
|
32
|
+
memories: z
|
|
33
|
+
.array(
|
|
34
|
+
z.object({
|
|
35
|
+
content: z.string(),
|
|
36
|
+
type: z.nativeEnum(MemoryType).optional(),
|
|
37
|
+
emotion: z.nativeEnum(Emotion).optional(),
|
|
38
|
+
emotionWeight: z.number().min(0).max(1).optional(),
|
|
39
|
+
context: z.string().optional(),
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
.min(1)
|
|
43
|
+
.max(50)
|
|
44
|
+
.describe("Array of memories to encode"),
|
|
45
|
+
}),
|
|
34
46
|
z.object({
|
|
35
47
|
action: z.literal("reconsolidate"),
|
|
36
48
|
id: z.string().describe("Memory ID to update"),
|
|
@@ -47,12 +59,7 @@ server.registerTool(
|
|
|
47
59
|
"memory_recall",
|
|
48
60
|
{
|
|
49
61
|
title: "Recall Memories",
|
|
50
|
-
description: `
|
|
51
|
-
|
|
52
|
-
Actions:
|
|
53
|
-
- action:"recall" — Cue-based retrieval with spreading activation. Params: cue (required), limit? (default 5), type? (semantic|episodic|procedural), context?, associative? (default true), verbose?
|
|
54
|
-
- action:"inspect" — Examine a specific memory's full lifecycle. Params: id (required, full ID or prefix)
|
|
55
|
-
- action:"stats" — Memory system overview (counts, working memory usage, last consolidation). No extra params.`,
|
|
62
|
+
description: `Actions: recall(cue) — cue-based retrieval | list — browse without activation effects | inspect(id) — full lifecycle | stats — system overview. Optional: limit, type, context, format, verbose.`,
|
|
56
63
|
inputSchema: z.discriminatedUnion("action", [
|
|
57
64
|
z.object({
|
|
58
65
|
action: z.literal("recall").optional().default("recall"),
|
|
@@ -62,11 +69,20 @@ Actions:
|
|
|
62
69
|
context: z.string().optional().describe("Filter by context"),
|
|
63
70
|
associative: z.boolean().optional().describe("Spreading activation (default: true)"),
|
|
64
71
|
verbose: z.boolean().optional().describe("Full fields"),
|
|
72
|
+
format: z.enum(["full", "content", "ids"]).optional().describe("Response format (default: full)"),
|
|
65
73
|
}),
|
|
66
74
|
z.object({
|
|
67
75
|
action: z.literal("inspect"),
|
|
68
76
|
id: z.string().describe("Memory ID or prefix"),
|
|
69
77
|
}),
|
|
78
|
+
z.object({
|
|
79
|
+
action: z.literal("list"),
|
|
80
|
+
type: z.nativeEnum(MemoryType).optional().describe("Filter by type"),
|
|
81
|
+
context: z.string().optional().describe("Filter by context prefix"),
|
|
82
|
+
limit: z.number().optional().describe("Max results (default: 20)"),
|
|
83
|
+
offset: z.number().optional().describe("Skip first N results (default: 0)"),
|
|
84
|
+
format: z.enum(["full", "content", "ids"]).optional().describe("Response format (default: full)"),
|
|
85
|
+
}),
|
|
70
86
|
z.object({
|
|
71
87
|
action: z.literal("stats"),
|
|
72
88
|
}),
|
|
@@ -79,14 +95,7 @@ server.registerTool(
|
|
|
79
95
|
"memory_manage",
|
|
80
96
|
{
|
|
81
97
|
title: "Manage Memory",
|
|
82
|
-
description: `
|
|
83
|
-
|
|
84
|
-
Actions:
|
|
85
|
-
- action:"consolidate" — Run sleep cycle (strengthen, prune, extract patterns, discover links). No extra params.
|
|
86
|
-
- action:"focus_push" — Push to working memory buffer. Params: content (required), memoryRef?
|
|
87
|
-
- action:"focus_pop" — Remove most recent item from working memory. No extra params.
|
|
88
|
-
- action:"focus_get" — View current working memory contents. No extra params.
|
|
89
|
-
- action:"focus_clear" — Clear all working memory. No extra params.`,
|
|
98
|
+
description: `Actions: consolidate — run sleep cycle | recall_to_focus(cue) — recall and load to working memory | focus_push(content) — push to buffer | focus_pop — pop newest | focus_get — view buffer | focus_clear — empty buffer.`,
|
|
90
99
|
inputSchema: z.discriminatedUnion("action", [
|
|
91
100
|
z.object({
|
|
92
101
|
action: z.literal("consolidate"),
|
|
@@ -105,6 +114,13 @@ Actions:
|
|
|
105
114
|
z.object({
|
|
106
115
|
action: z.literal("focus_clear"),
|
|
107
116
|
}),
|
|
117
|
+
z.object({
|
|
118
|
+
action: z.literal("recall_to_focus"),
|
|
119
|
+
cue: z.string().describe("Recall cue"),
|
|
120
|
+
limit: z.number().optional().describe("Max memories to load (default: 3)"),
|
|
121
|
+
type: z.nativeEnum(MemoryType).optional().describe("Filter by type"),
|
|
122
|
+
context: z.string().optional().describe("Filter by context"),
|
|
123
|
+
}),
|
|
108
124
|
]),
|
|
109
125
|
},
|
|
110
126
|
async (args) => handleManage(engine, args),
|
package/src/mcp/tools.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CognitiveConfig } from "../config/defaults.ts";
|
|
2
2
|
import type { EngramStorage } from "../storage/sqlite.ts";
|
|
3
3
|
import type { EngramEngine } from "../core/engine.ts";
|
|
4
|
-
import { isValidMemoryType } from "../core/memory.ts";
|
|
4
|
+
import { isValidMemoryType, MemoryType, Emotion } from "../core/memory.ts";
|
|
5
5
|
import { encode } from "../core/encoder.ts";
|
|
6
6
|
import { recall } from "../core/recall.ts";
|
|
7
7
|
import {
|
|
@@ -38,6 +38,8 @@ export function handleStore(
|
|
|
38
38
|
switch (args.action) {
|
|
39
39
|
case "encode":
|
|
40
40
|
return handleEncode(engine.storage, engine.config, args as any, engine.projectContext);
|
|
41
|
+
case "encode_batch":
|
|
42
|
+
return handleEncodeBatch(engine.storage, engine.config, args as any, engine.projectContext);
|
|
41
43
|
case "reconsolidate":
|
|
42
44
|
return handleReconsolidate(engine.storage, engine.config, args as any);
|
|
43
45
|
default:
|
|
@@ -55,6 +57,8 @@ export function handleRecall(
|
|
|
55
57
|
return handleRecallQuery(engine.storage, engine.config, args as any, engine.projectContext);
|
|
56
58
|
case "inspect":
|
|
57
59
|
return handleInspect(engine.storage, args as any);
|
|
60
|
+
case "list":
|
|
61
|
+
return handleList(engine.storage, args as any, engine.projectContext);
|
|
58
62
|
case "stats":
|
|
59
63
|
return handleStats(engine.storage, engine.config);
|
|
60
64
|
default:
|
|
@@ -77,6 +81,8 @@ export function handleManage(
|
|
|
77
81
|
return handleFocusGet(engine.storage, engine.config);
|
|
78
82
|
case "focus_clear":
|
|
79
83
|
return handleFocusClear(engine.storage);
|
|
84
|
+
case "recall_to_focus":
|
|
85
|
+
return handleRecallToFocus(engine.storage, engine.config, args as any, engine.projectContext);
|
|
80
86
|
default:
|
|
81
87
|
return errorResult(`Unknown manage action: ${args.action}`);
|
|
82
88
|
}
|
|
@@ -96,12 +102,12 @@ function handleEncode(
|
|
|
96
102
|
): ToolResult {
|
|
97
103
|
const typeStr = args.type ?? "semantic";
|
|
98
104
|
if (!isValidMemoryType(typeStr)) {
|
|
99
|
-
return errorResult(`Invalid type
|
|
105
|
+
return errorResult(`Invalid type '${typeStr}'. Valid: ${Object.values(MemoryType).join(", ")}`);
|
|
100
106
|
}
|
|
101
107
|
|
|
102
108
|
const emotionStr = args.emotion ?? "neutral";
|
|
103
109
|
if (!isValidEmotion(emotionStr)) {
|
|
104
|
-
return errorResult(`Invalid emotion
|
|
110
|
+
return errorResult(`Invalid emotion '${emotionStr}'. Valid: ${Object.values(Emotion).join(", ")}`);
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
const memory = encode(
|
|
@@ -116,17 +122,58 @@ function handleEncode(
|
|
|
116
122
|
config,
|
|
117
123
|
);
|
|
118
124
|
|
|
119
|
-
return textResult(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
return textResult(JSON.stringify({ id: memory.id }));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function handleEncodeBatch(
|
|
129
|
+
storage: EngramStorage,
|
|
130
|
+
config: CognitiveConfig,
|
|
131
|
+
args: {
|
|
132
|
+
memories: Array<{
|
|
133
|
+
content: string;
|
|
134
|
+
type?: string;
|
|
135
|
+
emotion?: string;
|
|
136
|
+
emotionWeight?: number;
|
|
137
|
+
context?: string;
|
|
138
|
+
}>;
|
|
139
|
+
},
|
|
140
|
+
defaultContext?: string | null,
|
|
141
|
+
): ToolResult {
|
|
142
|
+
const ids: string[] = [];
|
|
143
|
+
const errors: string[] = [];
|
|
144
|
+
|
|
145
|
+
storage.transaction(() => {
|
|
146
|
+
for (let i = 0; i < args.memories.length; i++) {
|
|
147
|
+
const m = args.memories[i]!;
|
|
148
|
+
const typeStr = m.type ?? "semantic";
|
|
149
|
+
if (!isValidMemoryType(typeStr)) {
|
|
150
|
+
errors.push(`[${i}] Invalid type '${typeStr}'`);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const emotionStr = m.emotion ?? "neutral";
|
|
154
|
+
if (!isValidEmotion(emotionStr)) {
|
|
155
|
+
errors.push(`[${i}] Invalid emotion '${emotionStr}'`);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const memory = encode(
|
|
159
|
+
storage,
|
|
160
|
+
{
|
|
161
|
+
content: m.content,
|
|
162
|
+
type: typeStr,
|
|
163
|
+
emotion: emotionStr,
|
|
164
|
+
emotionWeight: m.emotionWeight,
|
|
165
|
+
context: m.context ?? defaultContext ?? undefined,
|
|
166
|
+
},
|
|
167
|
+
config,
|
|
168
|
+
);
|
|
169
|
+
ids.push(memory.id);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
if (errors.length > 0) {
|
|
174
|
+
return textResult(JSON.stringify({ stored: ids, errors }));
|
|
175
|
+
}
|
|
176
|
+
return textResult(JSON.stringify({ stored: ids }));
|
|
130
177
|
}
|
|
131
178
|
|
|
132
179
|
function handleRecallQuery(
|
|
@@ -139,6 +186,7 @@ function handleRecallQuery(
|
|
|
139
186
|
context?: string;
|
|
140
187
|
associative?: boolean;
|
|
141
188
|
verbose?: boolean;
|
|
189
|
+
format?: "full" | "content" | "ids";
|
|
142
190
|
},
|
|
143
191
|
defaultContext?: string | null,
|
|
144
192
|
): ToolResult {
|
|
@@ -155,6 +203,15 @@ function handleRecallQuery(
|
|
|
155
203
|
return textResult("No memories found above retrieval threshold.");
|
|
156
204
|
}
|
|
157
205
|
|
|
206
|
+
const format = args.format ?? "full";
|
|
207
|
+
|
|
208
|
+
if (format === "ids") {
|
|
209
|
+
return textResult(JSON.stringify(results.map((r) => r.memory.id)));
|
|
210
|
+
}
|
|
211
|
+
if (format === "content") {
|
|
212
|
+
return textResult(JSON.stringify(results.map((r) => r.memory.content)));
|
|
213
|
+
}
|
|
214
|
+
|
|
158
215
|
const formatted = args.verbose
|
|
159
216
|
? results.map((r) => ({
|
|
160
217
|
id: r.memory.id,
|
|
@@ -178,6 +235,56 @@ function handleRecallQuery(
|
|
|
178
235
|
return textResult(JSON.stringify(formatted));
|
|
179
236
|
}
|
|
180
237
|
|
|
238
|
+
function handleList(
|
|
239
|
+
storage: EngramStorage,
|
|
240
|
+
args: {
|
|
241
|
+
type?: string;
|
|
242
|
+
context?: string;
|
|
243
|
+
limit?: number;
|
|
244
|
+
offset?: number;
|
|
245
|
+
format?: "full" | "content" | "ids";
|
|
246
|
+
},
|
|
247
|
+
defaultContext?: string | null,
|
|
248
|
+
): ToolResult {
|
|
249
|
+
const limit = args.limit ?? 20;
|
|
250
|
+
const offset = args.offset ?? 0;
|
|
251
|
+
const typeFilter = args.type && isValidMemoryType(args.type) ? args.type : undefined;
|
|
252
|
+
const context = args.context ?? defaultContext ?? undefined;
|
|
253
|
+
|
|
254
|
+
let results;
|
|
255
|
+
if (context) {
|
|
256
|
+
results = storage.getMemoriesByContext(context, typeFilter, limit + offset);
|
|
257
|
+
} else {
|
|
258
|
+
results = storage.getAllMemories(typeFilter).slice(0, limit + offset);
|
|
259
|
+
}
|
|
260
|
+
results = results.slice(offset, offset + limit);
|
|
261
|
+
|
|
262
|
+
if (results.length === 0) {
|
|
263
|
+
return textResult("No memories found.");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const format = args.format ?? "full";
|
|
267
|
+
|
|
268
|
+
if (format === "ids") {
|
|
269
|
+
return textResult(JSON.stringify(results.map((m) => m.id)));
|
|
270
|
+
}
|
|
271
|
+
if (format === "content") {
|
|
272
|
+
return textResult(JSON.stringify(results.map((m) => m.content)));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return textResult(
|
|
276
|
+
JSON.stringify(
|
|
277
|
+
results.map((m) => ({
|
|
278
|
+
id: m.id,
|
|
279
|
+
content: m.content,
|
|
280
|
+
type: m.type,
|
|
281
|
+
context: m.context,
|
|
282
|
+
activation: m.activation,
|
|
283
|
+
})),
|
|
284
|
+
),
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
181
288
|
function handleFocusPush(
|
|
182
289
|
storage: EngramStorage,
|
|
183
290
|
config: CognitiveConfig,
|
|
@@ -222,6 +329,34 @@ function handleFocusClear(storage: EngramStorage): ToolResult {
|
|
|
222
329
|
return textResult(`Cleared ${count} items from working memory.`);
|
|
223
330
|
}
|
|
224
331
|
|
|
332
|
+
function handleRecallToFocus(
|
|
333
|
+
storage: EngramStorage,
|
|
334
|
+
config: CognitiveConfig,
|
|
335
|
+
args: { cue: string; limit?: number; type?: string; context?: string },
|
|
336
|
+
defaultContext?: string | null,
|
|
337
|
+
): ToolResult {
|
|
338
|
+
const typeFilter = args.type && isValidMemoryType(args.type) ? args.type : undefined;
|
|
339
|
+
const limit = args.limit ?? 3;
|
|
340
|
+
|
|
341
|
+
const results = recall(storage, args.cue, config, {
|
|
342
|
+
limit,
|
|
343
|
+
type: typeFilter,
|
|
344
|
+
context: args.context ?? defaultContext ?? undefined,
|
|
345
|
+
associative: true,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const loaded: string[] = [];
|
|
349
|
+
for (const r of results) {
|
|
350
|
+
pushFocus(storage, r.memory.content, config, {
|
|
351
|
+
memoryRef: r.memory.id,
|
|
352
|
+
});
|
|
353
|
+
loaded.push(r.memory.id);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const { used, capacity } = focusUtilization(storage, config);
|
|
357
|
+
return textResult(JSON.stringify({ loaded, focus: { used, capacity } }));
|
|
358
|
+
}
|
|
359
|
+
|
|
225
360
|
function handleConsolidate(storage: EngramStorage, config: CognitiveConfig): ToolResult {
|
|
226
361
|
const result = consolidate(storage, config);
|
|
227
362
|
const chunks = discoverChunks(storage, config);
|
|
@@ -324,9 +459,6 @@ function handleReconsolidate(
|
|
|
324
459
|
return textResult(
|
|
325
460
|
JSON.stringify({
|
|
326
461
|
id: updated.id,
|
|
327
|
-
content: updated.content,
|
|
328
|
-
emotion: updated.emotion,
|
|
329
|
-
emotionWeight: updated.emotionWeight,
|
|
330
462
|
context: updated.context,
|
|
331
463
|
reconsolidationCount: updated.reconsolidationCount,
|
|
332
464
|
}),
|