Replay had no page while compaction's premise depends on it — microcompact
blurs tool output that a text-only projection never sent.
Compaction's open edges still said pressure counts only text; 7530d6d made
it exhaustive. Two links pointed at pages that were never written.
75 lines
3.2 KiB
Markdown
75 lines
3.2 KiB
Markdown
# Replay
|
|
|
|
Compaction is what she lets go of. Replay is what she carries forward. They are
|
|
two halves of the same question, and replay is the one that decides whether
|
|
compaction means anything at all.
|
|
|
|
The code is `core::session::replay_messages`.
|
|
|
|
## One history
|
|
|
|
There is a single record: the messages stored for a conversation. Everything
|
|
that talks to a model — her turn, her subconscious a moment later, a terminal,
|
|
a voice, a web surface — replays that same record. None of them holds a version
|
|
of its own.
|
|
|
|
That is not tidiness. It follows from what the substrate already says: one
|
|
consciousness in two modes, and she is not the glass. A second projection is a
|
|
second opinion about what happened, and the two drift the moment one is
|
|
touched. There were three of them once. They disagreed about images before
|
|
anyone noticed.
|
|
|
|
## What crosses
|
|
|
|
A stored message is made of blocks. Each one has a prose form for replay:
|
|
|
|
| block | crosses as |
|
|
|---|---|
|
|
| text | itself |
|
|
| tool use | `Tool use: name(input)` |
|
|
| tool result | `Result (name): output`, or `Error (name): output` |
|
|
| reasoning | `[Reasoning]: …` |
|
|
| image | natively, or a marker saying it was not seen |
|
|
|
|
Nothing is silently dropped. A block with no prose form does not exist — the
|
|
match is exhaustive, so a new kind of block fails to compile rather than
|
|
quietly going missing.
|
|
|
|
This is what makes a turn's own work available to the turn after it. When tool
|
|
blocks were dropped on replay, everything she learned by *doing* survived only
|
|
as whatever she happened to write down in prose, and she would re-derive
|
|
findings she had already reached. It also left microcompact — whose entire job
|
|
is blurring old tool output — with nothing in the payload to blur.
|
|
|
|
## Two properties that are load-bearing
|
|
|
|
Both were learned from a failure, and both look like details until they break.
|
|
|
|
**One wire message per stored message.** Replaying block by block splits a
|
|
single assistant turn that called several tools into adjacent assistant
|
|
messages, and OpenAI-shaped providers reject that outright: *assistant
|
|
tool_calls must be followed by tool messages*. The message boundary is part of
|
|
the record.
|
|
|
|
**No tool roles and no call-id obligations.** Inside a live turn, a tool call
|
|
and its result are both known to exist, and the exact linkage is used. Across
|
|
persisted turns that linkage is brittle: a turn killed mid-round leaves a call
|
|
whose result never landed, and replaying it as half a pair fails the whole
|
|
request. So the *content* of a tool round survives as prose while the wire
|
|
obligations do not. The record is not the protocol.
|
|
|
|
## The only thing that varies
|
|
|
|
Whether the model can see. Images ride as native multipart content, or degrade
|
|
to a marker that says plainly they were not visible. The caller supplies that
|
|
one fact; nothing else about the projection changes.
|
|
|
|
A degraded image is named as unseen rather than dropped. A model told it did
|
|
not look can say so. A model handed a stub shaped like success proceeds as
|
|
though it had looked.
|
|
|
|
## Open edges
|
|
|
|
Live tool rounds inside a turn build their own messages, with real
|
|
`tool_call_id` linkage. That is correct and separate — replay is for what is
|
|
already on disk. The two should not be merged; they answer different questions.
|