@jeremiaheth/neolata-mem 0.5.3 → 0.8.1
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 +202 -8
- package/docs/PRD-v0.6.md +2106 -0
- package/docs/PRD-v0.7.md +2294 -0
- package/docs/PRD-v0.8.1.md +155 -0
- package/docs/PRD-v0.8.md +1739 -0
- package/docs/deep-research-report.md +199 -0
- package/docs/guide.md +509 -30
- package/docs/prompt-1.md +120 -0
- package/docs/prompt-2.md +124 -0
- package/docs/prompt-3-4.md +176 -0
- package/docs/prompt-5-6.md +298 -0
- package/docs/prompt-7-8.md +203 -0
- package/package.json +8 -3
- package/src/graph.mjs +2689 -358
- package/src/index.mjs +15 -12
- package/src/storage.mjs +90 -28
- package/src/supabase-storage.mjs +213 -35
package/README.md
CHANGED
|
@@ -94,7 +94,7 @@ const report = await mem.decay({ dryRun: true }); // Preview what would be prun
|
|
|
94
94
|
await mem.decay(); // Archive weak memories, delete dead ones
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
### ⚔️ Conflict Resolution
|
|
97
|
+
### ⚔️ Conflict Resolution & Quarantine
|
|
98
98
|
|
|
99
99
|
Detects contradictions and evolves memories over time (requires LLM):
|
|
100
100
|
|
|
@@ -110,6 +110,54 @@ await mem.evolve('a', 'Server now runs on port 8080');
|
|
|
110
110
|
// Old version archived with evolution history
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
**Quarantine lane** — low-trust or structurally conflicting memories are quarantined instead of auto-superseding:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
// Store with claim metadata and provenance
|
|
117
|
+
await mem.store('a', 'Server runs on port 443', {
|
|
118
|
+
claim: { subject: 'server', predicate: 'port', value: '443' },
|
|
119
|
+
provenance: { source: 'user_explicit', trust: 1.0 },
|
|
120
|
+
onConflict: 'quarantine', // default — quarantine low-trust conflicts
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Review quarantined memories
|
|
124
|
+
const quarantined = await mem.listQuarantined();
|
|
125
|
+
await mem.reviewQuarantine(quarantined[0].id, { action: 'activate' });
|
|
126
|
+
// or: { action: 'reject' } to archive it
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 📋 Predicate Schema Registry
|
|
130
|
+
|
|
131
|
+
Define rules for how predicates handle conflicts, deduplication, and normalization:
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
const mem = createMemory({
|
|
135
|
+
predicateSchemas: {
|
|
136
|
+
'preferred_language': { cardinality: 'single', conflictPolicy: 'supersede', normalize: 'lowercase_trim' },
|
|
137
|
+
'spoken_languages': { cardinality: 'multi', dedupPolicy: 'corroborate' },
|
|
138
|
+
'salary': { cardinality: 'single', conflictPolicy: 'require_review', normalize: 'currency' },
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
mem.registerPredicate('timezone', { cardinality: 'single', normalize: 'trim' });
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 🔍 Explainability API
|
|
146
|
+
|
|
147
|
+
Understand why memories were returned, filtered, or superseded:
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
const results = await mem.search('kuro', 'port config', { explain: true });
|
|
151
|
+
console.log(results.meta); // { query, options, resultCount, ... }
|
|
152
|
+
console.log(results[0].explain); // { retrieved, rerank, statusFilter, ... }
|
|
153
|
+
|
|
154
|
+
const detail = await mem.explainMemory(memoryId);
|
|
155
|
+
// { id, status, trust, confidence, provenance, claimSummary }
|
|
156
|
+
|
|
157
|
+
const chain = await mem.explainSupersession(memoryId);
|
|
158
|
+
// { superseded, supersededBy, trustComparison: { original, superseding, delta } }
|
|
159
|
+
```
|
|
160
|
+
|
|
113
161
|
### 🌐 Multi-Agent
|
|
114
162
|
|
|
115
163
|
Native support for multiple agents with cross-agent search:
|
|
@@ -199,6 +247,67 @@ const mem = createMemory({
|
|
|
199
247
|
});
|
|
200
248
|
```
|
|
201
249
|
|
|
250
|
+
### Episodes (Temporal Grouping)
|
|
251
|
+
Group related memories into named episodes with time ranges:
|
|
252
|
+
```javascript
|
|
253
|
+
// Manual: group specific memories
|
|
254
|
+
const ep = await mem.createEpisode('Deploy v2.0', [id1, id2, id3], { tags: ['deploy'] });
|
|
255
|
+
|
|
256
|
+
// Auto-capture: grab all memories in a time window
|
|
257
|
+
const ep2 = await mem.captureEpisode('kuro', 'Morning standup', {
|
|
258
|
+
start: '2026-02-25T09:00:00Z',
|
|
259
|
+
end: '2026-02-25T10:00:00Z',
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Search within an episode
|
|
263
|
+
const results = await mem.searchEpisode(ep.id, 'database migration');
|
|
264
|
+
|
|
265
|
+
// LLM-generated summary
|
|
266
|
+
const { summary } = await mem.summarizeEpisode(ep.id);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Memory Compression
|
|
270
|
+
Consolidate redundant memories into digests (extractive or LLM-based):
|
|
271
|
+
```javascript
|
|
272
|
+
// Compress specific memories
|
|
273
|
+
const digest = await mem.compress([id1, id2, id3], {
|
|
274
|
+
method: 'llm', // 'extractive' (default) or 'llm'
|
|
275
|
+
archiveOriginals: true, // archive source memories after compression
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Compress an episode or cluster
|
|
279
|
+
await mem.compressEpisode(episodeId);
|
|
280
|
+
await mem.compressCluster(0); // by cluster index from clusters()
|
|
281
|
+
|
|
282
|
+
// Auto-compress stale clusters
|
|
283
|
+
const result = await mem.autoCompress({ minClusterSize: 3, maxDigests: 5 });
|
|
284
|
+
// { compressed: 3, totalSourceMemories: 15, digests: [...] }
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Labeled Clusters
|
|
288
|
+
Organize memories into persistent named groups:
|
|
289
|
+
```javascript
|
|
290
|
+
const cl = await mem.createCluster('Security findings', [id1, id2]);
|
|
291
|
+
await mem.refreshCluster(cl.id); // Re-expand via BFS traversal
|
|
292
|
+
await mem.autoLabelClusters(); // LLM labels unlabeled clusters
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Consolidation (Full Maintenance)
|
|
296
|
+
Single call that runs the complete memory maintenance lifecycle:
|
|
297
|
+
```javascript
|
|
298
|
+
const report = await mem.consolidate({
|
|
299
|
+
dedupThreshold: 0.95, // Similarity threshold for dedup
|
|
300
|
+
compressAge: 30, // Compress clusters older than N days
|
|
301
|
+
pruneSuperseded: true, // Archive old superseded memories
|
|
302
|
+
pruneQuarantined: false, // Archive old unreviewed quarantined memories
|
|
303
|
+
pruneAge: 90, // Archive superseded older than N days
|
|
304
|
+
dryRun: false, // Preview without changes
|
|
305
|
+
});
|
|
306
|
+
// report: { deduplicated, contradictions, corroborated, compressed, pruned, before, after, duration_ms }
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Phases: dedup → contradiction resolution → cross-source corroboration → compress stale clusters → prune.
|
|
310
|
+
|
|
202
311
|
## CLI
|
|
203
312
|
|
|
204
313
|
```bash
|
|
@@ -220,12 +329,14 @@ Factory function. All options are optional — zero-config returns a working ins
|
|
|
220
329
|
|
|
221
330
|
| Method | Description |
|
|
222
331
|
|--------|-------------|
|
|
223
|
-
| `store(agent, text, opts?)` | Store with A-MEM auto-linking |
|
|
224
|
-
| `search(agent, query, opts?)` | Semantic/keyword search
|
|
332
|
+
| `store(agent, text, opts?)` | Store with A-MEM auto-linking. Opts: `claim`, `provenance`, `onConflict` |
|
|
333
|
+
| `search(agent, query, opts?)` | Semantic/keyword search. Opts: `explain`, `statusFilter`, `sessionId` |
|
|
225
334
|
| `searchAll(query, opts?)` | Cross-agent search |
|
|
226
335
|
| `evolve(agent, text, opts?)` | Store with conflict resolution |
|
|
227
336
|
| `ingest(agent, text, opts?)` | Bulk extract facts and store |
|
|
228
337
|
| `context(agent, query, opts?)` | Generate context briefing |
|
|
338
|
+
| `storeMany(agent, items, opts?)` | Batch store with atomic rollback |
|
|
339
|
+
| `searchMany(agent, queries, opts?)` | Batch search (single embed call) |
|
|
229
340
|
|
|
230
341
|
### Graph Methods
|
|
231
342
|
|
|
@@ -245,6 +356,68 @@ Factory function. All options are optional — zero-config returns a working ins
|
|
|
245
356
|
| `reinforce(memoryId, boost?)` | Boost memory importance |
|
|
246
357
|
| `health()` | Full health report |
|
|
247
358
|
| `timeline(agent?, days?)` | Date-grouped memory view |
|
|
359
|
+
| `consolidate(opts?)` | Full maintenance: dedup → contradiction check → corroborate → compress → prune |
|
|
360
|
+
|
|
361
|
+
### Episode Methods
|
|
362
|
+
|
|
363
|
+
| Method | Description |
|
|
364
|
+
|--------|-------------|
|
|
365
|
+
| `createEpisode(name, ids, opts?)` | Group memories into a named episode |
|
|
366
|
+
| `captureEpisode(agent, name, opts)` | Auto-capture episode from time window |
|
|
367
|
+
| `getEpisode(id)` | Get episode with resolved memories |
|
|
368
|
+
| `addToEpisode(id, memoryIds)` | Add memories to an episode |
|
|
369
|
+
| `removeFromEpisode(id, memoryIds)` | Remove memories from an episode |
|
|
370
|
+
| `listEpisodes(opts?)` | List episodes (filter by agent, tag, time) |
|
|
371
|
+
| `searchEpisode(id, query, opts?)` | Semantic search within an episode |
|
|
372
|
+
| `summarizeEpisode(id)` | LLM-generated episode summary |
|
|
373
|
+
| `deleteEpisode(id)` | Delete episode (memories preserved) |
|
|
374
|
+
|
|
375
|
+
### Compression Methods
|
|
376
|
+
|
|
377
|
+
| Method | Description |
|
|
378
|
+
|--------|-------------|
|
|
379
|
+
| `compress(ids, opts?)` | Compress memories into a digest (extractive or LLM) |
|
|
380
|
+
| `compressEpisode(id, opts?)` | Compress all memories in an episode |
|
|
381
|
+
| `compressCluster(index, opts?)` | Compress an auto-detected cluster |
|
|
382
|
+
| `autoCompress(opts?)` | Auto-detect and compress stale clusters |
|
|
383
|
+
|
|
384
|
+
### Labeled Cluster Methods
|
|
385
|
+
|
|
386
|
+
| Method | Description |
|
|
387
|
+
|--------|-------------|
|
|
388
|
+
| `createCluster(label, ids, opts?)` | Create a named cluster |
|
|
389
|
+
| `labelCluster(index, label, opts?)` | Label an auto-detected cluster |
|
|
390
|
+
| `listClusters()` | List all labeled clusters |
|
|
391
|
+
| `getCluster(id)` | Get cluster with resolved memories |
|
|
392
|
+
| `refreshCluster(id)` | Re-expand cluster via BFS |
|
|
393
|
+
| `deleteCluster(id)` | Delete cluster (memories preserved) |
|
|
394
|
+
| `autoLabelClusters(opts?)` | LLM-generated labels for unlabeled clusters |
|
|
395
|
+
|
|
396
|
+
### Predicate Schema Methods
|
|
397
|
+
|
|
398
|
+
| Method | Description |
|
|
399
|
+
|--------|-------------|
|
|
400
|
+
| `registerPredicate(name, schema)` | Register conflict/normalization rules for a predicate |
|
|
401
|
+
| `registerPredicates(map)` | Bulk register from object or Map |
|
|
402
|
+
| `getPredicateSchema(name)` | Get effective schema (with defaults) |
|
|
403
|
+
| `listPredicateSchemas()` | List all registered schemas |
|
|
404
|
+
|
|
405
|
+
### Explainability Methods
|
|
406
|
+
|
|
407
|
+
| Method | Description |
|
|
408
|
+
|--------|-------------|
|
|
409
|
+
| `explainMemory(memoryId)` | Trust, confidence, provenance, claim summary |
|
|
410
|
+
| `explainSupersession(memoryId)` | Supersession chain with trust comparison |
|
|
411
|
+
|
|
412
|
+
### Quarantine Methods
|
|
413
|
+
|
|
414
|
+
| Method | Description |
|
|
415
|
+
|--------|-------------|
|
|
416
|
+
| `quarantine(memoryId, opts?)` | Manually quarantine an active memory |
|
|
417
|
+
| `listQuarantined(opts?)` | List quarantined memories (filterable by agent) |
|
|
418
|
+
| `reviewQuarantine(memoryId, opts)` | Activate or reject a quarantined memory |
|
|
419
|
+
| `pendingConflicts()` | List unresolved structural conflicts |
|
|
420
|
+
| `resolveConflict(conflictId, opts)` | Resolve a pending conflict |
|
|
248
421
|
|
|
249
422
|
### Advanced: Bring Your Own Providers
|
|
250
423
|
|
|
@@ -252,7 +425,10 @@ Factory function. All options are optional — zero-config returns a working ins
|
|
|
252
425
|
import { MemoryGraph } from '@jeremiaheth/neolata-mem';
|
|
253
426
|
|
|
254
427
|
const graph = new MemoryGraph({
|
|
255
|
-
storage: myCustomStorage, // { load, save, loadArchive, saveArchive, genId
|
|
428
|
+
storage: myCustomStorage, // { load, save, loadArchive, saveArchive, genId,
|
|
429
|
+
// loadEpisodes?, saveEpisodes?, genEpisodeId?,
|
|
430
|
+
// loadClusters?, saveClusters?, genClusterId?,
|
|
431
|
+
// loadPendingConflicts?, savePendingConflicts? }
|
|
256
432
|
embeddings: myCustomEmbedder, // { embed(texts) → number[][] }
|
|
257
433
|
extraction: myExtractor, // { extract(text) → Fact[] }
|
|
258
434
|
llm: myLLM, // { chat(prompt) → string }
|
|
@@ -264,16 +440,29 @@ const graph = new MemoryGraph({
|
|
|
264
440
|
|
|
265
441
|
```
|
|
266
442
|
Text → [Embed] → [Find Related] → [Link Bidirectionally] → [Store]
|
|
267
|
-
↑
|
|
268
|
-
Existing memories
|
|
269
|
-
with embeddings
|
|
443
|
+
↑ ↓
|
|
444
|
+
Existing memories [Structural Conflict Check]
|
|
445
|
+
with embeddings (claim matching by subject/predicate)
|
|
446
|
+
↓
|
|
447
|
+
[Trust Comparison] → quarantine or supersede
|
|
270
448
|
|
|
271
|
-
Conflict Detection:
|
|
449
|
+
Conflict Detection (evolve):
|
|
272
450
|
New fact → [Embed] → [Find high-similarity] → [LLM: conflict/update/novel?]
|
|
273
451
|
→ CONFLICT: archive old, store new
|
|
274
452
|
→ UPDATE: modify existing in-place (with evolution history)
|
|
275
453
|
→ NOVEL: normal A-MEM store
|
|
276
454
|
|
|
455
|
+
Structural Conflict Detection (store with claims):
|
|
456
|
+
New claim → [Match subject+predicate+scope] → [Compare trust scores]
|
|
457
|
+
→ Higher trust: supersede existing
|
|
458
|
+
→ Lower trust: quarantine new (or keep_active via onConflict option)
|
|
459
|
+
→ Equal trust or require_review policy: add to pending conflicts
|
|
460
|
+
|
|
461
|
+
Trust Score:
|
|
462
|
+
trust = sourceWeight + corroborationBonus + feedbackSignal - recencyPenalty
|
|
463
|
+
Sources: user_explicit(1.0), system(0.95), tool_output(0.85),
|
|
464
|
+
user_implicit(0.7), document(0.6), inference(0.5)
|
|
465
|
+
|
|
277
466
|
Decay Cycle:
|
|
278
467
|
For each memory:
|
|
279
468
|
strength = (importance × ageFactor × touchFactor × categoryWeight) + linkBonus + accessBonus
|
|
@@ -291,6 +480,11 @@ Decay Cycle:
|
|
|
291
480
|
| Graph traversal | ✅ | ❌ | ❌ | ✅ |
|
|
292
481
|
| Multi-agent native | ✅ | ❌ | ❌ | ❌ |
|
|
293
482
|
| Conflict resolution | ✅ | ✅ | ❌ | ❌ |
|
|
483
|
+
| Quarantine lane | ✅ | ❌ | ❌ | ❌ |
|
|
484
|
+
| Predicate schemas | ✅ | ❌ | ❌ | ❌ |
|
|
485
|
+
| Explainability API | ✅ | ❌ | ❌ | ❌ |
|
|
486
|
+
| Episodes & compression | ✅ | ❌ | ❌ | ❌ |
|
|
487
|
+
| Labeled clusters | ✅ | ❌ | ❌ | ❌ |
|
|
294
488
|
| Works offline | ✅ | ✅ | ✅ | ❌ |
|
|
295
489
|
| No Python needed | ✅ | ❌ | ❌ | ❌ |
|
|
296
490
|
| Zero-config start | ✅ | ❌ | ❌ | ❌ |
|