anthropic.messages.stream({ … }, options?): MessageStreamanthropic.messages.stream() returns a MessageStream, which emits events, has an async
iterator, and exposes helper methods to accumulate stream events into a convenient shape and make it easy to reason
about the conversation.
Alternatively, you can use anthropic.messages.create({ stream: true, … }) which returns an async
iterable of the chunks in the stream and uses less memory (most notably, it does not accumulate a message
object for you).
If you need to cancel a stream, you can break from a for await loop or call stream.abort().
See an example of streaming helpers in action in examples/streaming.ts.
The first event that is fired when the connection with the Anthropic API is established.
The event fired when a stream event is received from the API. Not fired when it is not streaming. The snapshot
returns an accumulated Message which is progressively built-up over events.
The event fired when a text delta is sent by the API. The second parameter returns a textSnapshot.
The event fired when a json delta is sent by the API. The second parameter returns a jsonSnapshot.
The event fired when a message is done being streamed by the API. Corresponds to the message_stop SSE event.
The event fired when a content block is done being streamed by the API. Corresponds to the
content_block_stop SSE event.
The event fired for the final message. Currently this is equivalent to the message event, but is fired after
it.
The event fired when an error is encountered while streaming.
The event fired when the stream receives a signal to abort.
The last event fired in the stream.
Aborts the runner and the streaming request, equivalent to .controller.abort(). Calling .abort() on a
MessageStream will also abort any in-flight network requests.
An empty promise which resolves when the stream is done.
Returns the current state of the message that is being accumulated, or undefined if there is no such
message.
A promise which resolves with the last message received from the API. Throws if no such message exists.
A promise which resolves with the text of the last message received from the API.
A mutable array of all messages in the conversation.
The underlying AbortController for the runner.
The SDK provides helper functions to create runnable tools that can be automatically invoked by the .toolRunner() method. These helpers simplify tool creation with JSON Schema or Zod validation.
import { betaZodTool } from '@anthropic-ai/sdk/helpers/zod';
import { z } from 'zod';
const weatherTool = betaZodTool({
name: 'get_weather',
inputSchema: z.object({
location: z.string(),
}),
description: 'Get the current weather in a given location',
run: (input) => {
return `The weather in ${input.location} is foggy and 60°F`;
},
});
const finalMessage = await anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1000,
messages: [{ role: 'user', content: 'What is the weather in San Francisco?' }],
tools: [weatherTool],
});
console.log(finalMessage.content);When you need to process intermediate messages or control the conversation flow, you can iterate through
BetaToolRunner.
const runner = anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1000,
messages: [{ role: 'user', content: 'What is the weather in San Francisco?' }],
tools: [weatherTool],
});
// Process each message as it arrives
for await (const message of runner) {
console.log(message);
}
// Get the final result
console.log(await runner);See examples/tools-helpers-advanced.ts for a more in-depth
example.
const runner = anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1000,
messages: [{ role: 'user', content: 'What is the weather in San Francisco?' }],
tools: [calculatorTool],
stream: true,
});
// When streaming, the runner returns BetaMessageStream
for await (const messageStream of runner) {
for await (const event of messageStream) {
console.log('event:', event);
}
console.log('message:', await messageStream.finalMessage());
}
console.log(await runner);See examples/tools-helpers-advanced-streaming.ts for a more
in-depth example.
Zod schemas can be used to define the input schema for your tools:
import { betaZodTool } from '@anthropic-ai/sdk/helpers/zod';
const weatherTool = betaZodTool({
name: 'get_weather',
inputSchema: z.object({
location: z.string().describe('The city and state, e.g. San Francisco, CA'),
unit: z.enum(['celsius', 'fahrenheit']).default('fahrenheit'),
}),
description: 'Get the current weather in a given location',
run: async (input) => {
return `The weather in ${input.location} is ${input.unit === 'celsius' ? '22°C' : '72°F'}`;
},
});You can use JSON Schema to define the input schema for your tools. betaTool will infer the type of input for you
based on the supplied JSON Schema.
import { betaTool } from '@anthropic-ai/sdk/helpers/json-schema';
const calculatorTool = betaTool({
name: 'calculator',
input_schema: {
type: 'object',
properties: {
operation: { type: 'string', enum: ['add', 'subtract', 'multiply', 'divide'] },
a: { type: 'number' },
b: { type: 'number' },
},
required: ['operation', 'a', 'b'],
},
description: 'Perform basic arithmetic operations',
run: (input) => {
const { operation, a, b } = input;
switch (operation) {
case 'add':
return String(a + b);
case 'subtract':
return String(a - b);
case 'multiply':
return String(a * b);
case 'divide':
return String(a / b);
default:
throw new Error(`Unknown operation: ${operation}`);
}
},
});Parameters: All standard message parameters plus:
tools: Array<BetaToolUnion | BetaRunnableTool>- Array of toolsmax_iterations?: number- Maximum number of tool execution iterations (default: no limit)
Returns:: BetaToolRunner
Waits for the conversation to complete and returns the final message.
// Start consuming the iterator
for await (const message of runner) {
console.log('Message:', message);
}
// Wait for completion
const finalMessage = await runner.done();Waits for the conversation and returns the final assistant message. Unlike done(), this will eagerly read the stream.
const finalMessage = await runner.runUntilDone();The BetaToolRunner is directly awaitable, which is equivalent to calling .runUntilDone():
const finalMessage = await runner;Updates the conversation parameters. Can accept new parameters or a mutator function.
// Direct parameter update
runner.setMessagesParams({
...runner.params,
model: 'claude-3-5-haiku-20241022',
max_tokens: 500,
});
// Using mutator function
runner.setMessagesParams((prevParams) => ({
...prevParams,
max_tokens: prevParams.max_tokens * 2,
messages: [...prevParams.messages, { role: 'user', content: 'Additional context' }],
}));Adds messages to the conversation history.
runner.pushMessages(
{ role: 'user', content: 'Please also consider this information...' },
{ role: 'assistant', content: 'I understand, let me factor that in.' },
);Gets the tool response for the last assistant message (if any tools need to be executed).
for await (const message of runner) {
const toolResponse = await runner.generateToolResponse();
if (toolResponse) {
console.log('Tool results:', toolResponse.content);
}
}Read-only access to the current conversation parameters.
console.log('Current model:', runner.params.model);
console.log('Message count:', runner.params.messages.length);See the following example files for more usage patterns:
examples/tools-helpers-zod.ts- Zod-based toolsexamples/tools-helpers-json-schema.ts- JSON Schema toolsexamples/tools.ts- Basic tool usage