@cartisien/engram 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +104 -203
  2. package/dist/adapters/base.d.ts +2 -0
  3. package/dist/adapters/base.d.ts.map +1 -0
  4. package/dist/adapters/base.js +2 -0
  5. package/dist/adapters/base.js.map +1 -0
  6. package/dist/adapters/memory.d.ts +17 -0
  7. package/dist/adapters/memory.d.ts.map +1 -0
  8. package/dist/adapters/memory.js +58 -0
  9. package/dist/adapters/memory.js.map +1 -0
  10. package/dist/adapters/postgres.d.ts +33 -0
  11. package/dist/adapters/postgres.d.ts.map +1 -0
  12. package/dist/adapters/postgres.js +47 -0
  13. package/dist/adapters/postgres.js.map +1 -0
  14. package/dist/adapters/sqlite.d.ts +19 -0
  15. package/dist/adapters/sqlite.d.ts.map +1 -0
  16. package/dist/adapters/sqlite.js +33 -0
  17. package/dist/adapters/sqlite.js.map +1 -0
  18. package/dist/engram.d.ts +57 -0
  19. package/dist/engram.d.ts.map +1 -0
  20. package/dist/engram.js +148 -0
  21. package/dist/engram.js.map +1 -0
  22. package/dist/index.d.ts +99 -122
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +458 -468
  25. package/dist/index.js.map +1 -1
  26. package/dist/types.d.ts +48 -0
  27. package/dist/types.d.ts.map +1 -0
  28. package/dist/types.js +8 -0
  29. package/dist/types.js.map +1 -0
  30. package/dist/utils/embeddings.d.ts +20 -0
  31. package/dist/utils/embeddings.d.ts.map +1 -0
  32. package/dist/utils/embeddings.js +28 -0
  33. package/dist/utils/embeddings.js.map +1 -0
  34. package/dist/utils/similarity.d.ts +10 -0
  35. package/dist/utils/similarity.d.ts.map +1 -0
  36. package/dist/utils/similarity.js +31 -0
  37. package/dist/utils/similarity.js.map +1 -0
  38. package/package.json +4 -3
  39. package/LICENSE +0 -21
  40. package/dist/example/temporal-demo.js +0 -91
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Engram
2
2
 
3
- > **Persistent memory for AI assistants with temporal recall.**
3
+ > **Persistent semantic memory for AI agents.**
4
+
5
+ ![Engram demo](assets/demo.gif)
4
6
 
5
7
  ```typescript
6
8
  import { Engram } from '@cartisien/engram';
@@ -8,11 +10,11 @@ import { Engram } from '@cartisien/engram';
8
10
  const memory = new Engram({ dbPath: './memory.db' });
9
11
 
10
12
  // Store
11
- await memory.remember('user_123', 'I ride a Triumph Bonneville', 'user');
13
+ await memory.remember('user_123', 'User prefers TypeScript and dark mode', 'user');
12
14
 
13
- // Recall with temporal queries
14
- const yesterday = await memory.recallByTime('user_123', 'yesterday');
15
- const lastWeek = await memory.recallByTime('user_123', 'last week');
15
+ // Recall semantically finds the right memory even without exact keyword match
16
+ const context = await memory.recall('user_123', 'what are the user\'s preferences?', 5);
17
+ // [{ content: 'User prefers TypeScript and dark mode', similarity: 0.82, ... }]
16
18
  ```
17
19
 
18
20
  ---
@@ -21,16 +23,16 @@ const lastWeek = await memory.recallByTime('user_123', 'last week');
21
23
 
22
24
  AI assistants are amnesiacs. Every conversation starts fresh. Context windows fill up. Important details get lost.
23
25
 
24
- You wouldn't hire an employee who forgot every meeting. Why accept it from your AI?
26
+ Stuffing everything into the system prompt wastes tokens and still misses things. You need a retrieval layer — not a dump.
25
27
 
26
28
  ## The Solution
27
29
 
28
- Engram gives your assistants **persistent, queryable memory** — backed by SQLite, designed for simplicity.
30
+ Engram gives your agents **persistent, semantically searchable memory** — SQLite-backed, TypeScript-first, zero config.
29
31
 
