Skip to main content
Memory consolidation runs a scheduled, off-hot-path pass that merges duplicate memories, promotes durable facts, and prunes stale entries — refusing any rewrite that would drop more than a set fraction of your store. Long-lived agents capture memories inline during a turn, so the store accretes near-duplicate, never-pruned entries that degrade recall and grow token cost. Consolidation is the background maintenance pass that cleans it up safely.
Today the core SDK exposes the protocol and loss-guard contract only — the MemoryConsolidationProtocol interface plus the ConsolidationResult math. The heavy LLM consolidation pass and its scheduling ship in praisonai-plugins. Until that plugin lands, you implement the protocol yourself and run it behind your own scheduler.

Quick Start

1

Check a result under the loss guard

Construct a ConsolidationResult, read loss_fraction, and ask the guard whether a pass drops too much.
2

Wire a consolidator to an Agent

Implement MemoryConsolidationProtocol and hand it your agent’s memory on a schedule — the agent keeps chatting while consolidation runs in the background.

How It Works

Consolidation is background maintenance: the user never invokes it mid-conversation — a scheduler runs it off-turn, and the loss guard decides whether the rewrite is applied. The protocols are @runtime_checkable, so isinstance works at runtime, and both consolidate and aconsolidate carry a resolvable ConsolidationResult return annotation for introspection.

Configuration Options

ConsolidationResult reports what a pass did and carries the loss-guard math. No feature_configs.py entry exists — this is a protocol, not a config class — so these are the fields the dataclass exposes. Methods:

Loss-Guard Semantics

The loss guard is the invariant that keeps a bad rewrite from wiping your memory. Originals-based vs net-count loss. loss_fraction normally divides the drop in entries by entries_before. When you set retained_originals, it instead measures how many original entries survived — which catches destructive rewrites that keep the count the same.
Empty-store safety. An empty store reports 0.0, never a divide-by-zero, and growth never reports negative loss.
Fail-closed threshold validation. An invalid threshold can never silently permit a destructive rewrite — exceeds_loss raises ValueError on NaN, inf, out-of-range, or non-numeric input.

Common Patterns

Implement the sync protocol and reject rewrites that trip the guard:
Use the async protocol when your store or LLM calls are awaitable:
Run consolidation off the hot path behind a scheduler — the actual scheduler wiring lives in praisonai-plugins:
Verify structural typing at runtime — both protocols are @runtime_checkable:

Sync vs Async

Pick the protocol that matches how your memory store and consolidation logic run.

Layering

Consolidation is built in three layers so the core stays dependency-free.

Best Practices

The 0.25 default is a sane starting point — it lets a pass merge and prune meaningfully while blocking anything that would gut a quarter of your store. Lower it if your memories are high-value and irreplaceable.
Net entry-count loss misses destructive equal-size rewrites. If your implementation knows how many original entries survived, set retained_originals so the guard measures real loss, not just the change in count.
Consolidation is a heavy background pass — schedule it (nightly cron, idle window) so it never adds latency to a user turn. The plugin layer wires this for you.
Populate context with counts and timings so you can observe merge/prune/reject rates over time and tune max_loss_fraction.

Memory Lifecycle Hooks

React to compression, session switches, writes, and delegation from inside your memory backend.

Pre-Compaction Memory Flush

Save durable facts to long-term memory before compaction discards them.