mnemocyte 0.1.2 → 0.1.3
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 +137 -103
- package/dist/index.mjs +141 -59
- package/dist/index.mjs.map +1 -1
- package/migrations/0000_initial.sql +33 -44
- package/migrations/meta/0000_snapshot.json +284 -0
- package/migrations/meta/_journal.json +13 -0
- package/package.json +19 -15
package/README.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Mnemocyte
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Infrastructure-native memory for TypeScript AI applications.
|
|
4
4
|
|
|
5
|
-
Mnemocyte stores
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
a separate vector database.
|
|
5
|
+
Mnemocyte stores durable memories for users, agents, sessions, and other
|
|
6
|
+
entities. It gives your app hybrid recall, prompt-ready context, pruning, audit
|
|
7
|
+
logs, and duplicate-consolidation tools on top of your existing infrastructure.
|
|
9
8
|
|
|
10
9
|
> Mnemocyte is early software. APIs may change before v1.0.
|
|
11
10
|
|
|
12
11
|
## Features
|
|
13
12
|
|
|
14
|
-
- In-memory backend for tests
|
|
13
|
+
- In-memory backend for tests and demos.
|
|
15
14
|
- Postgres + pgvector backend for persistent storage.
|
|
16
|
-
-
|
|
17
|
-
|
|
15
|
+
- User-supplied `Embedder` interface.
|
|
16
|
+
- Hybrid recall with vector similarity, lexical matching, recency, confidence,
|
|
17
|
+
access count, and importance.
|
|
18
18
|
- Prompt-ready context output in Markdown, plain text, or XML.
|
|
19
19
|
- Provider timeouts, retries, and `AbortSignal` cancellation.
|
|
20
20
|
- Pruning, duplicate detection, audit logs, and experimental consolidation.
|
|
@@ -55,92 +55,117 @@ const memories = await client.recall({
|
|
|
55
55
|
explain: true,
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
+
const context = await client.buildContext({
|
|
59
|
+
entityId: "user_123",
|
|
60
|
+
query: "How should I respond?",
|
|
61
|
+
format: "markdown",
|
|
62
|
+
maxTokens: 500,
|
|
63
|
+
});
|
|
64
|
+
|
|
58
65
|
await client.close();
|
|
59
66
|
```
|
|
60
67
|
|
|
61
68
|
When `databaseUrl` is omitted, Mnemocyte uses the in-memory backend.
|
|
62
69
|
|
|
63
|
-
##
|
|
70
|
+
## Embedder
|
|
64
71
|
|
|
65
|
-
|
|
66
|
-
pass `databaseUrl`:
|
|
72
|
+
Mnemocyte accepts any embedder that returns one vector per input text.
|
|
67
73
|
|
|
68
74
|
```ts
|
|
69
75
|
const client = createMnemocyte({
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
embedder: {
|
|
77
|
+
model: "text-embedding-3-small",
|
|
78
|
+
dimensions: 1536,
|
|
79
|
+
async embed(texts, options) {
|
|
80
|
+
return embedWithYourProvider(texts, {
|
|
81
|
+
signal: options?.signal,
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
},
|
|
72
85
|
});
|
|
73
86
|
```
|
|
74
87
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
The current Postgres schema uses `embedding vector(1536)`. If
|
|
78
|
-
`embedder.dimensions` is anything else, `createMnemocyte` throws a
|
|
79
|
-
`MnemocyteError` with code `"CONFIG"` before opening the connection pool. The
|
|
80
|
-
in-memory backend does not enforce this constraint.
|
|
88
|
+
Official embedder helpers are planned, starting with `openaiEmbedder()`.
|
|
81
89
|
|
|
82
|
-
##
|
|
90
|
+
## Postgres
|
|
83
91
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
disabled by default.
|
|
92
|
+
For persistent storage, apply the bundled migration to a Postgres database with
|
|
93
|
+
pgvector enabled, then pass `databaseUrl`.
|
|
87
94
|
|
|
88
95
|
```ts
|
|
89
96
|
const client = createMnemocyte({
|
|
97
|
+
databaseUrl: process.env.DATABASE_URL!,
|
|
90
98
|
embedder,
|
|
91
|
-
provider: {
|
|
92
|
-
timeoutMs: 5_000,
|
|
93
|
-
retries: 2,
|
|
94
|
-
baseDelayMs: 200,
|
|
95
|
-
maxDelayMs: 2_000,
|
|
96
|
-
},
|
|
97
99
|
});
|
|
100
|
+
```
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
The package includes:
|
|
103
|
+
|
|
104
|
+
```txt
|
|
105
|
+
migrations/0000_initial.sql
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The current Postgres schema uses `embedding vector(1536)`, so the Postgres
|
|
109
|
+
backend currently requires a 1536-dimensional embedder.
|
|
101
110
|
|
|
111
|
+
If dimensions do not match, `createMnemocyte` throws a `MnemocyteError` with
|
|
112
|
+
code `"CONFIG"` before opening the connection pool.
|
|
113
|
+
|
|
114
|
+
The migration creates an HNSW pgvector index for cosine search. Configurable
|
|
115
|
+
embedding dimensions are planned for `0.2.0`.
|
|
116
|
+
|
|
117
|
+
## API
|
|
118
|
+
|
|
119
|
+
### `remember`
|
|
120
|
+
|
|
121
|
+
```ts
|
|
102
122
|
await client.remember({
|
|
103
123
|
entityId: "user_123",
|
|
104
|
-
content: "
|
|
105
|
-
|
|
124
|
+
content: "Likes concise answers.",
|
|
125
|
+
type: "preference",
|
|
126
|
+
importance: "high",
|
|
127
|
+
tags: ["communication"],
|
|
106
128
|
});
|
|
107
129
|
```
|
|
108
130
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- `"TIMEOUT"`: a provider attempt exceeded `timeoutMs`.
|
|
112
|
-
- `"ABORTED"`: the operation was cancelled via `signal` and is not retried.
|
|
113
|
-
- `"EMBEDDING"`: the embedder failed after retries were exhausted.
|
|
131
|
+
### `recall`
|
|
114
132
|
|
|
115
|
-
|
|
133
|
+
```ts
|
|
134
|
+
const memories = await client.recall({
|
|
135
|
+
entityId: "user_123",
|
|
136
|
+
query: "How should I respond to this user?",
|
|
137
|
+
limit: 5,
|
|
138
|
+
explain: true,
|
|
139
|
+
});
|
|
140
|
+
```
|
|
116
141
|
|
|
117
|
-
`
|
|
118
|
-
`prune({})` is rejected to avoid accidental full deletion.
|
|
142
|
+
### `buildContext`
|
|
119
143
|
|
|
120
144
|
```ts
|
|
121
|
-
await client.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
145
|
+
const context = await client.buildContext({
|
|
146
|
+
entityId: "user_123",
|
|
147
|
+
query: "User communication preferences",
|
|
148
|
+
format: "markdown",
|
|
149
|
+
maxTokens: 500,
|
|
126
150
|
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### `prune`
|
|
127
154
|
|
|
155
|
+
```ts
|
|
128
156
|
const preview = await client.prune({
|
|
129
157
|
entityId: "user_123",
|
|
130
158
|
superseded: true,
|
|
131
159
|
dryRun: true,
|
|
132
160
|
});
|
|
133
|
-
console.log(preview.matchedCount);
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
Available selectors: `entityId`, `expired`, `superseded`, `createdBefore`,
|
|
137
|
-
`notAccessedSince`, `types`, `tags`, `maxImportance`. Selectors are combined
|
|
138
|
-
with AND semantics.
|
|
139
161
|
|
|
140
|
-
|
|
162
|
+
await client.prune({
|
|
163
|
+
entityId: "user_123",
|
|
164
|
+
expired: true,
|
|
165
|
+
});
|
|
166
|
+
```
|
|
141
167
|
|
|
142
|
-
`findDuplicates`
|
|
143
|
-
near-identical memories for one entity using pairwise cosine similarity.
|
|
168
|
+
### `findDuplicates`
|
|
144
169
|
|
|
145
170
|
```ts
|
|
146
171
|
const pairs = await client.findDuplicates({
|
|
@@ -148,20 +173,9 @@ const pairs = await client.findDuplicates({
|
|
|
148
173
|
threshold: 0.95,
|
|
149
174
|
limit: 50,
|
|
150
175
|
});
|
|
151
|
-
|
|
152
|
-
for (const { a, b, similarity } of pairs) {
|
|
153
|
-
console.log(similarity.toFixed(3), a.content, "<>", b.content);
|
|
154
|
-
}
|
|
155
176
|
```
|
|
156
177
|
|
|
157
|
-
|
|
158
|
-
`types` and `tags` must match on both memories in each pair. Superseded and
|
|
159
|
-
expired memories are excluded by default.
|
|
160
|
-
|
|
161
|
-
## Audit Log
|
|
162
|
-
|
|
163
|
-
When `audit.enabled` is `true`, Mnemocyte records an entry for state-changing
|
|
164
|
-
operations. Read entries with `client.listAuditLog()`.
|
|
178
|
+
### `listAuditLog`
|
|
165
179
|
|
|
166
180
|
```ts
|
|
167
181
|
const client = createMnemocyte({
|
|
@@ -169,53 +183,61 @@ const client = createMnemocyte({
|
|
|
169
183
|
audit: { enabled: true },
|
|
170
184
|
});
|
|
171
185
|
|
|
172
|
-
await client.
|
|
173
|
-
await client.prune({ entityId: "user_123", expired: true });
|
|
174
|
-
|
|
175
|
-
const log = await client.listAuditLog({
|
|
186
|
+
const events = await client.listAuditLog({
|
|
176
187
|
entityId: "user_123",
|
|
177
188
|
limit: 100,
|
|
178
189
|
});
|
|
179
|
-
|
|
180
|
-
for (const event of log) {
|
|
181
|
-
console.log(event.timestamp, event.description, event.metadata);
|
|
182
|
-
}
|
|
183
190
|
```
|
|
184
191
|
|
|
185
|
-
|
|
192
|
+
### `experimental.consolidate`
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
await client.experimental.consolidate({
|
|
196
|
+
entityId: "user_123",
|
|
197
|
+
survivorId: "mem_survivor",
|
|
198
|
+
supersededIds: ["mem_duplicate"],
|
|
199
|
+
});
|
|
200
|
+
```
|
|
186
201
|
|
|
187
|
-
|
|
188
|
-
- `"memory.deleted"`: single `forget`.
|
|
189
|
-
- `"entity.cleared"`: `forgetAll`.
|
|
190
|
-
- `"memory.pruned"`: non-dry-run `prune` with an `entityId` selector.
|
|
191
|
-
- `"memory.superseded"`: experimental consolidation.
|
|
202
|
+
The `experimental` namespace may change before v1.0.
|
|
192
203
|
|
|
193
|
-
|
|
194
|
-
audit by leaving `audit.enabled` unset.
|
|
204
|
+
## Provider Resilience
|
|
195
205
|
|
|
196
|
-
|
|
206
|
+
```ts
|
|
207
|
+
const client = createMnemocyte({
|
|
208
|
+
embedder,
|
|
209
|
+
provider: {
|
|
210
|
+
timeoutMs: 5_000,
|
|
211
|
+
retries: 2,
|
|
212
|
+
baseDelayMs: 200,
|
|
213
|
+
maxDelayMs: 2_000,
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
```
|
|
197
217
|
|
|
198
|
-
`
|
|
199
|
-
superseded by a survivor. Superseded memories are excluded from `recall` by
|
|
200
|
-
default. Tags are unioned onto the survivor unless `mergeTags: false`.
|
|
218
|
+
Pass `signal` to cancel an operation:
|
|
201
219
|
|
|
202
220
|
```ts
|
|
203
|
-
const
|
|
221
|
+
const controller = new AbortController();
|
|
222
|
+
|
|
223
|
+
await client.remember({
|
|
204
224
|
entityId: "user_123",
|
|
205
|
-
|
|
225
|
+
content: "Prefers short answers.",
|
|
226
|
+
signal: controller.signal,
|
|
206
227
|
});
|
|
207
|
-
|
|
208
|
-
for (const { a, b } of pairs) {
|
|
209
|
-
await client.experimental.consolidate({
|
|
210
|
-
entityId: "user_123",
|
|
211
|
-
survivorId: a.id,
|
|
212
|
-
supersededIds: [b.id],
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
228
|
```
|
|
216
229
|
|
|
217
|
-
|
|
218
|
-
|
|
230
|
+
Common `MnemocyteError` codes:
|
|
231
|
+
|
|
232
|
+
```txt
|
|
233
|
+
TIMEOUT
|
|
234
|
+
ABORTED
|
|
235
|
+
EMBEDDING
|
|
236
|
+
VALIDATION
|
|
237
|
+
CONFIG
|
|
238
|
+
DB
|
|
239
|
+
NOT_FOUND
|
|
240
|
+
```
|
|
219
241
|
|
|
220
242
|
## Retrieval Tuning
|
|
221
243
|
|
|
@@ -238,19 +260,31 @@ const client = createMnemocyte({
|
|
|
238
260
|
});
|
|
239
261
|
```
|
|
240
262
|
|
|
263
|
+
## Roadmap
|
|
264
|
+
|
|
265
|
+
Near-term work:
|
|
266
|
+
|
|
267
|
+
- production safety and HNSW documentation
|
|
268
|
+
- official `openaiEmbedder()`
|
|
269
|
+
- configurable embedding dimensions with `mnemocyte_meta`
|
|
270
|
+
- `Store` abstraction
|
|
271
|
+
- `drizzleStore(db)` for caller-owned Drizzle clients
|
|
272
|
+
- `@mnemocyte/mcp`
|
|
273
|
+
|
|
274
|
+
See [ROADMAP.md](./ROADMAP.md).
|
|
275
|
+
|
|
241
276
|
## Development
|
|
242
277
|
|
|
243
278
|
```bash
|
|
244
279
|
pnpm checktypes
|
|
245
280
|
pnpm lint
|
|
246
|
-
pnpm
|
|
281
|
+
pnpm test
|
|
247
282
|
pnpm run test:integration
|
|
248
283
|
pnpm run pack:check
|
|
249
284
|
```
|
|
250
285
|
|
|
251
|
-
`test:integration` skips
|
|
286
|
+
`test:integration` skips when `DATABASE_URL` is not set.
|
|
252
287
|
|
|
253
288
|
## Architecture
|
|
254
289
|
|
|
255
|
-
See [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
256
|
-
[ROADMAP.md](./ROADMAP.md) for planned work.
|
|
290
|
+
See [ARCHITECTURE.md](./ARCHITECTURE.md).
|