Skip to content

Conversation history

A long conversation runs into a hard wall: the model’s context window. Everything on this page exists because of that wall, and the interesting part is what gets thrown away, what gets kept, and what can be got back.

They are not alternatives so much as a ladder, cheapest first.

Mechanism Cost Keeps Loses
Elision Nothing Every word of the narrative Uneventful older tool results
Image shedding Nothing The text around them Old screenshots
Snapshots Nothing Every word, as pixels Legibility to a non-vision model
Summary One model call A narrative The details it did not pick

Elision and shedding run first because they are free and lossless in the way that matters: they drop bulk nobody was going to re-read.

A summary is the only one of the four that spends a model call and the only one that decides for you what mattered. Both are real costs. The call is the more interesting one, because of when it happens.

Compaction usually runs ahead of the wall, on a threshold. But it also runs reactively, after the provider itself rejects a request as too large — the heuristic estimate under-counted what the provider actually measured. In that situation a summarizing compactor has to make a request to shrink the context, and the request it makes is the one that just overflowed.

Snapshot compaction renders discarded history onto dense pages of pixel glyphs and hands them back as images.

The premise is a billing quirk: a vision model charges for an image at a flat or area-proportional rate that has nothing to do with how many characters are in it. Twelve thousand characters of discarded conversation cost twelve thousand characters’ worth of text tokens. The same characters rendered onto one page cost one image.

What makes it worth having rather than merely clever is that it needs no model call, no key and no network. It is the one strategy that is always available during overflow recovery.

The reconstruction shape is verbatim head, imaged middle, verbatim tail. The head is the task and the constraints that everything downstream refers back to; the tail is where the work currently is. The middle is what gets re-read least and costs most.

Snapshots are re-rendered from retained source text on each pass, never from the previous pass’s pixels. Imaging an image degrades the glyphs one generation per compaction until nothing can read them.

Historically every harness run started from an empty history and rebuilt continuity from a <context> block in the prompt — a summary of the conversation rather than the conversation. Three things followed from that:

  • Resume was a re-tell. The model never saw its own earlier reasoning or the actual bytes its tools returned, only a description of them.
  • Rewind died with the process. A checkpoint is an index into the live message list, so a restart lost every label the model had set.
  • Retry could not tell “nothing to retry” from “nothing loaded”. After a restart the failed turn is gone from live state either way.

All three are fixed by persisting the transcript. It is saved at every turn boundary and never mid-turn: a history captured between a tool call and its result is one no provider will accept, so a crash at that instant restores the turn before rather than a half-turn that cannot be replayed.

A resumed run is trimmed to its newest messages, cutting at a boundary that is not an orphaned tool result — a result whose call was trimmed away is a request providers reject outright, and a transcript that cannot be sent is worse than a short one.

Every message records the one it continues from, and every conversation names its current branch tip. That one decision is the whole feature.

Branching writes nothing. It moves the pointer. The path you left is still there, so switching back is another pointer move rather than a restore — and editing a prompt to re-run it stops costing you the answer you were comparing against.

Without it, every form of going back has to hide or delete messages, and hiding is a lie the next reader cannot see through.

Branch Fork
What happens The pointer moves The path is copied
Where it goes Same conversation A new conversation
Cost Nothing One copy of the branch

A fork copies with fresh ids rather than sharing rows. Two conversations sharing rows would show each other’s later messages, which is the one thing a fork must not do.

The in-run checkpoint / rewind pair marks a clean turn boundary and returns to it after an exploration, keeping a digest. Because checkpoints are persisted alongside the transcript, a label the model set before a restart still lands where it was set. A checkpoint whose target did not survive a trim is dropped, not clamped — rewinding “to the label” and landing somewhere else is exactly the failure a label exists to prevent.