pgmem
Concepts

Compaction (MAGE)

Rolling summarization of the turn buffer into the state tree.

Context windows are not memory. As a conversation grows, pgmem compacts the live turn buffer into transparent execution summaries — an append-only tree of state nodes — and validates each summary off the response path. The agent keeps answering while validation runs, and raw turns are never deleted.

Why it matters

Left alone, the turn buffer grows until it's slow and noisy, and naive summarization silently loses decisions. Compaction keeps context bounded without amnesia: the active path stays available, every raw turn remains auditable, and a summary that drops something can be revised into a new branch instead of overwriting history.

The model (MAGE)

Compaction is rolling, incremental summarization into an append-only state tree — not a destructive truncation:

  1. Compress — take the active (uncompressed) turns, summarize them into one new state node, append it to the active path, and advance the compaction boundary past them. The raw turns stay; the compiler just stops including them in the recent-turns window.
  2. Maintain — a judge LLM checks the summary preserved what the turns carried. Pass → the node is compressed. Fail → it's failed, the verdict becomes a hint, and you can revise.
  3. Revise — abandon a rejected branch (turns are marked abandoned, not deleted) and its note becomes a "prior attempt" hint so the agent doesn't repeat the mistake.

The summary is incremental: each Compress is fed the parent node's summary, so the state tree is a rolling digest down the active path.

How it works

You control when it runs; pgmem never compacts inside add_turn.

# Explicit, at a natural topic boundary.
await session.compress(label="Enterprise-plan evaluation", kind="topic")

# Threshold-gated: a no-op until the active-turn count crosses the threshold
# (default 20). The cheap default strategy drops tool-result noise, no LLM.
await session.compact()

# Off the turn (the voice-safe path): Compress + async Maintain in the
# background; returns immediately.
task = await session.compact_async()

compress with no summary uses the LLM; passing an explicit summary (or the tool_clear strategy) skips it. Maintain can run separately, or as part of compact_async.

Tradeoffs & pitfalls

compile_context reporting compaction_triggered: true is not compaction — that's the budget fitter trimming recent turns for one prompt. Nothing durable happened. Treat it as a signal to call compact_async(), which is the real operation.

  • Compaction (LLM summarization) is heavy — keep it off the response path with compact_async. See Compaction off the critical path.
  • A failed Maintain doesn't lose data: the raw turns are intact and the branch can be revised. Summaries are proposals until validated.

On this page