[Feature]: Durable conversation compaction for the Pro agent runtime (land the deferred 'later slice')
Problem or Motivation
The Pro agent runtime runs without context transformation: every run replays the full entry-tree history (lib/server/agent-runtime/runner.ts seeds buildAgent with the whole branch), so long sessions grow unboundedly until the gateway rejects the oversized prompt. The reserved OPENMAIC_AGENT_COMPACTION_* knobs in lib/server/agent-runtime/config.ts have no consumers, and .env.example says outright: "The reusable compaction runtime is not implemented yet — it lands in a later slice of work."
The classroom Director already ships a working compaction runtime (lib/chat/pi/director-compaction.ts, wired via transformContext), but it is stateless by design: history arrives per request, compaction runs on an in-memory session repo rebuilt every time, and nothing is persisted. The Pro runtime cannot copy it because its correctness model is the opposite — the PG entry tree is the single durable history source, with lease-protected ordered writes and crash recovery. That durability gap is exactly why this was deferred from the 1.0 agent-workbench release (PRs #1167 / #1176: "the reusable compaction runtime is a later slice").
Proposed Solution
Durable conversation compaction for the Pro runner, landing the deferred "later slice":
- Durable, non-destructive: compaction is an
appendCompactionentry (summary+firstKeptEntryId) on the entry tree; raw entries are never deleted. The read-side view already exists —lib/server/agent-runtime/entry-tree-storage.tsvalidates compaction entries and rebuilds the model view (summary + kept suffix) — so the work concentrates on the write path and its consumers. - Trigger at safe boundaries only (run start / before
prompt()), not via the stock per-LLM-calltransformContexthook: mid-tool-loop compaction can summarize the user frame away while keeping the assistant/tool suffix and orphan tool calls (the hazard therunner.ts/skill-preload.ts"compaction view" comments already wrestle with). - Crash-safe write path: the compaction write goes through the lease-protected ordered chain; every crash window (decided-to-compact → summary LLM returned → entry appended) gets a defined recovery;
planResumetail classification is extended for a transcript that ends at a compaction summary. - Audit every transcript consumer against the compacted view: skill detection from transcript, undelivered-message requeue cursors (raw
cursorMessagesare already compaction-unaffected),terminalLoopError, orphan-tool-call repair. - Summarization call: decide the model/stage (the driver route model vs. a cheaper stage), a Pro-specific preservation focus (course refs, scene ids/revisions, active skill, pending follow-ups — mirroring the Director's classroom focus list), and a failure policy: on summarization failure, fall back to the #1572 pre-flight guard instead of sending an oversized prompt.
- Share the token estimator with #1572 (pi
estimateContextTokens+ all-zero-usage fallback), so the "should compact" threshold and the hard gate use one code path. - UI: event-based replay is independent of the model view, so history stays visible; decide whether to surface a "history summarized" divider (product call).
Acceptance Criteria
- With
OPENMAIC_AGENT_COMPACTION_ENABLED=true, long sessions compact automatically at a safe boundary and continue instead of hard-failing; with it unset/false, behavior is exactly today's + the #1572 guard - Compaction entries are durable and crash-recoverable: each write window has a defined recovery covered by tests (incl. PG contract suite)
-
planResume, orphan-tool-call repair, and transcript-based skill detection behave correctly over compacted transcripts (unit tests) - Summarization failure falls back to the #1572 guard rather than sending an oversized prompt
- No behavior change for sessions that stay under the threshold
Alternatives Considered
- Keep relying on the #1572 guard alone — stops the repeated-failure pain but forfeits long sessions instead of continuing them.
- Port the Director's stateless runtime as-is — rejected: it discards compacted state every request, which contradicts the entry tree being the single durable history and would break resume semantics.
Area
Storage / persistence
Additional Context
- Storage read-side support that makes this tractable now:
entry-tree-storage.ts(compaction-entry validation + view rebuild,cursorMessageskept raw). - Write-path invariants the implementation must respect: lease heartbeat /
markLeaseLost, the single ordered write chain, at-least-once tool idempotency notes inresume.ts. - Precedent for the runtime shape:
lib/chat/pi/director-compaction.ts(settings scaling by window, trace events, provider usage fallback). - Immediate mitigation that this issue supersedes when enabled: #1572.
Source: THU-MAIC/OpenMAIC