-
Notifications
You must be signed in to change notification settings - Fork 0
Message Loop
The stage sequence every turn walks through, with per-stage responsibilities.
The why (turn boundaries, concurrency, cancellation, backpressure) lives in Execution Model. This page is the what-happens-at-each-stage.
sequenceDiagram
autonumber
participant Input as User / Command
participant Core
participant CtxP as Context Providers
participant Prov as Provider
participant LLM as LLM backend
participant Tool as Tool executor
participant UI
Input->>Core: RECEIVE_INPUT
Core->>CtxP: COMPOSE_REQUEST
CtxP-->>Core: context slices
Core->>Prov: SEND_REQUEST
Prov->>LLM: ai-sdk request
LLM-->>Prov: streamed tokens + tool call
Prov-->>Core: STREAM_RESPONSE
Core->>Tool: TOOL_CALL
Tool-->>Core: result
Core->>Prov: SEND_REQUEST (continuation)
Prov->>LLM: continued request
LLM-->>Prov: final tokens
Prov-->>Core: STREAM_RESPONSE
Core->>UI: RENDER
Each stage has pre and post hook points. When an SM is attached, the message loop runs inside each SM stage execution — a sequential stage execution is itself a session turn; a parallel fan-out group (siblings + optional join) bundles multiple stage executions into a single compound turn (Execution Model § Reentrancy). In either case, every stage execution runs its own pass of the stages below: the stage's rendered body (produced at Init, see SM Stage Lifecycle) is the system prompt, allowedTools narrows the tool manifest, the completion channel is injected alongside, and turnCap bounds the continuation loop below. SM authority over this message loop is scoped to tool-call approval at TOOL_CALL, not a per-turn-stage gate; see Execution Model § Authority during a turn.
Intent. Accept user input (or a command) and start the pass.
Inputs. Resolved input payload from the UI / command (default-chat turn); or the stage's rendered body from Init (SM stage execution). UIs may render large pasted blocks as placeholders while editing, but the payload handed to core has those placeholders expanded back to the original pasted text in insertion order.
Outputs. A normalized input record attached to the pass.
Responsibilities.
- Assign a correlation ID.
- Default-chat turn. Write the input into the session message history via the active Session Store.
- SM stage execution. Feed the rendered body into the stage-local transcript only — the stage-local transcript is not written to session message history; see Stage Executions.
- Emit the
SessionTurnStartevent on the event bus once per session turn and only for the default-chat case. For SM stage executions,SessionTurnStartis already emitted — at the stage execution'sSetupfor a sequential stage, or at the scheduler's fan-out spawn for a parallel fan-out compound turn — and is not re-emitted here. See Stage Executions § Turn boundary and persistence.
Hook opportunities.
-
transform: normalize input (e.g., strip trailing whitespace). -
guard: refuse input on pattern (e.g., empty). -
observer: log the raw input.
Intent. Build the request the provider will send to the LLM: system prompt + history + tool definitions + Context Provider output.
Inputs. Session state, the active Context Providers, the active Tools, the active Provider's model capabilities. Outputs. A composed request record.
Responsibilities.
- Run context assembly — pulls Context Provider outputs within budget.
- Attach tool definitions the active provider supports.
- Run compaction if the composed size would exceed the model's context window. See Compaction and Memory.
Hook opportunities.
-
transform: rewrite the composed request before dispatch (e.g., prepend a system message). -
guard: refuse dispatch (e.g., request too large). -
observer: audit what was composed.
SM contribution. When the pass runs inside an SM stage execution, the stage's rendered body (produced at Init) is the system prompt and allowedTools narrows the tool manifest (the completion channel is injected alongside). Composition does not poll the SM per turn stage; the stage's contributions were fixed at Init against the StageContext that Setup populated. See Stage Definitions and Stage Executions.
Invariant. Context assembly itself is core. Context Providers are the only sanctioned inputs. See LLM Context Isolation.
Intent. Hand the composed request to the active provider.
Inputs. The composed request record. Outputs. A handle on the provider's response stream.
Responsibilities.
- Invoke the provider with the composed request.
- Start the cancellation-token chain for this call.
- Start the
correlationspan for observability.
Hook opportunities.
-
transform: modify the wire-shape at the last moment (rare — preferCOMPOSE_REQUEST). -
observer: dispatch audit. -
guard: block at the wire (e.g., retries beyond a limit).
Intent. Consume the provider's streamed response: tokens, tool calls, finish reasons.
Inputs. The response stream handle. Outputs. A sequence of token events and (possibly) one or more tool-call records.
Responsibilities.
- Publish token events on the event bus as they arrive.
- Buffer emitted tool calls until complete.
- On finish without tool call → transition to
RENDER. - On finish with tool call(s) → transition to
TOOL_CALL.
Hook opportunities.
-
transform: filter or rewrite tokens in flight (use sparingly — affects user-visible output). -
observer: stream-level analytics. -
guard: rare; may cut off a response on policy.
Non-authoritative. Tokens ride the event bus. Any "stop this response" decision must route through the Interaction Protocol, the SM, or a guard hook — not through event subscription.
Intent. Execute each tool call emitted by the provider.
Inputs. One or more tool-call records with arguments. Outputs. One tool result per call.
Responsibilities.
- Run the authority stack for each call in order:
-
SM decision. If an SM stage is driving, the proposed call is checked against the stage's
allowedToolsand matchinggrantStageTooltokens. In-envelope or token-consuming calls are SM-approved (mode gate bypassed); out-of-envelope calls auto-issue agrantStageToolinteraction (approval via the active interactor set is part of this step). If the grant is denied, defers, or no interactor is active, the proposal is blocked asGrantDenied— the mode gate does not see it. -
Security-mode gate. Applies only when no SM is attached. The mode gate may itself prompt the active interactor set — this is where
askmode and allowlist-miss prompts happen. Interaction fan-out is part of the mode-gate step, not a separate later stage. - Guard hooks. Run on every approved call, after approval has been obtained and before execute. Guard-deny wins in any mode.
- Execute via the Tools contract.
-
SM decision. If an SM stage is driving, the proposed call is checked against the stage's
- Execute approved calls via the Tools contract. Local and remote (MCP) execute through the same stage.
- Serialize approval prompts in call order before fanning each prompt out through active interactors.
- Collect results; emit them back to the provider for continuation.
Hook opportunities.
-
transform: rewrite tool arguments pre-execution. -
guard: pre-execution deny (e.g., path-based policy). -
observer: pre/post tool audit.
Invariants.
- SM precedence over mode gate. See Security Modes.
- Parallel approvals are serialized. See Parallel Tool Approvals flow.
- Mode is session-fixed; no runtime switch.
After tool execution, the loop returns to COMPOSE_REQUEST with the results appended to the session, unless the provider signalled a terminal tool call (which is rare and provider-specific).
Intent. Deliver the final response to the user.
Inputs. The final response text / structured output / tool summary. Outputs. Rendered output to the active UI.
Responsibilities.
- Default-chat turn. Persist the assistant response in the session message history.
-
SM stage execution. Do not persist the stage-local transcript to session message history; the stage's
Exitwrites whatever the SM authors durably into the SM's state slot. The render payload may still be forwarded to the UI for progress display. - Emit the
SessionTurnEndevent once per session turn and only for the default-chat case. For SM stage executions,SessionTurnEndfires at the stage execution'sExit(sequential) or after the last sibling'sExit/ thejoinstage'sExit(parallel fan-out compound turn) — not here. See Stage Executions § Turn boundary and persistence. - Hand the render payload to the UI subscriber set via the event bus.
Hook opportunities.
-
transform: rewrite the render payload (e.g., mask sensitive spans). -
observer: final audit of the turn.
Stages COMPOSE_REQUEST → SEND_REQUEST → STREAM_RESPONSE → TOOL_CALL may iterate any number of times within a single turn. Each iteration starts from COMPOSE_REQUEST with the new tool results appended. A turn terminates when STREAM_RESPONSE finishes without emitting a tool call and transitions to RENDER.
A loop bound applies per turn:
- For a default-chat turn, core enforces the session-resolved
settings.json.runtime.continuation.maxIterationsbound. Default:50. Reaching the bound fires a terminal error whose message makes it explicit that prior tool calls may already have completed successfully. - For an SM stage execution, the stage's
turnCapis the loop bound. Core checks the counter at the top of each continuation iteration, immediately before callingCOMPOSE_REQUESTfor the next LLM turn. IfturnCapis reached, no new LLM turn is dispatched: in-flight tool calls from the most recent LLM turn complete normally and their results are appended to the stage-local transcript, but those results are not sent back to the LLM.Actends withcapHit: true;Assertreceives the finalized transcript and decidesok,retry, orfail. See SM Stage Lifecycle — Act.
The counted unit is a continuation round (TOOL_CALL -> COMPOSE_REQUEST), not a tool count. Multiple tool calls emitted by one provider response consume one round together.
turnCap is a normal Act-ending branch, not a turn cancellation. Strict cancel (triggered by sibling failure or user interrupt) is separate and does not run Exit; see Stage Executions — Strict cancellation.
See Error Model.
Every turn-stage transition emits an event on the event bus:
-
StagePreFired{stage, turnId, correlationId}— just before the stage body runs. -
StagePostFired{stage, turnId, correlationId, outcome}— after the stage body completes. -
SessionTurnStart,SessionTurnEnd— bracket the whole turn.
These turn-stage events are distinct from the SM stage-execution events (StageEntered, StageExited, StageCheckGateResult, StageAssertOutcome, StageGranted, StageCancelled, WorkflowExit) which are emitted by a driving SM's stage pipeline — see Stage Executions § Audit and Event Bus § event kinds.
Provider streaming emits ProviderRequestStarted, ProviderTokensStreamed, ProviderRequestCompleted, ProviderRequestFailed. Tool lifecycle emits ToolInvocationProposed, ToolInvocationStarted, ToolInvocationSucceeded, ToolInvocationFailed, ToolInvocationCancelled. Tool-approval decisions are audited separately as ToolCallApproved / ToolCallDenied / ToolCallModeInvoked — see Tool Approvals § audit and Security Modes § audit.
These events are projection only — see Event Bus § non-authoritative rule and Event and Command Ordering for guarantees.
| Stage | Core does | Extensions may |
|---|---|---|
RECEIVE_INPUT |
Normalize, persist, event | Transform / guard / observe input |
COMPOSE_REQUEST |
Assembly, compaction, tool list | Transform composed request; feed via Context Providers |
SEND_REQUEST |
Invoke provider, start cancel chain | Observe dispatch; transform wire-shape |
STREAM_RESPONSE |
Publish tokens, buffer tool calls | Filter/observe tokens |
TOOL_CALL |
Approval gate, dispatch, serialize prompts | Execute the tool; transform args; guard; observe |
RENDER |
Persist, event, hand to UI | Transform render payload; observe |
Core owns the shape of every stage. Extensions attach through contracts; they never redefine stage boundaries. See Extensibility Boundary.
- Execution Model
- Message Loop
- Concurrency and Cancellation
- Error Model
- Event and Command Ordering
- Event Bus
- Command Model
- Interaction Protocol
- Hook Taxonomy
- Host API
- Extension Lifecycle
- Env Provider
- Prompt Registry
- Resource Registry
- Session Lifecycle
- Session Manifest
- Persistence and Recovery
- Stage Executions
- Subagent Sessions
- Contract Pattern
- Versioning and Compatibility
- Deprecation Policy
- Capability Negotiation
- Dependency Resolution
- Validation Pipeline
- Cardinality and Activation
- Extension State
- Conformance and Testing
- Providers
- Provider Params
- Tools
- Hooks
- UI
- Loggers
- State Machines
- SM Stage Lifecycle
- Stage Definitions
- Commands
- Session Store
- Context Providers
- Settings Shape
- Trust Model
- Project Trust
- Extension Isolation
- Extension Integrity
- LLM Context Isolation
- Secrets Hygiene
- Security Modes
- Tool Approvals
- MCP Trust
- Sandboxing
- Configuration Scopes
- Project Root
- Extension Discovery
- Extension Installation
- Extension Reloading
- Headless and Interactor
- Determinism and Ordering
- Launch Arguments
- Network Policy
- Platform Integration
Tools
UI
Session Stores
Loggers
Providers
Hooks
Context Providers
Commands
- First Run
- Default Chat
- Tool Call Cycle
- Hook Interception
- Guard Deny Reproposal
- State Machine Workflow
- SM Stage Retry
- Hot Model Switch
- Capability Mismatch Switch
- Session Resume
- Session Resume Drift
- Approval and Auth
- Interaction Timeout
- Headless Run
- Parallel Tool Approvals
- Subagent Delegation
- Scope Layering
- Project First-Run Trust
- Reload Mid-Turn
- Compaction Warning
- MCP Remote Tool Call
- MCP Prompt Consume
- MCP Resource Bind
- MCP Reconnect