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 CHANGED
@@ -1,20 +1,20 @@
1
1
  # Mnemocyte
2
2
 
3
- Persistent memory for TypeScript AI applications.
3
+ Infrastructure-native memory for TypeScript AI applications.
4
4
 
5
- Mnemocyte stores small, durable memories for users, agents, sessions, or
6
- other entities. It provides hybrid retrieval, context formatting, lifecycle
7
- operations, audit logging, and duplicate-consolidation tools without requiring
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, demos, and short-lived processes.
13
+ - In-memory backend for tests and demos.
15
14
  - Postgres + pgvector backend for persistent storage.
16
- - Hybrid recall using vector similarity, lexical matching, recency,
17
- confidence, access count, and importance.
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
- ## Postgres
70
+ ## Embedder
64
71
 
65
- Apply the bundled migration to a Postgres database with pgvector enabled, then
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
- databaseUrl: process.env.DATABASE_URL,
71
- embedder, // embedder.dimensions must be 1536 for the Postgres backend.
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
- The published package includes `migrations/0000_initial.sql`.
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
- ## Provider Resilience
90
+ ## Postgres
83
91
 
84
- Mnemocyte can apply timeouts and retries to embedder calls, and forwards
85
- `AbortSignal` cancellation to in-flight attempts. Retries and timeouts are
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
- const controller = new AbortController();
100
- setTimeout(() => controller.abort(), 1_000);
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: "Prefers short answers.",
105
- signal: controller.signal,
124
+ content: "Likes concise answers.",
125
+ type: "preference",
126
+ importance: "high",
127
+ tags: ["communication"],
106
128
  });
107
129
  ```
108
130
 
109
- Provider failures surface as `MnemocyteError` values with stable `code`s:
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
- ## Pruning
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
- `prune` deletes memories matching a filter. At least one selector is required;
118
- `prune({})` is rejected to avoid accidental full deletion.
142
+ ### `buildContext`
119
143
 
120
144
  ```ts
121
- await client.prune({ entityId: "user_123", expired: true });
122
-
123
- await client.prune({
124
- notAccessedSince: new Date(Date.now() - 30 * 24 * 3600 * 1000),
125
- maxImportance: "normal",
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
- ## Duplicate Detection
162
+ await client.prune({
163
+ entityId: "user_123",
164
+ expired: true,
165
+ });
166
+ ```
141
167
 
142
- `findDuplicates` is an experimental, read-only scan that surfaces
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
- Optional selectors: `types`, `tags`, `includeSuperseded`, `includeExpired`.
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.remember({ entityId: "user_123", content: "Likes tea." });
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
- Recorded `description` slugs:
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
- - `"memory.created"`: single insert.
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
- Audit entries are sticky: `forgetAll` does not erase prior log entries. Disable
194
- audit by leaving `audit.enabled` unset.
204
+ ## Provider Resilience
195
205
 
196
- ## Consolidation
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
- `client.experimental.consolidate()` marks likely-duplicate memories as
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 pairs = await client.findDuplicates({
221
+ const controller = new AbortController();
222
+
223
+ await client.remember({
204
224
  entityId: "user_123",
205
- threshold: 0.97,
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
- The `experimental` namespace is intentionally unstable. Members may change or
218
- move before v1.0.
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 run test:retrieval
281
+ pnpm test
247
282
  pnpm run test:integration
248
283
  pnpm run pack:check
249
284
  ```
250
285
 
251
- `test:integration` skips cleanly when `DATABASE_URL` is not set.
286
+ `test:integration` skips when `DATABASE_URL` is not set.
252
287
 
253
288
  ## Architecture
254
289
 
255
- See [ARCHITECTURE.md](./ARCHITECTURE.md) for implementation details and
256
- [ROADMAP.md](./ROADMAP.md) for planned work.
290
+ See [ARCHITECTURE.md](./ARCHITECTURE.md).