Skip to main content

Module turn

Module turn 

Source
Expand description

The turn typestate: Assembling -> Calling -> ToolWave -> Recording, phase changes carrying &mut dyn Ledger. Interrupts are consumed only at phase boundaries — the boundary snapshot is a parameter of every transition, and no method exists that could observe one mid-phase. That absence is A9’s structural half. A wave is many effects rather than one, so every call in it is a boundary of the same kind: the executor is asked before each, and a halt ends the wave there instead of after its last call. Steer consumes at a boundary too, but advances: it is an addition to the window, not an ending.

Lines that record a moment the turn waited for - model_called, model_returned, tool_called, tool_result - carry that moment, read from the clock the driver handed to Turn::begin; every other line of the turn carries the turn’s stamp. Order is seq’s business.

crates/runtime/spec/Turn.lean proves what the boundaries must hold (§8-3): a cancel before call k leaves exactly the first k calls accounted, and a steer never ends a turn.

Structs§

Assembling
CallShape
Which model this run calls, how much it may say, and how hard it may think — the frozen [model] config section as the turn sees it. effort comes from kernel::FrozenConfig and cannot change within the run: the provider renders it into the cached prompt prefix.
Calling
PromptRecord
The prompt_assembled payload a run wrote last; empty before its first turn. It lives across turns, in the run’s own state.
Recording
RunPrompt
The prompt one turn is assembled from: the run’s frozen prefix, and what the run has already recorded of it.
ToolWave
Turn
The typestate carrier. Phase data lives in S and is private to this module: a phase literal cannot be forged, a phase cannot be skipped, and no method returns an earlier phase. Everything the turn writes goes through journal, which is the module’s only ledger door.
TurnCancelled
The turn ended at a boundary: cancel_received is on the ledger and its ref is the last entry. Freezing (handoff + run_frozen) is the run loop’s move, not the turn’s.
TurnReport
What a completed turn hands the run loop. assistant and wave_results are the window-folding material — the turn’s exchange, compacted at the closing boundary of record. The records are what the compaction works from: model_returned.data.content keeps the reply whole, and each tool_result is the payload the window text was printed from. runtime::fork rebuilds both from those records through the same compaction at the same boundary, so a rebuild and a live fold still share one source.

Enums§

Admitted
What admitting one call decided.
Generating
Who acts on a model’s answer while it is still being generated. The one place that decides which door of the model port a turn takes.
Interrupt
Boundary snapshot, supplied by the executor at every phase change. Cancel ends the turn at the boundary; Steer records and advances (the executor folds the text into its Conversation).
NextCall
Whether the wave may start its next call, asked once before each of them.
PhaseOutcome
A phase change either advances or ends the turn at the boundary. Exhaustive, as every enum in this workspace is: a new outcome must force every executor to decide, not fall through a catch-all.

Traits§

ConcurrentInvoke
A wave’s tools in three stages, so the calls that only read can run at once while everything they decide stays in call order.