@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.
- package/README.md +104 -203
- package/dist/adapters/base.d.ts +2 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +2 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/memory.d.ts +17 -0
- package/dist/adapters/memory.d.ts.map +1 -0
- package/dist/adapters/memory.js +58 -0
- package/dist/adapters/memory.js.map +1 -0
- package/dist/adapters/postgres.d.ts +33 -0
- package/dist/adapters/postgres.d.ts.map +1 -0
- package/dist/adapters/postgres.js +47 -0
- package/dist/adapters/postgres.js.map +1 -0
- package/dist/adapters/sqlite.d.ts +19 -0
- package/dist/adapters/sqlite.d.ts.map +1 -0
- package/dist/adapters/sqlite.js +33 -0
- package/dist/adapters/sqlite.js.map +1 -0
- package/dist/engram.d.ts +57 -0
- package/dist/engram.d.ts.map +1 -0
- package/dist/engram.js +148 -0
- package/dist/engram.js.map +1 -0
- package/dist/index.d.ts +99 -122
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +458 -468
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +48 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/embeddings.d.ts +20 -0
- package/dist/utils/embeddings.d.ts.map +1 -0
- package/dist/utils/embeddings.js +28 -0
- package/dist/utils/embeddings.js.map +1 -0
- package/dist/utils/similarity.d.ts +10 -0
- package/dist/utils/similarity.d.ts.map +1 -0
- package/dist/utils/similarity.js +31 -0
- package/dist/utils/similarity.js.map +1 -0
- package/package.json +4 -3
- package/LICENSE +0 -21
- 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
|
|
3
|
+
> **Persistent semantic memory for AI agents.**
|
|
4
|
+
|
|
5
|
+

|
|
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', '
|
|
13
|
+
await memory.remember('user_123', 'User prefers TypeScript and dark mode', 'user');
|
|
12
14
|
|
|
13
|
-
// Recall
|
|
14
|
-
const
|
|
15
|
-
|
|
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
|
-
|
|
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
|
|
30
|
+
Engram gives your agents **persistent, semantically searchable memory** — SQLite-backed, TypeScript-first, zero config.
|
|
29
31
|
|
|
30
|
-
- **
|
|
31
|
-
- **
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
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'
|
|
60
|
+
dbPath: './bot-memory.db',
|
|
61
|
+
embeddingUrl: 'http://localhost:11434', // Ollama default
|
|
49
62
|
});
|
|
50
63
|
|
|
51
|
-
// In your chat handler
|
|
52
|
-
async function
|
|
53
|
-
// 1.
|
|
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
|
-
//
|
|
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
|
-
|
|
72
|
+
// 3. Get AI response
|
|
73
|
+
const response = await llm.chat(prompt);
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
// 4. Store both sides
|
|
76
|
+
await memory.remember(sessionId, message, 'user');
|
|
77
|
+
await memory.remember(sessionId, response, 'assistant');
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
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',
|
|
131
|
-
maxContextLength: 4000
|
|
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
|
|
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
|
|
107
|
+
Retrieve relevant memories. Uses semantic search when available, keyword fallback otherwise. Returns entries sorted by similarity score.
|
|
148
108
|
|
|
149
109
|
```typescript
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
### `
|
|
114
|
+
### `history(sessionId, limit?)`
|
|
169
115
|
|
|
170
|
-
|
|
116
|
+
Chronological conversation history.
|
|
171
117
|
|
|
172
118
|
```typescript
|
|
173
|
-
const
|
|
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
|
-
### `
|
|
122
|
+
### `forget(sessionId, options?)`
|
|
184
123
|
|
|
185
|
-
|
|
124
|
+
Delete memories.
|
|
186
125
|
|
|
187
126
|
```typescript
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
### `
|
|
132
|
+
### `graph(sessionId, entity)`
|
|
193
133
|
|
|
194
|
-
|
|
134
|
+
Returns a one-hop relationship map for a named entity — all connected entities and the memories that link them.
|
|
195
135
|
|
|
196
|
-
|
|
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
|
|
209
|
-
'
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
220
|
-
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
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
|
-
### `
|
|
229
|
-
|
|
230
|
-
Get chronological conversation history.
|
|
156
|
+
### `recall()` with graph augmentation
|
|
231
157
|
|
|
232
158
|
```typescript
|
|
233
|
-
const
|
|
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 },
|
|
168
|
+
// { total: 42, byRole: { user: 21, assistant: 21 }, withEmbeddings: 42, graphNodes: 18, graphEdges: 31 }
|
|
264
169
|
```
|
|
265
170
|
|
|
266
|
-
|
|
171
|
+
## MCP Server
|
|
267
172
|
|
|
268
|
-
|
|
173
|
+
Use Engram directly in Claude Desktop, Cursor, or any MCP client:
|
|
269
174
|
|
|
270
|
-
```
|
|
271
|
-
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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."*
|
|
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
|
|
198
|
+
Engram doesn't just persist data — it gives your agents **continuity**. The ability to learn, reference, and grow across conversations.
|
|
302
199
|
|
|
303
|
-
|
|
200
|
+
## Roadmap
|
|
304
201
|
|
|
305
|
-
|
|
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
|
-
|
|
207
|
+
## The Cartisien Memory Suite
|
|
308
208
|
|
|
309
209
|
| Package | Purpose |
|
|
310
210
|
|---------|---------|
|
|
311
|
-
| `@cartisien/engram` |
|
|
312
|
-
| `@cartisien/
|
|
313
|
-
| `@cartisien/
|
|
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
|
|
224
|
+
**Built for people who think forgetting is a bug.**
|
|
@@ -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 @@
|
|
|
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"}
|