docs
0
# Messages and Content
1
2
Messages and content blocks provide structured communication between user and Claude. Messages are the top-level containers for conversation turns, while content blocks compose the actual content within messages.
3
4
## Capabilities
5
6
### Message Types
7
8
All messages are instances of one of five types, united by the `Message` type union.
9
10
```python { .api }
11
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage | StreamEvent
12
```
13
14
#### UserMessage
15
16
Messages from the user to Claude.
17
18
```python { .api }
19
@dataclass
20
class UserMessage:
21
"""Message from user to Claude."""
22
23
content: str | list[ContentBlock]
24
parent_tool_use_id: str | None = None
25
```
26
27
**Fields:**
28
29
- `content` (str | list[ContentBlock]): The message content. Can be a simple string or a list of content blocks for complex messages with mixed content types.
30
31
- `parent_tool_use_id` (str | None): Optional parent tool use ID for nested conversations. Used when this message is a response to a tool's sub-agent request.
32
33
**Usage Example:**
34
35
```python
36
from claude_agent_sdk import UserMessage, TextBlock
37
38
# Simple string content
39
user_msg = UserMessage(content="What is 2 + 2?")
40
41
# Complex content with blocks
42
user_msg = UserMessage(
43
content=[
44
TextBlock(text="Analyze this code:")
45
],
46
parent_tool_use_id=None
47
)
48
```
49
50
#### AssistantMessage
51
52
Messages from Claude to the user.
53
54
```python { .api }
55
@dataclass
56
class AssistantMessage:
57
"""Message from Claude to user."""
58
59
content: list[ContentBlock]
60
model: str
61
parent_tool_use_id: str | None = None
62
```
63
64
**Fields:**
65
66
- `content` (list[ContentBlock]): List of content blocks composing the message. Can include text, thinking blocks, and tool use/result blocks.
67
68
- `model` (str): The AI model that generated this message (e.g., "claude-sonnet-4-5-20250929").
69
70
- `parent_tool_use_id` (str | None): Optional parent tool use ID for nested conversations.
71
72
**Usage Example:**
73
74
```python
75
from claude_agent_sdk import query, AssistantMessage, TextBlock, ThinkingBlock
76
77
async for message in query(prompt="Explain quantum computing"):
78
if isinstance(message, AssistantMessage):
79
print(f"Model: {message.model}")
80
for block in message.content:
81
if isinstance(block, TextBlock):
82
print(f"Text: {block.text}")
83
elif isinstance(block, ThinkingBlock):
84
print(f"Thinking: {block.thinking}")
85
```
86
87
#### SystemMessage
88
89
System-level messages providing metadata and status information.
90
91
```python { .api }
92
@dataclass
93
class SystemMessage:
94
"""System-level message."""
95
96
subtype: str
97
data: dict[str, Any]
98
```
99
100
**Fields:**
101
102
- `subtype` (str): Type of system message (e.g., "info", "warning", "error").
103
104
- `data` (dict[str, Any]): System message payload with arbitrary data.
105
106
**Usage Example:**
107
108
```python
109
from claude_agent_sdk import query, SystemMessage
110
111
async for message in query(prompt="Hello"):
112
if isinstance(message, SystemMessage):
113
print(f"System {message.subtype}: {message.data}")
114
```
115
116
#### ResultMessage
117
118
Final result of a conversation turn, including cost and usage statistics.
119
120
```python { .api }
121
@dataclass
122
class ResultMessage:
123
"""Final result of conversation turn."""
124
125
subtype: str
126
duration_ms: int
127
duration_api_ms: int
128
is_error: bool
129
num_turns: int
130
session_id: str
131
total_cost_usd: float | None = None
132
usage: dict[str, Any] | None = None
133
result: str | None = None
134
structured_output: Any = None
135
```
136
137
**Fields:**
138
139
- `subtype` (str): Result subtype indicating the nature of completion.
140
141
- `duration_ms` (int): Total duration of the conversation turn in milliseconds.
142
143
- `duration_api_ms` (int): API call duration in milliseconds (subset of total duration).
144
145
- `is_error` (bool): Whether the result represents an error condition.
146
147
- `num_turns` (int): Number of conversation turns in this interaction.
148
149
- `session_id` (str): Session identifier for this conversation.
150
151
- `total_cost_usd` (float | None): Total cost in USD for this turn, if available.
152
153
- `usage` (dict[str, Any] | None): Token usage details including input_tokens, output_tokens, and cache information.
154
155
- `result` (str | None): Optional result text summarizing the outcome.
156
157
- `structured_output` (Any): Structured output when using `output_format` option, validated against the provided JSON schema.
158
159
**Usage Example:**
160
161
```python
162
from claude_agent_sdk import query, ResultMessage
163
164
async for message in query(prompt="Calculate 42 * 17"):
165
if isinstance(message, ResultMessage):
166
print(f"Duration: {message.duration_ms}ms")
167
print(f"Cost: ${message.total_cost_usd:.4f}")
168
print(f"Turns: {message.num_turns}")
169
print(f"Usage: {message.usage}")
170
if message.is_error:
171
print(f"Error: {message.result}")
172
```
173
174
**Structured Output Example:**
175
176
```python
177
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
178
179
options = ClaudeAgentOptions(
180
output_format={
181
"type": "json_schema",
182
"schema": {
183
"type": "object",
184
"properties": {
185
"answer": {"type": "number"},
186
"explanation": {"type": "string"}
187
},
188
"required": ["answer"]
189
}
190
}
191
)
192
193
async for message in query(prompt="What is 2 + 2?", options=options):
194
if isinstance(message, ResultMessage):
195
output = message.structured_output
196
print(f"Answer: {output['answer']}")
197
print(f"Explanation: {output.get('explanation', 'N/A')}")
198
```
199
200
#### StreamEvent
201
202
Raw stream events from the Anthropic API for advanced use cases.
203
204
```python { .api }
205
@dataclass
206
class StreamEvent:
207
"""Raw stream event from Anthropic API."""
208
209
uuid: str
210
session_id: str
211
event: dict[str, Any]
212
parent_tool_use_id: str | None = None
213
```
214
215
**Fields:**
216
217
- `uuid` (str): Unique identifier for this event.
218
219
- `session_id` (str): Session identifier.
220
221
- `event` (dict[str, Any]): Raw API event data from Anthropic's streaming API.
222
223
- `parent_tool_use_id` (str | None): Optional parent tool use ID.
224
225
**Usage Example:**
226
227
```python
228
from claude_agent_sdk import query, ClaudeAgentOptions, StreamEvent
229
230
options = ClaudeAgentOptions(include_partial_messages=True)
231
232
async for message in query(prompt="Generate code", options=options):
233
if isinstance(message, StreamEvent):
234
# Process raw streaming events
235
event_type = message.event.get("type")
236
if event_type == "content_block_delta":
237
# Handle partial content updates
238
delta = message.event.get("delta", {})
239
print(f"Partial: {delta}")
240
```
241
242
### Content Block Types
243
244
Content blocks are the building blocks of message content, united by the `ContentBlock` type union.
245
246
```python { .api }
247
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock
248
```
249
250
#### TextBlock
251
252
Plain text content.
253
254
```python { .api }
255
@dataclass
256
class TextBlock:
257
"""Plain text content."""
258
259
text: str
260
```
261
262
**Fields:**
263
264
- `text` (str): The text content.
265
266
**Usage Example:**
267
268
```python
269
from claude_agent_sdk import query, AssistantMessage, TextBlock
270
271
async for message in query(prompt="Hello"):
272
if isinstance(message, AssistantMessage):
273
for block in message.content:
274
if isinstance(block, TextBlock):
275
print(block.text)
276
```
277
278
#### ThinkingBlock
279
280
Extended thinking content showing Claude's reasoning process.
281
282
```python { .api }
283
@dataclass
284
class ThinkingBlock:
285
"""Extended thinking content."""
286
287
thinking: str
288
signature: str
289
```
290
291
**Fields:**
292
293
- `thinking` (str): The thinking/reasoning content.
294
295
- `signature` (str): Cryptographic signature verifying the thinking content.
296
297
**Usage Example:**
298
299
```python
300
from claude_agent_sdk import query, AssistantMessage, ThinkingBlock
301
302
async for message in query(prompt="Solve this complex problem"):
303
if isinstance(message, AssistantMessage):
304
for block in message.content:
305
if isinstance(block, ThinkingBlock):
306
print(f"Claude's reasoning: {block.thinking}")
307
```
308
309
#### ToolUseBlock
310
311
Tool invocation request from Claude.
312
313
```python { .api }
314
@dataclass
315
class ToolUseBlock:
316
"""Tool invocation request."""
317
318
id: str
319
name: str
320
input: dict[str, Any]
321
```
322
323
**Fields:**
324
325
- `id` (str): Unique identifier for this tool use request.
326
327
- `name` (str): Name of the tool being invoked (e.g., "Read", "Write", "Bash").
328
329
- `input` (dict[str, Any]): Tool input parameters as a dictionary.
330
331
**Usage Example:**
332
333
```python
334
from claude_agent_sdk import query, AssistantMessage, ToolUseBlock
335
336
async for message in query(prompt="Read file.txt"):
337
if isinstance(message, AssistantMessage):
338
for block in message.content:
339
if isinstance(block, ToolUseBlock):
340
print(f"Tool: {block.name}")
341
print(f"Input: {block.input}")
342
print(f"ID: {block.id}")
343
```
344
345
#### ToolResultBlock
346
347
Tool execution result returned to Claude.
348
349
```python { .api }
350
@dataclass
351
class ToolResultBlock:
352
"""Tool execution result."""
353
354
tool_use_id: str
355
content: str | list[dict[str, Any]] | None = None
356
is_error: bool | None = None
357
```
358
359
**Fields:**
360
361
- `tool_use_id` (str): ID of the corresponding ToolUseBlock that triggered this result.
362
363
- `content` (str | list[dict[str, Any]] | None): Result content. Can be a string, a list of content items, or None.
364
365
- `is_error` (bool | None): Whether the tool execution resulted in an error.
366
367
**Usage Example:**
368
369
```python
370
from claude_agent_sdk import query, AssistantMessage, ToolResultBlock
371
372
async for message in query(prompt="Read config.json"):
373
if isinstance(message, AssistantMessage):
374
for block in message.content:
375
if isinstance(block, ToolResultBlock):
376
if block.is_error:
377
print(f"Tool error: {block.content}")
378
else:
379
print(f"Tool result: {block.content}")
380
```
381
382
## Message Flow Patterns
383
384
### Simple Query-Response
385
386
```python
387
from claude_agent_sdk import query, AssistantMessage, TextBlock, ResultMessage
388
389
async def simple_flow():
390
async for message in query(prompt="What is Python?"):
391
if isinstance(message, AssistantMessage):
392
for block in message.content:
393
if isinstance(block, TextBlock):
394
print(f"Response: {block.text}")
395
elif isinstance(message, ResultMessage):
396
print(f"Complete in {message.duration_ms}ms")
397
```
398
399
### Tool Usage Flow
400
401
```python
402
from claude_agent_sdk import (
403
query, ClaudeAgentOptions, AssistantMessage,
404
TextBlock, ToolUseBlock, ToolResultBlock
405
)
406
407
async def tool_flow():
408
options = ClaudeAgentOptions(
409
allowed_tools=["Read", "Write"],
410
permission_mode="acceptEdits"
411
)
412
413
async for message in query(prompt="Create hello.py", options=options):
414
if isinstance(message, AssistantMessage):
415
for block in message.content:
416
if isinstance(block, TextBlock):
417
print(f"Claude says: {block.text}")
418
elif isinstance(block, ToolUseBlock):
419
print(f"Using tool: {block.name}")
420
print(f"With input: {block.input}")
421
elif isinstance(block, ToolResultBlock):
422
print(f"Tool result: {block.content}")
423
```
424
425
### Extended Thinking Flow
426
427
```python
428
from claude_agent_sdk import query, AssistantMessage, TextBlock, ThinkingBlock
429
430
async def thinking_flow():
431
async for message in query(prompt="Design a database schema"):
432
if isinstance(message, AssistantMessage):
433
for block in message.content:
434
if isinstance(block, ThinkingBlock):
435
print(f"[THINKING]: {block.thinking}")
436
elif isinstance(block, TextBlock):
437
print(f"[RESPONSE]: {block.text}")
438
```
439
440
### Interactive Multi-Turn Flow
441
442
```python
443
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock
444
445
async def interactive_flow():
446
async with ClaudeSDKClient() as client:
447
# Turn 1
448
await client.query("What is Python?")
449
async for msg in client.receive_response():
450
if isinstance(msg, AssistantMessage):
451
for block in msg.content:
452
if isinstance(block, TextBlock):
453
print(f"Turn 1: {block.text}")
454
455
# Turn 2 - follow-up in same session
456
await client.query("What are its main features?")
457
async for msg in client.receive_response():
458
if isinstance(msg, AssistantMessage):
459
for block in msg.content:
460
if isinstance(block, TextBlock):
461
print(f"Turn 2: {block.text}")
462
```
463
464
## Type Guards and Pattern Matching
465
466
Python's pattern matching (3.10+) works well with message and content types:
467
468
```python
469
from claude_agent_sdk import query
470
471
async for message in query(prompt="Hello"):
472
match message:
473
case AssistantMessage(content=blocks):
474
for block in blocks:
475
match block:
476
case TextBlock(text=t):
477
print(f"Text: {t}")
478
case ThinkingBlock(thinking=t):
479
print(f"Thinking: {t}")
480
case ToolUseBlock(name=n, input=i):
481
print(f"Tool {n}: {i}")
482
case ResultMessage(total_cost_usd=cost, num_turns=turns):
483
print(f"Done: {turns} turns, ${cost}")
484
case SystemMessage(subtype=st, data=d):
485
print(f"System [{st}]: {d}")
486
```
487
488
Traditional type guards also work:
489
490
```python
491
from claude_agent_sdk import (
492
query, AssistantMessage, TextBlock, ThinkingBlock,
493
ToolUseBlock, ToolResultBlock, ResultMessage
494
)
495
496
async for message in query(prompt="Hello"):
497
if isinstance(message, AssistantMessage):
498
for block in message.content:
499
if isinstance(block, TextBlock):
500
handle_text(block.text)
501
elif isinstance(block, ThinkingBlock):
502
handle_thinking(block.thinking)
503
elif isinstance(block, ToolUseBlock):
504
handle_tool_use(block.name, block.input)
505
elif isinstance(block, ToolResultBlock):
506
handle_tool_result(block.content, block.is_error)
507
elif isinstance(message, ResultMessage):
508
handle_result(message)
509
```
510