Conversation compaction #
Operational status #
Compactor versions 1 and 2 repeatedly timed out on the first natural frozen prefix and emitted no boundary. Version 3 adopted the same operating shape as Letta's local sliding-window compaction: trigger from actual active-context pressure, summarize only the oldest prefix, keep a coherent exact recent tail, and let the trusted parent wrap plain model text in the typed boundary event. That Pi/Tinker parent-compactor pair is currently retained but disabled while the persistent Letta resident owns direct Telegram continuity. Canonical reconstruction remains complete regardless of projection activation or success.
This contract covers model-context compaction for persistent conversation agents. It does not delete, rewrite, or retain less event history. Storage-retention compaction remains out of scope.
Pipeline #
Conversation state has four authority layers:
- Canonical reconstruction folds immutable source, run, correction, proposal, and delivery evidence into exact effective turns.
- A specialized compactor consumes one frozen prefix and emits a private recursive boundary.
- The ordinary agent's selector substitutes the latest valid boundary for its covered prefix and retains exact post-boundary turns under its normal policy.
- Pi composition renders the selected boundary, native messages, current prompt/images, and trusted documents for one provider request.
A compaction policy never changes canonical reconstruction. A boundary is a derived claim by a named model execution, not a replacement event and not a new source message.
Compactor clone #
The ordinary conversation declaration names exactly one reciprocal compactor. The compactor is a separate consumer id and role so its runs, accounting, progress, failures, and output cannot masquerade as ordinary replies. Runtime registration requires both declarations to agree on:
- target and compactor ids;
- enabled state;
- provider profile and model;
- source patterns and sensitive privacy admission;
- admitted conversation-history agent ids;
- exact subscribed identity/memory documents and document budget.
The compactor uses Pi plain-text compaction mode with no tools, proposals, external actions, learned adapter, or dispatcher route. It shares the ordinary agent's identity/memory documents to interpret names and obligations, but its prompt has one job: summarize a frozen historical prefix without answering or continuing the conversation. The trusted parent validates one bounded text part and deterministically wraps it in the typed compaction output contract; the model does not manufacture provenance JSON. The normal Telegram dispatcher applies the direct-reply agent allowlist to failed direct-message runs as well as successful replies, so internal compactor failures remain private operational evidence. Production incident projection still records those failures, but its Telegram route does not duplicate agent-run failures into the same chat.
Trigger and frozen input #
The producer policy names triggerInputChars and retainInputChars, with retain strictly smaller than trigger. Character accounting uses the exact native messages that would enter model context, including a prior recursive boundary when present. On each admitted source message:
- the first eligible turn persists one immutable activation-frontier document bound to the compactor version/fingerprint, route, policy, admitted history agents, and activating event. For an established source, the frontier retains the newest complete source groups needed to reach the character trigger, so
replay: nownever turns an unbounded historical stream into accidental first-run input; - below the trigger, context preflight appends a content-dark
skippedrun and advances compactor progress without reserving inference or calling a model; - at the trigger, the compiler groups exact eligible turns by Telegram source sequence, walks backward to retain a coherent exact tail within the retention-character target, and freezes the oldest remaining groups;
- the frozen prefix must fit the declaration's complete event/character bounds. Silent truncation is forbidden;
- the packet is persisted as an immutable retry-stable context document before provider dispatch.
The current Stream policy triggers at 80,000 active conversation characters and retains an exact tail of at most 40,000 characters. A single latest turn larger than the tail target fails closed rather than being split or silently truncated.
Boundary event #
stream.thought.derived.conversation.compaction@1 is always sensitive. The trusted parent, not the model, binds:
- target agent and admitted history-agent set;
- conversation source, chat, and sender;
- previous boundary id/hash and prior covered source sequence;
- activation-frontier document id/hash and source sequence;
- covered-through turn id/source sequence;
- trigger/retention character policy, pre-compaction input size, retained exact-tail size, and covered-source count;
- exact input turn count, character count, turn-id hash, and rendered-message hash;
- compactor version/fingerprint, prompt hash, exact context-snapshot identity/hashes, output-contract identity, run identity, model evidence, and boundary hash.
The model supplies only one bounded plain-text historical summary. The trusted parent derives the bounded preview and empty auxiliary compatibility lists, validates the complete semantic object, and binds it to the trusted plan and event hash.
Recursive chain and selection #
The first boundary begins immediately after its persisted activation frontier. Each later compactor input is:
previous typed boundary + newly frozen exact raw turns
Each later event must name the immediately preceding boundary and its content hash, and coverage must advance. The resolver revalidates every candidate against the currently registered reciprocal compactor declaration, activation and context snapshots, completed run/result/model receipt, exact trigger, context plan, frozen input hashes, route, privacy, and prior boundary. A missing link, fork, stale declaration, divergent hash, wrong route, fabricated run, or non-advancing boundary fails closed.
Compactor version plus declaration fingerprint define an activation epoch. Historical boundaries from retired epochs remain immutable and inspectable but are ineligible for the current resolver before chain validation. A prompt, policy, or version upgrade therefore starts a new activation snapshot and first boundary without allowing an old epoch to brick the parent. Multiple or forked boundaries inside the current epoch still fail closed.
A correction or delayed delivery may change current canonical evidence for a source sequence after a boundary was created. The resolver does not mutate or invalidate the frozen boundary. It compares current effective history with the boundary's exact snapshot and, when they diverge, derives a bounded typed covered-history amendment. The ordinary parent receives boundary + amendment + exact raw tail; the next compactor receives the same amendment beside the prior boundary so a later boundary can absorb the newer evidence. Amendment content and hash appear in the parent context manifest. Oversized amendments fail closed rather than silently truncating a correction.
The ordinary selector receives only the latest valid boundary, any typed covered-history amendment, and exact turns after its covered sequence. It reserves the exact rendered boundary/amendment characters and message slots before bounding the raw tail. Internally both historical projections use a first-class compaction conversation role. The provider protocol has no native compaction role, so the sandbox adapter renders each as a fixed user-role historical-summary envelope explicitly marked untrusted-history-summary, not as an assistant utterance or system instruction. Provenance stays in the private manifest and does not enter the summary body.
Covered raw events remain immutable and inspectable. They are absent from that model request because a named derived boundary stands in for them, not because they were deleted.
Activation and proof #
Source tests prove preflight skipping, bounded activation against an established source, context-pressure planning, coherent exact-tail retention, plain-text summary wrapping, separate compactor execution with real model/usage metadata, strict boundary settlement, recursive chaining, late-correction amendments, boundary-aware packet limits, and fork rejection. Repository readiness does not prove live compaction. Activation requires installing the reciprocal declarations together, restarting the exact consumer process, verifying registration and source progress, then waiting for a natural trigger. No synthetic production message may be created merely to manufacture a boundary receipt.