Follow Discord
Sweep 22 Oct 2026 · 04:32Z Build v2.1.308 527 read Stable v2.1.308 Latest v2.1.308 Next v2.1.308 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-code

Streaming Input changedagent-sdk/streaming-vs-single-mode

Nearest release: v2.1.287, published 5 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 1 Oct 2026 22:40 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 20 Oct 2026 18:37 UTC.

Upstream edited
Recorded here
Lines+219added
Lines−223removed
From line 29 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits5to this page, all time

The whole hunk

from line 29, old and new numbered
/
lines
from line 29
2929 
3030These examples read an image named `diagram.png` from the working directory. Create one there first, or change the filename to point at your own image.
3131 
32<CodeGroup>
33 ```typescript TypeScript theme={null}
34 import { query, type SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
35 import { readFile } from "fs/promises";
32```typescript TypeScript theme={null}
33import { query, type SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
34import { readFile } from "fs/promises";
3635 
37 async function* generateMessages(): AsyncGenerator<SDKUserMessage> {
38 // First message
39 yield {
40 type: "user",
41 message: {
42 role: "user",
43 content: "Analyze this codebase for security issues"
44 },
45 parent_tool_use_id: null
46 };
36async function* generateMessages(): AsyncGenerator<SDKUserMessage> {
37 // First message
38 yield {
39 type: "user",
40 message: {
41 role: "user",
42 content: "Analyze this codebase for security issues"
43 },
44 parent_tool_use_id: null
45 };
4746 
48 // Wait for conditions or user input
49 await new Promise((resolve) => setTimeout(resolve, 2000));
47 // Wait for conditions or user input
48 await new Promise((resolve) => setTimeout(resolve, 2000));
5049 
51 // Follow-up with image
52 yield {
53 type: "user",
54 message: {
55 role: "user",
56 content: [
57 {
58 type: "text",
59 text: "Review this architecture diagram"
60 },
61 {
62 type: "image",
63 source: {
64 type: "base64",
65 media_type: "image/png",
66 data: await readFile("diagram.png", "base64")
67 }
50 // Follow-up with image
51 yield {
52 type: "user",
53 message: {
54 role: "user",
55 content: [
56 {
57 type: "text",
58 text: "Review this architecture diagram"
59 },
60 {
61 type: "image",
62 source: {
63 type: "base64",
64 media_type: "image/png",
65 data: await readFile("diagram.png", "base64")
6866 }
69 ]
70 },
71 parent_tool_use_id: null
72 };
73 }
67 }
68 ]
69 },
70 parent_tool_use_id: null
71 };
72}
7473 
75 // Process streaming responses
76 for await (const message of query({
77 prompt: generateMessages(),
78 options: {
79 maxTurns: 10,
80 allowedTools: ["Read", "Grep"]
81 }
82 })) {
83 if (message.type === "result" && message.subtype === "success") {
84 console.log(message.result);
85 }
74// Process streaming responses
75for await (const message of query({
76 prompt: generateMessages(),
77 options: {
78 maxTurns: 10,
79 allowedTools: ["Read", "Grep"]
8680 }
87 ```
81})) {
82 if (message.type === "result" && message.subtype === "success") {
83 console.log(message.result);
84 }
85}
86```
8887 
89 ```python Python theme={null}
90 from claude_agent_sdk import (
91 ClaudeSDKClient,
92 ClaudeAgentOptions,
93 AssistantMessage,
94 TextBlock,
95 )
96 import asyncio
97 import base64
88```python Python theme={null}
89from claude_agent_sdk import (
90 ClaudeSDKClient,
91 ClaudeAgentOptions,
92 AssistantMessage,
93 TextBlock,
94)
95import asyncio
96import base64
9897 
9998 
100 async def streaming_analysis():
101 async def message_generator():
102 # First message
103 yield {
104 "type": "user",
105 "message": {
106 "role": "user",
107 "content": "Analyze this codebase for security issues",
108 },
109 }
99async def streaming_analysis():
100 async def message_generator():
101 # First message
102 yield {
103 "type": "user",
104 "message": {
105 "role": "user",
106 "content": "Analyze this codebase for security issues",
107 },
108 }
110109 
111 # Wait for conditions
112 await asyncio.sleep(2)
110 # Wait for conditions
111 await asyncio.sleep(2)
113112 
114 # Follow-up with image
115 with open("diagram.png", "rb") as f:
116 image_data = base64.b64encode(f.read()).decode()
113 # Follow-up with image
114 with open("diagram.png", "rb") as f:
115 image_data = base64.b64encode(f.read()).decode()
117116 
118 yield {
119 "type": "user",
120 "message": {
121 "role": "user",
122 "content": [
123 {"type": "text", "text": "Review this architecture diagram"},
124 {
125 "type": "image",
126 "source": {
127 "type": "base64",
128 "media_type": "image/png",
129 "data": image_data,
130 },
131 },
132 ],
133 },
134 }
117 yield {
118 "type": "user",
119 "message": {
120 "role": "user",
121 "content": [
122 {"type": "text", "text": "Review this architecture diagram"},
123 {
124 "type": "image",
125 "source": {
126 "type": "base64",
127 "media_type": "image/png",
128 "data": image_data,
129 },
130 },
131 ],
132 },
133 }
135134 
136 # Use ClaudeSDKClient for streaming input
137 options = ClaudeAgentOptions(max_turns=10, allowed_tools=["Read", "Grep"])
135 # Use ClaudeSDKClient for streaming input
136 options = ClaudeAgentOptions(max_turns=10, allowed_tools=["Read", "Grep"])
138137 
139 async with ClaudeSDKClient(options) as client:
140 # Send streaming input
141 await client.query(message_generator())
138 async with ClaudeSDKClient(options) as client:
139 # Send streaming input
140 await client.query(message_generator())
142141 
143 # Process responses
144 async for message in client.receive_response():
145 if isinstance(message, AssistantMessage):
146 for block in message.content:
147 if isinstance(block, TextBlock):
148 print(block.text)
142 # Process responses
143 async for message in client.receive_response():
144 if isinstance(message, AssistantMessage):
145 for block in message.content:
146 if isinstance(block, TextBlock):
147 print(block.text)
149148 
150149 
151 asyncio.run(streaming_analysis())
152 ```
153</CodeGroup>
150asyncio.run(streaming_analysis())
151```
154152 
155153When you run the example, the TypeScript version prints each response as it completes. The Python version's `receive_response()` loop ends at the first result message, so it prints the security analysis; to read both responses, use one `query()` and `receive_response()` pair per message as shown in the [Python reference's example of continuing a conversation](/docs/en/agent-sdk/python#example-continuing-a-conversation).
156154 
157155If an image block's `source` is missing or isn't an object, the SDK doesn't report an error. Claude Code sends Claude a text note in place of the image, such as `[Image could not be processed: image block has no source object]`, and the session continues.
158156 
159<Note>
160 In the TypeScript SDK, if your message generator throws, for example when a file it reads is missing, the stream ends with an error that reads `Claude Code process aborted by user` instead of the original error, so check the code inside your generator first when you see that message. The error may also be preceded by a long minified line of bundled SDK source, so read to the end of the output for the error text.
157> [!NOTE]
158>
159> In the TypeScript SDK, if your message generator throws, for example when a file it reads is missing, the stream ends with an error that reads `Claude Code process aborted by user` instead of the original error, so check the code inside your generator first when you see that message. The error may also be preceded by a long minified line of bundled SDK source, so read to the end of the output for the error text.
160>
161> In the Python SDK, a generator exception is logged at debug level and the session stalls without raising, so if a streaming session hangs with no output, enable debug logging and check your generator.
161162 
162 In the Python SDK, a generator exception is logged at debug level and the session stalls without raising, so if a streaming session hangs with no output, enable debug logging and check your generator.
163</Note>
164 
165163## Single Message Input
166164 
167165Single message input is simpler but more limited.
from line 174
176174 
177175### Limitations
178176 
179<Warning>
180 Single message input mode does **not** support:
177> [!WARNING]
178>
179> Single message input mode does **not** support:
180>
181> * Direct image attachments in messages
182> * Dynamic message queueing
183> * Real-time interruption
184> * Natural multi-turn conversations
181185 
182 * Direct image attachments in messages
183 * Dynamic message queueing
184 * Real-time interruption
185 * Natural multi-turn conversations
186</Warning>
187 
188186If a query ends with an error result, such as `error_max_turns`, a single message `query()` call raises an error that includes the failure text after yielding the final result message, so wrap the loop in a try block if your code needs to continue. See [Handle the result](/docs/en/agent-sdk/agent-loop#handle-the-result) for the result subtypes.
189187 
190188### Implementation Example
191189 
192<CodeGroup>
193 ```typescript TypeScript theme={null}
194 import { query } from "@anthropic-ai/claude-agent-sdk";
190```typescript TypeScript theme={null}
191import { query } from "@anthropic-ai/claude-agent-sdk";
195192 
196 // Simple one-shot query
197 // query() throws after an error result, such as error_max_turns
198 try {
199 for await (const message of query({
200 prompt: "Explain the authentication flow",
201 options: {
202 maxTurns: 5,
203 allowedTools: ["Read", "Grep"]
204 }
205 })) {
206 if (message.type === "result" && message.subtype === "success") {
207 console.log(message.result);
208 }
193// Simple one-shot query
194// query() throws after an error result, such as error_max_turns
195try {
196 for await (const message of query({
197 prompt: "Explain the authentication flow",
198 options: {
199 maxTurns: 5,
200 allowedTools: ["Read", "Grep"]
209201 }
210 } catch (error) {
211 console.error(`Query failed: ${error}`);
202 })) {
203 if (message.type === "result" && message.subtype === "success") {
204 console.log(message.result);
205 }
212206 }
207} catch (error) {
208 console.error(`Query failed: ${error}`);
209}
213210 
214 // Continue conversation with session management
215 try {
216 for await (const message of query({
217 prompt: "Now explain the authorization process",
218 options: {
219 continue: true,
220 maxTurns: 5
221 }
222 })) {
223 if (message.type === "result" && message.subtype === "success") {
224 console.log(message.result);
225 }
211// Continue conversation with session management
212try {
213 for await (const message of query({
214 prompt: "Now explain the authorization process",
215 options: {
216 continue: true,
217 maxTurns: 5
226218 }
227 } catch (error) {
228 console.error(`Query failed: ${error}`);
219 })) {
220 if (message.type === "result" && message.subtype === "success") {
221 console.log(message.result);
222 }
229223 }
230 ```
224} catch (error) {
225 console.error(`Query failed: ${error}`);
226}
227```
231228 
232 ```python Python theme={null}
233 from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
234 import asyncio
229```python Python theme={null}
230from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
231import asyncio
235232 
236233 
237 async def single_message_example():
238 # Simple one-shot query using query() function
239 # query() raises ResultError after an error result, such as error_max_turns
240 try:
241 async for message in query(
242 prompt="Explain the authentication flow",
243 options=ClaudeAgentOptions(max_turns=5, allowed_tools=["Read", "Grep"]),
244 ):
245 if isinstance(message, ResultMessage) and message.subtype == "success":
246 print(message.result)
247 except Exception as e:
248 print(f"Query failed: {e}")
234async def single_message_example():
235 # Simple one-shot query using query() function
236 # query() raises ResultError after an error result, such as error_max_turns
237 try:
238 async for message in query(
239 prompt="Explain the authentication flow",
240 options=ClaudeAgentOptions(max_turns=5, allowed_tools=["Read", "Grep"]),
241 ):
242 if isinstance(message, ResultMessage) and message.subtype == "success":
243 print(message.result)
244 except Exception as e:
245 print(f"Query failed: {e}")
249246 
250 # Continue conversation with session management
251 try:
252 async for message in query(
253 prompt="Now explain the authorization process",
254 options=ClaudeAgentOptions(continue_conversation=True, max_turns=5),
255 ):
256 if isinstance(message, ResultMessage) and message.subtype == "success":
257 print(message.result)
258 except Exception as e:
259 print(f"Query failed: {e}")
247 # Continue conversation with session management
248 try:
249 async for message in query(
250 prompt="Now explain the authorization process",
251 options=ClaudeAgentOptions(continue_conversation=True, max_turns=5),
252 ):
253 if isinstance(message, ResultMessage) and message.subtype == "success":
254 print(message.result)
255 except Exception as e:
256 print(f"Query failed: {e}")
260257 
261258 
262 asyncio.run(single_message_example())
263 ```
264</CodeGroup>
259asyncio.run(single_message_example())
260```
265261 
266262When you run the example, each query prints its final result text: first the authentication explanation, then the authorization explanation.
267263 
Feedback