Repository navigation
compaction: model-capability context compaction (not API payload slices) #552
Description
Parent
#548 (agent session architecture)
Problem
The only “compaction” we have is drop oldest rows and slice the
string. That is an API-payload habit. Other harnesses (Pi
CompactionEntry + retainedTail; OpenCode summary parts) compact to
the model window and keep a checkpoint so they do not re-walk the entire
log.
We need that for intelligence, independent of how Blob is paged.
Goal
A compaction mechanism keyed on model capability (A3’s budget):
- When projected prompt tokens would exceed
window - reserve, summarize
older turns at clean turn boundaries (never split a tool call from its
result). - Persist a checkpoint (summary + retained tail) on the session so the
next turn does not resend the warehouse. - Storage may still hold the full Blob (OpenCode lesson: logical compact ≠
delete disk). Paint does not need the pre-checkpoint body.
Success: a 6-hour session on a 200k model still produces a coherent
continue; the Gateway POST stays inside the window; the agent can answer
from the checkpoint + tail + working notes (A2) + tool fold (A1).
Constraints (lock)
- Compaction text is labeled as a summary, never as live assistant
prose (honesty). - Do not compact mid-tool-call / mid-
tool_rungroup. - Function/Gateway transport ceilings still apply to the prompt we send.
- Wasm does not run the summarizer (server / host fold only).
Non-goals
- Deleting Blob history when we compact the prompt
- Client tokenizer as fake
%UI (harness: show live context size from model usage (not client math) #327 / feat(#539): context/usage status slot — bounded provider-usage summary (chat+agent, JSON + stream done) folded into the Wasm context slot #547) - Pi’s JSONL DAG /
/treebranching (out of scope unless a later spike)
Suggested next
create-plan after A3’s window source is locked (or one combined plan if
reviewer prefers). Depends on A1/A2 or the compacted summary will have
nothing useful to say about tools/findings.
Peer harness notes
Pi compaction (take the mechanics, not JSONL-on-disk):
- Trigger:
contextTokens > contextWindow - reserve(inference budget: replace 400-row / 3.5M-char fold with model-window token budget #551 policy). - Walk back to a
keepRecentTokenstail; cut only on user/assistant/
custom boundaries — never betweentool_useandtool_result(agent memory: structured truncated tool_result on the wire (not Tool: crumbs) #549). serializeConversation()with tool outputs capped (~2k chars) at compact
time.- Extract read/modified paths from the tool log into the summary so
“what did you already find?” works without raw dumps. - Persist
CompactionEntry+retainedTail; later builds start at the
checkpoint. OpenCode discards verbose completed tool parts from the
prompt but keeps them on disk — same as our Blob vs inference split.
Skip: /tree branch summaries, SQLite, part/*.json.
Orrery (2026-08-15)
Compaction is a cache-flush event. Only run it at:
- an explicit phase boundary (plan accepted, milestone, wrap-up — phase from feat: session TODO lists — one item per turn, host auto-continues with full list in the prompt #536 todos, not vibes), or
- a hard ceiling (
occupancy > window − reserve).
Write the summary into a durable-spec slot (stable region, with #550 notes + files-touched), not as a new history head that churns every compact. Post-compact prefix bills fresh until re-warmed — do not compact mid-mechanical tool streak.
Family switch (#551) prefers the same boundary. retainedTail still starts after the checkpoint.
Activity
btipling commentedon Aug 19, 2026
2026-08-19 source-level peer research
Compaction is how a long session stays one mind after the window fills. Locks for the create-plan:
Persist the replacement, not just a summary string
Compacted.replacement_historyon the rollout — resume == live post-compact vectorsession_messagetype: "compaction" { summary, recent }; history query cuts off at that seq; new Context EpochsurfaceOp: replaceon the model-visible surface; log intact (FTS can still find shadowed reads)CompactionEntry+ tail; default snapcompact PNG archive (vision). Skip the PNGs.Steal Codex/OpenCode: the checkpoint we persist is the next Function’s model-facing history, not a prose souvenir we re-fold from 8 MiB of paint. Device-switch resume must see the same compacted view.
Do not delete the Blob when we compact the prompt (OpenCode: logical compact ≠ delete disk). We have no DeepSeek
session-queryFTS over shadowed ranges — so the summary must carry findings: files-touched, decisions (#550 notes kept verbatim), not “we looked at some files.”Tool outputs after compact
Codex is harsher than DeepSeek: tool results are dropped from the live vector. OpenCode hides old rows from
SessionHistory.load. After compact, #693 becomes urgent: even the stale snapshot is gone; the model re-reads from the files-touched list.Never cut between
tool_useandtool_result(already in the body). Checkpoint is labeled summary, never live assistant prose.When
Keep the Orrery lock: phase boundary (#536 tags) or hard ceiling (
occupancy > window − reserve). Mid-turn compact (OMP default true) is a Function-timeout hazard on Vercel — prefer turn-boundary unless the create-plan proves a mid-loop compact fitsmaxDuration.Skip: snapcompact pixel-font frames,
/treebranch summaries, SQLite SoT, rewriting history in place as Codex’s only store (we already persist Blob).Merge pull request #956 from btipling/plan/a4-compaction-p4-test-hard…
Merge pull request #957 from btipling/plan/a4-compaction-p5-living-docs
btipling commentedon Sep 7, 2026
Done — model-capability compaction is on
mainvia parent #947 (phases 1–5) and merge #957 (b31ca512e7ddee162fa8313cc52f549822e2d23a).Checkpoint + retained tail keyed on the selected model's window − reserve; honesty-labeled summary; logical compact (Blob history retained); Wasm does not run the summarizer.