@199-bio/engram 0.4.2 → 0.5.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/dist/consolidation/consolidator.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/storage/database.d.ts.map +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/consolidation/consolidator.ts +349 -0
- package/src/index.ts +1 -1
- package/src/storage/database.ts +265 -3
- package/src/web/server.ts +105 -0
- package/src/web/static/app.js +222 -3
- package/src/web/static/index.html +49 -1
- package/src/web/static/style.css +201 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidator.d.ts","sourceRoot":"","sources":["../../src/consolidation/consolidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,cAAc,EAAU,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAoCxE,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,EAAE,CAAiB;gBAEf,EAAE,EAAE,cAAc;IAS9B,YAAY,IAAI,OAAO;IAIvB;;;OAGG;IACG,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC;QAC3D,cAAc,EAAE,MAAM,CAAC;QACvB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;IAwEF;;OAEG;YACW,gBAAgB;IA4D9B;;OAEG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA8GjE;;OAEG;IACH,SAAS,IAAI;QACX,UAAU,EAAE,OAAO,CAAC;QACpB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC;QACrB,wBAAwB,EAAE,MAAM,CAAC;KAClC;CAYF"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,cAAc,CAAC;IAChE,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,IAAI,CAAC;IACjB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3C,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,SAAS,CAA8C;gBAEnD,MAAM,EAAE,MAAM;IAoB1B,OAAO,CAAC,UAAU;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"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"}
|
package/dist/web/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAkBtD,UAAU,gBAAgB;IACxB,EAAE,EAAE,cAAc,CAAC;IACnB,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,IAAI,CAAS;gBAET,OAAO,EAAE,gBAAgB;IAa/B,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAkB9B,IAAI,IAAI,IAAI;YAOE,aAAa;YA+Bb,SAAS;YA8ST,WAAW;IAgCzB,OAAO,CAAC,SAAS;CAclB"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Consolidator
|
|
3
|
+
*
|
|
4
|
+
* Uses Opus 4.5 with extended thinking to consolidate memories into digests
|
|
5
|
+
* and detect contradictions. Inspired by how the brain consolidates
|
|
6
|
+
* short-term memories into long-term storage during sleep.
|
|
7
|
+
*
|
|
8
|
+
* Levels:
|
|
9
|
+
* - L1: Session digests (consolidate recent memories)
|
|
10
|
+
* - L2: Topic clusters (group related digests)
|
|
11
|
+
* - L3: Entity profiles (comprehensive view of each entity)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
15
|
+
import { EngramDatabase, Memory, Digest } from "../storage/database.js";
|
|
16
|
+
|
|
17
|
+
const CONSOLIDATION_SYSTEM = `You are a memory consolidation system. Your job is to:
|
|
18
|
+
|
|
19
|
+
1. CONSOLIDATE: Take a batch of related memories and produce a concise summary that preserves all important facts, dates, names, and relationships. Be factual and precise.
|
|
20
|
+
|
|
21
|
+
2. DETECT CONTRADICTIONS: If any memories contain conflicting information (e.g., different ages, dates, locations, or facts about the same topic), identify them clearly.
|
|
22
|
+
|
|
23
|
+
Output JSON with this structure:
|
|
24
|
+
{
|
|
25
|
+
"digest": "Your consolidated summary here. Include all key facts, dates, names. Be concise but complete.",
|
|
26
|
+
"topic": "A short topic label (2-5 words)",
|
|
27
|
+
"contradictions": [
|
|
28
|
+
{
|
|
29
|
+
"description": "Clear description of the contradiction",
|
|
30
|
+
"memory_ids": ["id1", "id2"]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Rules:
|
|
36
|
+
- Preserve specific details: names, numbers, dates, locations
|
|
37
|
+
- Use present tense for current facts, past tense for past events
|
|
38
|
+
- If memories are about a person, structure the digest around that person
|
|
39
|
+
- Only flag true contradictions (not just incomplete information)
|
|
40
|
+
- Be concise - consolidate 10 memories into 2-3 sentences typically`;
|
|
41
|
+
|
|
42
|
+
interface ConsolidationResult {
|
|
43
|
+
digest: string;
|
|
44
|
+
topic: string;
|
|
45
|
+
contradictions: Array<{
|
|
46
|
+
description: string;
|
|
47
|
+
memory_ids: string[];
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface ConsolidateOptions {
|
|
52
|
+
batchSize?: number;
|
|
53
|
+
minMemoriesForConsolidation?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class Consolidator {
|
|
57
|
+
private client: Anthropic | null = null;
|
|
58
|
+
private db: EngramDatabase;
|
|
59
|
+
|
|
60
|
+
constructor(db: EngramDatabase) {
|
|
61
|
+
this.db = db;
|
|
62
|
+
|
|
63
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
64
|
+
if (apiKey) {
|
|
65
|
+
this.client = new Anthropic({ apiKey });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
isConfigured(): boolean {
|
|
70
|
+
return this.client !== null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Run consolidation on unconsolidated memories
|
|
75
|
+
* Returns number of digests created and contradictions found
|
|
76
|
+
*/
|
|
77
|
+
async consolidate(options: ConsolidateOptions = {}): Promise<{
|
|
78
|
+
digestsCreated: number;
|
|
79
|
+
contradictionsFound: number;
|
|
80
|
+
memoriesProcessed: number;
|
|
81
|
+
}> {
|
|
82
|
+
if (!this.client) {
|
|
83
|
+
throw new Error("Consolidator not configured - set ANTHROPIC_API_KEY");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const { batchSize = 15, minMemoriesForConsolidation = 5 } = options;
|
|
87
|
+
|
|
88
|
+
// Get unconsolidated memories
|
|
89
|
+
const memories = this.db.getUnconsolidatedMemories(undefined, 100);
|
|
90
|
+
|
|
91
|
+
if (memories.length < minMemoriesForConsolidation) {
|
|
92
|
+
return {
|
|
93
|
+
digestsCreated: 0,
|
|
94
|
+
contradictionsFound: 0,
|
|
95
|
+
memoriesProcessed: 0,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let digestsCreated = 0;
|
|
100
|
+
let contradictionsFound = 0;
|
|
101
|
+
let memoriesProcessed = 0;
|
|
102
|
+
|
|
103
|
+
// Process in batches
|
|
104
|
+
for (let i = 0; i < memories.length; i += batchSize) {
|
|
105
|
+
const batch = memories.slice(i, i + batchSize);
|
|
106
|
+
if (batch.length < 3) break; // Skip tiny batches
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const result = await this.consolidateBatch(batch);
|
|
110
|
+
|
|
111
|
+
if (result) {
|
|
112
|
+
// Create digest
|
|
113
|
+
const memoryIds = batch.map((m) => m.id);
|
|
114
|
+
const periodStart = new Date(
|
|
115
|
+
Math.min(...batch.map((m) => m.timestamp.getTime()))
|
|
116
|
+
);
|
|
117
|
+
const periodEnd = new Date(
|
|
118
|
+
Math.max(...batch.map((m) => m.timestamp.getTime()))
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
this.db.createDigest(result.digest, 1, memoryIds, {
|
|
122
|
+
topic: result.topic,
|
|
123
|
+
periodStart,
|
|
124
|
+
periodEnd,
|
|
125
|
+
});
|
|
126
|
+
digestsCreated++;
|
|
127
|
+
memoriesProcessed += batch.length;
|
|
128
|
+
|
|
129
|
+
// Create contradictions
|
|
130
|
+
for (const c of result.contradictions) {
|
|
131
|
+
if (c.memory_ids.length >= 2) {
|
|
132
|
+
// Find the actual memory IDs from our batch
|
|
133
|
+
const [idA, idB] = c.memory_ids.slice(0, 2);
|
|
134
|
+
const memA = batch.find((m) => m.id === idA);
|
|
135
|
+
const memB = batch.find((m) => m.id === idB);
|
|
136
|
+
|
|
137
|
+
if (memA && memB) {
|
|
138
|
+
this.db.createContradiction(memA.id, memB.id, c.description);
|
|
139
|
+
contradictionsFound++;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error("[Consolidator] Batch consolidation failed:", error);
|
|
146
|
+
// Continue with next batch
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { digestsCreated, contradictionsFound, memoriesProcessed };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Consolidate a batch of memories using Opus 4.5 with extended thinking
|
|
155
|
+
*/
|
|
156
|
+
private async consolidateBatch(
|
|
157
|
+
memories: Memory[]
|
|
158
|
+
): Promise<ConsolidationResult | null> {
|
|
159
|
+
if (!this.client) return null;
|
|
160
|
+
|
|
161
|
+
// Format memories for the prompt
|
|
162
|
+
const memoriesText = memories
|
|
163
|
+
.map(
|
|
164
|
+
(m) =>
|
|
165
|
+
`[${m.id}] (${m.timestamp.toISOString().split("T")[0]}) ${m.content}`
|
|
166
|
+
)
|
|
167
|
+
.join("\n\n");
|
|
168
|
+
|
|
169
|
+
const userPrompt = `Consolidate these ${memories.length} memories into a single digest. Identify any contradictions.
|
|
170
|
+
|
|
171
|
+
MEMORIES:
|
|
172
|
+
${memoriesText}
|
|
173
|
+
|
|
174
|
+
Respond with JSON only.`;
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
const response = await this.client.messages.create({
|
|
178
|
+
model: "claude-opus-4-5-20251101",
|
|
179
|
+
max_tokens: 16000,
|
|
180
|
+
thinking: {
|
|
181
|
+
type: "enabled",
|
|
182
|
+
budget_tokens: 4000,
|
|
183
|
+
},
|
|
184
|
+
messages: [
|
|
185
|
+
{
|
|
186
|
+
role: "user",
|
|
187
|
+
content: userPrompt,
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
system: CONSOLIDATION_SYSTEM,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Extract text response (skip thinking blocks)
|
|
194
|
+
let text = "";
|
|
195
|
+
for (const block of response.content) {
|
|
196
|
+
if (block.type === "text") {
|
|
197
|
+
text = block.text;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!text) return null;
|
|
203
|
+
|
|
204
|
+
// Parse JSON response
|
|
205
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
206
|
+
if (!jsonMatch) return null;
|
|
207
|
+
|
|
208
|
+
const result = JSON.parse(jsonMatch[0]) as ConsolidationResult;
|
|
209
|
+
return result;
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error("[Consolidator] API call failed:", error);
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Create an entity profile by consolidating all observations about an entity
|
|
218
|
+
*/
|
|
219
|
+
async consolidateEntity(entityId: string): Promise<Digest | null> {
|
|
220
|
+
if (!this.client) {
|
|
221
|
+
throw new Error("Consolidator not configured - set ANTHROPIC_API_KEY");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const entity = this.db.getEntity(entityId);
|
|
225
|
+
if (!entity) return null;
|
|
226
|
+
|
|
227
|
+
const observations = this.db.getEntityObservations(entityId);
|
|
228
|
+
if (observations.length < 2) return null;
|
|
229
|
+
|
|
230
|
+
// Get source memories for each observation
|
|
231
|
+
const memories: Memory[] = [];
|
|
232
|
+
for (const obs of observations) {
|
|
233
|
+
if (obs.source_memory_id) {
|
|
234
|
+
const mem = this.db.getMemory(obs.source_memory_id);
|
|
235
|
+
if (mem) memories.push(mem);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (memories.length < 2) return null;
|
|
240
|
+
|
|
241
|
+
// Consolidate with entity context
|
|
242
|
+
const memoriesText = memories
|
|
243
|
+
.map(
|
|
244
|
+
(m) =>
|
|
245
|
+
`[${m.id}] (${m.timestamp.toISOString().split("T")[0]}) ${m.content}`
|
|
246
|
+
)
|
|
247
|
+
.join("\n\n");
|
|
248
|
+
|
|
249
|
+
const userPrompt = `Create a comprehensive profile for the entity "${entity.name}" (${entity.type}) based on these memories. Include all known facts, relationships, preferences, and history.
|
|
250
|
+
|
|
251
|
+
MEMORIES ABOUT ${entity.name}:
|
|
252
|
+
${memoriesText}
|
|
253
|
+
|
|
254
|
+
Respond with JSON only.`;
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
const response = await this.client.messages.create({
|
|
258
|
+
model: "claude-opus-4-5-20251101",
|
|
259
|
+
max_tokens: 16000,
|
|
260
|
+
thinking: {
|
|
261
|
+
type: "enabled",
|
|
262
|
+
budget_tokens: 6000,
|
|
263
|
+
},
|
|
264
|
+
messages: [
|
|
265
|
+
{
|
|
266
|
+
role: "user",
|
|
267
|
+
content: userPrompt,
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
system: CONSOLIDATION_SYSTEM,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
let text = "";
|
|
274
|
+
for (const block of response.content) {
|
|
275
|
+
if (block.type === "text") {
|
|
276
|
+
text = block.text;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (!text) return null;
|
|
282
|
+
|
|
283
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
284
|
+
if (!jsonMatch) return null;
|
|
285
|
+
|
|
286
|
+
const result = JSON.parse(jsonMatch[0]) as ConsolidationResult;
|
|
287
|
+
|
|
288
|
+
// Create level 3 entity profile digest
|
|
289
|
+
const memoryIds = memories.map((m) => m.id);
|
|
290
|
+
const periodStart = new Date(
|
|
291
|
+
Math.min(...memories.map((m) => m.timestamp.getTime()))
|
|
292
|
+
);
|
|
293
|
+
const periodEnd = new Date(
|
|
294
|
+
Math.max(...memories.map((m) => m.timestamp.getTime()))
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const digest = this.db.createDigest(result.digest, 3, memoryIds, {
|
|
298
|
+
topic: `Profile: ${entity.name}`,
|
|
299
|
+
entityId: entity.id,
|
|
300
|
+
periodStart,
|
|
301
|
+
periodEnd,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// Record any contradictions
|
|
305
|
+
for (const c of result.contradictions) {
|
|
306
|
+
if (c.memory_ids.length >= 2) {
|
|
307
|
+
const [idA, idB] = c.memory_ids.slice(0, 2);
|
|
308
|
+
const memA = memories.find((m) => m.id === idA);
|
|
309
|
+
const memB = memories.find((m) => m.id === idB);
|
|
310
|
+
|
|
311
|
+
if (memA && memB) {
|
|
312
|
+
this.db.createContradiction(
|
|
313
|
+
memA.id,
|
|
314
|
+
memB.id,
|
|
315
|
+
c.description,
|
|
316
|
+
entity.id
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return digest;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.error("[Consolidator] Entity profile failed:", error);
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Get consolidation status
|
|
331
|
+
*/
|
|
332
|
+
getStatus(): {
|
|
333
|
+
configured: boolean;
|
|
334
|
+
unconsolidatedMemories: number;
|
|
335
|
+
totalDigests: number;
|
|
336
|
+
unresolvedContradictions: number;
|
|
337
|
+
} {
|
|
338
|
+
const unconsolidated = this.db.getUnconsolidatedMemories(undefined, 1000);
|
|
339
|
+
const digests = this.db.getDigests(undefined, 1000);
|
|
340
|
+
const contradictions = this.db.getContradictions(false, 1000);
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
configured: this.isConfigured(),
|
|
344
|
+
unconsolidatedMemories: unconsolidated.length,
|
|
345
|
+
totalDigests: digests.length,
|
|
346
|
+
unresolvedContradictions: contradictions.length,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
}
|