pgmem
Guides

Compaction off the critical path

Keep summarization off the response path for voice.

Compaction is an LLM operation — summarising the turn buffer and validating the result. For a voice agent, none of that can happen while the user waits. The rule is simple: call compact_async after you've replied, and never await heavy compaction inline.

Prerequisites

Steps

Fire compaction after the reply

compact_async starts Compress + Maintain in the background and returns a CompactionTask immediately. Call it once you've already returned the reply.

await session.add_turn(role="assistant", content=reply)
task = await session.compact_async()   # returns at once; work runs off-turn
return reply

(Optional) await the result off-turn

If you need to know the outcome (e.g. for logging), await the task after the turn, not before:

result = await task.await_result(timeout=10.0)   # or check task.done()

Let the threshold drive it

compact_async Compresses whatever is in the active buffer; compact() is threshold-gated and no-ops until the active-turn count crosses compact_threshold (default 20). Set the threshold per session if you want a different cadence:

session = await mem.session.create(group_id="acme", compact_threshold=12)

Verify

The agent keeps responding while validation runs. A successful Maintain marks the state node compressed; a failed one marks it failed and surfaces a hint you can revise. Either way the raw turns are intact — inspect compactions via Inspecting memory.

Gotchas

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

  • Never await session.compress(...) (the synchronous LLM path) on the response path — use compact_async so the turn returns first.
  • compact_async needs a second pooled connection; with max_size: 1 it will contend with the turn's own queries.

On this page