Streaming input mode is the preferred way to use the Claude Agent SDK. It provides full access to the agent’s capabilities and enables rich, interactive experiences.It allows the agent to operate as a long lived process that takes in user input, handles interruptions, surfaces permission requests, and handles session management.
import { query, type SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";import { readFile } from "fs/promises";async function* generateMessages(): AsyncGenerator<SDKUserMessage> { // First message yield { type: "user", message: { role: "user", content: "Analyze this codebase for security issues" }, parent_tool_use_id: null }; // Wait for conditions or user input await new Promise((resolve) => setTimeout(resolve, 2000)); // Follow-up with image yield { type: "user", message: { role: "user", content: [ { type: "text", text: "Review this architecture diagram" }, { type: "image", source: { type: "base64", media_type: "image/png", data: await readFile("diagram.png", "base64") } } ] }, parent_tool_use_id: null };}// Process streaming responsesfor await (const message of query({ prompt: generateMessages(), options: { maxTurns: 10, allowedTools: ["Read", "Grep"] }})) { if (message.type === "result" && message.subtype === "success") { console.log(message.result); }}
from claude_agent_sdk import ( ClaudeSDKClient, ClaudeAgentOptions, AssistantMessage, TextBlock,)import asyncioimport base64async def streaming_analysis(): async def message_generator(): # First message yield { "type": "user", "message": { "role": "user", "content": "Analyze this codebase for security issues", }, } # Wait for conditions await asyncio.sleep(2) # Follow-up with image with open("diagram.png", "rb") as f: image_data = base64.b64encode(f.read()).decode() yield { "type": "user", "message": { "role": "user", "content": [ {"type": "text", "text": "Review this architecture diagram"}, { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": image_data, }, }, ], }, } # Use ClaudeSDKClient for streaming input options = ClaudeAgentOptions(max_turns=10, allowed_tools=["Read", "Grep"]) async with ClaudeSDKClient(options) as client: # Send streaming input await client.query(message_generator()) # Process responses async for message in client.receive_response(): if isinstance(message, AssistantMessage): for block in message.content: if isinstance(block, TextBlock): print(block.text)asyncio.run(streaming_analysis())
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.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.
If 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 for the result subtypes.
import { query } from "@anthropic-ai/claude-agent-sdk";// Simple one-shot queryfor await (const message of query({ prompt: "Explain the authentication flow", options: { maxTurns: 1, allowedTools: ["Read", "Grep"] }})) { if (message.type === "result" && message.subtype === "success") { console.log(message.result); }}// Continue conversation with session managementfor await (const message of query({ prompt: "Now explain the authorization process", options: { continue: true, maxTurns: 1 }})) { if (message.type === "result" && message.subtype === "success") { console.log(message.result); }}
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessageimport asyncioasync def single_message_example(): # Simple one-shot query using query() function async for message in query( prompt="Explain the authentication flow", options=ClaudeAgentOptions(max_turns=1, allowed_tools=["Read", "Grep"]), ): if isinstance(message, ResultMessage): print(message.result) # Continue conversation with session management async for message in query( prompt="Now explain the authorization process", options=ClaudeAgentOptions(continue_conversation=True, max_turns=1), ): if isinstance(message, ResultMessage): print(message.result)asyncio.run(single_message_example())