Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build LLM-powered apps with the Anthropic Claude API or SDK across Python, TypeScript, Java, Go, Ruby, C#, and PHP.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
typescript/claude-api/streaming.md
1# Streaming — TypeScript23## Quick Start45```typescript6const stream = client.messages.stream({7model: "claude-opus-4-7",8max_tokens: 64000,9messages: [{ role: "user", content: "Write a story" }],10});1112for await (const event of stream) {13if (14event.type === "content_block_delta" &&15event.delta.type === "text_delta"16) {17process.stdout.write(event.delta.text);18}19}20```2122---2324## Handling Different Content Types2526> **Opus 4.7 / Opus 4.6:** Use `thinking: {type: "adaptive"}`. On older models, use `thinking: {type: "enabled", budget_tokens: N}` instead.2728```typescript29const stream = client.messages.stream({30model: "claude-opus-4-7",31max_tokens: 64000,32thinking: { type: "adaptive" },33messages: [{ role: "user", content: "Analyze this problem" }],34});3536for await (const event of stream) {37switch (event.type) {38case "content_block_start":39switch (event.content_block.type) {40case "thinking":41console.log("\n[Thinking...]");42break;43case "text":44console.log("\n[Response:]");45break;46}47break;48case "content_block_delta":49switch (event.delta.type) {50case "thinking_delta":51process.stdout.write(event.delta.thinking);52break;53case "text_delta":54process.stdout.write(event.delta.text);55break;56}57break;58}59}60```6162---6364## Streaming with Tool Use (Tool Runner)6566Use the tool runner with `stream: true`. The outer loop iterates over tool runner iterations (messages), the inner loop processes stream events:6768```typescript69import Anthropic from "@anthropic-ai/sdk";70import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";71import { z } from "zod";7273const client = new Anthropic();7475const getWeather = betaZodTool({76name: "get_weather",77description: "Get current weather for a location",78inputSchema: z.object({79location: z.string().describe("City and state, e.g., San Francisco, CA"),80}),81run: async ({ location }) => `72°F and sunny in ${location}`,82});8384const runner = client.beta.messages.toolRunner({85model: "claude-opus-4-7",86max_tokens: 64000,87tools: [getWeather],88messages: [89{ role: "user", content: "What's the weather in Paris and London?" },90],91stream: true,92});9394// Outer loop: each tool runner iteration95for await (const messageStream of runner) {96// Inner loop: stream events for this iteration97for await (const event of messageStream) {98switch (event.type) {99case "content_block_delta":100switch (event.delta.type) {101case "text_delta":102process.stdout.write(event.delta.text);103break;104case "input_json_delta":105// Tool input being streamed106break;107}108break;109}110}111}112```113114---115116## Getting the Final Message117118```typescript119const stream = client.messages.stream({120model: "claude-opus-4-7",121max_tokens: 64000,122messages: [{ role: "user", content: "Hello" }],123});124125for await (const event of stream) {126// Process events...127}128129const finalMessage = await stream.finalMessage();130console.log(`Tokens used: ${finalMessage.usage.output_tokens}`);131```132133---134135## Stream Event Types136137| Event Type | Description | When it fires |138| --------------------- | --------------------------- | --------------------------------- |139| `message_start` | Contains message metadata | Once at the beginning |140| `content_block_start` | New content block beginning | When a text/tool_use block starts |141| `content_block_delta` | Incremental content update | For each token/chunk |142| `content_block_stop` | Content block complete | When a block finishes |143| `message_delta` | Message-level updates | Contains `stop_reason`, usage |144| `message_stop` | Message complete | Once at the end |145146## Best Practices1471481. **Always flush output** — Use `process.stdout.write()` for immediate display1492. **Handle partial responses** — If the stream is interrupted, you may have incomplete content1503. **Track token usage** — The `message_delta` event contains usage information1514. **Use `finalMessage()`** — Get the complete `Anthropic.Message` object even when streaming. Don't wrap `.on()` events in `new Promise()` — `finalMessage()` handles all completion/error/abort states internally1525. **Buffer for web UIs** — Consider buffering a few tokens before rendering to avoid excessive DOM updates1536. **Use `stream.on("text", ...)` for deltas** — The `text` event provides just the delta string, simpler than manually filtering `content_block_delta` events1547. **For agentic loops with streaming** — See the [Streaming Manual Loop](./tool-use.md#streaming-manual-loop) section in tool-use.md for combining `stream()` + `finalMessage()` with a tool-use loop155156## Raw SSE Format157158If using raw HTTP (not SDKs), the stream returns Server-Sent Events:159160```161event: message_start162data: {"type":"message_start","message":{"id":"msg_...","type":"message",...}}163164event: content_block_start165data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}166167event: content_block_delta168data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}169170event: content_block_stop171data: {"type":"content_block_stop","index":0}172173event: message_delta174data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":12}}175176event: message_stop177data: {"type":"message_stop"}178```179