30
- - **Zero config:** Works out of the box
31
- - **Fast:** SQLite with proper indexes
32
- - **Temporal:** Natural language time queries ("yesterday", "last week", "3 days ago")
33
- - **Portable:** Single file database
32
+ - **Semantic search:** Finds relevant memories by meaning, not just keywords (via local Ollama embeddings)
33
+ - **Zero config:** Works out of the box, falls back to keyword search without Ollama
34
+ - **Local-first:** Your data stays on your machine. No API keys, no cloud required
35
+ - **MCP-native:** Drop into Claude Desktop or Cursor via [`@cartisien/engram-mcp`](https://github.com/Cartisien/engram-mcp)
34
36
  - **Typed:** Full TypeScript support
35
37
 
36
38
  ## Installation
@@ -39,285 +41,184 @@ Engram gives your assistants **persistent, queryable memory** — backed by SQLi
39
41
  npm install @cartisien/engram
40
42
  ```
41
43
 
44
+ ### Optional: Local Embeddings (Recommended)
45
+
46
+ For semantic search, install [Ollama](https://ollama.ai) and pull the embedding model:
47
+
48
+ ```bash
49
+ ollama pull nomic-embed-text
50
+ ```
51
+
52
+ Without Ollama, Engram falls back to keyword search automatically.
53
+
42
54
  ## Quick Start
43
55
 
44
56
  ```typescript
45
57
  import { Engram } from '@cartisien/engram';
46
58
 
47
59
  const memory = new Engram({
48
- dbPath: './bot-memory.db' // or ':memory:' for ephemeral
60
+ dbPath: './bot-memory.db',
61
+ embeddingUrl: 'http://localhost:11434', // Ollama default
49
62
  });
50
63
 
51
- // In your chat handler
52
- async function handleChat(sessionId: string, message: string) {
53
- // 1. Store the user's message
54
- await memory.remember(sessionId, message, 'user');
55
-
56
- // 2. Retrieve relevant context
64
+ // In your agent/chat handler
65
+ async function handleMessage(sessionId: string, message: string) {
66
+ // 1. Recall relevant context semantically
57
67
  const context = await memory.recall(sessionId, message, 5);
58
-
59
- // 3. Build prompt with memory
68
+
69
+ // 2. Build prompt with memory
60
70
  const prompt = buildPrompt(context, message);
61
-
62
- // 4. Get AI response
63
- const response = await openai.chat.completions.create({ messages: prompt });
64
-
65
- // 5. Store the response
66
- await memory.remember(sessionId, response.choices[0].message.content, 'assistant');
67
-
68
- return response;
69
- }
70
- ```
71
71
 
72
- ## Temporal Recall
72
+ // 3. Get AI response
73
+ const response = await llm.chat(prompt);
73
74
 
74
- Engram understands natural language time expressions. Ask for memories from any point in time:
75
+ // 4. Store both sides
76
+ await memory.remember(sessionId, message, 'user');
77
+ await memory.remember(sessionId, response, 'assistant');
75
78
 
76
- ```typescript
77
- // Simple temporal queries
78
- const yesterday = await memory.recallByTime('session_123', 'yesterday');
79
- const lastWeek = await memory.recallByTime('session_123', 'last week');
80
- const threeDaysAgo = await memory.recallByTime('session_123', '3 days ago');
81
-
82
- // Combined with keyword search
83
- const meetingsLastWeek = await memory.recallByTime(
84
- 'session_123',
85
- 'last week',
86
- 'meeting' // Only entries containing "meeting"
87
- );
88
-
89
- // Recent memories (last 7 days)
90
- const recent = await memory.recallRecent('session_123', 7);
91
-
92
- // Since a specific date
93
- const sinceLaunch = await memory.recallSince('session_123', new Date('2024-01-01'));
94
-
95
- // Daily summaries
96
- const lastWeekByDay = await memory.dailySummary('session_123', 7);
97
- // Returns: [{ date, entries: [...], count }, ...]
79
+ return response;
80
+ }
98
81
  ```
99
82
 
100
- ### Supported Temporal Expressions
101
-
102
- | Expression | Meaning |
103
- |------------|---------|
104
- | `today` | From midnight to now |
105
- | `yesterday` | Full previous day |
106
- | `tomorrow` | Next day (useful for scheduled items) |
107
- | `3 days ago` | Specific day 3 days back |
108
- | `a week ago` | 7 days ago |
109
- | `2 weeks ago` | 14 days ago |
110
- | `last monday` | Most recent Monday |
111
- | `last week` | Previous full week (Sun-Sat) |
112
- | `last month` | Previous full month |
113
- | `this week` | Current week (Sun-today) |
114
- | `this month` | Current month |
115
- | `last 3 days` | Last 72 hours |
116
- | `last 7 days` | Last week (rolling) |
117
- | `january 15` | Specific date |
118
- | `3/15` | March 15 (current year) |
119
- | `jan 15 to jan 20` | Date range |
120
- | `recent`, `lately` | Last 7 days |
121
-
122
83
  ## API
123
84
 
124
85
  ### `new Engram(config?)`
125
86
 
126
- Create a memory instance.
127
-
128
87
  ```typescript
129
88
  const memory = new Engram({
130
- dbPath: './memory.db', // Database file path
131
- maxContextLength: 4000 // Max characters per entry
89
+ dbPath: './memory.db', // SQLite file path (default: ':memory:')
90
+ maxContextLength: 4000, // Max chars per entry (default: 4000)
91
+ embeddingUrl: 'http://localhost:11434', // Ollama base URL
92
+ embeddingModel: 'nomic-embed-text', // Embedding model
93
+ semanticSearch: true, // Enable semantic search (default: true)
132
94
  });
133
95
  ```
134
96
 
135
97
  ### `remember(sessionId, content, role?, metadata?)`
136
98
 
137
- Store a memory entry.
99
+ Store a memory. Embedding is generated automatically.
138
100
 
139
101
  ```typescript
140
- await memory.remember('session_abc', 'User loves Thai food', 'user', {
141
- source: 'preference_extraction'
142
- });
102
+ await memory.remember('session_abc', 'User loves Thai food', 'user');
143
103
  ```
144
104
 
145
105
  ### `recall(sessionId, query?, limit?, options?)`
146
106
 
147
- Retrieve memories for a session. Supports temporal filtering via `options.temporalQuery`.
107
+ Retrieve relevant memories. Uses semantic search when available, keyword fallback otherwise. Returns entries sorted by similarity score.
148
108
 
149
109
  ```typescript
150
- // Recent memories
151
- const recent = await memory.recall('session_abc', undefined, 10);
152
-
153
- // Keyword search
154
- const relevant = await memory.recall('session_abc', 'food preferences', 5);
155
-
156
- // Temporal + keyword
157
- const yesterdayMeetings = await memory.recall(
158
- 'session_abc',
159
- 'meeting',
160
- 10,
161
- { temporalQuery: 'yesterday' }
162
- );
163
-
164
- // Filtered by role
165
- const userOnly = await memory.recall('session_abc', undefined, 10, { role: 'user' });
110
+ const results = await memory.recall('session_abc', 'food preferences', 5);
111
+ // [{ content: '...', similarity: 0.84, ... }]
166
112
  ```
167
113
 
168
- ### `recallByTime(sessionId, temporalQuery, keyword?, limit?, options?)`
114
+ ### `history(sessionId, limit?)`
169
115
 
170
- Recall memories by natural language time expression.
116
+ Chronological conversation history.
171
117
 
172
118
  ```typescript
173
- const { entries, range } = await memory.recallByTime(
174
- 'session_abc',
175
- 'last week',
176
- 'project update' // optional keyword filter
177
- );
178
-
179
- console.log(`Found ${entries.length} entries from ${range.description}`);
180
- console.log(`Range: ${range.start.toDateString()} to ${range.end.toDateString()}`);
119
+ const chat = await memory.history('session_abc', 20);
181
120
  ```
182
121
 
183
- ### `recallRecent(sessionId, days?, keyword?, limit?, options?)`
122
+ ### `forget(sessionId, options?)`
184
123
 
185
- Get memories from the last N days.
124
+ Delete memories.
186
125
 
187
126
  ```typescript
188
- const { entries, days, since } = await memory.recallRecent('session_abc', 7);
189
- console.log(`${entries.length} entries in the last ${days} days`);
127
+ await memory.forget('session_abc'); // all
128
+ await memory.forget('session_abc', { id: 'entry_id' }); // one
129
+ await memory.forget('session_abc', { before: new Date() }); // old entries
190
130
  ```
191
131
 
192
- ### `recallSince(sessionId, since, keyword?, limit?, options?)`
132
+ ### `graph(sessionId, entity)`
193
133
 
194
- Get memories since a specific date.
134
+ Returns a one-hop relationship map for a named entity — all connected entities and the memories that link them.
195
135
 
196
- ```typescript
197
- const { entries, count } = await memory.recallSince(
198
- 'session_abc',
199
- new Date('2024-01-01')
200
- );
201
- ```
202
-
203
- ### `recallBetween(sessionId, start, end, keyword?, limit?, options?)`
204
-
205
- Get memories between two dates.
136
+ Requires `graphMemory: true` in config and a running Ollama instance with `qwen2.5:32b` (or override via `graphModel`).
206
137
 
207
138
  ```typescript
208
- const { entries, count } = await memory.recallBetween(
209
- 'session_abc',
210
- new Date('2024-01-01'),
211
- new Date('2024-01-31')
212
- );
213
- ```
214
-
215
- ### `dailySummary(sessionId, days?)`
216
-
217
- Get memories grouped by day.
139
+ const memory = new Engram({
140
+ dbPath: './memory.db',
141
+ graphMemory: true,
142
+ graphModel: 'qwen2.5:32b', // default
143
+ });
218
144
 
219
- ```typescript
220
- const summary = await memory.dailySummary('session_abc', 7);
221
- // [
222
- // { date: Date, entries: MemoryEntry[], count: 5 },
223
- // { date: Date, entries: MemoryEntry[], count: 3 },
224
- // ...
225
- // ]
145
+ const graph = await memory.graph('session_abc', 'GovScout');
146
+ // {
147
+ // entity: 'GovScout',
148
+ // edges: [
149
+ // { relation: 'uses', target: 'MUI', sourceMemoryId: '...' },
150
+ // { relation: 'built_by', target: 'Jeff', sourceMemoryId: '...' },
151
+ // ],
152
+ // memories: [ { content: '...', ... } ]
153
+ // }
226
154
  ```
227
155
 
228
- ### `history(sessionId, limit?)`
229
-
230
- Get chronological conversation history.
156
+ ### `recall()` with graph augmentation
231
157
 
232
158
  ```typescript
233
- const chat = await memory.history('session_abc', 20);
234
- ```
235
-
236
- ### `forget(sessionId, options?)`
237
-
238
- Delete memories.
239
-
240
- ```typescript
241
- // Delete all for session
242
- await memory.forget('session_abc');
243
-
244
- // Delete specific entry
245
- await memory.forget('session_abc', { id: 'entry_id' });
246
-
247
- // Delete before a date
248
- await memory.forget('session_abc', { before: new Date('2024-01-01') });
249
-
250
- // Delete in a date range
251
- await memory.forget('session_abc', {
252
- after: new Date('2024-01-01'),
253
- before: new Date('2024-02-01')
159
+ const results = await memory.recall('session_abc', 'what is GovScout?', 5, {
160
+ includeGraph: true, // augment top results with graph-connected memories
254
161
  });
255
162
  ```
256
163
 
257
164
  ### `stats(sessionId)`
258
165
 
259
- Get memory statistics.
260
-
261
166
  ```typescript
262
167
  const stats = await memory.stats('session_abc');
263
- // { total: 42, byRole: { user: 21, assistant: 21 }, oldest: Date, newest: Date }
168
+ // { total: 42, byRole: { user: 21, assistant: 21 }, withEmbeddings: 42, graphNodes: 18, graphEdges: 31 }
264
169
  ```
265
170
 
266
- ### `temporalStats(sessionId, days?)`
171
+ ## MCP Server
267
172
 
268
- Get activity statistics grouped by day.
173
+ Use Engram directly in Claude Desktop, Cursor, or any MCP client:
269
174
 
270
- ```typescript
271
- const activity = await memory.temporalStats('session_abc', 30);
272
- // [
273
- // { date: '2024-01-15', count: 5, byRole: { user: 3, assistant: 2 } },
274
- // ...
275
- // ]
175
+ ```bash
176
+ npx -y @cartisien/engram-mcp
276
177
  ```
277
178
 
278
- ## The TemporalQuery Parser
279
-
280
- You can use the temporal parser standalone:
281
-
282
- ```typescript
283
- import { TemporalQuery } from '@cartisien/engram';
284
-
285
- const parser = new TemporalQuery();
286
- const range = parser.parse('last week');
287
-
288
- if (range) {
289
- console.log(range.description); // "last week"
290
- console.log(range.start); // Sun, Jan 07 2024 00:00:00
291
- console.log(range.end); // Sat, Jan 13 2024 23:59:59
179
+ ```json
180
+ {
181
+ "mcpServers": {
182
+ "engram": {
183
+ "command": "npx",
184
+ "args": ["-y", "@cartisien/engram-mcp"]
185
+ }
186
+ }
292
187
  }
293
188
  ```
294
189
 
190
+ → [`@cartisien/engram-mcp`](https://github.com/Cartisien/engram-mcp) on GitHub
191
+
295
192
  ## Philosophy
296
193
 
297
- > *"The trace precedes presence."* — Derrida
194
+ > *"The trace precedes presence."*
298
195
 
299
196
  Memory isn't storage. It's the substrate of self.
300
197
 
301
- Engram doesn't just persist data. It gives your assistants **continuity** the ability to learn, reference, and grow across conversations. Time is not a sequence of moments to be archived, but a horizon of meaning that shifts with each recollection.
198
+ Engram doesn't just persist data it gives your agents **continuity**. The ability to learn, reference, and grow across conversations.
302
199
 
303
- The Cartesian cogito assumed memory was given. We're making it so.
200
+ ## Roadmap
304
201
 
305
- ## The Trilogy
202
+ - **v0.1** ✅ SQLite persistence, keyword search
203
+ - **v0.2** ✅ Semantic search via local Ollama embeddings
204
+ - **v0.3** ✅ Graph memory — entity relationships, connected context
205
+ - **v0.4** 📋 Memory consolidation, long-term summarization
306
206
 
307
- Engram is part of the **Cartisien Memory Suite**:
207
+ ## The Cartisien Memory Suite
308
208
 
309
209
  | Package | Purpose |
310
210
  |---------|---------|
311
- | `@cartisien/engram` | **This package**persistent memory with temporal recall |
312
- | `@cartisien/extensa` | Vector infrastructure (coming soon) |
313
- | `@cartisien/cogito` | Identity & state management (coming soon) |
211
+ | [`@cartisien/engram`](https://github.com/Cartisien/engram) | Persistent memory SDK **this package** |
212
+ | [`@cartisien/engram-mcp`](https://github.com/Cartisien/engram-mcp) | MCP server for Claude Desktop / Cursor |
213
+ | `@cartisien/extensa` | Vector infrastructure *(coming soon)* |
214
+ | `@cartisien/cogito` | Agent identity & lifecycle *(coming soon)* |
314
215
 
315
216
  *Res cogitans meets res extensa.*
316
217
 
317
218
  ## License
318
219
 
319
- MIT © Cartisien Interactive
220
+ MIT © [Cartisien Interactive](https://cartisien.com)
320
221
 
321
222
  ---
322
223
 
323
- **Built with 🖤 by people who think forgetting is a bug.**
224
+ **Built for people who think forgetting is a bug.**
@@ -0,0 +1,2 @@
1
+ export type { IMemoryAdapter } from '../types.js';
2
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import type { IMemoryAdapter, Memory, SearchOptions, SearchResult } from '../types.js';
2
+ /**
3
+ * In-process MemoryAdapter — no persistence, ideal for testing and ephemeral agents.
4
+ * The simplest possible trace: exists only as long as the process lives.
5
+ */
6
+ export declare class MemoryAdapter implements IMemoryAdapter {
7
+ private _cache;
8
+ init(): Promise<void>;
9
+ store(memory: Memory): Promise<Memory>;
10
+ get(id: string): Promise<Memory | null>;
11
+ search(embedding: number[], options: Required<SearchOptions>): Promise<SearchResult[]>;
12
+ forget(id: string): Promise<void>;
13
+ list(agentId: string, limit?: number): Promise<Memory[]>;
14
+ close(): Promise<void>;
15
+ get size(): number;
16
+ }
17
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAGtF;;;GAGG;AACH,qBAAa,aAAc,YAAW,cAAc;IAClD,OAAO,CAAC,MAAM,CAA4B;IAEpC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKtC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAcvC,MAAM,CACV,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,GAC/B,OAAO,CAAC,YAAY,EAAE,CAAC;IAepB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAOpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,58 @@
1
+ import { cosineSimilarity } from '../utils/similarity.js';
2
+ /**
3
+ * In-process MemoryAdapter — no persistence, ideal for testing and ephemeral agents.
4
+ * The simplest possible trace: exists only as long as the process lives.
5
+ */
6
+ export class MemoryAdapter {
7
+ constructor() {
8
+ this._cache = new Map();
9
+ }
10
+ async init() {
11
+ // nothing to set up
12
+ }
13
+ async store(memory) {
14
+ this._cache.set(memory.id, memory);
15
+ return memory;
16
+ }
17
+ async get(id) {
18
+ const memory = this._cache.get(id) ?? null;
19
+ if (memory) {
20
+ const updated = {
21
+ ...memory,
22
+ accessedAt: new Date(),
23
+ accessCount: memory.accessCount + 1,
24
+ };
25
+ this._cache.set(id, updated);
26
+ return updated;
27
+ }
28
+ return null;
29
+ }
30
+ async search(embedding, options) {
31
+ const results = [];
32
+ for (const memory of this._cache.values()) {
33
+ const score = cosineSimilarity(embedding, memory.embedding);
34
+ if (score >= options.threshold) {
35
+ results.push({ memory, score });
36
+ }
37
+ }
38
+ return results
39
+ .sort((a, b) => b.score - a.score)
40
+ .slice(0, options.limit);
41
+ }
42
+ async forget(id) {
43
+ this._cache.delete(id);
44
+ }
45
+ async list(agentId, limit = 50) {
46
+ return [...this._cache.values()]
47
+ .filter((m) => m.agentId === agentId)
48
+ .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
49
+ .slice(0, limit);
50
+ }
51
+ async close() {
52
+ this._cache.clear();
53
+ }
54
+ get size() {
55
+ return this._cache.size;
56
+ }
57
+ }
58
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEzD;;;GAGG;AACH,MAAM,OAAO,aAAa;IAA1B;QACU,WAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IA6D5C,CAAC;IA3DC,KAAK,CAAC,IAAI;QACR,oBAAoB;IACtB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;QAClC,OAAO,MAAM,CAAA;IACf,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAU;QAClB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAA;QAC1C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,OAAO,GAAW;gBACtB,GAAG,MAAM;gBACT,UAAU,EAAE,IAAI,IAAI,EAAE;gBACtB,WAAW,EAAE,MAAM,CAAC,WAAW,GAAG,CAAC;aACpC,CAAA;YACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;YAC5B,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK,CAAC,MAAM,CACV,SAAmB,EACnB,OAAgC;QAEhC,MAAM,OAAO,GAAmB,EAAE,CAAA;QAElC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;YAC3D,IAAI,KAAK,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC/B,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;QAED,OAAO,OAAO;aACX,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;aACjC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACxB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAe,EAAE,KAAK,GAAG,EAAE;QACpC,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;aAC7B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC;aACpC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;aAC7D,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACpB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;IACrB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAA;IACzB,CAAC;CACF"}
@@ -0,0 +1,33 @@
1
+ import type { IMemoryAdapter, Memory, SearchOptions, SearchResult } from '../types.js';
2
+ /**
3
+ * PostgresAdapter — uses pgvector for semantic similarity search.
4
+ *
5
+ * TODO: implement with `pg` + pgvector extension.
6
+ * Requires: CREATE EXTENSION IF NOT EXISTS vector;
7
+ *
8
+ * Schema:
9
+ * CREATE TABLE engram_memories (
10
+ * id TEXT PRIMARY KEY,
11
+ * agent_id TEXT NOT NULL,
12
+ * content TEXT NOT NULL,
13
+ * embedding vector(1536),
14
+ * importance FLOAT NOT NULL DEFAULT 0.5,
15
+ * metadata JSONB NOT NULL DEFAULT '{}',
16
+ * created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
17
+ * accessed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
18
+ * access_count INT NOT NULL DEFAULT 0
19
+ * );
20
+ * CREATE INDEX ON engram_memories USING ivfflat (embedding vector_cosine_ops);
21
+ */
22
+ export declare class PostgresAdapter implements IMemoryAdapter {
23
+ private readonly connectionString;
24
+ constructor(connectionString: string);
25
+ init(): Promise<void>;
26
+ store(_memory: Memory): Promise<Memory>;
27
+ get(_id: string): Promise<Memory | null>;
28
+ search(_embedding: number[], _options: Required<SearchOptions>): Promise<SearchResult[]>;
29
+ forget(_id: string): Promise<void>;
30
+ list(_agentId: string, _limit?: number): Promise<Memory[]>;
31
+ close(): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/adapters/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAEtF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,eAAgB,YAAW,cAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,MAAM;IAE/C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIvC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIxC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAIxF,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAI1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * PostgresAdapter — uses pgvector for semantic similarity search.
3
+ *
4
+ * TODO: implement with `pg` + pgvector extension.
5
+ * Requires: CREATE EXTENSION IF NOT EXISTS vector;
6
+ *
7
+ * Schema:
8
+ * CREATE TABLE engram_memories (
9
+ * id TEXT PRIMARY KEY,
10
+ * agent_id TEXT NOT NULL,
11
+ * content TEXT NOT NULL,
12
+ * embedding vector(1536),
13
+ * importance FLOAT NOT NULL DEFAULT 0.5,
14
+ * metadata JSONB NOT NULL DEFAULT '{}',
15
+ * created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
16
+ * accessed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
17
+ * access_count INT NOT NULL DEFAULT 0
18
+ * );
19
+ * CREATE INDEX ON engram_memories USING ivfflat (embedding vector_cosine_ops);
20
+ */
21
+ export class PostgresAdapter {
22
+ constructor(connectionString) {
23
+ this.connectionString = connectionString;
24
+ }
25
+ async init() {
26
+ throw new Error('PostgresAdapter not yet implemented. Use MemoryAdapter for now.');
27
+ }
28
+ async store(_memory) {
29
+ throw new Error('Not implemented');
30
+ }
31
+ async get(_id) {
32
+ throw new Error('Not implemented');
33
+ }
34
+ async search(_embedding, _options) {
35
+ throw new Error('Not implemented');
36
+ }
37
+ async forget(_id) {
38
+ throw new Error('Not implemented');
39
+ }
40
+ async list(_agentId, _limit) {
41
+ throw new Error('Not implemented');
42
+ }
43
+ async close() {
44
+ // no-op until implemented
45
+ }
46
+ }
47
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/adapters/postgres.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,eAAe;IAC1B,YAA6B,gBAAwB;QAAxB,qBAAgB,GAAhB,gBAAgB,CAAQ;IAAG,CAAC;IAEzD,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;IACpF,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAe;QACzB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,UAAoB,EAAE,QAAiC;QAClE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAgB,EAAE,MAAe;QAC1C,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,0BAA0B;IAC5B,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import type { IMemoryAdapter, Memory, SearchOptions, SearchResult } from '../types.js';
2
+ /**
3
+ * SqliteAdapter — local file-backed persistence with vector search.
4
+ *
5
+ * TODO: implement with `better-sqlite3` + manual cosine similarity
6
+ * (sqlite-vss or sqlite-vec extension optional).
7
+ */
8
+ export declare class SqliteAdapter implements IMemoryAdapter {
9
+ private readonly filePath;
10
+ constructor(filePath: string);
11
+ init(): Promise<void>;
12
+ store(_memory: Memory): Promise<Memory>;
13
+ get(_id: string): Promise<Memory | null>;
14
+ search(_embedding: number[], _options: Required<SearchOptions>): Promise<SearchResult[]>;
15
+ forget(_id: string): Promise<void>;
16
+ list(_agentId: string, _limit?: number): Promise<Memory[]>;
17
+ close(): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=sqlite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/adapters/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAEtF;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,cAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAEvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIvC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIxC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAIxF,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAI1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}