- Context compaction — automatically summarizes conversation history when the context window fills up, preserving recent turns and discarding older ones.
- Semantic memory — indexes discarded messages so the agent can retrieve past context on demand via the
memory_searchtool.
What this guide is for
Use this guide when you want to understand or configure:- long-horizon conversation behavior
- semantic recall via
memory_search - compaction thresholds
- the relationship between compaction and semantic memory
Feature flags
Compaction and semantic memory have separate build-time and runtime switches.The CLI’s default features include the memory backend/session wiring, but not
session-compaction. For no-default/custom source builds, enable the memory features explicitly when you need memory_search.AgentFactory::memory(true) enables the semantic memory path (HnswMemoryStore + memory_search). Compaction is controlled independently by whether the binary is built with session-compaction and whether a compactor is wired into the session path.
- compaction enabled, semantic memory disabled
- semantic memory enabled, compaction unavailable
- both enabled together
CompactionConfig
Controls when and how compaction runs.How compaction triggers
Compaction is checked at every turn boundary, just before the next LLM call. The decision flow:1
Skip turn 0
The first turn always skips compaction.
2
Loop guard check
If compaction occurred at turn N, no compaction until turn N +
min_turns_between_compactions.3
Dual threshold evaluation
Compaction triggers if EITHER:
last_input_tokens >= auto_compact_threshold(input tokens from the last LLM response), ORestimated_history_tokens >= auto_compact_threshold(JSON bytes of all messages / 4).
What happens during compaction
When compaction triggers:1
Emit CompactionStarted event
Emitted with input/estimated token counts and message count.
2
Send compaction prompt to LLM
The current conversation history plus a compaction prompt is sent to the LLM with no tools and
max_summary_tokens as the response limit.3
Handle result
On failure: a CompactionFailed event is emitted and the session is not mutated (safe failure).On success:
DefaultCompactor::rebuild_history produces new messages:- System prompt is preserved verbatim (if present).
- A summary message is injected as a User message with the prefix
[Context compacted]. - The last
recent_turn_budgetcomplete turns are retained. - All other messages become
discarded.
4
Index discarded memory
If semantic memory is enabled, discarded messages are indexed before the compacted history is committed.
5
Replace session messages
The session messages are replaced with the rebuilt history after memory indexing accepts the discarded content.
6
Record usage and emit completion event
Compaction usage is recorded against the session and budget. A CompactionCompleted event is emitted with summary token count and before/after message counts.
The compaction prompt
The compaction prompt
The compactor sends this prompt to the LLM:
You are performing a CONTEXT COMPACTION. Your job is to create a handoff summary so work can continue seamlessly. Include:Be concise and structured. Prioritize information the next context needs to act, not narrate.
- Current progress and key decisions made
- Important context, constraints, or user preferences discovered
- What remains to be done (clear next steps)
- Any critical data, file paths, examples, or references needed to continue
- Tool call patterns that worked or failed
Memory indexing after compaction
When both aCompactor and a MemoryStore are wired into the agent, discarded messages are indexed into semantic memory before compacted history is committed. If the memory store rejects indexing, Meerkat preserves the original history, emits a CompactionFailed event, and skips that compaction attempt instead of dropping the only authoritative copy of the discarded text.
For each discarded message:
- The message’s indexable text content is extracted via
message.as_indexable_text(). - If non-empty, it is indexed with
MemoryMetadatacontaining the session ID, the typed source handle (the offset range of the source message(s)), and a timestamp.
memory_search tool.
The memory_search tool
When memory is enabled, the agent gains a memory_search tool.
Tool definition
Parameters
Natural language search query describing what you want to recall.
Maximum number of results to return. Capped at 20.
Response format
Returns a JSON array of result objects:The text content of the memory entry.
Similarity score from 0.0 (no match) to 1.0 (exact match). Typical useful matches are above 0.7.
The half-open
[start, end) offset range of the source message(s) the entry
was indexed from. Memory is scoped to a single session; results do not carry a
session_id, and there is no cross-session recall.Memory store implementations
- HnswMemoryStore (production)
- SimpleMemoryStore (test-only)
Uses:
- hnsw_rs (v0.3) for approximate nearest-neighbor search with cosine distance.
- SQLite for persistent metadata and text storage.
{store_path}/memory/memory.sqlite3Key characteristics:- Embedding: Bag-of-words TF with hash-based dimensionality reduction (4096-dimensional vectors, L2-normalized). Each word is hashed to a bucket and its presence increments that dimension.
- Persistence: Data survives process restart.
open()runs a one-time in-place schema migration (indexedsession_idprojection column + durable point-ID allocator table, inside oneBEGIN IMMEDIATEtransaction) and an idempotent heal of legacy rows; it scans and embeds nothing. A scope’s HNSW graph is built lazily on first use (search / index / enumerate / drop), so opening the store no longer pays for every session in the realm. - Scoping: One HNSW index per session owner, built on demand from the scope’s durable rows.
- Lifecycle:
drop_scope(owner)deletes a scope’s durable rows all-or-nothing and drops its live index (dropped point IDs are never reused);enumerate_scoped(scope, request)pages raw scope rows in durable-id order with optionalsource_range-overlap andindexed_afterfilters (a zerolimitis rejected with a typed error). - Score conversion: HNSW cosine distance (0 = identical, 2 = opposite) is converted to a 0..1 similarity score:
score = 1.0 - (distance / 2.0). - Thread safety: Point IDs are allocated transactionally from the durable allocator table (never reused, collision-free across concurrent store instances). Insertions, scope drops, and lazy scope loads are serialized via a
Mutex; the scoped-index map sits behind aRwLockfor concurrent searches. - Parameters (
HnswParamsdefaults):max_nb_connection = 16,max_layer = 16,ef_construction = 200,ef_search = 200.
How memory gets wired
When thememory-store-session feature is compiled in and memory is enabled:
- An
HnswMemoryStoreis opened at{store_path}/memory/. - The
memory_searchtool is added to the agent’s tool set. - A
DefaultCompactoris attached only ifsession-compactionis also enabled. - A built-in
memory-retrievalskill is injected into the system prompt, teaching the agent how to use memory search.
Examples
- CLI
- SDK
Custom CompactionConfig
See also
- Configuration: memory and compaction - config file settings
- Architecture - how compaction fits into the agent loop
