Each proposed step now dispatches the serial agent/step-boundary event after claiming input, then agent/model, and publishes the chosen model selection as the optional agent.step until the step ends or its proposal is rejected, fails, or is cancelled. agent/pre-step listeners, tool conditions, prompt sections, and the provider and model variables read agent.step, so the pre-step payload, AssembleContext, and ToolActivationContext carry no model selection field. Plan mode commits pending selections at the step boundary, before model choice, and still narrates the switch in the first admitted step. The system prompt assembles once after step/start, including runtime context, and system-prompt/prepare is removed. The runtime-context snapshot is admitted after the step's accepted messages, so a changed runtime context alone no longer opens a step.
6.1 KiB
Agent Turn And Step Lifecycle
This sequence is the visual companion to architecture.md. It keeps durable replay facts on session/event and live control/status on agent/*.
sequenceDiagram
participant User
participant Agent
participant Driver
participant Hooks as hook listeners
participant Prompt as ctx.systemPrompt
participant LLM as ctx.llm
participant Tools as ctx.tools
participant Session
participant SDK as UI or SDK listener
User->>Agent: followup(content)
Agent-->>SDK: <code>agent/inbox/spliced</code>
Agent-->>SDK: <code>agent/inbox/inserted</code> { message }
Agent->>Driver: queued work wakes driver
Driver-->>SDK: <code>agent/status</code> running
Driver->>Session: <code>turn/start</code>
Note over Agent,Driver: claim pending next-step input plus one queued prompt
Driver-->>SDK: <code>agent/inbox/spliced</code> pure deletion
Driver-->>SDK: <code>agent/inbox/claimed</code> { message, turn } per message
Driver->>Hooks: <code>agent/step-boundary</code> serial commits selections pending for this step
Driver->>Hooks: <code>agent/model</code> waterfall chooses provider, model, and effort, published as agent.step
Driver->>Hooks: <code>agent/pre-step</code> waterfall reads agent.step
Hooks-->>Driver: authoritative reject or enter(messages)
alt proposed step rejected, first batch empty, or pre-step failed
Driver-->>Driver: claimed batch stays removed, the open turn spends no step
else enter proposed step
Driver->>Session: <code>step/start</code>
Driver->>Tools: resolve({ agent, signal }) once per step
Driver->>Prompt: <code>system-prompt/assemble</code> contexts, variables, sections, and the step tool set
Driver->>Hooks: <code>agent/request</code> waterfall with the step model selection
Driver->>LLM: prepareCall(config, signal)
Note over Driver,LLM: cancellation during preparation commits neither system nor users
Note over Driver,Session: synchronous admission using the prepared call capability
Driver->>Session: <code>system/message</code> ordered per-node reconciliation
Driver->>Session: <code>user/message</code> per entered message, then a changed runtime-context snapshot
Driver->>Session: <code>request/header</code> and <code>request/context</code> as needed
Driver->>Driver: derive and freeze request from the log
Driver->>LLM: bound prepared call through <code>llm/stream</code> waterfall
LLM-->>Driver: StreamChunk*
Driver-->>SDK: <code>agent/assistant-stream</code> chunk*
alt final adapter or terminal in-band request failure
Driver->>Session: <code>assistant/attempt</code>
Driver-->>SDK: <code>agent/assistant-stream</code> committed end
Driver->>Hooks: <code>agent/request-error</code> waterfall
Hooks-->>Driver: return retry action or preserve the original error
Note over Driver,LLM: retry in the open step: request and prepare again with the same model selection, tool set, and prompt without repeating pre-step or users
else model request succeeded
Driver->>Session: <code>assistant/message</code>
Driver-->>SDK: <code>agent/assistant-stream</code> committed end
Driver->>Tools: classify pending call by executionMode
loop barriers and bounded rolling pool, reclassify before start
opt call starts
Driver->>Session: <code>tool/call</code>
Driver->>Tools: ordered pre, concurrent execute with the step tool set
Tools-->>Session: tool-owned events when applicable
end
opt next model-order result ready
Driver->>Tools: ordered post
Driver->>Session: <code>tool/result</code>
end
end
Driver->>Tools: dispose the step tool set
Driver->>Session: <code>step/end</code>
opt natural stop and next-step inbox empty
Driver->>Hooks: <code>agent/turn-stopping</code> serial terminal checkpoint
end
opt next-step input is pending
Driver-->>Driver: claim pending next-step input
Driver-->>SDK: <code>agent/inbox/claimed</code> { message, turn } per message
Driver->>Hooks: <code>agent/step-boundary</code> serial
Driver->>Hooks: <code>agent/model</code> waterfall
Driver->>Hooks: <code>agent/pre-step</code> waterfall
Hooks-->>Driver: authoritative reject or enter(messages)
end
end
end
Driver->>Session: <code>turn/end</code>
Driver-->>SDK: <code>agent/status</code> idle
The assistant/message event records every successful provider call, including content-less and max-tokens finishes, and embeds the exact compact timed stream. Empty content stays out of derived history. A failed, retried, cancelled, or stream-error attempt that reaches settlement without a surface message records its stream as assistant/attempt. Live agent/assistant-stream chunk frames are transient; replay reads either durable settlement, and a hard process loss before settlement leaves no durable attempt stream.
dsh-compaction-basic uses agent/pre-step for pressure before request derivation and agent/request-error only for canonical context overflow. Once either trigger qualifies, optional tool-result pruning runs before summary selection. Recovery runs within the open step and retries only when pruning or summarization advances the surface replacement generation; otherwise the original request error remains authoritative. Each retry prepares its call with the step model selection and reconciles the retained rendered assembly before request derivation, without repeating model selection, tool resolution, assembly, pre-step, or user admission.
The returned agent/pre-step decision is authoritative; listeners wrapping next() preserve downstream messages and startsRequestSeries unless replacement is intentional. Steering and injected context pass through the same waterfall after a later claim operation takes their next-step batch.
SDK users that need replayable transcript data should consume session/event; agent/* is the live coordination API for queue/status, prompt interception, request construction, steering, continuation, and errors.
Maintenance mode: curated Mermaid sequence; exact event signatures live in the generated Cordis catalog.