What each pipeline owns
TL;DR
Four pipelines, two scopes. Two of them fire once per turn (bookends — before and after the model is dispatched). Two of them fire once per iteration of the dispatch loop (the sandwich around each call to the executor).
The reason it splits like this is a cost story: turn-scoped work runs once, dispatch-scoped work runs every iteration. Put retrieval in the wrong pipeline and a ten-iteration dispatch costs you ten times what it should. The pipelines do not enforce this — the conventions exist precisely because the runner won't catch you doing it wrong.
The mental model
The pipelines do not enforce what runs inside them. Nothing stops you from dispatching a tool from turnInputPipeline or doing retrieval inside dispatchInputPipeline. The contracts are about when a pipeline fires and what context its middlewares see. What they do is convention.
Convention because the cost model is unforgiving. Turn-level work runs once per turn; dispatch-level work runs once per iteration. Confuse them and you pay for retrieval ten times in a ten-iteration dispatch, or you persist a half-built record before the dispatch has decided what the record is.
Top to bottom is one turn: turnInputPipeline builds context, the dispatch loop runs (dispatchInputPipeline → executor → dispatchOutputPipeline, repeated until ack, nack, or abort), and on ack — only on ack — turnOutputPipeline performs post-hoc turn work like safety, memory, and telemetry.
The four pipelines at a glance
| Pipeline | Scope | When | Owns |
|---|---|---|---|
turnInputPipeline | Turn | Once, before dispatch | Assemble what the model is about to see |
dispatchInputPipeline | Dispatch | Per iteration, before executor | Shape what this iteration sees |
dispatchOutputPipeline | Dispatch | Per iteration, after executor | Decide whether the loop continues |
turnOutputPipeline | Turn | Once, after dispatch (only on ack) | Post-hoc turn work — safety, memory, telemetry |
The split into two scopes is deliberate: turn-level cost should not be paid on every iteration, and a dispatch-scoped helper has no business leaking into the next turn. Turn-scoped pipelines see the TurnContext; dispatch-scoped pipelines see the DispatchContext, which adds the executor-iteration primitives.
Detail pages
- Turn-scoped pipelines —
turnInputPipeline(assemble the model's view) andturnOutputPipeline(post-hoc turn work). - Dispatch-scoped pipelines —
dispatchInputPipeline(per-iteration setup) anddispatchOutputPipeline(per-iteration decision).