Agent loop: user message → streamed response → tool dispatch → stop hooks
Overview
This flow traces how a submitted user prompt drives the main query loop, streams assistant output from the model, dispatches any tool calls, and finally runs Stop hooks before yielding terminal state . The entry point is the SDK/headless path that calls QueryEngine.submitMessage .
Steps
- In headless mode,
runHeadlessloads prior transcript vialoadInitialMessagesand ultimately drives the engine through its command queue .drainCommandQueuedequeues batched prompt commands and forwards each to the engine . submitMessageassembles the system prompt viagetSystemPrompt, wrapscanUseToolto track denials, and builds the initialProcessUserInputContextbefore entering the loop . The system prompt is wrapped as an immutableSystemPrompttoken .- Control transfers into
queryLoop, which destructures mutableStateat the top of each iteration and projectsmessagesForQueryfrom the compact boundary forward . Token accounting usestokenCountWithEstimationand may trigger autocompact once the threshold fromgetAutoCompactThresholdis exceeded . - The loop calls
queryModel, which builds betas, filters tools (honoring tool-search andextractDiscoveredToolNames), computes params viaparamsFromContext, and yields streaming events plus the final assistant message . The request is wrapped inwithRetryto handle 429/529, fast-mode fallback, andFallbackTriggeredError. - On API errors,
getAssistantMessageFromErrorsynthesizes a user-visible assistant error message instead of crashing the loop .startsWithApiErrorPrefixis used to detect error sentinels embedded in streamed text . - For each
tool_useblock in the assistant message,runToolUseresolves the tool by name (including deprecated aliases) and delegates to permission checking .checkPermissionsAndCallToolvalidates input with the tool's zod schema, runs pre-tool hooks, resolvescanUseTool, and finally invokestool.call. - Tool results are wrapped as user messages via
createUserMessagewithsourceToolAssistantUUIDso the loop can feed them back into the next model turn . Sub-agent tool calls route throughAgentTool.callwhich in turn callsrunAgentwith forked context . - When the assistant stops requesting tools, the loop invokes
handleStopHooks, which executes Stop/SubagentStop hooks, collects blocking errors as meta user messages, and returns aStopHookResult. Blocking errors cause another iteration; otherwise the loop yieldsTerminalandsubmitMessagecompletes the generator . - If autocompact fires mid-loop,
compactConversationruns PreCompact hooks, callsstreamCompactSummary, and emits a new boundary viacreateCompactBoundaryMessage, after whichmarkPostCompactionandnotifyCompactionreset cache tracking .
State touched
Decisions
The whitelist contains no [decision:...] tokens, so no design-decision citations are available for this flow .