149 lines
4.8 KiB
Markdown
149 lines
4.8 KiB
Markdown
---
|
|
title: "Streaming vs Single Message Input"
|
|
aliases: [streaming-input, input-modes, single-message-input]
|
|
tags: [agent-sdk, streaming, input, typescript, session-management]
|
|
sources: [raw/Streaming Input.md]
|
|
created: 2026-04-17
|
|
updated: 2026-04-17
|
|
---
|
|
|
|
## Overview
|
|
|
|
The Claude Agent SDK supports two distinct input modes for `query()`:
|
|
|
|
| Mode | Type | Use case |
|
|
|------|------|----------|
|
|
| **Streaming Input** | `AsyncGenerator` of messages | Long-lived sessions, multi-turn, images, hooks |
|
|
| **Single Message** | `string` | One-shot queries, stateless environments |
|
|
|
|
Streaming input is the **default and recommended** approach.
|
|
|
|
## Streaming Input Mode
|
|
|
|
Pass an `AsyncGenerator` as the `prompt`. The agent runs as a long-lived process that consumes messages as they are yielded, handling tool execution and session state between turns.
|
|
|
|
### Capabilities (streaming only)
|
|
|
|
- **Image uploads** — attach `base64` images directly in message content
|
|
- **Queued messages** — yield multiple messages; they process sequentially
|
|
- **Interruption** — send an interrupt/cancel mid-session
|
|
- **Hook integration** — lifecycle hooks fire normally
|
|
- **Real-time feedback** — responses stream back as tokens are generated
|
|
- **Context persistence** — conversation context maintained across all turns automatically
|
|
|
|
### How it works
|
|
|
|
```
|
|
App yields Message 1 → Agent executes tools → Streams partial response back
|
|
App yields Message 2 + Image → Agent processes → Streams response 2
|
|
App queues Message 3 → App sends Interrupt → Agent handles interruption
|
|
↕
|
|
Session stays alive; file system state persists
|
|
```
|
|
|
|
### TypeScript example
|
|
|
|
```typescript
|
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
import { readFile } from "fs/promises";
|
|
|
|
async function* generateMessages() {
|
|
yield {
|
|
type: "user" as const,
|
|
message: {
|
|
role: "user" as const,
|
|
content: "Analyze this codebase for security issues"
|
|
}
|
|
};
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
|
|
// Follow-up with image attachment
|
|
yield {
|
|
type: "user" as const,
|
|
message: {
|
|
role: "user" as const,
|
|
content: [
|
|
{ type: "text", text: "Review this architecture diagram" },
|
|
{
|
|
type: "image",
|
|
source: {
|
|
type: "base64",
|
|
media_type: "image/png",
|
|
data: await readFile("diagram.png", "base64")
|
|
}
|
|
}
|
|
]
|
|
}
|
|
};
|
|
}
|
|
|
|
for await (const message of query({
|
|
prompt: generateMessages(),
|
|
options: { maxTurns: 10, allowedTools: ["Read", "Grep"] }
|
|
})) {
|
|
if (message.type === "result") console.log(message.result);
|
|
}
|
|
```
|
|
|
|
## Single Message Input
|
|
|
|
Pass a plain `string` as `prompt`. Best for simple one-shot tasks or stateless environments (e.g. Lambda functions).
|
|
|
|
### Limitations (single message)
|
|
|
|
- No direct image attachments
|
|
- No dynamic message queueing
|
|
- No real-time interruption
|
|
- No hook integration
|
|
- No natural multi-turn conversations
|
|
|
|
### Session resuming with single message
|
|
|
|
Use `continue: true` to resume a previous session:
|
|
|
|
```typescript
|
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
|
|
// First query
|
|
for await (const message of query({
|
|
prompt: "Explain the authentication flow",
|
|
options: { maxTurns: 1, allowedTools: ["Read", "Grep"] }
|
|
})) {
|
|
if (message.type === "result") console.log(message.result);
|
|
}
|
|
|
|
// Resume same session
|
|
for await (const message of query({
|
|
prompt: "Now explain the authorization process",
|
|
options: { continue: true, maxTurns: 1 }
|
|
})) {
|
|
if (message.type === "result") console.log(message.result);
|
|
}
|
|
```
|
|
|
|
## Choosing the Right Mode
|
|
|
|
| Requirement | Use |
|
|
|-------------|-----|
|
|
| Multi-turn conversation | Streaming |
|
|
| Image attachments | Streaming |
|
|
| Hooks / lifecycle events | Streaming |
|
|
| Real-time token streaming | Streaming |
|
|
| Lambda / stateless function | Single message |
|
|
| Simple one-shot query | Single message |
|
|
| Session resume across calls | Single message + `continue: true` |
|
|
|
|
## Key Takeaways
|
|
|
|
- **Streaming input = `AsyncGenerator` prompt** — yield messages as needed; the session stays alive between them
|
|
- **Single message = `string` prompt** — simpler API but loses images, hooks, interrupts, and natural multi-turn
|
|
- Streaming is the default; single message is the escape hatch for stateless environments
|
|
- `continue: true` lets single-message mode resume a prior session without rebuilding the generator
|
|
- Real-time token streaming (output side) works independently of which input mode you choose — see [[wiki/agent-sdk/streaming-output|streaming-output]]
|
|
- Hooks only fire in streaming input mode; see [[wiki/agent-sdk/sdk-hooks|sdk-hooks]] for hook setup
|
|
- For approval/interruption patterns see [[wiki/agent-sdk/user-input-approvals|user-input-approvals]]
|
|
|
|
## Sources
|
|
|
|
- `raw/Streaming Input.md` — source: https://code.claude.com/docs/en/agent-sdk/streaming-vs-single-mode
|