mnemocyte 0.0.3 → 0.0.5
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 +95 -8
- package/dist/index.d.mts +39 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +206 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,16 +1,103 @@
|
|
|
1
|
+
# Mnemocyte
|
|
2
|
+
|
|
3
|
+
Persistent memory for TypeScript AI apps.
|
|
4
|
+
|
|
1
5
|
> Warning
|
|
2
6
|
>
|
|
3
|
-
> Mnemocyte is in active early development.
|
|
4
|
-
> APIs may change significantly before v1.0.
|
|
5
|
-
>
|
|
6
|
-
> The package is currently being built in public.
|
|
7
|
+
> Mnemocyte is in active early development. APIs may change significantly before v1.0.
|
|
7
8
|
|
|
8
9
|
## Current status
|
|
9
10
|
|
|
10
|
-
Mnemocyte
|
|
11
|
-
|
|
11
|
+
Mnemocyte currently provides an MVP API with two backends:
|
|
12
|
+
|
|
13
|
+
- **In-memory backend** when `databaseUrl` is omitted.
|
|
14
|
+
- **Postgres + pgvector backend** when `databaseUrl` is provided.
|
|
12
15
|
|
|
13
16
|
The package is ESM-only. Use `import` rather than CommonJS `require`.
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add mnemocyte
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Basic usage
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { createMnemocyte } from "mnemocyte";
|
|
28
|
+
|
|
29
|
+
const client = createMnemocyte({
|
|
30
|
+
embedder: {
|
|
31
|
+
model: "demo",
|
|
32
|
+
dimensions: 3,
|
|
33
|
+
async embed(texts) {
|
|
34
|
+
return texts.map((text) => [text.length, 1, 0]);
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await client.remember({
|
|
40
|
+
entityId: "user_123",
|
|
41
|
+
content: "Prefers short, direct answers.",
|
|
42
|
+
type: "preference",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const memories = await client.recall({
|
|
46
|
+
entityId: "user_123",
|
|
47
|
+
query: "How should I respond?",
|
|
48
|
+
limit: 5,
|
|
49
|
+
explain: true,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await client.close();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Postgres usage
|
|
56
|
+
|
|
57
|
+
Run the included migration against a Postgres database with pgvector enabled, then pass `databaseUrl`:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const client = createMnemocyte({
|
|
61
|
+
databaseUrl: process.env.DATABASE_URL,
|
|
62
|
+
embedder,
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The published package includes `migrations/0000_initial.sql`.
|
|
67
|
+
|
|
68
|
+
## Retrieval tuning
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const client = createMnemocyte({
|
|
72
|
+
embedder,
|
|
73
|
+
retrieval: {
|
|
74
|
+
weights: {
|
|
75
|
+
vector: 0.55,
|
|
76
|
+
lexical: 0.2,
|
|
77
|
+
recency: 0.1,
|
|
78
|
+
confidence: 0.05,
|
|
79
|
+
access: 0.05,
|
|
80
|
+
importance: 0.05,
|
|
81
|
+
},
|
|
82
|
+
recencyHalfLifeDays: 90,
|
|
83
|
+
accessSaturation: 10,
|
|
84
|
+
candidateMultiplier: 3,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Development checks
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pnpm checktypes
|
|
93
|
+
pnpm lint
|
|
94
|
+
pnpm run test:retrieval
|
|
95
|
+
pnpm run test:integration
|
|
96
|
+
pnpm pack --dry-run
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`test:integration` skips cleanly when `DATABASE_URL` is not set.
|
|
100
|
+
|
|
101
|
+
## Architecture
|
|
102
|
+
|
|
103
|
+
See `ARCHITECTURE.md` for the canonical architecture, roadmap, and production plan.
|
package/dist/index.d.mts
CHANGED
|
@@ -9,6 +9,7 @@ interface MnemocyteConfig {
|
|
|
9
9
|
limit?: number;
|
|
10
10
|
minScore?: number;
|
|
11
11
|
};
|
|
12
|
+
retrieval?: RetrievalConfig;
|
|
12
13
|
}
|
|
13
14
|
interface Embedder {
|
|
14
15
|
readonly model: string;
|
|
@@ -38,12 +39,33 @@ interface RetrievalScores {
|
|
|
38
39
|
vector: number;
|
|
39
40
|
lexical: number;
|
|
40
41
|
recency: number;
|
|
42
|
+
confidence: number;
|
|
43
|
+
access: number;
|
|
44
|
+
importance: number;
|
|
45
|
+
}
|
|
46
|
+
interface RetrievalScoreWeights {
|
|
47
|
+
vector?: number;
|
|
48
|
+
lexical?: number;
|
|
49
|
+
recency?: number;
|
|
50
|
+
confidence?: number;
|
|
51
|
+
access?: number;
|
|
52
|
+
importance?: number;
|
|
53
|
+
}
|
|
54
|
+
interface RetrievalConfig {
|
|
55
|
+
weights?: RetrievalScoreWeights;
|
|
56
|
+
recencyHalfLifeDays?: number;
|
|
57
|
+
accessSaturation?: number;
|
|
58
|
+
candidateMultiplier?: number;
|
|
41
59
|
}
|
|
42
60
|
interface RetrievalExplanation {
|
|
43
61
|
vectorScore: number;
|
|
44
62
|
lexicalScore: number;
|
|
45
63
|
recencyScore: number;
|
|
64
|
+
confidenceScore: number;
|
|
65
|
+
accessScore: number;
|
|
66
|
+
importanceScore: number;
|
|
46
67
|
importanceBoost: number;
|
|
68
|
+
weights: Required<RetrievalScoreWeights>;
|
|
47
69
|
finalScore: number;
|
|
48
70
|
}
|
|
49
71
|
interface MemoryWithScore extends Memory {
|
|
@@ -75,6 +97,22 @@ interface RecallInput {
|
|
|
75
97
|
includeExpired?: boolean;
|
|
76
98
|
explain?: boolean;
|
|
77
99
|
}
|
|
100
|
+
interface TokenCounter {
|
|
101
|
+
count(text: string): number;
|
|
102
|
+
}
|
|
103
|
+
interface BuildContextInput {
|
|
104
|
+
entityId: string;
|
|
105
|
+
query: string;
|
|
106
|
+
format?: ContextFormat;
|
|
107
|
+
maxTokens?: number;
|
|
108
|
+
limit?: number;
|
|
109
|
+
minScore?: number;
|
|
110
|
+
types?: MemoryType[];
|
|
111
|
+
tags?: string[];
|
|
112
|
+
includeSuperseded?: boolean;
|
|
113
|
+
includeExpired?: boolean;
|
|
114
|
+
tokenCounter?: TokenCounter;
|
|
115
|
+
}
|
|
78
116
|
interface EntityStats {
|
|
79
117
|
entityId: string;
|
|
80
118
|
memoryCount: number;
|
|
@@ -93,6 +131,7 @@ interface MnemocyteClient {
|
|
|
93
131
|
remember(input: RememberInput): Promise<Memory>;
|
|
94
132
|
rememberMany(inputs: readonly RememberInput[]): Promise<Memory[]>;
|
|
95
133
|
recall(input: RecallInput): Promise<MemoryWithScore[]>;
|
|
134
|
+
buildContext(input: BuildContextInput): Promise<string>;
|
|
96
135
|
forget(input: {
|
|
97
136
|
entityId: string;
|
|
98
137
|
memoryId: string;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/client.ts","../src/errors.ts"],"mappings":";KAAY,UAAA;AAAA,KAQA,eAAA;AAAA,KAEA,aAAA;AAAA,UAEK,eAAA;EAChB,WAAA;EACA,QAAA,EAAU,QAAA;EACV,QAAA;IACC,KAAA;IACA,QAAA;EAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/client.ts","../src/errors.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -74,6 +74,84 @@ function createDatabase(databaseUrl) {
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
//#endregion
|
|
77
|
+
//#region src/context/formatter.ts
|
|
78
|
+
function escapeXml(value) {
|
|
79
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'");
|
|
80
|
+
}
|
|
81
|
+
function formatMetadata(memory) {
|
|
82
|
+
const parts = [
|
|
83
|
+
`type=${memory.type}`,
|
|
84
|
+
`importance=${memory.importance}`,
|
|
85
|
+
`score=${memory.score.toFixed(3)}`
|
|
86
|
+
];
|
|
87
|
+
if (memory.source) parts.push(`source=${memory.source}`);
|
|
88
|
+
if (memory.tags.length > 0) parts.push(`tags=${memory.tags.join(",")}`);
|
|
89
|
+
return parts.join("; ");
|
|
90
|
+
}
|
|
91
|
+
function formatMarkdown(memories, query) {
|
|
92
|
+
const lines = [
|
|
93
|
+
"# Memory Context",
|
|
94
|
+
"",
|
|
95
|
+
`Query: ${query}`,
|
|
96
|
+
"",
|
|
97
|
+
"## Relevant Memories"
|
|
98
|
+
];
|
|
99
|
+
for (const memory of memories) lines.push("", `- ${memory.content}`, ` - ${formatMetadata(memory)}`);
|
|
100
|
+
return lines.join("\n");
|
|
101
|
+
}
|
|
102
|
+
function formatPlain(memories, query) {
|
|
103
|
+
const lines = [
|
|
104
|
+
"MEMORY CONTEXT",
|
|
105
|
+
"",
|
|
106
|
+
`QUERY: ${query}`,
|
|
107
|
+
"",
|
|
108
|
+
"RELEVANT MEMORIES"
|
|
109
|
+
];
|
|
110
|
+
for (const memory of memories) lines.push("", memory.content, formatMetadata(memory));
|
|
111
|
+
return lines.join("\n");
|
|
112
|
+
}
|
|
113
|
+
function formatXml(memories, query) {
|
|
114
|
+
const lines = [`<memory_context query="${escapeXml(query)}">`];
|
|
115
|
+
for (const memory of memories) lines.push(` <memory id="${escapeXml(memory.id)}" type="${escapeXml(memory.type)}" importance="${escapeXml(memory.importance)}" score="${memory.score.toFixed(3)}">`, ` <content>${escapeXml(memory.content)}</content>`, ` <metadata>${escapeXml(formatMetadata(memory))}</metadata>`, " </memory>");
|
|
116
|
+
lines.push("</memory_context>");
|
|
117
|
+
return lines.join("\n");
|
|
118
|
+
}
|
|
119
|
+
function formatContext(memories, query, format) {
|
|
120
|
+
switch (format) {
|
|
121
|
+
case "markdown": return formatMarkdown(memories, query);
|
|
122
|
+
case "plain": return formatPlain(memories, query);
|
|
123
|
+
case "xml": return formatXml(memories, query);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/context/tokens.ts
|
|
128
|
+
const heuristicTokenCounter = { count(text) {
|
|
129
|
+
return Math.ceil(text.length / 4);
|
|
130
|
+
} };
|
|
131
|
+
function trimToTokenBudget(text, maxTokens, tokenCounter) {
|
|
132
|
+
if (maxTokens < 1 || tokenCounter.count(text) <= maxTokens) return text;
|
|
133
|
+
let low = 0;
|
|
134
|
+
let high = text.length;
|
|
135
|
+
let best = "";
|
|
136
|
+
while (low <= high) {
|
|
137
|
+
const mid = Math.floor((low + high) / 2);
|
|
138
|
+
const output = `${text.slice(0, mid).trimEnd()}\n[truncated to fit token budget]`;
|
|
139
|
+
if (tokenCounter.count(output) <= maxTokens) {
|
|
140
|
+
best = output;
|
|
141
|
+
low = mid + 1;
|
|
142
|
+
} else high = mid - 1;
|
|
143
|
+
}
|
|
144
|
+
return best || "[truncated to fit token budget]";
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/context/builder.ts
|
|
148
|
+
async function buildContext(options) {
|
|
149
|
+
const format = options.input.format ?? "markdown";
|
|
150
|
+
const maxTokens = options.input.maxTokens ?? 1200;
|
|
151
|
+
const tokenCounter = options.input.tokenCounter ?? heuristicTokenCounter;
|
|
152
|
+
return trimToTokenBudget(formatContext(await options.recall(options.input), options.input.query, format), maxTokens, tokenCounter);
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
77
155
|
//#region src/errors.ts
|
|
78
156
|
var MnemocyteError = class extends Error {
|
|
79
157
|
code;
|
|
@@ -164,6 +242,18 @@ function validateRecallInput(input) {
|
|
|
164
242
|
if (input.limit !== void 0) assertLimit(input.limit);
|
|
165
243
|
if (input.minScore !== void 0) assertMinScore(input.minScore);
|
|
166
244
|
}
|
|
245
|
+
function contextInputToRecallInput(input) {
|
|
246
|
+
return {
|
|
247
|
+
entityId: input.entityId,
|
|
248
|
+
query: input.query,
|
|
249
|
+
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
250
|
+
...input.minScore === void 0 ? {} : { minScore: input.minScore },
|
|
251
|
+
...input.types === void 0 ? {} : { types: input.types },
|
|
252
|
+
...input.tags === void 0 ? {} : { tags: input.tags },
|
|
253
|
+
...input.includeSuperseded === void 0 ? {} : { includeSuperseded: input.includeSuperseded },
|
|
254
|
+
...input.includeExpired === void 0 ? {} : { includeExpired: input.includeExpired }
|
|
255
|
+
};
|
|
256
|
+
}
|
|
167
257
|
function matchesRecallFilter(memory, input, now) {
|
|
168
258
|
if (memory.entityId !== input.entityId) return false;
|
|
169
259
|
if (!input.includeSuperseded && memory.supersededBy !== null) return false;
|
|
@@ -176,12 +266,22 @@ function matchesRecallFilter(memory, input, now) {
|
|
|
176
266
|
}
|
|
177
267
|
//#endregion
|
|
178
268
|
//#region src/retrieval/scorer.ts
|
|
179
|
-
const
|
|
180
|
-
low:
|
|
181
|
-
normal:
|
|
182
|
-
high: .
|
|
183
|
-
critical:
|
|
269
|
+
const IMPORTANCE_SCORES = {
|
|
270
|
+
low: 0,
|
|
271
|
+
normal: .5,
|
|
272
|
+
high: .8,
|
|
273
|
+
critical: 1
|
|
274
|
+
};
|
|
275
|
+
const DEFAULT_WEIGHTS = {
|
|
276
|
+
vector: .55,
|
|
277
|
+
lexical: .2,
|
|
278
|
+
recency: .1,
|
|
279
|
+
confidence: .05,
|
|
280
|
+
access: .05,
|
|
281
|
+
importance: .05
|
|
184
282
|
};
|
|
283
|
+
const DEFAULT_RECENCY_HALF_LIFE_DAYS = 90;
|
|
284
|
+
const DEFAULT_ACCESS_SATURATION = 10;
|
|
185
285
|
function cosineSimilarity(a, b) {
|
|
186
286
|
let dot = 0;
|
|
187
287
|
let aMagnitude = 0;
|
|
@@ -202,28 +302,62 @@ function lexicalScore(content, query) {
|
|
|
202
302
|
const lowerContent = content.toLowerCase();
|
|
203
303
|
return terms.filter((term) => lowerContent.includes(term)).length / terms.length;
|
|
204
304
|
}
|
|
205
|
-
function
|
|
305
|
+
function clampScore(value) {
|
|
306
|
+
if (!Number.isFinite(value)) return 0;
|
|
307
|
+
return Math.max(0, Math.min(1, value));
|
|
308
|
+
}
|
|
309
|
+
function normalizeWeights(weights) {
|
|
310
|
+
const merged = {
|
|
311
|
+
...DEFAULT_WEIGHTS,
|
|
312
|
+
...weights
|
|
313
|
+
};
|
|
314
|
+
const total = merged.vector + merged.lexical + merged.recency + merged.confidence + merged.access + merged.importance;
|
|
315
|
+
if (total <= 0) return DEFAULT_WEIGHTS;
|
|
316
|
+
return {
|
|
317
|
+
vector: merged.vector / total,
|
|
318
|
+
lexical: merged.lexical / total,
|
|
319
|
+
recency: merged.recency / total,
|
|
320
|
+
confidence: merged.confidence / total,
|
|
321
|
+
access: merged.access / total,
|
|
322
|
+
importance: merged.importance / total
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function recencyScore(createdAt, halfLifeDays) {
|
|
206
326
|
const ageMs = Date.now() - createdAt.getTime();
|
|
207
327
|
const ageDays = Math.max(0, ageMs / 864e5);
|
|
208
|
-
return Math.exp(-Math.LN2 * ageDays /
|
|
328
|
+
return Math.exp(-Math.LN2 * ageDays / halfLifeDays);
|
|
209
329
|
}
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
330
|
+
function accessScore(accessCount, saturation) {
|
|
331
|
+
if (accessCount <= 0) return 0;
|
|
332
|
+
return Math.min(1, Math.log1p(accessCount) / Math.log1p(saturation));
|
|
333
|
+
}
|
|
334
|
+
function toScoredMemory(memory, vector, lexical, input, config) {
|
|
335
|
+
const weights = normalizeWeights(config?.weights);
|
|
336
|
+
const recency = recencyScore(memory.createdAt, config?.recencyHalfLifeDays ?? DEFAULT_RECENCY_HALF_LIFE_DAYS);
|
|
337
|
+
const confidence = clampScore(memory.confidence);
|
|
338
|
+
const access = accessScore(memory.accessCount, config?.accessSaturation ?? DEFAULT_ACCESS_SATURATION);
|
|
339
|
+
const importance = IMPORTANCE_SCORES[memory.importance];
|
|
340
|
+
const score = Math.max(0, Math.min(1, clampScore(vector) * weights.vector + clampScore(lexical) * weights.lexical + recency * weights.recency + confidence * weights.confidence + access * weights.access + importance * weights.importance));
|
|
214
341
|
return {
|
|
215
342
|
...cloneMemory(memory),
|
|
216
343
|
score,
|
|
217
344
|
scores: {
|
|
218
|
-
vector,
|
|
219
|
-
lexical,
|
|
220
|
-
recency
|
|
345
|
+
vector: clampScore(vector),
|
|
346
|
+
lexical: clampScore(lexical),
|
|
347
|
+
recency,
|
|
348
|
+
confidence,
|
|
349
|
+
access,
|
|
350
|
+
importance
|
|
221
351
|
},
|
|
222
352
|
explanation: input.explain ? {
|
|
223
|
-
vectorScore: vector,
|
|
224
|
-
lexicalScore: lexical,
|
|
353
|
+
vectorScore: clampScore(vector),
|
|
354
|
+
lexicalScore: clampScore(lexical),
|
|
225
355
|
recencyScore: recency,
|
|
226
|
-
|
|
356
|
+
confidenceScore: confidence,
|
|
357
|
+
accessScore: access,
|
|
358
|
+
importanceScore: importance,
|
|
359
|
+
importanceBoost: importance * weights.importance,
|
|
360
|
+
weights,
|
|
227
361
|
finalScore: score
|
|
228
362
|
} : null
|
|
229
363
|
};
|
|
@@ -292,6 +426,13 @@ function createInMemoryClient(config) {
|
|
|
292
426
|
}
|
|
293
427
|
return scored;
|
|
294
428
|
},
|
|
429
|
+
async buildContext(input) {
|
|
430
|
+
assertOpen();
|
|
431
|
+
return buildContext({
|
|
432
|
+
input,
|
|
433
|
+
recall: (contextInput) => this.recall(contextInputToRecallInput(contextInput))
|
|
434
|
+
});
|
|
435
|
+
},
|
|
295
436
|
async forget(input) {
|
|
296
437
|
assertOpen();
|
|
297
438
|
assertNonEmptyString(input.entityId, "entityId");
|
|
@@ -447,6 +588,40 @@ async function lexicalSearch(db, input) {
|
|
|
447
588
|
`);
|
|
448
589
|
}
|
|
449
590
|
//#endregion
|
|
591
|
+
//#region src/retrieval/index.ts
|
|
592
|
+
async function hybridRecall(input) {
|
|
593
|
+
const queryEmbedding = await embedOne(input.embedder, input.input.query);
|
|
594
|
+
const candidateMultiplier = input.retrieval?.candidateMultiplier ?? 3;
|
|
595
|
+
const candidateLimit = Math.max(input.limit, input.limit * candidateMultiplier);
|
|
596
|
+
const [vectorRows, lexicalRows] = await Promise.all([vectorSearch(input.db, {
|
|
597
|
+
...input.input,
|
|
598
|
+
embedding: queryEmbedding,
|
|
599
|
+
limit: candidateLimit,
|
|
600
|
+
minScore: 0
|
|
601
|
+
}), lexicalSearch(input.db, {
|
|
602
|
+
...input.input,
|
|
603
|
+
limit: candidateLimit
|
|
604
|
+
})]);
|
|
605
|
+
const merged = /* @__PURE__ */ new Map();
|
|
606
|
+
for (const row of vectorRows) merged.set(row.id, {
|
|
607
|
+
row,
|
|
608
|
+
vectorScore: row.vectorScore,
|
|
609
|
+
lexicalScore: 0
|
|
610
|
+
});
|
|
611
|
+
for (const row of lexicalRows) {
|
|
612
|
+
const existing = merged.get(row.id);
|
|
613
|
+
if (existing) existing.lexicalScore = row.lexicalScore;
|
|
614
|
+
else merged.set(row.id, {
|
|
615
|
+
row,
|
|
616
|
+
vectorScore: 0,
|
|
617
|
+
lexicalScore: row.lexicalScore
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
const scored = Array.from(merged.values()).map((entry) => toScoredMemory(rowToMemory(entry.row), Math.max(0, entry.vectorScore), Math.max(0, entry.lexicalScore), input.input, input.retrieval)).filter((memory) => memory.score >= input.minScore).sort((a, b) => b.score - a.score).slice(0, input.limit);
|
|
621
|
+
await markMemoryAccessed(input.db, scored.map((memory) => memory.id));
|
|
622
|
+
return scored;
|
|
623
|
+
}
|
|
624
|
+
//#endregion
|
|
450
625
|
//#region src/memory/postgres.ts
|
|
451
626
|
function createPostgresClient(config, handle) {
|
|
452
627
|
let closed = false;
|
|
@@ -495,34 +670,21 @@ function createPostgresClient(config, handle) {
|
|
|
495
670
|
const minScore = input.minScore ?? config.defaults?.minScore ?? 0;
|
|
496
671
|
assertLimit(limit);
|
|
497
672
|
assertMinScore(minScore);
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
limit
|
|
503
|
-
minScore
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
lexicalScore: 0
|
|
673
|
+
return hybridRecall({
|
|
674
|
+
db: handle.db,
|
|
675
|
+
embedder: config.embedder,
|
|
676
|
+
input,
|
|
677
|
+
limit,
|
|
678
|
+
minScore,
|
|
679
|
+
retrieval: config.retrieval
|
|
680
|
+
});
|
|
681
|
+
},
|
|
682
|
+
async buildContext(input) {
|
|
683
|
+
assertOpen();
|
|
684
|
+
return buildContext({
|
|
685
|
+
input,
|
|
686
|
+
recall: (contextInput) => this.recall(contextInputToRecallInput(contextInput))
|
|
513
687
|
});
|
|
514
|
-
for (const row of lexicalRows) {
|
|
515
|
-
const existing = merged.get(row.id);
|
|
516
|
-
if (existing) existing.lexicalScore = row.lexicalScore;
|
|
517
|
-
else merged.set(row.id, {
|
|
518
|
-
row,
|
|
519
|
-
vectorScore: 0,
|
|
520
|
-
lexicalScore: row.lexicalScore
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
const scored = Array.from(merged.values()).map((entry) => toScoredMemory(rowToMemory(entry.row), Math.max(0, entry.vectorScore), Math.max(0, entry.lexicalScore), input)).filter((memory) => memory.score >= minScore).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
524
|
-
await markMemoryAccessed(handle.db, scored.map((memory) => memory.id));
|
|
525
|
-
return scored;
|
|
526
688
|
},
|
|
527
689
|
async forget(input) {
|
|
528
690
|
assertOpen();
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/db/schema.ts","../src/db/index.ts","../src/errors.ts","../src/memory/shared.ts","../src/retrieval/scorer.ts","../src/memory/in-memory.ts","../src/db/queries/events.ts","../src/db/queries/memories.ts","../src/memory/postgres.ts","../src/client.ts"],"sourcesContent":["import { sql } from \"drizzle-orm\";\nimport {\n\tcustomType,\n\tindex,\n\tinteger,\n\tjsonb,\n\tpgTable,\n\treal,\n\ttext,\n\ttimestamp,\n} from \"drizzle-orm/pg-core\";\n\nconst vector = customType<{ data: number[]; driverData: string }>({\n\tdataType(config) {\n\t\tconst dimensions = typeof config === \"number\" ? config : 1536;\n\t\treturn `vector(${dimensions})`;\n\t},\n\ttoDriver(value) {\n\t\treturn `[${value.join(\",\")}]`;\n\t},\n\tfromDriver(value) {\n\t\treturn value.slice(1, -1).split(\",\").filter(Boolean).map(Number);\n\t},\n});\n\nexport const memoriesTable = pgTable(\n\t\"mnemocyte_memories\",\n\t{\n\t\tid: text(\"id\").primaryKey(),\n\t\tentityId: text(\"entity_id\").notNull(),\n\t\tcontent: text(\"content\").notNull(),\n\t\ttype: text(\"type\").notNull().default(\"fact\"),\n\t\timportance: text(\"importance\").notNull().default(\"normal\"),\n\t\ttags: text(\"tags\").array().notNull().default(sql`'{}'::text[]`),\n\t\tsource: text(\"source\"),\n\t\tmetadata: jsonb(\"metadata\").notNull().default({}),\n\t\tconfidence: real(\"confidence\").notNull().default(1),\n\t\tembedding: vector(\"embedding\", { dimensions: 1536 }),\n\t\tembeddingModel: text(\"embedding_model\").notNull(),\n\t\tembeddingDimensions: integer(\"embedding_dimensions\").notNull(),\n\t\tsupersededBy: text(\"superseded_by\"),\n\t\tsupersededAt: timestamp(\"superseded_at\", { withTimezone: true }),\n\t\texpiresAt: timestamp(\"expires_at\", { withTimezone: true }),\n\t\tlastAccessedAt: timestamp(\"last_accessed_at\", { withTimezone: true }),\n\t\taccessCount: integer(\"access_count\").notNull().default(0),\n\t\tcreatedAt: timestamp(\"created_at\", { withTimezone: true })\n\t\t\t.notNull()\n\t\t\t.defaultNow(),\n\t\tupdatedAt: timestamp(\"updated_at\", { withTimezone: true })\n\t\t\t.notNull()\n\t\t\t.defaultNow(),\n\t},\n\t(table) => [\n\t\tindex(\"mnemocyte_memories_entity_idx\").on(table.entityId),\n\t\tindex(\"mnemocyte_memories_entity_type_idx\").on(table.entityId, table.type),\n\t],\n);\n\nexport const eventsTable = pgTable(\n\t\"mnemocyte_events\",\n\t{\n\t\tid: text(\"id\").primaryKey(),\n\t\tentityId: text(\"entity_id\").notNull(),\n\t\tdescription: text(\"description\").notNull(),\n\t\tmetadata: jsonb(\"metadata\").notNull().default({}),\n\t\ttimestamp: timestamp(\"timestamp\", { withTimezone: true })\n\t\t\t.notNull()\n\t\t\t.defaultNow(),\n\t},\n\t(table) => [\n\t\tindex(\"mnemocyte_events_entity_time_idx\").on(\n\t\t\ttable.entityId,\n\t\t\ttable.timestamp,\n\t\t),\n\t],\n);\n\nexport type MemoryRow = typeof memoriesTable.$inferSelect;\nexport type NewMemoryRow = typeof memoriesTable.$inferInsert;\nexport type EventRow = typeof eventsTable.$inferSelect;\nexport type NewEventRow = typeof eventsTable.$inferInsert;\n","import { drizzle, type PostgresJsDatabase } from \"drizzle-orm/postgres-js\";\nimport postgres, { type Sql } from \"postgres\";\nimport * as schema from \"./schema.js\";\n\nexport type MnemocyteDatabase = PostgresJsDatabase<typeof schema>;\n\nexport interface DatabaseHandle {\n\tdb: MnemocyteDatabase;\n\tclose(): Promise<void>;\n}\n\nexport function createDatabase(databaseUrl: string): DatabaseHandle {\n\tconst client = postgres(databaseUrl, {\n\t\tmax: 10,\n\t\tidle_timeout: 20,\n\t\tconnect_timeout: 10,\n\t});\n\n\treturn {\n\t\tdb: drizzle(client, { schema }),\n\t\tasync close() {\n\t\t\tawait client.end();\n\t\t},\n\t};\n}\n\nexport function useDatabase(client: Sql): DatabaseHandle {\n\treturn {\n\t\tdb: drizzle(client, { schema }),\n\t\tasync close() {},\n\t};\n}\n\nexport { schema };\n","export type MnemocyteErrorCode =\n\t| \"CONFIG\"\n\t| \"VALIDATION\"\n\t| \"DB\"\n\t| \"EMBEDDING\"\n\t| \"NOT_FOUND\"\n\t| \"MIGRATION\";\n\nexport class MnemocyteError extends Error {\n\treadonly code: MnemocyteErrorCode;\n\toverride readonly cause?: unknown;\n\n\tconstructor(message: string, code: MnemocyteErrorCode, cause?: unknown) {\n\t\tsuper(message);\n\t\tthis.name = \"MnemocyteError\";\n\t\tthis.code = code;\n\t\tthis.cause = cause;\n\t}\n}\n","import type { MemoryRow } from \"../db/schema.js\";\nimport { MnemocyteError } from \"../errors.js\";\nimport type {\n\tEmbedder,\n\tImportanceLevel,\n\tMemory,\n\tMemoryType,\n\tRecallInput,\n\tRememberInput,\n} from \"../types.js\";\n\nexport const DEFAULT_LIMIT = 10;\nexport const DEFAULT_MIN_SCORE = 0;\nexport const DEFAULT_TYPE: MemoryType = \"fact\";\nexport const DEFAULT_IMPORTANCE: ImportanceLevel = \"normal\";\n\nexport interface StoredMemory extends Memory {\n\tembedding: number[];\n}\n\nexport function assertNonEmptyString(value: string, field: string): void {\n\tif (value.trim().length === 0) {\n\t\tthrow new MnemocyteError(\n\t\t\t`${field} must be a non-empty string.`,\n\t\t\t\"VALIDATION\",\n\t\t);\n\t}\n}\n\nexport function assertLimit(value: number): void {\n\tif (!Number.isInteger(value) || value < 1) {\n\t\tthrow new MnemocyteError(\"limit must be a positive integer.\", \"VALIDATION\");\n\t}\n}\n\nexport function assertMinScore(value: number): void {\n\tif (!Number.isFinite(value) || value < 0 || value > 1) {\n\t\tthrow new MnemocyteError(\n\t\t\t\"minScore must be a number between 0 and 1.\",\n\t\t\t\"VALIDATION\",\n\t\t);\n\t}\n}\n\nexport function assertEmbedder(embedder: Embedder): void {\n\tif (!embedder || typeof embedder.embed !== \"function\") {\n\t\tthrow new MnemocyteError(\n\t\t\t\"embedder with an embed function is required.\",\n\t\t\t\"CONFIG\",\n\t\t);\n\t}\n\tassertNonEmptyString(embedder.model, \"embedder.model\");\n\tif (!Number.isInteger(embedder.dimensions) || embedder.dimensions < 1) {\n\t\tthrow new MnemocyteError(\n\t\t\t\"embedder.dimensions must be a positive integer.\",\n\t\t\t\"CONFIG\",\n\t\t);\n\t}\n}\n\nexport function normalizeTags(tags: readonly string[] | undefined): string[] {\n\tif (!tags) {\n\t\treturn [];\n\t}\n\treturn [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];\n}\n\nexport function createId(): string {\n\treturn `mem_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function isExpired(memory: Memory, now: Date): boolean {\n\treturn (\n\t\tmemory.expiresAt !== null && memory.expiresAt.getTime() <= now.getTime()\n\t);\n}\n\nexport function cloneMemory(memory: Memory): Memory {\n\treturn {\n\t\t...memory,\n\t\ttags: [...memory.tags],\n\t\tmetadata: { ...memory.metadata },\n\t\texpiresAt: memory.expiresAt ? new Date(memory.expiresAt) : null,\n\t\tlastAccessedAt: memory.lastAccessedAt\n\t\t\t? new Date(memory.lastAccessedAt)\n\t\t\t: null,\n\t\tcreatedAt: new Date(memory.createdAt),\n\t\tupdatedAt: new Date(memory.updatedAt),\n\t};\n}\n\nexport function rowToMemory(row: MemoryRow): Memory {\n\treturn {\n\t\tid: row.id,\n\t\tentityId: row.entityId,\n\t\tcontent: row.content,\n\t\ttype: row.type as MemoryType,\n\t\timportance: row.importance as ImportanceLevel,\n\t\ttags: row.tags,\n\t\tsource: row.source,\n\t\tmetadata: row.metadata as Record<string, unknown>,\n\t\tconfidence: row.confidence,\n\t\tembeddingModel: row.embeddingModel,\n\t\tembeddingDimensions: row.embeddingDimensions,\n\t\tsupersededBy: row.supersededBy,\n\t\texpiresAt: row.expiresAt,\n\t\tlastAccessedAt: row.lastAccessedAt,\n\t\taccessCount: row.accessCount,\n\t\tcreatedAt: row.createdAt,\n\t\tupdatedAt: row.updatedAt,\n\t};\n}\n\nexport async function embedOne(\n\tembedder: Embedder,\n\ttext: string,\n): Promise<number[]> {\n\tlet embeddings: number[][];\n\ttry {\n\t\tembeddings = await embedder.embed([text]);\n\t} catch (error) {\n\t\tthrow new MnemocyteError(\"Failed to embed text.\", \"EMBEDDING\", error);\n\t}\n\tconst embedding = embeddings[0];\n\tif (!embedding) {\n\t\tthrow new MnemocyteError(\"Embedder returned no embedding.\", \"EMBEDDING\");\n\t}\n\tif (embedding.length !== embedder.dimensions) {\n\t\tthrow new MnemocyteError(\n\t\t\t\"Embedder returned an embedding with unexpected dimensions.\",\n\t\t\t\"EMBEDDING\",\n\t\t);\n\t}\n\treturn embedding;\n}\n\nexport function validateRememberInput(input: RememberInput): void {\n\tassertNonEmptyString(input.entityId, \"entityId\");\n\tassertNonEmptyString(input.content, \"content\");\n\tif (\n\t\tinput.confidence !== undefined &&\n\t\t(!Number.isFinite(input.confidence) ||\n\t\t\tinput.confidence < 0 ||\n\t\t\tinput.confidence > 1)\n\t) {\n\t\tthrow new MnemocyteError(\n\t\t\t\"confidence must be a number between 0 and 1.\",\n\t\t\t\"VALIDATION\",\n\t\t);\n\t}\n}\n\nexport function validateRecallInput(input: RecallInput): void {\n\tassertNonEmptyString(input.entityId, \"entityId\");\n\tassertNonEmptyString(input.query, \"query\");\n\tif (input.limit !== undefined) {\n\t\tassertLimit(input.limit);\n\t}\n\tif (input.minScore !== undefined) {\n\t\tassertMinScore(input.minScore);\n\t}\n}\n\nexport function matchesRecallFilter(\n\tmemory: Memory,\n\tinput: RecallInput,\n\tnow: Date,\n): boolean {\n\tif (memory.entityId !== input.entityId) {\n\t\treturn false;\n\t}\n\tif (!input.includeSuperseded && memory.supersededBy !== null) {\n\t\treturn false;\n\t}\n\tif (!input.includeExpired && isExpired(memory, now)) {\n\t\treturn false;\n\t}\n\tif (input.types && !input.types.includes(memory.type)) {\n\t\treturn false;\n\t}\n\tif (input.tags && !input.tags.every((tag) => memory.tags.includes(tag))) {\n\t\treturn false;\n\t}\n\tif (input.before && memory.createdAt >= input.before) {\n\t\treturn false;\n\t}\n\tif (input.after && memory.createdAt <= input.after) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n","import { cloneMemory } from \"../memory/shared.js\";\nimport type {\n\tImportanceLevel,\n\tMemory,\n\tMemoryWithScore,\n\tRecallInput,\n} from \"../types.js\";\n\nconst IMPORTANCE_BOOSTS: Record<ImportanceLevel, number> = {\n\tlow: -0.05,\n\tnormal: 0,\n\thigh: 0.08,\n\tcritical: 0.15,\n};\n\nexport function cosineSimilarity(\n\ta: readonly number[],\n\tb: readonly number[],\n): number {\n\tlet dot = 0;\n\tlet aMagnitude = 0;\n\tlet bMagnitude = 0;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst av = a[i] ?? 0;\n\t\tconst bv = b[i] ?? 0;\n\t\tdot += av * bv;\n\t\taMagnitude += av * av;\n\t\tbMagnitude += bv * bv;\n\t}\n\tif (aMagnitude === 0 || bMagnitude === 0) {\n\t\treturn 0;\n\t}\n\treturn dot / (Math.sqrt(aMagnitude) * Math.sqrt(bMagnitude));\n}\n\nexport function lexicalScore(content: string, query: string): number {\n\tconst terms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n\tif (terms.length === 0) {\n\t\treturn 0;\n\t}\n\tconst lowerContent = content.toLowerCase();\n\tconst matches = terms.filter((term) => lowerContent.includes(term)).length;\n\treturn matches / terms.length;\n}\n\nfunction recencyScore(createdAt: Date): number {\n\tconst ageMs = Date.now() - createdAt.getTime();\n\tconst ageDays = Math.max(0, ageMs / 86_400_000);\n\treturn Math.exp((-Math.LN2 * ageDays) / 90);\n}\n\nexport function toScoredMemory(\n\tmemory: Memory,\n\tvector: number,\n\tlexical: number,\n\tinput: RecallInput,\n): MemoryWithScore {\n\tconst recency = recencyScore(memory.createdAt);\n\tconst importanceBoost = IMPORTANCE_BOOSTS[memory.importance];\n\tconst score = Math.max(\n\t\t0,\n\t\tMath.min(1, vector * 0.7 + lexical * 0.2 + recency * 0.1 + importanceBoost),\n\t);\n\treturn {\n\t\t...cloneMemory(memory),\n\t\tscore,\n\t\tscores: { vector, lexical, recency },\n\t\texplanation: input.explain\n\t\t\t? {\n\t\t\t\t\tvectorScore: vector,\n\t\t\t\t\tlexicalScore: lexical,\n\t\t\t\t\trecencyScore: recency,\n\t\t\t\t\timportanceBoost,\n\t\t\t\t\tfinalScore: score,\n\t\t\t\t}\n\t\t\t: null,\n\t};\n}\n","import { MnemocyteError } from \"../errors.js\";\nimport {\n\tcosineSimilarity,\n\tlexicalScore,\n\ttoScoredMemory,\n} from \"../retrieval/scorer.js\";\nimport type {\n\tEntityStats,\n\tGlobalStats,\n\tMemory,\n\tMnemocyteClient,\n\tMnemocyteConfig,\n\tRememberInput,\n} from \"../types.js\";\nimport {\n\tassertLimit,\n\tassertMinScore,\n\tassertNonEmptyString,\n\tcloneMemory,\n\tcreateId,\n\tDEFAULT_IMPORTANCE,\n\tDEFAULT_LIMIT,\n\tDEFAULT_MIN_SCORE,\n\tDEFAULT_TYPE,\n\tembedOne,\n\tisExpired,\n\tmatchesRecallFilter,\n\tnormalizeTags,\n\ttype StoredMemory,\n\tvalidateRecallInput,\n\tvalidateRememberInput,\n} from \"./shared.js\";\n\nexport function createInMemoryClient(config: MnemocyteConfig): MnemocyteClient {\n\tconst memories = new Map<string, StoredMemory>();\n\tlet closed = false;\n\n\tfunction assertOpen(): void {\n\t\tif (closed) {\n\t\t\tthrow new MnemocyteError(\"Mnemocyte client is closed.\", \"DB\");\n\t\t}\n\t}\n\n\tasync function remember(input: RememberInput): Promise<Memory> {\n\t\tassertOpen();\n\t\tvalidateRememberInput(input);\n\t\tconst embedding = await embedOne(config.embedder, input.content);\n\t\tconst now = new Date();\n\t\tconst memory: StoredMemory = {\n\t\t\tid: createId(),\n\t\t\tentityId: input.entityId,\n\t\t\tcontent: input.content,\n\t\t\ttype: input.type ?? DEFAULT_TYPE,\n\t\t\timportance: input.importance ?? DEFAULT_IMPORTANCE,\n\t\t\ttags: normalizeTags(input.tags),\n\t\t\tsource: input.source ?? null,\n\t\t\tmetadata: input.metadata ?? {},\n\t\t\tconfidence: input.confidence ?? 1,\n\t\t\tembeddingModel: config.embedder.model,\n\t\t\tembeddingDimensions: config.embedder.dimensions,\n\t\t\tsupersededBy: null,\n\t\t\texpiresAt: input.expiresAt ?? null,\n\t\t\tlastAccessedAt: null,\n\t\t\taccessCount: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t\tembedding,\n\t\t};\n\t\tmemories.set(memory.id, memory);\n\t\treturn cloneMemory(memory);\n\t}\n\n\treturn {\n\t\tremember,\n\t\tasync rememberMany(inputs) {\n\t\t\tassertOpen();\n\t\t\tconst result: Memory[] = [];\n\t\t\tfor (const input of inputs) {\n\t\t\t\tresult.push(await remember(input));\n\t\t\t}\n\t\t\treturn result;\n\t\t},\n\t\tasync recall(input) {\n\t\t\tassertOpen();\n\t\t\tvalidateRecallInput(input);\n\t\t\tconst limit = input.limit ?? config.defaults?.limit ?? DEFAULT_LIMIT;\n\t\t\tconst minScore =\n\t\t\t\tinput.minScore ?? config.defaults?.minScore ?? DEFAULT_MIN_SCORE;\n\t\t\tassertLimit(limit);\n\t\t\tassertMinScore(minScore);\n\t\t\tconst queryEmbedding = await embedOne(config.embedder, input.query);\n\t\t\tconst now = new Date();\n\t\t\tconst scored = Array.from(memories.values())\n\t\t\t\t.filter((memory) => matchesRecallFilter(memory, input, now))\n\t\t\t\t.map((memory) =>\n\t\t\t\t\ttoScoredMemory(\n\t\t\t\t\t\tmemory,\n\t\t\t\t\t\tMath.max(0, cosineSimilarity(memory.embedding, queryEmbedding)),\n\t\t\t\t\t\tlexicalScore(memory.content, input.query),\n\t\t\t\t\t\tinput,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.filter((memory) => memory.score >= minScore)\n\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t.slice(0, limit);\n\t\t\tfor (const memory of scored) {\n\t\t\t\tconst stored = memories.get(memory.id);\n\t\t\t\tif (stored) {\n\t\t\t\t\tstored.lastAccessedAt = now;\n\t\t\t\t\tstored.accessCount += 1;\n\t\t\t\t\tstored.updatedAt = now;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn scored;\n\t\t},\n\t\tasync forget(input) {\n\t\t\tassertOpen();\n\t\t\tassertNonEmptyString(input.entityId, \"entityId\");\n\t\t\tassertNonEmptyString(input.memoryId, \"memoryId\");\n\t\t\tconst memory = memories.get(input.memoryId);\n\t\t\tif (!memory || memory.entityId !== input.entityId) {\n\t\t\t\tthrow new MnemocyteError(\"Memory was not found.\", \"NOT_FOUND\");\n\t\t\t}\n\t\t\tmemories.delete(input.memoryId);\n\t\t},\n\t\tasync forgetAll(input) {\n\t\t\tassertOpen();\n\t\t\tassertNonEmptyString(input.entityId, \"entityId\");\n\t\t\tfor (const [id, memory] of memories) {\n\t\t\t\tif (memory.entityId === input.entityId) {\n\t\t\t\t\tmemories.delete(id);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tasync stats(input) {\n\t\t\tassertOpen();\n\t\t\tconst now = new Date();\n\t\t\tconst allMemories = Array.from(memories.values());\n\t\t\tconst selected = input?.entityId\n\t\t\t\t? allMemories.filter((memory) => memory.entityId === input.entityId)\n\t\t\t\t: allMemories;\n\t\t\tconst activeMemoryCount = selected.filter(\n\t\t\t\t(memory) => !isExpired(memory, now) && memory.supersededBy === null,\n\t\t\t).length;\n\t\t\tconst expiredMemoryCount = selected.filter((memory) =>\n\t\t\t\tisExpired(memory, now),\n\t\t\t).length;\n\t\t\tconst supersededMemoryCount = selected.filter(\n\t\t\t\t(memory) => memory.supersededBy !== null,\n\t\t\t).length;\n\t\t\tif (input?.entityId) {\n\t\t\t\treturn {\n\t\t\t\t\tentityId: input.entityId,\n\t\t\t\t\tmemoryCount: selected.length,\n\t\t\t\t\tactiveMemoryCount,\n\t\t\t\t\texpiredMemoryCount,\n\t\t\t\t\tsupersededMemoryCount,\n\t\t\t\t} satisfies EntityStats;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tentityCount: new Set(allMemories.map((memory) => memory.entityId)).size,\n\t\t\t\tmemoryCount: selected.length,\n\t\t\t\tactiveMemoryCount,\n\t\t\t\texpiredMemoryCount,\n\t\t\t\tsupersededMemoryCount,\n\t\t\t} satisfies GlobalStats;\n\t\t},\n\t\tasync close() {\n\t\t\tclosed = true;\n\t\t\tmemories.clear();\n\t\t},\n\t};\n}\n","import { and, desc, eq, gt, lt } from \"drizzle-orm\";\nimport type { MnemocyteDatabase } from \"../index.js\";\nimport { type EventRow, eventsTable, type NewEventRow } from \"../schema.js\";\n\nexport interface EventFilter {\n\tentityId: string;\n\tlimit?: number;\n\tbefore?: Date;\n\tafter?: Date;\n}\n\nexport async function insertEvent(\n\tdb: MnemocyteDatabase,\n\trow: NewEventRow,\n): Promise<EventRow> {\n\tconst result = await db.insert(eventsTable).values(row).returning();\n\tconst inserted = result[0];\n\tif (!inserted) {\n\t\tthrow new Error(\"Event insert returned no rows.\");\n\t}\n\treturn inserted;\n}\n\nexport async function listEvents(\n\tdb: MnemocyteDatabase,\n\tfilter: EventFilter,\n): Promise<EventRow[]> {\n\treturn db\n\t\t.select()\n\t\t.from(eventsTable)\n\t\t.where(\n\t\t\tand(\n\t\t\t\teq(eventsTable.entityId, filter.entityId),\n\t\t\t\tfilter.before ? lt(eventsTable.timestamp, filter.before) : undefined,\n\t\t\t\tfilter.after ? gt(eventsTable.timestamp, filter.after) : undefined,\n\t\t\t),\n\t\t)\n\t\t.orderBy(desc(eventsTable.timestamp))\n\t\t.limit(filter.limit ?? 50);\n}\n\nexport async function deleteEventsForEntity(\n\tdb: MnemocyteDatabase,\n\tentityId: string,\n): Promise<number> {\n\tconst result = await db\n\t\t.delete(eventsTable)\n\t\t.where(eq(eventsTable.entityId, entityId))\n\t\t.returning({ id: eventsTable.id });\n\treturn result.length;\n}\n","import { and, eq, gt, inArray, isNull, lt, sql } from \"drizzle-orm\";\nimport type { MemoryType } from \"../../types.js\";\nimport type { MnemocyteDatabase } from \"../index.js\";\nimport { type MemoryRow, memoriesTable, type NewMemoryRow } from \"../schema.js\";\n\nexport interface MemoryFilter {\n\tentityId: string;\n\ttypes?: readonly MemoryType[];\n\ttags?: readonly string[];\n\tbefore?: Date;\n\tafter?: Date;\n\tincludeSuperseded?: boolean;\n\tincludeExpired?: boolean;\n}\n\nexport interface VectorSearchInput extends MemoryFilter {\n\tembedding: readonly number[];\n\tlimit: number;\n\tminScore?: number;\n}\n\nexport interface LexicalSearchInput extends MemoryFilter {\n\tquery: string;\n\tlimit: number;\n}\n\nfunction vectorLiteral(embedding: readonly number[]): string {\n\treturn `[${embedding.join(\",\")}]`;\n}\n\nfunction filterConditions(filter: MemoryFilter) {\n\treturn and(\n\t\teq(memoriesTable.entityId, filter.entityId),\n\t\tfilter.includeSuperseded ? undefined : isNull(memoriesTable.supersededBy),\n\t\tfilter.includeExpired\n\t\t\t? undefined\n\t\t\t: sql`(${memoriesTable.expiresAt} IS NULL OR ${memoriesTable.expiresAt} > now())`,\n\t\tfilter.types && filter.types.length > 0\n\t\t\t? inArray(memoriesTable.type, [...filter.types])\n\t\t\t: undefined,\n\t\tfilter.tags && filter.tags.length > 0\n\t\t\t? sql`${memoriesTable.tags} && ${filter.tags}`\n\t\t\t: undefined,\n\t\tfilter.before ? lt(memoriesTable.createdAt, filter.before) : undefined,\n\t\tfilter.after ? gt(memoriesTable.createdAt, filter.after) : undefined,\n\t);\n}\n\nexport async function insertMemory(\n\tdb: MnemocyteDatabase,\n\trow: NewMemoryRow,\n): Promise<MemoryRow> {\n\tconst result = await db.insert(memoriesTable).values(row).returning();\n\tconst inserted = result[0];\n\tif (!inserted) {\n\t\tthrow new Error(\"Memory insert returned no rows.\");\n\t}\n\treturn inserted;\n}\n\nexport async function getMemoryById(\n\tdb: MnemocyteDatabase,\n\tentityId: string,\n\tmemoryId: string,\n): Promise<MemoryRow | null> {\n\tconst result = await db\n\t\t.select()\n\t\t.from(memoriesTable)\n\t\t.where(\n\t\t\tand(eq(memoriesTable.entityId, entityId), eq(memoriesTable.id, memoryId)),\n\t\t)\n\t\t.limit(1);\n\treturn result[0] ?? null;\n}\n\nexport async function listMemories(\n\tdb: MnemocyteDatabase,\n\tfilter: MemoryFilter,\n): Promise<MemoryRow[]> {\n\treturn db.select().from(memoriesTable).where(filterConditions(filter));\n}\n\nexport async function deleteMemory(\n\tdb: MnemocyteDatabase,\n\tentityId: string,\n\tmemoryId: string,\n): Promise<boolean> {\n\tconst result = await db\n\t\t.delete(memoriesTable)\n\t\t.where(\n\t\t\tand(eq(memoriesTable.entityId, entityId), eq(memoriesTable.id, memoryId)),\n\t\t)\n\t\t.returning({ id: memoriesTable.id });\n\treturn result.length > 0;\n}\n\nexport async function deleteMemoriesForEntity(\n\tdb: MnemocyteDatabase,\n\tentityId: string,\n): Promise<number> {\n\tconst result = await db\n\t\t.delete(memoriesTable)\n\t\t.where(eq(memoriesTable.entityId, entityId))\n\t\t.returning({ id: memoriesTable.id });\n\treturn result.length;\n}\n\nexport async function markMemoryAccessed(\n\tdb: MnemocyteDatabase,\n\tmemoryIds: readonly string[],\n): Promise<void> {\n\tif (memoryIds.length === 0) {\n\t\treturn;\n\t}\n\tawait db\n\t\t.update(memoriesTable)\n\t\t.set({\n\t\t\tlastAccessedAt: new Date(),\n\t\t\taccessCount: sql`${memoriesTable.accessCount} + 1`,\n\t\t\tupdatedAt: new Date(),\n\t\t})\n\t\t.where(inArray(memoriesTable.id, [...memoryIds]));\n}\n\nexport async function vectorSearch(\n\tdb: MnemocyteDatabase,\n\tinput: VectorSearchInput,\n): Promise<Array<MemoryRow & { vectorScore: number }>> {\n\tconst embedding = vectorLiteral(input.embedding);\n\tconst minScore = input.minScore ?? 0;\n\tconst rows = await db.execute(sql`\n\t\tSELECT\n\t\t\tid,\n\t\t\tentity_id AS \"entityId\",\n\t\t\tcontent,\n\t\t\ttype,\n\t\t\timportance,\n\t\t\ttags,\n\t\t\tsource,\n\t\t\tmetadata,\n\t\t\tconfidence,\n\t\t\tembedding,\n\t\t\tembedding_model AS \"embeddingModel\",\n\t\t\tembedding_dimensions AS \"embeddingDimensions\",\n\t\t\tsuperseded_by AS \"supersededBy\",\n\t\t\tsuperseded_at AS \"supersededAt\",\n\t\t\texpires_at AS \"expiresAt\",\n\t\t\tlast_accessed_at AS \"lastAccessedAt\",\n\t\t\taccess_count AS \"accessCount\",\n\t\t\tcreated_at AS \"createdAt\",\n\t\t\tupdated_at AS \"updatedAt\",\n\t\t\t1 - (embedding <=> ${embedding}::vector) AS \"vectorScore\"\n\t\tFROM mnemocyte_memories\n\t\tWHERE\n\t\t\tentity_id = ${input.entityId}\n\t\t\tAND embedding IS NOT NULL\n\t\t\t${input.includeSuperseded ? sql`` : sql`AND superseded_by IS NULL`}\n\t\t\t${input.includeExpired ? sql`` : sql`AND (expires_at IS NULL OR expires_at > now())`}\n\t\t\t${\n\t\t\t\tinput.types && input.types.length > 0\n\t\t\t\t\t? sql`AND type IN (${sql.join(\n\t\t\t\t\t\t\tinput.types.map((type) => sql`${type}`),\n\t\t\t\t\t\t\tsql`, `,\n\t\t\t\t\t\t)})`\n\t\t\t\t\t: sql``\n\t\t\t}\n\t\t\t${input.tags && input.tags.length > 0 ? sql`AND tags && ${input.tags}` : sql``}\n\t\t\t${input.before ? sql`AND created_at < ${input.before}` : sql``}\n\t\t\t${input.after ? sql`AND created_at > ${input.after}` : sql``}\n\t\t\tAND 1 - (embedding <=> ${embedding}::vector) >= ${minScore}\n\t\tORDER BY embedding <=> ${embedding}::vector\n\t\tLIMIT ${input.limit}\n\t`);\n\treturn rows as unknown as Array<MemoryRow & { vectorScore: number }>;\n}\n\nexport async function lexicalSearch(\n\tdb: MnemocyteDatabase,\n\tinput: LexicalSearchInput,\n): Promise<Array<MemoryRow & { lexicalScore: number }>> {\n\tconst rows = await db.execute(sql`\n\t\tSELECT\n\t\t\tid,\n\t\t\tentity_id AS \"entityId\",\n\t\t\tcontent,\n\t\t\ttype,\n\t\t\timportance,\n\t\t\ttags,\n\t\t\tsource,\n\t\t\tmetadata,\n\t\t\tconfidence,\n\t\t\tembedding,\n\t\t\tembedding_model AS \"embeddingModel\",\n\t\t\tembedding_dimensions AS \"embeddingDimensions\",\n\t\t\tsuperseded_by AS \"supersededBy\",\n\t\t\tsuperseded_at AS \"supersededAt\",\n\t\t\texpires_at AS \"expiresAt\",\n\t\t\tlast_accessed_at AS \"lastAccessedAt\",\n\t\t\taccess_count AS \"accessCount\",\n\t\t\tcreated_at AS \"createdAt\",\n\t\t\tupdated_at AS \"updatedAt\",\n\t\t\tts_rank(to_tsvector('english', content), websearch_to_tsquery('english', ${input.query})) AS \"lexicalScore\"\n\t\tFROM mnemocyte_memories\n\t\tWHERE\n\t\t\tentity_id = ${input.entityId}\n\t\t\t${input.includeSuperseded ? sql`` : sql`AND superseded_by IS NULL`}\n\t\t\t${input.includeExpired ? sql`` : sql`AND (expires_at IS NULL OR expires_at > now())`}\n\t\t\t${\n\t\t\t\tinput.types && input.types.length > 0\n\t\t\t\t\t? sql`AND type IN (${sql.join(\n\t\t\t\t\t\t\tinput.types.map((type) => sql`${type}`),\n\t\t\t\t\t\t\tsql`, `,\n\t\t\t\t\t\t)})`\n\t\t\t\t\t: sql``\n\t\t\t}\n\t\t\t${input.tags && input.tags.length > 0 ? sql`AND tags && ${input.tags}` : sql``}\n\t\t\t${input.before ? sql`AND created_at < ${input.before}` : sql``}\n\t\t\t${input.after ? sql`AND created_at > ${input.after}` : sql``}\n\t\t\tAND to_tsvector('english', content) @@ websearch_to_tsquery('english', ${input.query})\n\t\tORDER BY \"lexicalScore\" DESC\n\t\tLIMIT ${input.limit}\n\t`);\n\treturn rows as unknown as Array<MemoryRow & { lexicalScore: number }>;\n}\n","import type { DatabaseHandle } from \"../db/index.js\";\nimport { deleteEventsForEntity } from \"../db/queries/events.js\";\nimport {\n\tdeleteMemoriesForEntity,\n\tdeleteMemory,\n\tinsertMemory,\n\tlexicalSearch,\n\tlistMemories,\n\tmarkMemoryAccessed,\n\tvectorSearch,\n} from \"../db/queries/memories.js\";\nimport { type MemoryRow, memoriesTable } from \"../db/schema.js\";\nimport { MnemocyteError } from \"../errors.js\";\nimport { toScoredMemory } from \"../retrieval/scorer.js\";\nimport type {\n\tEntityStats,\n\tGlobalStats,\n\tMemory,\n\tMnemocyteClient,\n\tMnemocyteConfig,\n\tRememberInput,\n} from \"../types.js\";\nimport {\n\tassertLimit,\n\tassertMinScore,\n\tassertNonEmptyString,\n\tcreateId,\n\tDEFAULT_IMPORTANCE,\n\tDEFAULT_LIMIT,\n\tDEFAULT_MIN_SCORE,\n\tDEFAULT_TYPE,\n\tembedOne,\n\tisExpired,\n\tnormalizeTags,\n\trowToMemory,\n\tvalidateRecallInput,\n\tvalidateRememberInput,\n} from \"./shared.js\";\n\ninterface ScoredRow {\n\trow: MemoryRow;\n\tvectorScore: number;\n\tlexicalScore: number;\n}\n\nexport function createPostgresClient(\n\tconfig: MnemocyteConfig,\n\thandle: DatabaseHandle,\n): MnemocyteClient {\n\tlet closed = false;\n\n\tfunction assertOpen(): void {\n\t\tif (closed) {\n\t\t\tthrow new MnemocyteError(\"Mnemocyte client is closed.\", \"DB\");\n\t\t}\n\t}\n\n\tasync function remember(input: RememberInput): Promise<Memory> {\n\t\tassertOpen();\n\t\tvalidateRememberInput(input);\n\t\tconst embedding = await embedOne(config.embedder, input.content);\n\t\tconst now = new Date();\n\t\tconst row = await insertMemory(handle.db, {\n\t\t\tid: createId(),\n\t\t\tentityId: input.entityId,\n\t\t\tcontent: input.content,\n\t\t\ttype: input.type ?? DEFAULT_TYPE,\n\t\t\timportance: input.importance ?? DEFAULT_IMPORTANCE,\n\t\t\ttags: normalizeTags(input.tags),\n\t\t\tsource: input.source ?? null,\n\t\t\tmetadata: input.metadata ?? {},\n\t\t\tconfidence: input.confidence ?? 1,\n\t\t\tembedding,\n\t\t\tembeddingModel: config.embedder.model,\n\t\t\tembeddingDimensions: config.embedder.dimensions,\n\t\t\tsupersededBy: null,\n\t\t\tsupersededAt: null,\n\t\t\texpiresAt: input.expiresAt ?? null,\n\t\t\tlastAccessedAt: null,\n\t\t\taccessCount: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t});\n\t\treturn rowToMemory(row);\n\t}\n\n\treturn {\n\t\tremember,\n\t\tasync rememberMany(inputs) {\n\t\t\tassertOpen();\n\t\t\tconst result: Memory[] = [];\n\t\t\tfor (const input of inputs) {\n\t\t\t\tresult.push(await remember(input));\n\t\t\t}\n\t\t\treturn result;\n\t\t},\n\t\tasync recall(input) {\n\t\t\tassertOpen();\n\t\t\tvalidateRecallInput(input);\n\t\t\tconst limit = input.limit ?? config.defaults?.limit ?? DEFAULT_LIMIT;\n\t\t\tconst minScore =\n\t\t\t\tinput.minScore ?? config.defaults?.minScore ?? DEFAULT_MIN_SCORE;\n\t\t\tassertLimit(limit);\n\t\t\tassertMinScore(minScore);\n\t\t\tconst queryEmbedding = await embedOne(config.embedder, input.query);\n\t\t\tconst [vectorRows, lexicalRows] = await Promise.all([\n\t\t\t\tvectorSearch(handle.db, {\n\t\t\t\t\t...input,\n\t\t\t\t\tembedding: queryEmbedding,\n\t\t\t\t\tlimit: limit * 2,\n\t\t\t\t\tminScore: 0,\n\t\t\t\t}),\n\t\t\t\tlexicalSearch(handle.db, { ...input, limit: limit * 2 }),\n\t\t\t]);\n\t\t\tconst merged = new Map<string, ScoredRow>();\n\t\t\tfor (const row of vectorRows) {\n\t\t\t\tmerged.set(row.id, {\n\t\t\t\t\trow,\n\t\t\t\t\tvectorScore: row.vectorScore,\n\t\t\t\t\tlexicalScore: 0,\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const row of lexicalRows) {\n\t\t\t\tconst existing = merged.get(row.id);\n\t\t\t\tif (existing) {\n\t\t\t\t\texisting.lexicalScore = row.lexicalScore;\n\t\t\t\t} else {\n\t\t\t\t\tmerged.set(row.id, {\n\t\t\t\t\t\trow,\n\t\t\t\t\t\tvectorScore: 0,\n\t\t\t\t\t\tlexicalScore: row.lexicalScore,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst scored = Array.from(merged.values())\n\t\t\t\t.map((entry) =>\n\t\t\t\t\ttoScoredMemory(\n\t\t\t\t\t\trowToMemory(entry.row),\n\t\t\t\t\t\tMath.max(0, entry.vectorScore),\n\t\t\t\t\t\tMath.max(0, entry.lexicalScore),\n\t\t\t\t\t\tinput,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.filter((memory) => memory.score >= minScore)\n\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t.slice(0, limit);\n\t\t\tawait markMemoryAccessed(\n\t\t\t\thandle.db,\n\t\t\t\tscored.map((memory) => memory.id),\n\t\t\t);\n\t\t\treturn scored;\n\t\t},\n\t\tasync forget(input) {\n\t\t\tassertOpen();\n\t\t\tassertNonEmptyString(input.entityId, \"entityId\");\n\t\t\tassertNonEmptyString(input.memoryId, \"memoryId\");\n\t\t\tconst deleted = await deleteMemory(\n\t\t\t\thandle.db,\n\t\t\t\tinput.entityId,\n\t\t\t\tinput.memoryId,\n\t\t\t);\n\t\t\tif (!deleted) {\n\t\t\t\tthrow new MnemocyteError(\"Memory was not found.\", \"NOT_FOUND\");\n\t\t\t}\n\t\t},\n\t\tasync forgetAll(input) {\n\t\t\tassertOpen();\n\t\t\tassertNonEmptyString(input.entityId, \"entityId\");\n\t\t\tawait Promise.all([\n\t\t\t\tdeleteMemoriesForEntity(handle.db, input.entityId),\n\t\t\t\tdeleteEventsForEntity(handle.db, input.entityId),\n\t\t\t]);\n\t\t},\n\t\tasync stats(input) {\n\t\t\tassertOpen();\n\t\t\tconst now = new Date();\n\t\t\tif (input?.entityId) {\n\t\t\t\tconst selected = await listMemories(handle.db, {\n\t\t\t\t\tentityId: input.entityId,\n\t\t\t\t\tincludeExpired: true,\n\t\t\t\t\tincludeSuperseded: true,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tentityId: input.entityId,\n\t\t\t\t\tmemoryCount: selected.length,\n\t\t\t\t\tactiveMemoryCount: selected.filter(\n\t\t\t\t\t\t(memory) =>\n\t\t\t\t\t\t\t!isExpired(rowToMemory(memory), now) &&\n\t\t\t\t\t\t\tmemory.supersededBy === null,\n\t\t\t\t\t).length,\n\t\t\t\t\texpiredMemoryCount: selected.filter((memory) =>\n\t\t\t\t\t\tisExpired(rowToMemory(memory), now),\n\t\t\t\t\t).length,\n\t\t\t\t\tsupersededMemoryCount: selected.filter(\n\t\t\t\t\t\t(memory) => memory.supersededBy !== null,\n\t\t\t\t\t).length,\n\t\t\t\t} satisfies EntityStats;\n\t\t\t}\n\t\t\tconst allMemories = await handle.db.select().from(memoriesTable);\n\t\t\treturn {\n\t\t\t\tentityCount: new Set(allMemories.map((memory) => memory.entityId)).size,\n\t\t\t\tmemoryCount: allMemories.length,\n\t\t\t\tactiveMemoryCount: allMemories.filter(\n\t\t\t\t\t(memory) =>\n\t\t\t\t\t\t!isExpired(rowToMemory(memory), now) &&\n\t\t\t\t\t\tmemory.supersededBy === null,\n\t\t\t\t).length,\n\t\t\t\texpiredMemoryCount: allMemories.filter((memory) =>\n\t\t\t\t\tisExpired(rowToMemory(memory), now),\n\t\t\t\t).length,\n\t\t\t\tsupersededMemoryCount: allMemories.filter(\n\t\t\t\t\t(memory) => memory.supersededBy !== null,\n\t\t\t\t).length,\n\t\t\t} satisfies GlobalStats;\n\t\t},\n\t\tasync close() {\n\t\t\tclosed = true;\n\t\t\tawait handle.close();\n\t\t},\n\t};\n}\n","import { createDatabase } from \"./db/index.js\";\nimport { createInMemoryClient } from \"./memory/in-memory.js\";\nimport { createPostgresClient } from \"./memory/postgres.js\";\nimport { assertEmbedder, assertNonEmptyString } from \"./memory/shared.js\";\nimport type { MnemocyteClient, MnemocyteConfig } from \"./types.js\";\n\nexport function createMnemocyte(config: MnemocyteConfig): MnemocyteClient {\n\tassertEmbedder(config.embedder);\n\tif (config.databaseUrl) {\n\t\tassertNonEmptyString(config.databaseUrl, \"databaseUrl\");\n\t\treturn createPostgresClient(config, createDatabase(config.databaseUrl));\n\t}\n\treturn createInMemoryClient(config);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/db/schema.ts","../src/db/index.ts","../src/context/formatter.ts","../src/context/tokens.ts","../src/context/builder.ts","../src/errors.ts","../src/memory/shared.ts","../src/retrieval/scorer.ts","../src/memory/in-memory.ts","../src/db/queries/events.ts","../src/db/queries/memories.ts","../src/retrieval/index.ts","../src/memory/postgres.ts","../src/client.ts"],"sourcesContent":["import { sql } from \"drizzle-orm\";\nimport {\n\tcustomType,\n\tindex,\n\tinteger,\n\tjsonb,\n\tpgTable,\n\treal,\n\ttext,\n\ttimestamp,\n} from \"drizzle-orm/pg-core\";\n\nconst vector = customType<{ data: number[]; driverData: string }>({\n\tdataType(config) {\n\t\tconst dimensions = typeof config === \"number\" ? config : 1536;\n\t\treturn `vector(${dimensions})`;\n\t},\n\ttoDriver(value) {\n\t\treturn `[${value.join(\",\")}]`;\n\t},\n\tfromDriver(value) {\n\t\treturn value.slice(1, -1).split(\",\").filter(Boolean).map(Number);\n\t},\n});\n\nexport const memoriesTable = pgTable(\n\t\"mnemocyte_memories\",\n\t{\n\t\tid: text(\"id\").primaryKey(),\n\t\tentityId: text(\"entity_id\").notNull(),\n\t\tcontent: text(\"content\").notNull(),\n\t\ttype: text(\"type\").notNull().default(\"fact\"),\n\t\timportance: text(\"importance\").notNull().default(\"normal\"),\n\t\ttags: text(\"tags\").array().notNull().default(sql`'{}'::text[]`),\n\t\tsource: text(\"source\"),\n\t\tmetadata: jsonb(\"metadata\").notNull().default({}),\n\t\tconfidence: real(\"confidence\").notNull().default(1),\n\t\tembedding: vector(\"embedding\", { dimensions: 1536 }),\n\t\tembeddingModel: text(\"embedding_model\").notNull(),\n\t\tembeddingDimensions: integer(\"embedding_dimensions\").notNull(),\n\t\tsupersededBy: text(\"superseded_by\"),\n\t\tsupersededAt: timestamp(\"superseded_at\", { withTimezone: true }),\n\t\texpiresAt: timestamp(\"expires_at\", { withTimezone: true }),\n\t\tlastAccessedAt: timestamp(\"last_accessed_at\", { withTimezone: true }),\n\t\taccessCount: integer(\"access_count\").notNull().default(0),\n\t\tcreatedAt: timestamp(\"created_at\", { withTimezone: true })\n\t\t\t.notNull()\n\t\t\t.defaultNow(),\n\t\tupdatedAt: timestamp(\"updated_at\", { withTimezone: true })\n\t\t\t.notNull()\n\t\t\t.defaultNow(),\n\t},\n\t(table) => [\n\t\tindex(\"mnemocyte_memories_entity_idx\").on(table.entityId),\n\t\tindex(\"mnemocyte_memories_entity_type_idx\").on(table.entityId, table.type),\n\t],\n);\n\nexport const eventsTable = pgTable(\n\t\"mnemocyte_events\",\n\t{\n\t\tid: text(\"id\").primaryKey(),\n\t\tentityId: text(\"entity_id\").notNull(),\n\t\tdescription: text(\"description\").notNull(),\n\t\tmetadata: jsonb(\"metadata\").notNull().default({}),\n\t\ttimestamp: timestamp(\"timestamp\", { withTimezone: true })\n\t\t\t.notNull()\n\t\t\t.defaultNow(),\n\t},\n\t(table) => [\n\t\tindex(\"mnemocyte_events_entity_time_idx\").on(\n\t\t\ttable.entityId,\n\t\t\ttable.timestamp,\n\t\t),\n\t],\n);\n\nexport type MemoryRow = typeof memoriesTable.$inferSelect;\nexport type NewMemoryRow = typeof memoriesTable.$inferInsert;\nexport type EventRow = typeof eventsTable.$inferSelect;\nexport type NewEventRow = typeof eventsTable.$inferInsert;\n","import { drizzle, type PostgresJsDatabase } from \"drizzle-orm/postgres-js\";\nimport postgres, { type Sql } from \"postgres\";\nimport * as schema from \"./schema.js\";\n\nexport type MnemocyteDatabase = PostgresJsDatabase<typeof schema>;\n\nexport interface DatabaseHandle {\n\tdb: MnemocyteDatabase;\n\tclose(): Promise<void>;\n}\n\nexport function createDatabase(databaseUrl: string): DatabaseHandle {\n\tconst client = postgres(databaseUrl, {\n\t\tmax: 10,\n\t\tidle_timeout: 20,\n\t\tconnect_timeout: 10,\n\t});\n\n\treturn {\n\t\tdb: drizzle(client, { schema }),\n\t\tasync close() {\n\t\t\tawait client.end();\n\t\t},\n\t};\n}\n\nexport function useDatabase(client: Sql): DatabaseHandle {\n\treturn {\n\t\tdb: drizzle(client, { schema }),\n\t\tasync close() {},\n\t};\n}\n\nexport { schema };\n","import type { ContextFormat, MemoryWithScore } from \"../types.js\";\n\nfunction escapeXml(value: string): string {\n\treturn value\n\t\t.replaceAll(\"&\", \"&\")\n\t\t.replaceAll(\"<\", \"<\")\n\t\t.replaceAll(\">\", \">\")\n\t\t.replaceAll('\"', \""\")\n\t\t.replaceAll(\"'\", \"'\");\n}\n\nfunction formatMetadata(memory: MemoryWithScore): string {\n\tconst parts = [\n\t\t`type=${memory.type}`,\n\t\t`importance=${memory.importance}`,\n\t\t`score=${memory.score.toFixed(3)}`,\n\t];\n\tif (memory.source) {\n\t\tparts.push(`source=${memory.source}`);\n\t}\n\tif (memory.tags.length > 0) {\n\t\tparts.push(`tags=${memory.tags.join(\",\")}`);\n\t}\n\treturn parts.join(\"; \");\n}\n\nfunction formatMarkdown(\n\tmemories: readonly MemoryWithScore[],\n\tquery: string,\n): string {\n\tconst lines = [\n\t\t\"# Memory Context\",\n\t\t\"\",\n\t\t`Query: ${query}`,\n\t\t\"\",\n\t\t\"## Relevant Memories\",\n\t];\n\tfor (const memory of memories) {\n\t\tlines.push(\"\", `- ${memory.content}`, ` - ${formatMetadata(memory)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction formatPlain(\n\tmemories: readonly MemoryWithScore[],\n\tquery: string,\n): string {\n\tconst lines = [\n\t\t\"MEMORY CONTEXT\",\n\t\t\"\",\n\t\t`QUERY: ${query}`,\n\t\t\"\",\n\t\t\"RELEVANT MEMORIES\",\n\t];\n\tfor (const memory of memories) {\n\t\tlines.push(\"\", memory.content, formatMetadata(memory));\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction formatXml(\n\tmemories: readonly MemoryWithScore[],\n\tquery: string,\n): string {\n\tconst lines = [`<memory_context query=\"${escapeXml(query)}\">`];\n\tfor (const memory of memories) {\n\t\tlines.push(\n\t\t\t` <memory id=\"${escapeXml(memory.id)}\" type=\"${escapeXml(memory.type)}\" importance=\"${escapeXml(memory.importance)}\" score=\"${memory.score.toFixed(3)}\">`,\n\t\t\t` <content>${escapeXml(memory.content)}</content>`,\n\t\t\t` <metadata>${escapeXml(formatMetadata(memory))}</metadata>`,\n\t\t\t\" </memory>\",\n\t\t);\n\t}\n\tlines.push(\"</memory_context>\");\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatContext(\n\tmemories: readonly MemoryWithScore[],\n\tquery: string,\n\tformat: ContextFormat,\n): string {\n\tswitch (format) {\n\t\tcase \"markdown\":\n\t\t\treturn formatMarkdown(memories, query);\n\t\tcase \"plain\":\n\t\t\treturn formatPlain(memories, query);\n\t\tcase \"xml\":\n\t\t\treturn formatXml(memories, query);\n\t}\n}\n","import type { TokenCounter } from \"../types.js\";\n\nexport const heuristicTokenCounter: TokenCounter = {\n\tcount(text) {\n\t\treturn Math.ceil(text.length / 4);\n\t},\n};\n\nexport function trimToTokenBudget(\n\ttext: string,\n\tmaxTokens: number,\n\ttokenCounter: TokenCounter,\n): string {\n\tif (maxTokens < 1 || tokenCounter.count(text) <= maxTokens) {\n\t\treturn text;\n\t}\n\tlet low = 0;\n\tlet high = text.length;\n\tlet best = \"\";\n\twhile (low <= high) {\n\t\tconst mid = Math.floor((low + high) / 2);\n\t\tconst candidate = text.slice(0, mid).trimEnd();\n\t\tconst output = `${candidate}\\n[truncated to fit token budget]`;\n\t\tif (tokenCounter.count(output) <= maxTokens) {\n\t\t\tbest = output;\n\t\t\tlow = mid + 1;\n\t\t} else {\n\t\t\thigh = mid - 1;\n\t\t}\n\t}\n\treturn best || \"[truncated to fit token budget]\";\n}\n","import type { BuildContextInput, MemoryWithScore } from \"../types.js\";\nimport { formatContext } from \"./formatter.js\";\nimport { heuristicTokenCounter, trimToTokenBudget } from \"./tokens.js\";\n\nexport interface BuildContextOptions {\n\tinput: BuildContextInput;\n\trecall(input: BuildContextInput): Promise<MemoryWithScore[]>;\n}\n\nexport async function buildContext(\n\toptions: BuildContextOptions,\n): Promise<string> {\n\tconst format = options.input.format ?? \"markdown\";\n\tconst maxTokens = options.input.maxTokens ?? 1200;\n\tconst tokenCounter = options.input.tokenCounter ?? heuristicTokenCounter;\n\tconst memories = await options.recall(options.input);\n\tconst context = formatContext(memories, options.input.query, format);\n\treturn trimToTokenBudget(context, maxTokens, tokenCounter);\n}\n","export type MnemocyteErrorCode =\n\t| \"CONFIG\"\n\t| \"VALIDATION\"\n\t| \"DB\"\n\t| \"EMBEDDING\"\n\t| \"NOT_FOUND\"\n\t| \"MIGRATION\";\n\nexport class MnemocyteError extends Error {\n\treadonly code: MnemocyteErrorCode;\n\toverride readonly cause?: unknown;\n\n\tconstructor(message: string, code: MnemocyteErrorCode, cause?: unknown) {\n\t\tsuper(message);\n\t\tthis.name = \"MnemocyteError\";\n\t\tthis.code = code;\n\t\tthis.cause = cause;\n\t}\n}\n","import type { MemoryRow } from \"../db/schema.js\";\nimport { MnemocyteError } from \"../errors.js\";\nimport type {\n\tBuildContextInput,\n\tEmbedder,\n\tImportanceLevel,\n\tMemory,\n\tMemoryType,\n\tRecallInput,\n\tRememberInput,\n} from \"../types.js\";\n\nexport const DEFAULT_LIMIT = 10;\nexport const DEFAULT_MIN_SCORE = 0;\nexport const DEFAULT_TYPE: MemoryType = \"fact\";\nexport const DEFAULT_IMPORTANCE: ImportanceLevel = \"normal\";\n\nexport interface StoredMemory extends Memory {\n\tembedding: number[];\n}\n\nexport function assertNonEmptyString(value: string, field: string): void {\n\tif (value.trim().length === 0) {\n\t\tthrow new MnemocyteError(\n\t\t\t`${field} must be a non-empty string.`,\n\t\t\t\"VALIDATION\",\n\t\t);\n\t}\n}\n\nexport function assertLimit(value: number): void {\n\tif (!Number.isInteger(value) || value < 1) {\n\t\tthrow new MnemocyteError(\"limit must be a positive integer.\", \"VALIDATION\");\n\t}\n}\n\nexport function assertMinScore(value: number): void {\n\tif (!Number.isFinite(value) || value < 0 || value > 1) {\n\t\tthrow new MnemocyteError(\n\t\t\t\"minScore must be a number between 0 and 1.\",\n\t\t\t\"VALIDATION\",\n\t\t);\n\t}\n}\n\nexport function assertEmbedder(embedder: Embedder): void {\n\tif (!embedder || typeof embedder.embed !== \"function\") {\n\t\tthrow new MnemocyteError(\n\t\t\t\"embedder with an embed function is required.\",\n\t\t\t\"CONFIG\",\n\t\t);\n\t}\n\tassertNonEmptyString(embedder.model, \"embedder.model\");\n\tif (!Number.isInteger(embedder.dimensions) || embedder.dimensions < 1) {\n\t\tthrow new MnemocyteError(\n\t\t\t\"embedder.dimensions must be a positive integer.\",\n\t\t\t\"CONFIG\",\n\t\t);\n\t}\n}\n\nexport function normalizeTags(tags: readonly string[] | undefined): string[] {\n\tif (!tags) {\n\t\treturn [];\n\t}\n\treturn [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];\n}\n\nexport function createId(): string {\n\treturn `mem_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function isExpired(memory: Memory, now: Date): boolean {\n\treturn (\n\t\tmemory.expiresAt !== null && memory.expiresAt.getTime() <= now.getTime()\n\t);\n}\n\nexport function cloneMemory(memory: Memory): Memory {\n\treturn {\n\t\t...memory,\n\t\ttags: [...memory.tags],\n\t\tmetadata: { ...memory.metadata },\n\t\texpiresAt: memory.expiresAt ? new Date(memory.expiresAt) : null,\n\t\tlastAccessedAt: memory.lastAccessedAt\n\t\t\t? new Date(memory.lastAccessedAt)\n\t\t\t: null,\n\t\tcreatedAt: new Date(memory.createdAt),\n\t\tupdatedAt: new Date(memory.updatedAt),\n\t};\n}\n\nexport function rowToMemory(row: MemoryRow): Memory {\n\treturn {\n\t\tid: row.id,\n\t\tentityId: row.entityId,\n\t\tcontent: row.content,\n\t\ttype: row.type as MemoryType,\n\t\timportance: row.importance as ImportanceLevel,\n\t\ttags: row.tags,\n\t\tsource: row.source,\n\t\tmetadata: row.metadata as Record<string, unknown>,\n\t\tconfidence: row.confidence,\n\t\tembeddingModel: row.embeddingModel,\n\t\tembeddingDimensions: row.embeddingDimensions,\n\t\tsupersededBy: row.supersededBy,\n\t\texpiresAt: row.expiresAt,\n\t\tlastAccessedAt: row.lastAccessedAt,\n\t\taccessCount: row.accessCount,\n\t\tcreatedAt: row.createdAt,\n\t\tupdatedAt: row.updatedAt,\n\t};\n}\n\nexport async function embedOne(\n\tembedder: Embedder,\n\ttext: string,\n): Promise<number[]> {\n\tlet embeddings: number[][];\n\ttry {\n\t\tembeddings = await embedder.embed([text]);\n\t} catch (error) {\n\t\tthrow new MnemocyteError(\"Failed to embed text.\", \"EMBEDDING\", error);\n\t}\n\tconst embedding = embeddings[0];\n\tif (!embedding) {\n\t\tthrow new MnemocyteError(\"Embedder returned no embedding.\", \"EMBEDDING\");\n\t}\n\tif (embedding.length !== embedder.dimensions) {\n\t\tthrow new MnemocyteError(\n\t\t\t\"Embedder returned an embedding with unexpected dimensions.\",\n\t\t\t\"EMBEDDING\",\n\t\t);\n\t}\n\treturn embedding;\n}\n\nexport function validateRememberInput(input: RememberInput): void {\n\tassertNonEmptyString(input.entityId, \"entityId\");\n\tassertNonEmptyString(input.content, \"content\");\n\tif (\n\t\tinput.confidence !== undefined &&\n\t\t(!Number.isFinite(input.confidence) ||\n\t\t\tinput.confidence < 0 ||\n\t\t\tinput.confidence > 1)\n\t) {\n\t\tthrow new MnemocyteError(\n\t\t\t\"confidence must be a number between 0 and 1.\",\n\t\t\t\"VALIDATION\",\n\t\t);\n\t}\n}\n\nexport function validateRecallInput(input: RecallInput): void {\n\tassertNonEmptyString(input.entityId, \"entityId\");\n\tassertNonEmptyString(input.query, \"query\");\n\tif (input.limit !== undefined) {\n\t\tassertLimit(input.limit);\n\t}\n\tif (input.minScore !== undefined) {\n\t\tassertMinScore(input.minScore);\n\t}\n}\n\nexport function contextInputToRecallInput(\n\tinput: BuildContextInput,\n): RecallInput {\n\treturn {\n\t\tentityId: input.entityId,\n\t\tquery: input.query,\n\t\t...(input.limit === undefined ? {} : { limit: input.limit }),\n\t\t...(input.minScore === undefined ? {} : { minScore: input.minScore }),\n\t\t...(input.types === undefined ? {} : { types: input.types }),\n\t\t...(input.tags === undefined ? {} : { tags: input.tags }),\n\t\t...(input.includeSuperseded === undefined\n\t\t\t? {}\n\t\t\t: { includeSuperseded: input.includeSuperseded }),\n\t\t...(input.includeExpired === undefined\n\t\t\t? {}\n\t\t\t: { includeExpired: input.includeExpired }),\n\t};\n}\n\nexport function matchesRecallFilter(\n\tmemory: Memory,\n\tinput: RecallInput,\n\tnow: Date,\n): boolean {\n\tif (memory.entityId !== input.entityId) {\n\t\treturn false;\n\t}\n\tif (!input.includeSuperseded && memory.supersededBy !== null) {\n\t\treturn false;\n\t}\n\tif (!input.includeExpired && isExpired(memory, now)) {\n\t\treturn false;\n\t}\n\tif (input.types && !input.types.includes(memory.type)) {\n\t\treturn false;\n\t}\n\tif (input.tags && !input.tags.every((tag) => memory.tags.includes(tag))) {\n\t\treturn false;\n\t}\n\tif (input.before && memory.createdAt >= input.before) {\n\t\treturn false;\n\t}\n\tif (input.after && memory.createdAt <= input.after) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n","import { cloneMemory } from \"../memory/shared.js\";\nimport type {\n\tImportanceLevel,\n\tMemory,\n\tMemoryWithScore,\n\tRecallInput,\n\tRetrievalConfig,\n\tRetrievalScoreWeights,\n} from \"../types.js\";\n\nconst IMPORTANCE_SCORES: Record<ImportanceLevel, number> = {\n\tlow: 0,\n\tnormal: 0.5,\n\thigh: 0.8,\n\tcritical: 1,\n};\n\nconst DEFAULT_WEIGHTS: Required<RetrievalScoreWeights> = {\n\tvector: 0.55,\n\tlexical: 0.2,\n\trecency: 0.1,\n\tconfidence: 0.05,\n\taccess: 0.05,\n\timportance: 0.05,\n};\n\nconst DEFAULT_RECENCY_HALF_LIFE_DAYS = 90;\nconst DEFAULT_ACCESS_SATURATION = 10;\nexport const DEFAULT_CANDIDATE_MULTIPLIER = 3;\n\nexport function cosineSimilarity(\n\ta: readonly number[],\n\tb: readonly number[],\n): number {\n\tlet dot = 0;\n\tlet aMagnitude = 0;\n\tlet bMagnitude = 0;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst av = a[i] ?? 0;\n\t\tconst bv = b[i] ?? 0;\n\t\tdot += av * bv;\n\t\taMagnitude += av * av;\n\t\tbMagnitude += bv * bv;\n\t}\n\tif (aMagnitude === 0 || bMagnitude === 0) {\n\t\treturn 0;\n\t}\n\treturn dot / (Math.sqrt(aMagnitude) * Math.sqrt(bMagnitude));\n}\n\nexport function lexicalScore(content: string, query: string): number {\n\tconst terms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n\tif (terms.length === 0) {\n\t\treturn 0;\n\t}\n\tconst lowerContent = content.toLowerCase();\n\tconst matches = terms.filter((term) => lowerContent.includes(term)).length;\n\treturn matches / terms.length;\n}\n\nfunction clampScore(value: number): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\treturn Math.max(0, Math.min(1, value));\n}\n\nfunction normalizeWeights(\n\tweights: RetrievalScoreWeights | undefined,\n): Required<RetrievalScoreWeights> {\n\tconst merged = { ...DEFAULT_WEIGHTS, ...weights };\n\tconst total =\n\t\tmerged.vector +\n\t\tmerged.lexical +\n\t\tmerged.recency +\n\t\tmerged.confidence +\n\t\tmerged.access +\n\t\tmerged.importance;\n\tif (total <= 0) {\n\t\treturn DEFAULT_WEIGHTS;\n\t}\n\treturn {\n\t\tvector: merged.vector / total,\n\t\tlexical: merged.lexical / total,\n\t\trecency: merged.recency / total,\n\t\tconfidence: merged.confidence / total,\n\t\taccess: merged.access / total,\n\t\timportance: merged.importance / total,\n\t};\n}\n\nfunction recencyScore(createdAt: Date, halfLifeDays: number): number {\n\tconst ageMs = Date.now() - createdAt.getTime();\n\tconst ageDays = Math.max(0, ageMs / 86_400_000);\n\treturn Math.exp((-Math.LN2 * ageDays) / halfLifeDays);\n}\n\nfunction accessScore(accessCount: number, saturation: number): number {\n\tif (accessCount <= 0) {\n\t\treturn 0;\n\t}\n\treturn Math.min(1, Math.log1p(accessCount) / Math.log1p(saturation));\n}\n\nexport function toScoredMemory(\n\tmemory: Memory,\n\tvector: number,\n\tlexical: number,\n\tinput: RecallInput,\n\tconfig?: RetrievalConfig,\n): MemoryWithScore {\n\tconst weights = normalizeWeights(config?.weights);\n\tconst recency = recencyScore(\n\t\tmemory.createdAt,\n\t\tconfig?.recencyHalfLifeDays ?? DEFAULT_RECENCY_HALF_LIFE_DAYS,\n\t);\n\tconst confidence = clampScore(memory.confidence);\n\tconst access = accessScore(\n\t\tmemory.accessCount,\n\t\tconfig?.accessSaturation ?? DEFAULT_ACCESS_SATURATION,\n\t);\n\tconst importance = IMPORTANCE_SCORES[memory.importance];\n\tconst score = Math.max(\n\t\t0,\n\t\tMath.min(\n\t\t\t1,\n\t\t\tclampScore(vector) * weights.vector +\n\t\t\t\tclampScore(lexical) * weights.lexical +\n\t\t\t\trecency * weights.recency +\n\t\t\t\tconfidence * weights.confidence +\n\t\t\t\taccess * weights.access +\n\t\t\t\timportance * weights.importance,\n\t\t),\n\t);\n\treturn {\n\t\t...cloneMemory(memory),\n\t\tscore,\n\t\tscores: {\n\t\t\tvector: clampScore(vector),\n\t\t\tlexical: clampScore(lexical),\n\t\t\trecency,\n\t\t\tconfidence,\n\t\t\taccess,\n\t\t\timportance,\n\t\t},\n\t\texplanation: input.explain\n\t\t\t? {\n\t\t\t\t\tvectorScore: clampScore(vector),\n\t\t\t\t\tlexicalScore: clampScore(lexical),\n\t\t\t\t\trecencyScore: recency,\n\t\t\t\t\tconfidenceScore: confidence,\n\t\t\t\t\taccessScore: access,\n\t\t\t\t\timportanceScore: importance,\n\t\t\t\t\timportanceBoost: importance * weights.importance,\n\t\t\t\t\tweights,\n\t\t\t\t\tfinalScore: score,\n\t\t\t\t}\n\t\t\t: null,\n\t};\n}\n","import { buildContext } from \"../context/builder.js\";\nimport { MnemocyteError } from \"../errors.js\";\nimport {\n\tcosineSimilarity,\n\tlexicalScore,\n\ttoScoredMemory,\n} from \"../retrieval/scorer.js\";\nimport type {\n\tEntityStats,\n\tGlobalStats,\n\tMemory,\n\tMnemocyteClient,\n\tMnemocyteConfig,\n\tRememberInput,\n} from \"../types.js\";\nimport {\n\tassertLimit,\n\tassertMinScore,\n\tassertNonEmptyString,\n\tcloneMemory,\n\tcontextInputToRecallInput,\n\tcreateId,\n\tDEFAULT_IMPORTANCE,\n\tDEFAULT_LIMIT,\n\tDEFAULT_MIN_SCORE,\n\tDEFAULT_TYPE,\n\tembedOne,\n\tisExpired,\n\tmatchesRecallFilter,\n\tnormalizeTags,\n\ttype StoredMemory,\n\tvalidateRecallInput,\n\tvalidateRememberInput,\n} from \"./shared.js\";\n\nexport function createInMemoryClient(config: MnemocyteConfig): MnemocyteClient {\n\tconst memories = new Map<string, StoredMemory>();\n\tlet closed = false;\n\n\tfunction assertOpen(): void {\n\t\tif (closed) {\n\t\t\tthrow new MnemocyteError(\"Mnemocyte client is closed.\", \"DB\");\n\t\t}\n\t}\n\n\tasync function remember(input: RememberInput): Promise<Memory> {\n\t\tassertOpen();\n\t\tvalidateRememberInput(input);\n\t\tconst embedding = await embedOne(config.embedder, input.content);\n\t\tconst now = new Date();\n\t\tconst memory: StoredMemory = {\n\t\t\tid: createId(),\n\t\t\tentityId: input.entityId,\n\t\t\tcontent: input.content,\n\t\t\ttype: input.type ?? DEFAULT_TYPE,\n\t\t\timportance: input.importance ?? DEFAULT_IMPORTANCE,\n\t\t\ttags: normalizeTags(input.tags),\n\t\t\tsource: input.source ?? null,\n\t\t\tmetadata: input.metadata ?? {},\n\t\t\tconfidence: input.confidence ?? 1,\n\t\t\tembeddingModel: config.embedder.model,\n\t\t\tembeddingDimensions: config.embedder.dimensions,\n\t\t\tsupersededBy: null,\n\t\t\texpiresAt: input.expiresAt ?? null,\n\t\t\tlastAccessedAt: null,\n\t\t\taccessCount: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t\tembedding,\n\t\t};\n\t\tmemories.set(memory.id, memory);\n\t\treturn cloneMemory(memory);\n\t}\n\n\treturn {\n\t\tremember,\n\t\tasync rememberMany(inputs) {\n\t\t\tassertOpen();\n\t\t\tconst result: Memory[] = [];\n\t\t\tfor (const input of inputs) {\n\t\t\t\tresult.push(await remember(input));\n\t\t\t}\n\t\t\treturn result;\n\t\t},\n\t\tasync recall(input) {\n\t\t\tassertOpen();\n\t\t\tvalidateRecallInput(input);\n\t\t\tconst limit = input.limit ?? config.defaults?.limit ?? DEFAULT_LIMIT;\n\t\t\tconst minScore =\n\t\t\t\tinput.minScore ?? config.defaults?.minScore ?? DEFAULT_MIN_SCORE;\n\t\t\tassertLimit(limit);\n\t\t\tassertMinScore(minScore);\n\t\t\tconst queryEmbedding = await embedOne(config.embedder, input.query);\n\t\t\tconst now = new Date();\n\t\t\tconst scored = Array.from(memories.values())\n\t\t\t\t.filter((memory) => matchesRecallFilter(memory, input, now))\n\t\t\t\t.map((memory) =>\n\t\t\t\t\ttoScoredMemory(\n\t\t\t\t\t\tmemory,\n\t\t\t\t\t\tMath.max(0, cosineSimilarity(memory.embedding, queryEmbedding)),\n\t\t\t\t\t\tlexicalScore(memory.content, input.query),\n\t\t\t\t\t\tinput,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.filter((memory) => memory.score >= minScore)\n\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t.slice(0, limit);\n\t\t\tfor (const memory of scored) {\n\t\t\t\tconst stored = memories.get(memory.id);\n\t\t\t\tif (stored) {\n\t\t\t\t\tstored.lastAccessedAt = now;\n\t\t\t\t\tstored.accessCount += 1;\n\t\t\t\t\tstored.updatedAt = now;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn scored;\n\t\t},\n\t\tasync buildContext(input) {\n\t\t\tassertOpen();\n\t\t\treturn buildContext({\n\t\t\t\tinput,\n\t\t\t\trecall: (contextInput) =>\n\t\t\t\t\tthis.recall(contextInputToRecallInput(contextInput)),\n\t\t\t});\n\t\t},\n\t\tasync forget(input) {\n\t\t\tassertOpen();\n\t\t\tassertNonEmptyString(input.entityId, \"entityId\");\n\t\t\tassertNonEmptyString(input.memoryId, \"memoryId\");\n\t\t\tconst memory = memories.get(input.memoryId);\n\t\t\tif (!memory || memory.entityId !== input.entityId) {\n\t\t\t\tthrow new MnemocyteError(\"Memory was not found.\", \"NOT_FOUND\");\n\t\t\t}\n\t\t\tmemories.delete(input.memoryId);\n\t\t},\n\t\tasync forgetAll(input) {\n\t\t\tassertOpen();\n\t\t\tassertNonEmptyString(input.entityId, \"entityId\");\n\t\t\tfor (const [id, memory] of memories) {\n\t\t\t\tif (memory.entityId === input.entityId) {\n\t\t\t\t\tmemories.delete(id);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tasync stats(input) {\n\t\t\tassertOpen();\n\t\t\tconst now = new Date();\n\t\t\tconst allMemories = Array.from(memories.values());\n\t\t\tconst selected = input?.entityId\n\t\t\t\t? allMemories.filter((memory) => memory.entityId === input.entityId)\n\t\t\t\t: allMemories;\n\t\t\tconst activeMemoryCount = selected.filter(\n\t\t\t\t(memory) => !isExpired(memory, now) && memory.supersededBy === null,\n\t\t\t).length;\n\t\t\tconst expiredMemoryCount = selected.filter((memory) =>\n\t\t\t\tisExpired(memory, now),\n\t\t\t).length;\n\t\t\tconst supersededMemoryCount = selected.filter(\n\t\t\t\t(memory) => memory.supersededBy !== null,\n\t\t\t).length;\n\t\t\tif (input?.entityId) {\n\t\t\t\treturn {\n\t\t\t\t\tentityId: input.entityId,\n\t\t\t\t\tmemoryCount: selected.length,\n\t\t\t\t\tactiveMemoryCount,\n\t\t\t\t\texpiredMemoryCount,\n\t\t\t\t\tsupersededMemoryCount,\n\t\t\t\t} satisfies EntityStats;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tentityCount: new Set(allMemories.map((memory) => memory.entityId)).size,\n\t\t\t\tmemoryCount: selected.length,\n\t\t\t\tactiveMemoryCount,\n\t\t\t\texpiredMemoryCount,\n\t\t\t\tsupersededMemoryCount,\n\t\t\t} satisfies GlobalStats;\n\t\t},\n\t\tasync close() {\n\t\t\tclosed = true;\n\t\t\tmemories.clear();\n\t\t},\n\t};\n}\n","import { and, desc, eq, gt, lt } from \"drizzle-orm\";\nimport type { MnemocyteDatabase } from \"../index.js\";\nimport { type EventRow, eventsTable, type NewEventRow } from \"../schema.js\";\n\nexport interface EventFilter {\n\tentityId: string;\n\tlimit?: number;\n\tbefore?: Date;\n\tafter?: Date;\n}\n\nexport async function insertEvent(\n\tdb: MnemocyteDatabase,\n\trow: NewEventRow,\n): Promise<EventRow> {\n\tconst result = await db.insert(eventsTable).values(row).returning();\n\tconst inserted = result[0];\n\tif (!inserted) {\n\t\tthrow new Error(\"Event insert returned no rows.\");\n\t}\n\treturn inserted;\n}\n\nexport async function listEvents(\n\tdb: MnemocyteDatabase,\n\tfilter: EventFilter,\n): Promise<EventRow[]> {\n\treturn db\n\t\t.select()\n\t\t.from(eventsTable)\n\t\t.where(\n\t\t\tand(\n\t\t\t\teq(eventsTable.entityId, filter.entityId),\n\t\t\t\tfilter.before ? lt(eventsTable.timestamp, filter.before) : undefined,\n\t\t\t\tfilter.after ? gt(eventsTable.timestamp, filter.after) : undefined,\n\t\t\t),\n\t\t)\n\t\t.orderBy(desc(eventsTable.timestamp))\n\t\t.limit(filter.limit ?? 50);\n}\n\nexport async function deleteEventsForEntity(\n\tdb: MnemocyteDatabase,\n\tentityId: string,\n): Promise<number> {\n\tconst result = await db\n\t\t.delete(eventsTable)\n\t\t.where(eq(eventsTable.entityId, entityId))\n\t\t.returning({ id: eventsTable.id });\n\treturn result.length;\n}\n","import { and, eq, gt, inArray, isNull, lt, sql } from \"drizzle-orm\";\nimport type { MemoryType } from \"../../types.js\";\nimport type { MnemocyteDatabase } from \"../index.js\";\nimport { type MemoryRow, memoriesTable, type NewMemoryRow } from \"../schema.js\";\n\nexport interface MemoryFilter {\n\tentityId: string;\n\ttypes?: readonly MemoryType[];\n\ttags?: readonly string[];\n\tbefore?: Date;\n\tafter?: Date;\n\tincludeSuperseded?: boolean;\n\tincludeExpired?: boolean;\n}\n\nexport interface VectorSearchInput extends MemoryFilter {\n\tembedding: readonly number[];\n\tlimit: number;\n\tminScore?: number;\n}\n\nexport interface LexicalSearchInput extends MemoryFilter {\n\tquery: string;\n\tlimit: number;\n}\n\nfunction vectorLiteral(embedding: readonly number[]): string {\n\treturn `[${embedding.join(\",\")}]`;\n}\n\nfunction filterConditions(filter: MemoryFilter) {\n\treturn and(\n\t\teq(memoriesTable.entityId, filter.entityId),\n\t\tfilter.includeSuperseded ? undefined : isNull(memoriesTable.supersededBy),\n\t\tfilter.includeExpired\n\t\t\t? undefined\n\t\t\t: sql`(${memoriesTable.expiresAt} IS NULL OR ${memoriesTable.expiresAt} > now())`,\n\t\tfilter.types && filter.types.length > 0\n\t\t\t? inArray(memoriesTable.type, [...filter.types])\n\t\t\t: undefined,\n\t\tfilter.tags && filter.tags.length > 0\n\t\t\t? sql`${memoriesTable.tags} && ${filter.tags}`\n\t\t\t: undefined,\n\t\tfilter.before ? lt(memoriesTable.createdAt, filter.before) : undefined,\n\t\tfilter.after ? gt(memoriesTable.createdAt, filter.after) : undefined,\n\t);\n}\n\nexport async function insertMemory(\n\tdb: MnemocyteDatabase,\n\trow: NewMemoryRow,\n): Promise<MemoryRow> {\n\tconst result = await db.insert(memoriesTable).values(row).returning();\n\tconst inserted = result[0];\n\tif (!inserted) {\n\t\tthrow new Error(\"Memory insert returned no rows.\");\n\t}\n\treturn inserted;\n}\n\nexport async function getMemoryById(\n\tdb: MnemocyteDatabase,\n\tentityId: string,\n\tmemoryId: string,\n): Promise<MemoryRow | null> {\n\tconst result = await db\n\t\t.select()\n\t\t.from(memoriesTable)\n\t\t.where(\n\t\t\tand(eq(memoriesTable.entityId, entityId), eq(memoriesTable.id, memoryId)),\n\t\t)\n\t\t.limit(1);\n\treturn result[0] ?? null;\n}\n\nexport async function listMemories(\n\tdb: MnemocyteDatabase,\n\tfilter: MemoryFilter,\n): Promise<MemoryRow[]> {\n\treturn db.select().from(memoriesTable).where(filterConditions(filter));\n}\n\nexport async function deleteMemory(\n\tdb: MnemocyteDatabase,\n\tentityId: string,\n\tmemoryId: string,\n): Promise<boolean> {\n\tconst result = await db\n\t\t.delete(memoriesTable)\n\t\t.where(\n\t\t\tand(eq(memoriesTable.entityId, entityId), eq(memoriesTable.id, memoryId)),\n\t\t)\n\t\t.returning({ id: memoriesTable.id });\n\treturn result.length > 0;\n}\n\nexport async function deleteMemoriesForEntity(\n\tdb: MnemocyteDatabase,\n\tentityId: string,\n): Promise<number> {\n\tconst result = await db\n\t\t.delete(memoriesTable)\n\t\t.where(eq(memoriesTable.entityId, entityId))\n\t\t.returning({ id: memoriesTable.id });\n\treturn result.length;\n}\n\nexport async function markMemoryAccessed(\n\tdb: MnemocyteDatabase,\n\tmemoryIds: readonly string[],\n): Promise<void> {\n\tif (memoryIds.length === 0) {\n\t\treturn;\n\t}\n\tawait db\n\t\t.update(memoriesTable)\n\t\t.set({\n\t\t\tlastAccessedAt: new Date(),\n\t\t\taccessCount: sql`${memoriesTable.accessCount} + 1`,\n\t\t\tupdatedAt: new Date(),\n\t\t})\n\t\t.where(inArray(memoriesTable.id, [...memoryIds]));\n}\n\nexport async function vectorSearch(\n\tdb: MnemocyteDatabase,\n\tinput: VectorSearchInput,\n): Promise<Array<MemoryRow & { vectorScore: number }>> {\n\tconst embedding = vectorLiteral(input.embedding);\n\tconst minScore = input.minScore ?? 0;\n\tconst rows = await db.execute(sql`\n\t\tSELECT\n\t\t\tid,\n\t\t\tentity_id AS \"entityId\",\n\t\t\tcontent,\n\t\t\ttype,\n\t\t\timportance,\n\t\t\ttags,\n\t\t\tsource,\n\t\t\tmetadata,\n\t\t\tconfidence,\n\t\t\tembedding,\n\t\t\tembedding_model AS \"embeddingModel\",\n\t\t\tembedding_dimensions AS \"embeddingDimensions\",\n\t\t\tsuperseded_by AS \"supersededBy\",\n\t\t\tsuperseded_at AS \"supersededAt\",\n\t\t\texpires_at AS \"expiresAt\",\n\t\t\tlast_accessed_at AS \"lastAccessedAt\",\n\t\t\taccess_count AS \"accessCount\",\n\t\t\tcreated_at AS \"createdAt\",\n\t\t\tupdated_at AS \"updatedAt\",\n\t\t\t1 - (embedding <=> ${embedding}::vector) AS \"vectorScore\"\n\t\tFROM mnemocyte_memories\n\t\tWHERE\n\t\t\tentity_id = ${input.entityId}\n\t\t\tAND embedding IS NOT NULL\n\t\t\t${input.includeSuperseded ? sql`` : sql`AND superseded_by IS NULL`}\n\t\t\t${input.includeExpired ? sql`` : sql`AND (expires_at IS NULL OR expires_at > now())`}\n\t\t\t${\n\t\t\t\tinput.types && input.types.length > 0\n\t\t\t\t\t? sql`AND type IN (${sql.join(\n\t\t\t\t\t\t\tinput.types.map((type) => sql`${type}`),\n\t\t\t\t\t\t\tsql`, `,\n\t\t\t\t\t\t)})`\n\t\t\t\t\t: sql``\n\t\t\t}\n\t\t\t${input.tags && input.tags.length > 0 ? sql`AND tags && ${input.tags}` : sql``}\n\t\t\t${input.before ? sql`AND created_at < ${input.before}` : sql``}\n\t\t\t${input.after ? sql`AND created_at > ${input.after}` : sql``}\n\t\t\tAND 1 - (embedding <=> ${embedding}::vector) >= ${minScore}\n\t\tORDER BY embedding <=> ${embedding}::vector\n\t\tLIMIT ${input.limit}\n\t`);\n\treturn rows as unknown as Array<MemoryRow & { vectorScore: number }>;\n}\n\nexport async function lexicalSearch(\n\tdb: MnemocyteDatabase,\n\tinput: LexicalSearchInput,\n): Promise<Array<MemoryRow & { lexicalScore: number }>> {\n\tconst rows = await db.execute(sql`\n\t\tSELECT\n\t\t\tid,\n\t\t\tentity_id AS \"entityId\",\n\t\t\tcontent,\n\t\t\ttype,\n\t\t\timportance,\n\t\t\ttags,\n\t\t\tsource,\n\t\t\tmetadata,\n\t\t\tconfidence,\n\t\t\tembedding,\n\t\t\tembedding_model AS \"embeddingModel\",\n\t\t\tembedding_dimensions AS \"embeddingDimensions\",\n\t\t\tsuperseded_by AS \"supersededBy\",\n\t\t\tsuperseded_at AS \"supersededAt\",\n\t\t\texpires_at AS \"expiresAt\",\n\t\t\tlast_accessed_at AS \"lastAccessedAt\",\n\t\t\taccess_count AS \"accessCount\",\n\t\t\tcreated_at AS \"createdAt\",\n\t\t\tupdated_at AS \"updatedAt\",\n\t\t\tts_rank(to_tsvector('english', content), websearch_to_tsquery('english', ${input.query})) AS \"lexicalScore\"\n\t\tFROM mnemocyte_memories\n\t\tWHERE\n\t\t\tentity_id = ${input.entityId}\n\t\t\t${input.includeSuperseded ? sql`` : sql`AND superseded_by IS NULL`}\n\t\t\t${input.includeExpired ? sql`` : sql`AND (expires_at IS NULL OR expires_at > now())`}\n\t\t\t${\n\t\t\t\tinput.types && input.types.length > 0\n\t\t\t\t\t? sql`AND type IN (${sql.join(\n\t\t\t\t\t\t\tinput.types.map((type) => sql`${type}`),\n\t\t\t\t\t\t\tsql`, `,\n\t\t\t\t\t\t)})`\n\t\t\t\t\t: sql``\n\t\t\t}\n\t\t\t${input.tags && input.tags.length > 0 ? sql`AND tags && ${input.tags}` : sql``}\n\t\t\t${input.before ? sql`AND created_at < ${input.before}` : sql``}\n\t\t\t${input.after ? sql`AND created_at > ${input.after}` : sql``}\n\t\t\tAND to_tsvector('english', content) @@ websearch_to_tsquery('english', ${input.query})\n\t\tORDER BY \"lexicalScore\" DESC\n\t\tLIMIT ${input.limit}\n\t`);\n\treturn rows as unknown as Array<MemoryRow & { lexicalScore: number }>;\n}\n","import type { MnemocyteDatabase } from \"../db/index.js\";\nimport {\n\tlexicalSearch,\n\tmarkMemoryAccessed,\n\tvectorSearch,\n} from \"../db/queries/memories.js\";\nimport type { MemoryRow } from \"../db/schema.js\";\nimport { embedOne, rowToMemory } from \"../memory/shared.js\";\nimport type {\n\tEmbedder,\n\tMemoryWithScore,\n\tRecallInput,\n\tRetrievalConfig,\n} from \"../types.js\";\nimport { DEFAULT_CANDIDATE_MULTIPLIER, toScoredMemory } from \"./scorer.js\";\n\ninterface HybridRecallInput {\n\tdb: MnemocyteDatabase;\n\tembedder: Embedder;\n\tinput: RecallInput;\n\tlimit: number;\n\tminScore: number;\n\tretrieval: RetrievalConfig | undefined;\n}\n\ninterface ScoredRow {\n\trow: MemoryRow;\n\tvectorScore: number;\n\tlexicalScore: number;\n}\n\nexport async function hybridRecall(\n\tinput: HybridRecallInput,\n): Promise<MemoryWithScore[]> {\n\tconst queryEmbedding = await embedOne(input.embedder, input.input.query);\n\tconst candidateMultiplier =\n\t\tinput.retrieval?.candidateMultiplier ?? DEFAULT_CANDIDATE_MULTIPLIER;\n\tconst candidateLimit = Math.max(\n\t\tinput.limit,\n\t\tinput.limit * candidateMultiplier,\n\t);\n\tconst [vectorRows, lexicalRows] = await Promise.all([\n\t\tvectorSearch(input.db, {\n\t\t\t...input.input,\n\t\t\tembedding: queryEmbedding,\n\t\t\tlimit: candidateLimit,\n\t\t\tminScore: 0,\n\t\t}),\n\t\tlexicalSearch(input.db, { ...input.input, limit: candidateLimit }),\n\t]);\n\tconst merged = new Map<string, ScoredRow>();\n\tfor (const row of vectorRows) {\n\t\tmerged.set(row.id, {\n\t\t\trow,\n\t\t\tvectorScore: row.vectorScore,\n\t\t\tlexicalScore: 0,\n\t\t});\n\t}\n\tfor (const row of lexicalRows) {\n\t\tconst existing = merged.get(row.id);\n\t\tif (existing) {\n\t\t\texisting.lexicalScore = row.lexicalScore;\n\t\t} else {\n\t\t\tmerged.set(row.id, {\n\t\t\t\trow,\n\t\t\t\tvectorScore: 0,\n\t\t\t\tlexicalScore: row.lexicalScore,\n\t\t\t});\n\t\t}\n\t}\n\tconst scored = Array.from(merged.values())\n\t\t.map((entry) =>\n\t\t\ttoScoredMemory(\n\t\t\t\trowToMemory(entry.row),\n\t\t\t\tMath.max(0, entry.vectorScore),\n\t\t\t\tMath.max(0, entry.lexicalScore),\n\t\t\t\tinput.input,\n\t\t\t\tinput.retrieval,\n\t\t\t),\n\t\t)\n\t\t.filter((memory) => memory.score >= input.minScore)\n\t\t.sort((a, b) => b.score - a.score)\n\t\t.slice(0, input.limit);\n\tawait markMemoryAccessed(\n\t\tinput.db,\n\t\tscored.map((memory) => memory.id),\n\t);\n\treturn scored;\n}\n","import { buildContext } from \"../context/builder.js\";\nimport type { DatabaseHandle } from \"../db/index.js\";\nimport { deleteEventsForEntity } from \"../db/queries/events.js\";\nimport {\n\tdeleteMemoriesForEntity,\n\tdeleteMemory,\n\tinsertMemory,\n\tlistMemories,\n} from \"../db/queries/memories.js\";\nimport { memoriesTable } from \"../db/schema.js\";\nimport { MnemocyteError } from \"../errors.js\";\nimport { hybridRecall } from \"../retrieval/index.js\";\nimport type {\n\tEntityStats,\n\tGlobalStats,\n\tMemory,\n\tMnemocyteClient,\n\tMnemocyteConfig,\n\tRememberInput,\n} from \"../types.js\";\nimport {\n\tassertLimit,\n\tassertMinScore,\n\tassertNonEmptyString,\n\tcontextInputToRecallInput,\n\tcreateId,\n\tDEFAULT_IMPORTANCE,\n\tDEFAULT_LIMIT,\n\tDEFAULT_MIN_SCORE,\n\tDEFAULT_TYPE,\n\tembedOne,\n\tisExpired,\n\tnormalizeTags,\n\trowToMemory,\n\tvalidateRecallInput,\n\tvalidateRememberInput,\n} from \"./shared.js\";\n\nexport function createPostgresClient(\n\tconfig: MnemocyteConfig,\n\thandle: DatabaseHandle,\n): MnemocyteClient {\n\tlet closed = false;\n\n\tfunction assertOpen(): void {\n\t\tif (closed) {\n\t\t\tthrow new MnemocyteError(\"Mnemocyte client is closed.\", \"DB\");\n\t\t}\n\t}\n\n\tasync function remember(input: RememberInput): Promise<Memory> {\n\t\tassertOpen();\n\t\tvalidateRememberInput(input);\n\t\tconst embedding = await embedOne(config.embedder, input.content);\n\t\tconst now = new Date();\n\t\tconst row = await insertMemory(handle.db, {\n\t\t\tid: createId(),\n\t\t\tentityId: input.entityId,\n\t\t\tcontent: input.content,\n\t\t\ttype: input.type ?? DEFAULT_TYPE,\n\t\t\timportance: input.importance ?? DEFAULT_IMPORTANCE,\n\t\t\ttags: normalizeTags(input.tags),\n\t\t\tsource: input.source ?? null,\n\t\t\tmetadata: input.metadata ?? {},\n\t\t\tconfidence: input.confidence ?? 1,\n\t\t\tembedding,\n\t\t\tembeddingModel: config.embedder.model,\n\t\t\tembeddingDimensions: config.embedder.dimensions,\n\t\t\tsupersededBy: null,\n\t\t\tsupersededAt: null,\n\t\t\texpiresAt: input.expiresAt ?? null,\n\t\t\tlastAccessedAt: null,\n\t\t\taccessCount: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t});\n\t\treturn rowToMemory(row);\n\t}\n\n\treturn {\n\t\tremember,\n\t\tasync rememberMany(inputs) {\n\t\t\tassertOpen();\n\t\t\tconst result: Memory[] = [];\n\t\t\tfor (const input of inputs) {\n\t\t\t\tresult.push(await remember(input));\n\t\t\t}\n\t\t\treturn result;\n\t\t},\n\t\tasync recall(input) {\n\t\t\tassertOpen();\n\t\t\tvalidateRecallInput(input);\n\t\t\tconst limit = input.limit ?? config.defaults?.limit ?? DEFAULT_LIMIT;\n\t\t\tconst minScore =\n\t\t\t\tinput.minScore ?? config.defaults?.minScore ?? DEFAULT_MIN_SCORE;\n\t\t\tassertLimit(limit);\n\t\t\tassertMinScore(minScore);\n\t\t\treturn hybridRecall({\n\t\t\t\tdb: handle.db,\n\t\t\t\tembedder: config.embedder,\n\t\t\t\tinput,\n\t\t\t\tlimit,\n\t\t\t\tminScore,\n\t\t\t\tretrieval: config.retrieval,\n\t\t\t});\n\t\t},\n\t\tasync buildContext(input) {\n\t\t\tassertOpen();\n\t\t\treturn buildContext({\n\t\t\t\tinput,\n\t\t\t\trecall: (contextInput) =>\n\t\t\t\t\tthis.recall(contextInputToRecallInput(contextInput)),\n\t\t\t});\n\t\t},\n\t\tasync forget(input) {\n\t\t\tassertOpen();\n\t\t\tassertNonEmptyString(input.entityId, \"entityId\");\n\t\t\tassertNonEmptyString(input.memoryId, \"memoryId\");\n\t\t\tconst deleted = await deleteMemory(\n\t\t\t\thandle.db,\n\t\t\t\tinput.entityId,\n\t\t\t\tinput.memoryId,\n\t\t\t);\n\t\t\tif (!deleted) {\n\t\t\t\tthrow new MnemocyteError(\"Memory was not found.\", \"NOT_FOUND\");\n\t\t\t}\n\t\t},\n\t\tasync forgetAll(input) {\n\t\t\tassertOpen();\n\t\t\tassertNonEmptyString(input.entityId, \"entityId\");\n\t\t\tawait Promise.all([\n\t\t\t\tdeleteMemoriesForEntity(handle.db, input.entityId),\n\t\t\t\tdeleteEventsForEntity(handle.db, input.entityId),\n\t\t\t]);\n\t\t},\n\t\tasync stats(input) {\n\t\t\tassertOpen();\n\t\t\tconst now = new Date();\n\t\t\tif (input?.entityId) {\n\t\t\t\tconst selected = await listMemories(handle.db, {\n\t\t\t\t\tentityId: input.entityId,\n\t\t\t\t\tincludeExpired: true,\n\t\t\t\t\tincludeSuperseded: true,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tentityId: input.entityId,\n\t\t\t\t\tmemoryCount: selected.length,\n\t\t\t\t\tactiveMemoryCount: selected.filter(\n\t\t\t\t\t\t(memory) =>\n\t\t\t\t\t\t\t!isExpired(rowToMemory(memory), now) &&\n\t\t\t\t\t\t\tmemory.supersededBy === null,\n\t\t\t\t\t).length,\n\t\t\t\t\texpiredMemoryCount: selected.filter((memory) =>\n\t\t\t\t\t\tisExpired(rowToMemory(memory), now),\n\t\t\t\t\t).length,\n\t\t\t\t\tsupersededMemoryCount: selected.filter(\n\t\t\t\t\t\t(memory) => memory.supersededBy !== null,\n\t\t\t\t\t).length,\n\t\t\t\t} satisfies EntityStats;\n\t\t\t}\n\t\t\tconst allMemories = await handle.db.select().from(memoriesTable);\n\t\t\treturn {\n\t\t\t\tentityCount: new Set(allMemories.map((memory) => memory.entityId)).size,\n\t\t\t\tmemoryCount: allMemories.length,\n\t\t\t\tactiveMemoryCount: allMemories.filter(\n\t\t\t\t\t(memory) =>\n\t\t\t\t\t\t!isExpired(rowToMemory(memory), now) &&\n\t\t\t\t\t\tmemory.supersededBy === null,\n\t\t\t\t).length,\n\t\t\t\texpiredMemoryCount: allMemories.filter((memory) =>\n\t\t\t\t\tisExpired(rowToMemory(memory), now),\n\t\t\t\t).length,\n\t\t\t\tsupersededMemoryCount: allMemories.filter(\n\t\t\t\t\t(memory) => memory.supersededBy !== null,\n\t\t\t\t).length,\n\t\t\t} satisfies GlobalStats;\n\t\t},\n\t\tasync close() {\n\t\t\tclosed = true;\n\t\t\tawait handle.close();\n\t\t},\n\t};\n}\n","import { createDatabase } from \"./db/index.js\";\nimport { createInMemoryClient } from \"./memory/in-memory.js\";\nimport { createPostgresClient } from \"./memory/postgres.js\";\nimport { assertEmbedder, assertNonEmptyString } from \"./memory/shared.js\";\nimport type { MnemocyteClient, MnemocyteConfig } from \"./types.js\";\n\nexport function createMnemocyte(config: MnemocyteConfig): MnemocyteClient {\n\tassertEmbedder(config.embedder);\n\tif (config.databaseUrl) {\n\t\tassertNonEmptyString(config.databaseUrl, \"databaseUrl\");\n\t\treturn createPostgresClient(config, createDatabase(config.databaseUrl));\n\t}\n\treturn createInMemoryClient(config);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mnemocyte",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Persistent memory for TypeScript AI apps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -64,7 +64,10 @@
|
|
|
64
64
|
"build": "tsdown src/index.ts",
|
|
65
65
|
"dev": "tsdown src/index.ts --watch",
|
|
66
66
|
"checktypes": "tsc --noEmit",
|
|
67
|
+
"test:retrieval": "pnpm build && node test/retrieval/quality.test.mjs",
|
|
68
|
+
"test:context": "pnpm build && node test/context/builder.test.mjs",
|
|
67
69
|
"test:integration": "pnpm build && node test/integration/postgres.test.mjs",
|
|
70
|
+
"bench:retrieval": "pnpm build && node test/benchmarks/retrieval.bench.mjs",
|
|
68
71
|
"lint": "biome lint --write",
|
|
69
72
|
"format": "biome format --write",
|
|
70
73
|
"db:generate": "drizzle-kit generate",
|