#1573·OpenMAIC

[Feature]: Durable conversation compaction for the Pro agent runtime (land the deferred 'later slice')

Author: cosarahCreated Sep 17, 2026Updated Sep 17, 2026
Labelsenhancement

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":

  1. Durable, non-destructive: compaction is an appendCompaction entry (summary + firstKeptEntryId) on the entry tree; raw entries are never deleted. The read-side view already exists — lib/server/agent-runtime/entry-tree-storage.ts validates compaction entries and rebuilds the model view (summary + kept suffix) — so the work concentrates on the write path and its consumers.
  2. Trigger at safe boundaries only (run start / before prompt()), not via the stock per-LLM-call transformContext hook: mid-tool-loop compaction can summarize the user frame away while keeping the assistant/tool suffix and orphan tool calls (the hazard the runner.ts / skill-preload.ts "compaction view" comments already wrestle with).
  3. 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; planResume tail classification is extended for a transcript that ends at a compaction summary.
  4. Audit every transcript consumer against the compacted view: skill detection from transcript, undelivered-message requeue cursors (raw cursorMessages are already compaction-unaffected), terminalLoopError, orphan-tool-call repair.
  5. 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.
  6. 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.
  7. 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, cursorMessages kept raw).
  • Write-path invariants the implementation must respect: lease heartbeat / markLeaseLost, the single ordered write chain, at-least-once tool idempotency notes in resume.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.