WorkflowAgent.stream() method parameters
WorkflowAgent.stream() accepts: prompt (string | Array<ModelMessage>, optional, either use prompt or messages but not both) or messages (Array<ModelMessage>, optional, the conversation messages to process), writable (WritableStream<ModelCallStreamPart>, optional, receives raw model stream parts in real-time), instructions (Instructions, optional, override agent instructions), system (string, optional, deprecated - use instructions instead), stopWhen (StopCondition | StopCondition[], optional, condition(s) for ending agent loop), toolChoice (ToolChoice, optional, override tool choice strategy, default 'auto'), activeTools (ActiveTools<TTools>, optional, limits subset of tools available), output (OutputSpecification, optional, structured output specification), timeout (number, optional, timeout in milliseconds), sendFinish (boolean, optional, whether to send 'finish' chunk to writable stream, default true), preventClose (boolean, optional, whether to prevent writable stream from closing, default false), includeRawChunks (boolean, optional, include raw unprocessed chunks from provider, default false), repairToolCall (ToolCallRepairFunction, optional, callback for automatic recovery on tool call parse failure), experimental_transform (StreamTextTransform | Array<StreamTextTransform>, optional, stream transformations applied in order), experimental_download (DownloadFunction, optional, custom download function), experimental_sandbox (Experimental_SandboxSession, optional, sandbox session, overrides constructor default), telemetry (TelemetryOptions, optional, per-call telemetry configuration), runtimeContext (Context, optional, shared runtime context, overrides constructor default, must be serializable), toolsContext (InferToolSetContext<TTools>, optional, per-tool context map, overrides constructor default, must be serializable), prepareStep (PrepareStepCallback, optional, per-call prepareStep override), experimental_onStart (WorkflowAgentOnStartCallback, optional, per-call onStart callback), experimental_onStepStart (WorkflowAgentOnStepStartCallback, optional, per-call onStepStart callback), onToolExecutionStart (WorkflowAgentonToolExecutionStartCallback, optional, per-call callback), onToolExecutionEnd (WorkflowAgentonToolExecutionEndCallback, optional, per-call callback), onStepEnd (WorkflowAgentOnStepEndCallback, optional, per-call callback), onStepFinish (WorkflowAgentOnStepFinishCallback, optional, deprecated - use onStepEnd instead), onEnd (WorkflowAgentOnEndCallback, optional, per-call callback), onError (WorkflowAgentOnErrorCallback, optional, callback when error occurs), onAbort (WorkflowAgentOnAbortCallback, optional, callback when operation is aborted).
WorkflowAgent.stream() returns WorkflowAgentStreamResult
WorkflowAgent.stream() returns Promise<WorkflowAgentStreamResult> with properties: messages (Array<ModelMessage>, final messages including all tool calls and results), steps (Array<StepResult>, details for all steps taken by agent), toolCalls (Array<ToolCall>, tool calls from last step, including unexecuted calls like tools requiring approval), toolResults (Array<ToolResult>, tool results from last step, only includes results for executed tools), output (OUTPUT, the structured output if an output specification was provided).
createModelCallToUIChunkTransform utility function
createModelCallToUIChunkTransform() from '@ai-sdk/workflow' creates a TransformStream that converts raw ModelCallStreamPart chunks (written by the agent to the writable stream) into UIMessageChunk objects suitable for client consumption. Example: createUIMessageStreamResponse({ stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()) }).
toUIMessageChunk utility function
toUIMessageChunk() from '@ai-sdk/workflow' converts a single ModelCallStreamPart to a UIMessageChunk. Returns undefined for parts that don't map to UI chunks.
ActiveTools type for WorkflowAgent
ActiveTools<TTools extends ToolSet> is defined as ReadonlyArray<keyof TTools & string> | undefined. It limits a workflow agent call to the listed tool names. undefined means no tool restriction is applied.
InferWorkflowAgentUIMessage type utility
InferWorkflowAgentUIMessage infers the UI message type for a WorkflowAgent instance. It optionally accepts a second type argument for custom message metadata. Example: type MyAgentUIMessage = InferWorkflowAgentUIMessage<typeof agent>;
InferWorkflowAgentTools type utility
InferWorkflowAgentTools infers the tool set type of a WorkflowAgent instance. Example: type MyTools = InferWorkflowAgentTools<typeof myAgent>;
WorkflowAgent basic agent with tools example
import { WorkflowAgent } from '@ai-sdk/workflow';
import { tool } from 'ai';
import { z } from 'zod';
const agent = new WorkflowAgent({
model: 'anthropic/claude-sonnet-4-6',
instructions: 'You are a helpful assistant.',
tools: {
weather: tool({
description: 'Get weather for a location',
inputSchema: z.object({
location: z.string(),
}),
execute: async ({ location }) => ({
location,
temperature: 72,
condition: 'sunny',
}),
}),
},
});
const result = await agent.stream({
messages: [
{
role: 'user',
content: [{ type: 'text', text: 'What is the weather in NYC?' }],
},
],
});
console.log(result.messages);
console.log(result.steps);
WorkflowAgent in workflow with durable tools example
import { WorkflowAgent, type ModelCallStreamPart } from '@ai-sdk/workflow';
import { convertToModelMessages, tool, type UIMessage } from 'ai';
import { getWritable } from 'workflow';
import { z } from 'zod';
// Tool execute functions marked with 'use step' become durable workflow steps
// with automatic retries and persistence
async function searchFlightsStep(input: {
origin: string;
destination: string;
}) {
'use step';
const response = await fetch(`https://api.flights.example/search?...`);
return response.json();
}
export async function chat(messages: UIMessage[]) {
'use workflow';
const modelMessages = await convertToModelMessages(messages);
const agent = new WorkflowAgent({
model: 'anthropic/claude-sonnet-4-6',
instructions: 'You are a flight booking assistant.',
tools: {
searchFlights: tool({
description: 'Search for available flights',
inputSchema: z.object({
origin: z.string(),
destination: z.string(),
}),
execute: searchFlightsStep,
}),
},
});
const result = await agent.stream({
messages: modelMessages,
writable: getWritable<ModelCallStreamPart>(),
});
return { messages: result.messages };
}
// In route handler:
import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow';
import { createUIMessageStreamResponse, type UIMessage } from 'ai';
import { start } from 'workflow/api';
import { chat } from '@/workflow/agent-chat';
export async function POST(request: Request) {
const { messages }: { messages: UIMessage[] } = await request.json();
const run = await start(chat, [messages]);
return createUIMessageStreamResponse({
stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()),
});
}
WorkflowAgent with structured output example
import { WorkflowAgent, Output } from '@ai-sdk/workflow';
import { z } from 'zod';
const analysisAgent = new WorkflowAgent({
model: 'anthropic/claude-sonnet-4-6',
});
const result = await analysisAgent.stream({
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'Analyze: "The product exceeded my expectations!"',
},
],
},
],
output: Output.object({
schema: z.object({
sentiment: z.enum(['positive', 'negative', 'neutral']),
score: z.number(),
summary: z.string(),
}),
}),
});
console.log(result.output);
// { sentiment: 'positive', score: 9, summary: '...' }
WorkflowAgent tool approval with needsApproval
For WorkflowAgent, tool approval is configured on the tool definition with needsApproval property set to true. This pauses the agent until user approves. Example: tool({ description: 'Book a flight', inputSchema: z.object({ flightId: z.string(), passengerName: z.string() }), needsApproval: true, execute: bookFlightStep })
WorkflowAgent lifecycle callbacks example
import { WorkflowAgent } from '@ai-sdk/workflow';
const agent = new WorkflowAgent({
model: 'anthropic/claude-sonnet-4-6',
tools: { weather: weatherTool },
// Agent-wide callbacks
onStepEnd({ usage }) {
console.log('Tokens used:', usage.totalTokens);
},
});
const result = await agent.stream({
messages,
// Per-call callbacks (both fire)
onStepEnd({ usage }) {
await trackUsage(usage);
},
onEnd({ steps, totalUsage }) {
console.log(
`Done in ${steps.length} steps, ${totalUsage.totalTokens} tokens`,
);
},
});
WorkflowAgent toolCalls vs toolResults distinction
In WorkflowAgentStreamResult, toolCalls includes all tool calls from the last step, including unexecuted calls (e.g., tools requiring approval). toolResults includes only tool results from the last step and only includes results for tools that were actually executed.
WorkflowAgent context flow and serialization
runtimeContext flows through prepareStep, lifecycle callbacks, and step results. toolsContext is a per-tool context map where each tool receives only its own validated entry as context. Both must be serializable when used in workflows and must not contain functions, class instances, symbols, database clients, or SDK clients.
WorkflowAgent prepareStep callback receives
prepareStep callback is called before each step in the agent loop and receives: step number, previous steps, messages, context, and sandbox. Use it to modify settings, manage context, inject messages dynamically, or override experimental_sandbox for the current step.
WorkflowAgent prepareCall callback restrictions
prepareCall callback is called once before the agent loop starts and can be used to transform model, instructions, tools configuration, or other settings based on runtime context. It cannot override tools, which are bound at construction for type safety.
WorkflowAgent maxRetries default value
maxRetries parameter in WorkflowAgent constructor has a default value of 2.
WorkflowAgent stopWhen with isLoopFinished
stopWhen can use isLoopFinished() to let the agent run until all tool calls have completed, but beware of potential runaway loops. See https://ai-sdk.dev/v7/docs/reference/ai-sdk-core/loop-finished#isloopfinished.
WorkflowAgent overview
WorkflowAgent is a durable, resumable AI agent from '@ai-sdk/workflow' designed to survive process restarts, pause for human approval, and integrate with the Workflow DevKit's step mechanism. It handles the agent loop, tool schema serialization across workflow step boundaries, and built-in tool approval flows. Unlike ToolLoopAgent from the 'ai' package, WorkflowAgent is built for workflow environments.
Experimental_Agent class renamed to ToolLoopAgent
The Experimental_Agent class has been replaced with ToolLoopAgent in AI SDK 6. Two key changes: (1) The system parameter has been renamed to instructions, and (2) The default stopWhen has changed from isStepCount(1) to isStepCount(20). Usage: import { ToolLoopAgent } from 'ai'; const agent = new ToolLoopAgent({ model: __MODEL__, instructions: 'You are a helpful assistant.', tools: { ... } }).
GenerateText callback event structures
The onStart callback receives a GenerateTextStartEvent and the onStepStart callback receives a GenerateTextStepStartEvent. Both events share common properties and have step-specific additions.
**Common properties in both events:**
- provider (string) - the provider identifier (e.g., 'openai', 'anthropic')
- modelId (string) - the specific model identifier (e.g., 'gpt-4o')
- instructions (Instructions | undefined) - the instructions provided to the model
- messages (Array<ModelMessage>) - the messages for this generation
- tools (TOOLS | undefined) - the tools available for this generation
- toolChoice (ToolChoice<TOOLS> | LanguageModelV4ToolChoice | undefined) - the tool choice strategy/configuration for this generation
- activeTools (ActiveTools<TOOLS>) - limits which tools are available for the model to call
- toolOrder (ToolOrder<TOOLS>) - controls the order in which tools are sent to the provider
- timeout (number | { totalMs?: number; stepMs?: number; firstChunkMs?: number; chunkMs?: number } | undefined) - timeout configuration
- headers (Record<string, string | undefined> | undefined) - additional HTTP headers
- providerOptions (ProviderOptions | undefined) - additional provider-specific options
- output (OUTPUT | undefined) - the output specification for structured outputs
- abortSignal (AbortSignal | undefined) - abort signal for cancelling the operation
- include ({ requestBody?: boolean; requestMessages?: boolean; responseBody?: boolean } | undefined) - settings for controlling what data is included in step results
- runtimeContext (CONTEXT) - user-defined shared runtime context object
- toolsContext (InferToolSetContext<TOOLS>) - per-tool context map keyed by tool name
**Properties only in GenerateTextStartEvent:**
- maxOutputTokens, temperature, topP, topK, presencePenalty, frequencyPenalty (all number | undefined) - sampling and generation parameters
- stopSequences (string[] | undefined) - sequences that will stop generation
- seed (number | undefined) - random seed for reproducible generation
- maxRetries (number) - maximum number of retries for failed requests
**Properties only in GenerateTextStepStartEvent:**
- steps (ReadonlyArray<StepResult<TOOLS>>) - array of results from previous steps (empty for first step)
- stopWhen (StopCondition<TOOLS> | Array<StopCondition<TOOLS>> | undefined) - condition(s) for stopping the generation
- runtimeContext and toolsContext may be updated from prepareStep between steps
Stop conditions in streamText agentic loop
The streamText agentic loop exits when any of the following stop conditions is met: (1) any of the configured stop conditions is met, (2) finish reason is not tool-calls, (3) a tool without execute is called, (4) a tool that needs approval is called, (5) there are deferred tool calls.
Stream Text loop structure - agentic control flow
The streamText function executes an agentic loop controlled by stop conditions. The loop executes: (1) prepare step, (2) convert step input messages to language model v4 messages, (3) call doStream with language model v4 messages, (4) transform stream for user-friendly format, (5) run tools transformation on stream which executes tools and injects tool results, (6) pipe stream with tool results through further transforms (add start-step, filter empty text chunks, tool input start, filter raw chunks when not enabled, add finish-step, add finish) with bookkeeping for tool calls/outputs/errors, timeout management, and telemetry events, (7) add transformed stream with minor augmentation to stitchable stream, (8) add new response model messages by converting assembled step output to additional response model messages. The loop continues while NOT (any stop condition is met OR finish reason is not tool-calls OR tool without execute is called OR tool that needs approval is called OR there are deferred tool calls). After the loop, transform the unified stream with custom user-defined transformations.
Multi-step workflow with forced tool calls example
This example shows a two-step workflow: Step 1 uses streamText with toolChoice: 'required' to force the model to extract a goal via a tool. Step 2 uses the messages from Step 1 (via await result1.response).messages combined with original messages and a different system prompt and model. The steps are merged without sending finish/start events between them to appear as a single message to the client.
stopWhen parameter with isStepCount condition
The stopWhen parameter in streamText accepts the isStepCount function to stop execution after a specified number of steps. Example: stopWhen: isStepCount(5) stops the agentic loop after 5 steps.
ToolLoopAgent.generate() and stream() parameters
Both generate() and stream() methods accept the following parameters:
**Shared parameters:**
- prompt (type: string | Array<ModelMessage>, required) - a text prompt or message array
- messages (type: Array<ModelMessage>, optional) - a full conversation history as a list of model messages
- abortSignal (type: AbortSignal, optional) - an optional abort signal for cancellation
- timeout (type: number | { totalMs?: number; stepMs?: number; firstChunkMs?: number; chunkMs?: number }, optional) - timeout in milliseconds
- experimental_sandbox (type: Experimental_SandboxSession, optional) - experimental sandbox environment passed to prepareStep, tool description functions, and tool execution
- options (type: CALL_OPTIONS, optional) - custom call options when the agent is configured with a callOptionsSchema
- onStart, onStepStart, onToolExecutionStart, onToolExecutionEnd, onStepEnd, onEnd (all optional callbacks) - lifecycle callbacks
**stream()-specific parameters:**
- experimental_transform (type: StreamTextTransform | Array<StreamTextTransform>, optional) - optional stream transformation(s) applied in order that must maintain stream structure
**Timeout behavior notes:**
- For generate(): firstChunkMs and chunkMs have no effect and are streaming-only parameters
- For stream(): firstChunkMs limits wait for the first content-bearing output in each model-call step and chunkMs limits gaps between later content-bearing output chunks
generateText prepareStep return values
The prepareStep callback can return PrepareStepResult<TOOLS> with the following optional properties to modify settings for the current step:
- model (LanguageModel, optional): Optionally override which LanguageModel instance is used for this step.
- maxOutputTokens (number, optional): Maximum number of tokens to generate for this step. Uses the top-level value when omitted or undefined.
- temperature (number, optional): Temperature for this step. Uses the top-level value when omitted or undefined.
- topP (number, optional): Nucleus sampling value for this step. Uses the top-level value when omitted or undefined.
- topK (number, optional): Top-K sampling value for this step. Uses the top-level value when omitted or undefined.
- presencePenalty (number, optional): Presence penalty for this step. Uses the top-level value when omitted or undefined.
- frequencyPenalty (number, optional): Frequency penalty for this step. Uses the top-level value when omitted or undefined.
- stopSequences (string[], optional): Stop sequences for this step. Uses the top-level value when omitted or undefined.
- seed (number, optional): Random sampling seed for this step. Uses the top-level value when omitted or undefined.
- reasoning (LanguageModelV4CallOptions["reasoning"], optional): Reasoning effort for this step. Uses the top-level value when omitted or undefined.
- toolChoice (ToolChoice<TOOLS>, optional): Optionally set which tool the model must call, or provide tool call configuration for this step.
- activeTools (ActiveTools<TOOLS>, optional): If provided, only these tools are enabled/available for this step.
- toolOrder (ToolOrder<TOOLS>, optional): If provided, overrides the order in which tools are sent to the provider for this step. Tools not listed are appended alphabetically.
- instructions (Instructions, optional): Optionally override the instructions sent to the model for this step. The override carries forward to later steps until prepareStep returns another instructions or system override.
- messages (Array<ModelMessage>, optional): Optionally override the full set of messages sent to the model for this step.
- runtimeContext (CONTEXT, optional): Shared runtime context. Changing it will affect this step and all subsequent steps.
- toolsContext (InferToolSetContext<TOOLS>): Per-tool context map. Changing it will affect tool-specific context in this step and all subsequent steps.
- experimental_sandbox (Experimental_SandboxSession, optional): Experimental sandbox environment for this step. Changing it will affect tool execution in this step only.
- providerOptions (ProviderOptions, optional): Additional provider-specific options for this step. Can be used to pass provider-specific configuration such as container IDs for Anthropic code execution.
generateText stopWhen parameter default
The stopWhen parameter defaults to isStepCount(1), which stops generation after one step (one tool result round). It can be a single StopCondition or an array of StopConditions, and when an array is provided, any of the conditions can be met to stop the generation.
generateText prepareStep callback options
The prepareStep callback receives PrepareStepOptions containing:
- steps (Array<StepResult<TOOLS>>): The steps that have been executed so far.
- stepNumber (number): The number of the step that is being executed.
- model (LanguageModel): The model that is being used.
- instructions (Instructions | undefined): The instructions that will be sent to the model for the current step. If prepareStep returns an instructions override, those instructions carry forward to later steps.
- initialInstructions (Instructions | undefined): The initial instructions that were passed into generateText or streamText.
- messages (Array<ModelMessage>): The messages that will be sent to the model for the current step. If prepareStep returns a messages override, those messages carry forward to later steps.
- runtimeContext (CONTEXT, optional): The shared runtime context passed via the runtimeContext setting.
- toolsContext (InferToolSetContext<TOOLS>): The per-tool context map passed via the toolsContext setting.
- experimental_sandbox (Experimental_SandboxSession | undefined, optional): The experimental sandbox environment passed via the experimental_sandbox setting.
isLoopFinished stop condition function description
isLoopFinished() creates a stop condition that lets the agent loop run until it naturally finishes.
isStepCount stop condition function description
isStepCount() creates a stop condition that triggers after a specified number of steps.
hasToolCall stop condition function description
hasToolCall() creates a stop condition that triggers when any specified tool is called.
streamText parameter: onStepEnd
The 'onStepEnd' parameter is of type function (result: StepResult<TOOLS>) => Promise<void> | void and is optional. It is a callback called when a step ends.
streamText parameter: stopWhen
The 'stopWhen' parameter is of type StopCondition<TOOLS> | Array<StopCondition<TOOLS>> and is optional, with default: isStepCount(1). It specifies conditions for stopping the generation when there are tool results in the last step. When the parameter is an array, any of the conditions can be met to stop the generation.
PrepareStepResult return values
PrepareStepResult<TOOLS> can return optional overrides: model (LanguageModel), maxOutputTokens (number), temperature (number), topP (number), topK (number), presencePenalty (number), frequencyPenalty (number), stopSequences (string[]), seed (number), reasoning (LanguageModelV4CallOptions["reasoning"]), toolChoice (ToolChoice<TOOLS>), activeTools (ActiveTools<TOOLS>), toolOrder (ToolOrder<TOOLS>), instructions (Instructions), messages (Array<ModelMessage>), runtimeContext (CONTEXT), toolsContext (InferToolSetContext<TOOLS>), experimental_sandbox (Experimental_SandboxSession), and providerOptions (ProviderOptions).
streamText parameter: prepareStep
The 'prepareStep' parameter is of type function (options: PrepareStepOptions) => PrepareStepResult<TOOLS> | Promise<PrepareStepResult<TOOLS>> and is optional. It is an optional function that provides different settings for each step, allowing modification of model, model call settings, tool choices, active tools, instructions, input messages, and experimental sandbox for each step.
streamText stopWhen parameter in onStepStart
The stopWhen parameter in onStepStart is of type StopCondition<TOOLS> | Array<StopCondition<TOOLS>> | undefined and is used for specifying condition(s) that control when generation stops. It flows through the onStepStart event callback.
PrepareStepOptions structure
PrepareStepOptions contains: steps (Array<StepResult<TOOLS>> - steps executed so far), stepNumber (number - the step being executed), model (LanguageModel - current model), instructions (Instructions | undefined - instructions for current step), initialInstructions (Instructions | undefined - initial instructions passed to generateText or streamText), messages (Array<ModelMessage> - messages for current step), runtimeContext (optional CONTEXT - shared runtime context), toolsContext (InferToolSetContext<TOOLS> - per-tool context map), and experimental_sandbox (optional Experimental_SandboxSession - sandbox passed through to prepareStep, tool descriptions, and tool execution).
pruneMessages helper for message compaction
The `pruneMessages` helper removes selected messages or message parts for context compaction. It accepts parameters: `messages` (array of ModelMessage), `reasoning` (string for reasoning handling), `toolCalls` (string for tool call handling), and `emptyMessages` (string for empty message handling). Options for reasoning include 'all'. Options for toolCalls include 'before-last-3-messages'. Options for emptyMessages include 'remove'. Use inside `prepareStep` when you want a simple compaction strategy based on triggers like token threshold.