Dual-Memory
A two-agent memory system for AI assistants. A fast Writer captures facts into a Neo4j graph, and a slower Editor keeps that graph clean.
- Stack
- TypeScript, Python, Neo4j, LLMs
Most assistant memory either appends text forever or searches a flat vector store. That works at first, then degrades: duplicates pile up, stale facts survive, and relationships are hard to query. Dual-Memory splits the job between two agents with different priorities.
Writer and Editor
- Writer (TypeScript, an OpenClaw memory plugin) prioritizes capture. It runs inline with the assistant, extracts facts after each conversation, embeds them, writes graph nodes, and retrieves relevant context before the next session.
- Editor (Python) prioritizes coherence. It periodically reviews the graph with broader context: deduplication, temporal supersession, entity resolution, relationship mining, and confidence scoring. Every edit is audited and every run can be rolled back.
Retrieval
Retrieval combines vector similarity with graph expansion, weighted by confidence and salience, with a penalty for superseded facts:
score = cosine
× (0.6 + 0.4 · confidence)
× (0.6 + 0.4 · salience)
× (0.7 if superseded else 1)
Evaluation
A gold-labelled harness pushes 40 synthetic sessions (102 facts) through the real write path, runs the Editor, and asks 50 questions through the real retrieval. It scores duplicates, supersessions, entity merges, and whether the right facts come back. LLM replies and embeddings are recorded, so CI replays the full loop without API keys.
Duplicate precision
Contradiction recall
Retrieval recall@5
LLM calls per run
- Baseline
- Relationship pairs from non-hub entities only
- True cosine similarity in the duplicate gate
- Temporal supersession
- Three-tier entity resolution
- Idempotent runs and rollback
- Editor effort raised to medium
- Names in one memory can never be merged
Show the numbers
| Step | Duplicate precision | Contradiction recall | Retrieval recall@5 | LLM calls per run |
|---|---|---|---|---|
| 1. Baseline | 55% | 13% | 82% | 270 |
| 2. Relationship pairs from non-hub entities only | 55% | 13% | 82% | 58 |
| 3. True cosine similarity in the duplicate gate | 68% | 7% | 88% | 57 |
| 4. Temporal supersession | 81% | 87% | 81% | 57 |
| 5. Three-tier entity resolution | 81% | 87% | 80% | 58 |
| 6. Idempotent runs and rollback | 81% | 87% | 80% | 58 |
| 7. Editor effort raised to medium | 89% | 100% | 86% | 61 |
| 8. Names in one memory can never be merged | 89% | 100% | 86% | 61 |
Integration tests against a real Neo4j cover idempotency and rollback.
The fixture was also used for tuning, each step is a single LLM sample, and it doesn’t evaluate conversation extraction. Running the Editor trades some recall (91.5% → 86.5%) for better ranking of stale facts.