An agentic memory engine designed for lossless, tiered verbatim storage and multi-hop retrieval.
Project description
EpochDB — Agentic Memory Engine
EpochDB is a high-performance, state-aware memory engine designed for lossless, tiered storage, atomic state management, and multi-hop relational reasoning. It is built specifically for AI agents that require perfect historical recall, long-term state persistence, and deterministic fact corrections.
Why EpochDB?
Flat vector databases retrieve text based on semantic similarity but struggle to resolve conflicting facts (e.g. "where does the user work now?" vs "where did they work last year?"). EpochDB solves this through Atomic State Management:
- Topic Lock & Entity Seeding: Ensures retrieval stays within the target topic by seeding candidates directly from the Knowledge Graph.
- State-Aware Supersession: Automatically identifies and filters out stale facts when they are updated.
- Tiered HNSW Hierarchy: Sub-millisecond recall across working memory (L1 RAM) and historical archives (L2 Disk).
- Memory Forking & Lineage: Supports logical branches (
db.fork) for multi-agent collaboration and hypothetical reasoning without copying data. - Rich Domain Objects: Returns structured
Memory,Entity, andGraphabstractions rather than raw database tuples.
Architecture
EpochDB uses a tiered hierarchy modeled after CPU caches to balance low latency and massive scale:
graph TD
Agent([Agent / Application]) -->|remember / add_memory| Engine[EpochDB Engine]
subgraph "Working Memory — RAM (Hot Tier)"
Engine --> HNSW_H[HNSW Vector Index]
Engine --> WAL[WAL: ACID Write-Ahead Log]
Engine --> KG[Active Knowledge Graph]
end
subgraph "Historical Archive — Disk (Cold Tier)"
HNSW_H -->|Async Flush| Parquet[(Parquet + F32 + Zstd)]
Parquet --- HNSW_C[HNSW Index per Epoch]
HNSW_C --- GEI[Global Entity Index]
end
subgraph "Retrieval Pipeline"
HNSW_H --> Pool[Candidate Pool]
HNSW_C --> Pool
Pool --> KG_Exp[KG Expansion & Topic Lock]
KG_Exp --> RRF[4-Way RRF Fusion + Supersession]
RRF --> Context[Agentic Context]
end
Performance, Latency & Token Efficiency
1. The 1.000 Sweep Benchmark
EpochDB achieves a perfect 1.000 score across named benchmark suites designed to validate engine logic:
| Benchmark | What it tests | Metric | Score |
|---|---|---|---|
| LoCoMo | Multi-hop relational reasoning | Multi-hop recall | 1.000 |
| ConvoMem | Fact correction & preference recall | recall@3 | 1.000 |
| LongMemEval | Longitudinal recall (cross-epoch) | recall@3 | 1.000 |
| NIAH | Needle in a Haystack (High-noise) | precision@3 | 1.000 |
Run the benchmark suite locally:
venv/bin/python -m benchmarks.run_all
2. Operational Latency
Precision metrics across Hot and Cold tiers:
- Direct/Multi-Hop Relational Retrieval (Hot Tier): 0.2 ms – 0.4 ms
- Historical HNSW Retrieval (Cold Tier): ~4.0 ms (30x speedup from ~125 ms via persistent indexing)
- Cold Tier Full Scan (
pyarrow.dataset): 45.0 ms (for cross-epoch scalar aggregations) - Scalar Range Query (B-tree): 0.8 ms
- Series Interpolation (IntervalTree): 1.2 ms
- Constraint Satisfaction (Z3 SAT Solver): 2.5 ms
- WAL Crash Recovery Replay: 9.1 ms
3. LangGraph Token Savings
When used as a checkpointer, EpochDB keeps LangGraph states "thin" by storing historical turns as Unified Memory Atoms and querying them selectively. This achieves linear $O(N)$ token scaling (saving 55% to 79% of input tokens compared to standard checkpointers' quadratic $O(N^2)$ accumulation).
4. Sync vs. Async Concurrency Benchmark
This benchmark evaluates E2E latency and input token consumption under concurrent multi-user load, comparing three execution configurations using the live Gemini API (gemini-embedding-2 and gemini-3-flash-preview):
- Sync LangGraph + Sync EpochDB: Sequential graph invocation with blocking I/O.
- Async LangGraph + Async EpochDB: Concurrent graph execution (
ainvoke) using async checkpointers and DB facades. - Async Astraea + EpochBlackboard: Decoupled event-driven reactive coordination running in parallel.
The scenario simulates 3 concurrent users executing 3 conversation turns each (9 turns total) over the live API:
| Metric | Sync LangGraph | Async LangGraph | Async Astraea |
|---|---|---|---|
| E2E Latency (seconds) | 352.060s | 113.027s | 39.869s |
| Average Turn Latency | 11735.3ms | 3767.6ms | 1329.0ms |
| Throughput Speedup | 1.00x (Baseline) | 3.11x | 8.83x |
| Total Input Tokens | 28,385 | 24,145 | 21,932 |
Key Insights
- Concurrency Speedup: Sequential synchronous execution causes network and database blocking latency to scale linearly ($O(U \times T)$), taking nearly 6 minutes. Parallelizing requests via async facades collapses the total duration to approximately a single user's timeline.
- Event-Driven Astraea: Astraea instantiates a pool of independent worker agents processing events in parallel tasks. This decoupled architecture achieves an 8.83x speedup over the synchronous baseline, outperforming Async LangGraph by over 2.8x.
- Context Size / Token Savings: In longer sessions (10 turns), Astraea's subgraph-based tiling achieves 9.2% token savings over Async LangGraph. While OABS graph serialization (node properties, relation types, and lineage metadata serialized by
ContextTiler) has a small formatting overhead, its subgraph-based tiling maintains flat prompt overhead as history scales, avoiding the linear growth of conversation context in standard systems.
Run the benchmark suite locally:
poetry run python examples/sync_async_benchmark.py
Installation
pip install epochdb
Quickstart
1. Synchronous API Facade
from epochdb import EpochDB
# Initialize with auto-embedding
with EpochDB(storage_dir="./memory", embedding_model="all-MiniLM-L6-v2") as db:
# Store a memory with KG triples
db.remember("User works at DataFlow.", metadata={"triples": [("user", "works_at", "DataFlow")]})
# Update facts (supersession resolves conflicts)
db.remember("Actually, user now works at VectorAI.", metadata={"triples": [("user", "works_at", "VectorAI")]})
# Query returns rich Memory objects
results = db.query("Where does the user work?", k=1)
print(results[0].text) # "Actually, user now works at VectorAI."
2. Asynchronous API Facade
import asyncio
from epochdb import AsyncEpochDB
async def main():
# Async context manager for non-blocking I/O in agent loops
async with AsyncEpochDB(storage_dir="./memory", embedding_model="all-MiniLM-L6-v2") as db:
await db.remember("VectorAI develops CRISPR-X platform.", metadata={"triples": [("VectorAI", "develops", "CRISPR-X")]})
results = await db.query("What does VectorAI build?", k=1)
print(results[0].text)
asyncio.run(main())
3. MongoDB-Style Metadata Filtering
# Filter retrieval using operators like $eq, $ne, $in, $nin, $gt, $gte, $lt, $lte
results = db.query(
"Query text",
k=5,
filters={
"author": "Jeff",
"importance": {"$gt": 3},
"category": {"$in": ["development", "production"]}
}
)
4. Soft-Delete & Compaction
# Mark memory as deleted (filtered out from queries by default)
db.delete(memory_id, hard=False)
# Reclaim space and deduplicate historical Parquet archives in the Cold Tier
db.compact()
5. Entity & Graph Traversal
# Retrieve entity object
vector_ai = db.get_entity("VectorAI")
# Traverse relations in Global Entity Index
related = vector_ai.related() # [Entity("user"), Entity("CRISPR-X")]
# Chronological timeline of the entity
timeline = vector_ai.timeline()
# Generate local graph segment
graph = db.entity_graph("VectorAI", depth=2)
print(graph.nodes) # ['VectorAI', 'user', 'CRISPR-X']
print(graph.edges) # List of edge dictionaries mapping sources and targets
Client-Server Architecture
EpochDB supports remote deployments via a client-server architecture, allowing multiple agents or server processes to share a single, central database over HTTP.
1. Starting the Server (ThreadingEpochDBServer)
Start the multi-threaded HTTP server on the host machine to serve an EpochDB instance:
from epochdb import EpochDB
from epochdb.api.server import start_server
db = EpochDB(storage_dir="./shared_memory", embedding_model="all-MiniLM-L6-v2")
server = start_server(db, host="0.0.0.0", port=8080)
try:
server.serve_forever()
finally:
db.close()
2. Communicating via the Client (RemoteEpochDB)
Use the remote client to execute queries, store memories, and retrieve timelines over HTTP REST:
from epochdb import RemoteEpochDB
# Initialize the client
client = RemoteEpochDB(host="127.0.0.1", port=8080)
# Store a memory
client.remember("Pollyanna is married to Jefferson.")
# Query the remote database
results = client.query("Who is Pollyanna married to?", k=1)
print(results[0].text) # "Pollyanna is married to Jefferson."
# Access database stats remotely
stats = client.stats()
print(stats)
Multi-Tenant Partitioning & WAL Optimizations
1. Multi-Tenant Isolation
For multi-tenant SaaS platforms or isolated agent sessions, EpochDB can physically partition database files on disk using the tenant parameter:
# Database files are physically isolated under the "tenants/tenant_alpha" subdirectory
db = EpochDB(storage_dir="./app_data", tenant="tenant_alpha")
2. Configurable WAL Sync Interval
By default, the Write-Ahead Log (WAL) synchronously forces an fsync call to disk on every transaction append, ensuring zero data loss but limiting write throughput. You can speed up writes dramatically by configuring asynchronous background syncing:
# Sync the WAL file to disk asynchronously every 0.1 seconds in a background thread
db = EpochDB(storage_dir="./memory", wal_sync_interval=0.1)
LangGraph Integration
EpochDB provides native checkpointer support for both synchronous and asynchronous workflows:
from epochdb.checkpointer import EpochDBCheckpointer
from epochdb import EpochDB
# Synchronous compile
with EpochDB(storage_dir="./agent_state") as db:
checkpointer = EpochDBCheckpointer(db)
app = workflow.compile(checkpointer=checkpointer)
For async runtimes:
from epochdb import AsyncEpochDB
from epochdb.checkpointer import EpochDBCheckpointer
async def run_agent():
async with AsyncEpochDB(storage_dir="./agent_state") as db:
checkpointer = EpochDBCheckpointer(db)
app = workflow.compile(checkpointer=checkpointer)
# Uses aput, aget_tuple, and alist internally under the hood
Repository Structure
The codebase is modularized to isolate engine subsystems:
core/: Core transactions, checkpointers, and base units.storage/: Hot Tier (RAM HNSW) and Cold Tier (Parquet storage).entities/: Global KG manager, cascade updates, and reflection rules.retrieval/: Multi-stage retrieval managers, quantitative indexes, and RRF fusion.api/: Public facade APIs (EpochDBandAsyncEpochDB) and domain objects (Memory,Entity,Graph).
Technical Specifications & Constants
+20.0Topic Lock Boost: Set mathematically larger than the maximum possible Reciprocal Rank Fusion (RRF) score sum (which caps at $\approx 0.05$ across semantic and recency ranks, using $K=60$). This acts as a "hard lock," ensuring query-intent-matched facts always outrank adjacent semantic noise.0.0001xSupersession Penalty: Multiplicatively demotes stale facts (e.g. older conflicting values for the same subject-predicate pair) to the bottom of the retrieval pool, resolving contradictions deterministically while preserving database history.1e-7Signal-to-Noise Demotion: Once a Topic-Locked fact is identified, all non-locked background noise is demoted by $10^{-7}$ to keep the LLM's context window clean and free from distractors.- Quantitative logic & Triggers: Native support for Scalars, Time-Series, and Constraints.
IntervalTreeenables precise $O(\log n + k)$ range queries with base-unit normalization via persistentschema_registry.json. - Reactive Cascade Graphs:
CascadeManagerautomatically triggers downstream policy updates, while Coefficient of Variation (CV) reflections auto-generate constraint atoms from observed historical data trends. - Analytical Cold Tier: Leveraging
pyarrow.datasetfor high-performance cross-epoch scanning and numeric aggregation directly over compressed Parquet archives. - ACID Crash Recovery: Zero data loss for in-flight memories via the synchronous Write-Ahead Log.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file epochdb-1.0.3.tar.gz.
File metadata
- Download URL: epochdb-1.0.3.tar.gz
- Upload date:
- Size: 68.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df9e09db78e763d587bf57b9a8046e9fe1f1c525a1eb149c79d8fd5942d3c580
|
|
| MD5 |
45ef96e54206a051d58f2690f12a6714
|
|
| BLAKE2b-256 |
ff2d1a8f719acc91c9cbf622b0b64d324f04635ca022a8a5f637d3b5b5c9d226
|
File details
Details for the file epochdb-1.0.3-py3-none-any.whl.
File metadata
- Download URL: epochdb-1.0.3-py3-none-any.whl
- Upload date:
- Size: 60.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b1a6f6ded7abce857f1dbc65f474ebb3f7a6226e5d9c2ada500cd960bbeb312
|
|
| MD5 |
7b8b4280c269efba41e197671319212e
|
|
| BLAKE2b-256 |
6fc7d14a07a16460d53e9f20e20a5941abf9e3eb6ab5dc773fe5da6c8d7b088a
|