Finish reasons
result.finishReason says why a run ended: the model’s own reason for its last
turn ('stop', 'length', 'tool_calls', 'content_filter', 'error'),
'awaiting-approval' (paused on a tool call that needs a human), 'aborted'
(cancelled with signal), 'max-steps', 'output-invalid' (the reply
did not match the output schema even after the repair step, see
Structured output), 'budget-exceeded' (a
limits budget such as maxTokens or maxCostUsd tripped; result.budget
says which, see Budgets), or 'guardrail' (an
input, output or tool guardrail blocked; result.guardrail says which, see
Input and output guardrails). 'max-steps' means the maxSteps
budget (default 10) ran out while the model still wanted to continue, so the
reply may be empty or partial; a run that finishes naturally within the budget
keeps its 'stop'. Steps carried over by initialSteps or an approval resume
count against the budget, and result.steps is the number of steps taken. The
same reason is on the finish event and on run.done in
streaming.
Cancellation
Pass anAbortSignal to stop a run: agent.send(input, { signal }),
AgentExecutor.execute({ ..., signal }) or
resumeAfterApproval(..., { signal }).
AbortSignal.timeout(ms):
- The signal is checked before every model call and every tool call. It is
passed to the provider (
GenerateOptions.signal, sent to theaiSDK asabortSignal) and to each tool asexecute(args, { abortSignal }), so in-flight work can stop early. The built-inhttpToolpasses it tofetch, and agents created withcreateDelegateTool()are aborted along with their parent. - An aborted run resolves (it does not reject) with
finishReason: 'aborted'and the messages and steps so far. A rejection caused by the abort, such as anAbortError, is not treated as a failure: it is not retried by the provider retry and fallback wrappers and is not compacted into a provider error. - The run’s events end with
run.donewithfinishReason: 'aborted'. - With
sessionId+checkpointStore, the state is checkpointed. Callingexecute()again with the samesessionIdresumes where the run stopped; newinputis appended as the next user message (see Durable execution). Tool calls the run never reached get an{ error }result saying they were cancelled, so the conversation stays valid for the provider. - An already-aborted signal returns at once without calling the provider.
Parallel tool calls
When the model asks for several tools in one turn, they run concurrently.toolConcurrency (on createAgent() and AgentExecutor.execute()) caps how
many run at once: a positive integer, or 'unbounded' (the default). Use 1
for strictly sequential execution, e.g. when your tools share state that is
not safe to touch concurrently.
- Transcript order is call order. Tool results are appended in the order the model requested the calls, not the order they finish, so the next provider request is deterministic.
- Events. Calls start in call order. A call’s
tool-callevent,onToolCall, argument validation,preToolCallhooks andneedsApprovalcheck run just before it starts, one call at a time. Itstool-resultevent fires when it finishes, so results arrive in completion order. WithtoolConcurrency: 1events alternate call/result exactly as before. - Approvals. The first call that needs approval stops the batch: the
calls before it run (concurrently) and their results are recorded, then the
run pauses on that call (
finishReason: 'awaiting-approval'). Calls after it never start in this run.resumeAfterApproval()records the paused call’s result (or rejection) and then runs those later calls the same way, so every call of the turn gets exactly one result - see Durable execution. - Failures are isolated. A tool that throws gets its own error result;
its siblings carry on. A propagating error (
PropagatingToolError, such as the delegation depth guard, or a throwing hook) stops new calls from starting, waits for the running ones to settle, then rejects the run. No tool is left running detached. - Cancellation. An abort while a batch runs resolves with
finishReason: 'aborted'. Calls that finished keep their results; the rest get a “cancelled” result. Running tools see the abort through theirabortSignal. - Checkpoints. With
sessionId+checkpointStore, the model’s turn is checkpointed before any call starts, then again each time the in-order run of finished calls grows (with1, after every call). A resumed run never runs a recorded call again, and never asks the model again for a turn it already checkpointed.