@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 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 (single agent) |
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 | ✅ | ❌ | ❌ | ❌ |