Skip to main content
Stream agent responses token-by-token — print to the terminal, or iterate tokens yourself to render them in a browser, webview, mobile app, or server. To stop a stream mid-flight, pass an AbortSignal — see Cancellation.

Which Mode Do I Want?

Pick the surface that matches where the answer renders.

Quick Start

1

Iterate tokens with stream()

Render tokens live anywhere — the for await loop pulls them at its own pace.
2

Terminal default (start / chat)

On the CLI, streaming is already on — tokens print to the terminal.
3

Structured events with streamEvents()

Same agent, structured events — handle text, finish, and error.
4

Streaming with Tools

Tool calls are woven into the same stream — text the model speaks before the tool ("Let me check."), the tool call itself, and the answer after it all arrive as they happen. This holds on every provider: OpenAI, Anthropic, Google, xAI, Groq, and any AI-SDK backend. Pre-tool commentary is delivered as tokens, not held back until the tool finishes.
Iterate agent.stream() to observe the pre-tool text in a non-console caller — each chunk is a token string.
5

Consume Tokens Yourself

Consume tokens yourself with agent.stream() — an async iterator over chunks.
6

Stop a Stream

Break the loop to stop the request — the provider stops generating and billing immediately.
For a UI Stop button, pass an AbortSignal:

Cancellation

Break out of the loop to stop the stream cleanly — no more tokens are queued and the in-flight provider request is aborted.
You can also pass an AbortSignal to cancel a turn from outside the loop.

How It Works

When tools are configured, the round routes through streamText on every provider — text spoken before the tool call streams as tokens, then the tool runs, then the answer after it streams too.

Streaming with Tools

Text deltas, tool calls, and tool results interleave on a single loop — the stream never stops just because the agent needs a tool.

Bounding the loop

Two knobs bound the run when the model chains many tools.
If the loop still needs another tool round-trip after maxIterations, chat() throws and agent.lastStopReason === 'max_steps'. Wrap in try/catch and either raise maxIterations or narrow the task.

Stop a stream

Two ways to cancel a streaming turn — both stop the upstream provider request so no further tokens are generated or billed.

Which one should I use?

opts.signal is turn-scoped and independent of the agent-level SimpleAgentConfig.signal. Aborting one turn does not disable the agent; the next stream() call runs normally.

Tell a Stop from a real error

agent.lastStopReason reports why the last run ended:

AgentEvent Reference

streamEvents() yields a discriminated union. Switch on event.type.
Match a tool_result to its tool_call by callId — it is the only reliable pairing key. plain stream() skips tool events and yields text only.

AgentStreamOptions Reference

Both stream() and streamEvents() accept an optional second argument.

Configuration Options

The stream config option controls the terminal default and whether token deltas are produced.
When the run does not stream tokens (stream: false, tools in use, or a structured outputSchema), stream() still yields the full response as a single token — callers never silently receive nothing.

Common Patterns

Stream to a Server-Sent Events endpoint

Log the full text once with streamEvents()

Terminal default (unchanged)


Seeing Tool Activity

If your UI needs to render tool calls and their results — not just the streamed text — use agent.streamEvents() instead of agent.chat(). It yields a typed union (text, tool_call, tool_result, finish, error) in the order the agent produced them, so a call is announced before it runs and its result carries an explicit ok field.

Best Practices

Anywhere tokens must land in a DOM, SSE, WebSocket, or React Native view, for await (const token of agent.stream(...)) gives you each token to route yourself.
Switch to streamEvents() to close a socket, log the full text once, react to tool activity, or fall back on error — the finish, error, tool_call, and tool_result events carry that context.
No separate AbortController is needed for the streaming surface itself — breaking out of the for await loop detaches the token sink and aborts the in-flight request. Pass opts.signal only when you need to cancel from outside the loop.
Every supported provider streams — OpenAI, Anthropic, Google, xAI, Groq, and any AI-SDK backend. That includes streaming while tools are running: text the model speaks before a tool_call is delivered as tokens, not held back until the tool finishes. Setting stream: false still works and collapses the round into a single non-streaming call.
On Anthropic, Google, xAI, Groq, and any AI-SDK backend, stream: true gives you pre-tool commentary as tokens. Setting stream: false collapses the round into one non-streaming call and delivers the same text at the end in one lump.
Agent.stream() owns the upstream request and cancels it in the iterator’s finally. Breaking a for await loop, or aborting a signal you passed via agent.stream(prompt, { signal }), both stop provider tokens from being generated. Use agent.lastStopReason === 'cancelled' to distinguish a user Stop from a real failure in your error handler.
Even when tools or outputSchema disable token deltas, stream() yields the full response as a single item, so callers always receive an answer.
Omitting the token sink (i.e. calling start() or chat()) still writes to process.stdout, so existing CLI scripts don’t change.

Beyond Text: Structured Events

For UIs that need to show tool activity live, use streamEvents() — it yields typed AgentEvents instead of just tokens.

Streaming Events

Stream tool calls, tool results, and text as structured events

Stream Events

Structured text and tool events

Agent

Full agent configuration

Providers

LLM provider setup