docs
0
# Message Types
1
2
Messages represent communication between you, Claude, and the system. The SDK emits different message types during conversation flow, including user inputs, assistant responses, system notifications, results, and streaming events.
3
4
## Capabilities
5
6
### Message Union Type
7
8
Union of all possible message types that can be received from Claude.
9
10
```python { .api }
11
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage | StreamEvent
12
"""
13
Union of all message types.
14
15
When iterating over messages from query() or ClaudeSDKClient, you receive
16
Message objects which can be one of five types:
17
18
- UserMessage: User input messages
19
- AssistantMessage: Claude's responses with content
20
- SystemMessage: System notifications and metadata
21
- ResultMessage: Final result with cost and usage info
22
- StreamEvent: Partial message updates (when streaming enabled)
23
24
Use isinstance() to determine the specific message type and access
25
type-specific fields.
26
"""
27
```
28
29
### UserMessage
30
31
Represents a user input message.
32
33
```python { .api }
34
@dataclass
35
class UserMessage:
36
"""
37
User message.
38
39
Represents a message sent by the user to Claude. This can be either
40
your initial prompt or follow-up messages during conversation.
41
42
Attributes:
43
content: The message content (string or list of content blocks)
44
parent_tool_use_id: Optional parent tool use ID for context
45
"""
46
47
content: str | list[ContentBlock]
48
"""Message content.
49
50
Can be:
51
- A string for simple text messages
52
- A list of ContentBlock objects for rich content (text, images, etc.)
53
54
Example:
55
"What is Python?"
56
[TextBlock(text="Analyze this"), ...]
57
"""
58
59
parent_tool_use_id: str | None = None
60
"""Optional parent tool use ID.
61
62
When set, indicates this user message is in response to a tool use
63
request from Claude. Used for tool result messages and maintaining
64
conversation context.
65
"""
66
```
67
68
### AssistantMessage
69
70
Represents Claude's response message.
71
72
```python { .api }
73
@dataclass
74
class AssistantMessage:
75
"""
76
Assistant message with content blocks.
77
78
Represents a complete response from Claude. The response is structured
79
as a list of content blocks, which can include text, thinking, tool uses,
80
and tool results.
81
82
Attributes:
83
content: List of content blocks making up the response
84
model: The model used to generate this response
85
parent_tool_use_id: Optional parent tool use ID for context
86
"""
87
88
content: list[ContentBlock]
89
"""List of content blocks.
90
91
Each block represents a different type of content in Claude's response:
92
- TextBlock: Normal text output
93
- ThinkingBlock: Extended thinking (when enabled)
94
- ToolUseBlock: Request to execute a tool
95
- ToolResultBlock: Result from a tool execution
96
97
See content-blocks.md for details on each block type.
98
"""
99
100
model: str
101
"""Model identifier.
102
103
The Claude model that generated this response. Examples:
104
- 'claude-sonnet-4-5-20250929'
105
- 'claude-opus-4-1-20250805'
106
- 'claude-opus-4-20250514'
107
"""
108
109
parent_tool_use_id: str | None = None
110
"""Optional parent tool use ID.
111
112
When set, indicates this assistant message is related to a specific
113
tool execution context.
114
"""
115
```
116
117
### SystemMessage
118
119
Represents system notifications and metadata.
120
121
```python { .api }
122
@dataclass
123
class SystemMessage:
124
"""
125
System message with metadata.
126
127
System messages provide notifications, status updates, and metadata
128
about the conversation flow. They're not part of the core user-assistant
129
dialogue but provide important context.
130
131
Attributes:
132
subtype: Type of system message
133
data: Message-specific data payload
134
"""
135
136
subtype: str
137
"""System message subtype.
138
139
Identifies the kind of system message. Common subtypes include:
140
- 'status': Status updates
141
- 'notification': System notifications
142
- 'metadata': Additional metadata
143
- Other internal message types
144
"""
145
146
data: dict[str, Any]
147
"""Message data payload.
148
149
Structure varies by subtype. Contains the actual information for
150
this system message.
151
152
Example:
153
{"status": "processing", "step": 2, "total": 5}
154
"""
155
```
156
157
### ResultMessage
158
159
Represents the final result of a conversation turn with cost and usage information.
160
161
```python { .api }
162
@dataclass
163
class ResultMessage:
164
"""
165
Result message with cost and usage information.
166
167
Marks the completion of a conversation turn and provides detailed
168
metrics including API usage, costs, duration, and session information.
169
170
This message type signals that Claude has finished processing and
171
you can proceed with follow-up actions or end the conversation.
172
173
Attributes:
174
subtype: Result message subtype
175
duration_ms: Total duration in milliseconds
176
duration_api_ms: API call duration in milliseconds
177
is_error: Whether an error occurred
178
num_turns: Number of conversation turns
179
session_id: Session identifier
180
total_cost_usd: Total cost in USD (if available)
181
usage: Detailed usage information (if available)
182
result: Optional result string
183
"""
184
185
subtype: str
186
"""Result subtype.
187
188
Identifies the kind of result. Common subtypes:
189
- 'success': Normal completion
190
- 'error': Error occurred
191
- 'interrupted': User interrupted
192
- 'max_turns': Hit max turns limit
193
"""
194
195
duration_ms: int
196
"""Total duration in milliseconds.
197
198
Time from start of request to completion, including all tool
199
executions and API calls.
200
"""
201
202
duration_api_ms: int
203
"""API call duration in milliseconds.
204
205
Time spent in Anthropic API calls only, excluding tool execution
206
time and other overhead.
207
"""
208
209
is_error: bool
210
"""Whether an error occurred.
211
212
True if the conversation ended due to an error, False for normal
213
completion.
214
"""
215
216
num_turns: int
217
"""Number of conversation turns.
218
219
Count of back-and-forth exchanges in this conversation session.
220
One turn = one user message + one assistant response.
221
"""
222
223
session_id: str
224
"""Session identifier.
225
226
Unique ID for this conversation session. Use with the `resume`
227
option in ClaudeAgentOptions to continue the conversation later.
228
"""
229
230
total_cost_usd: float | None = None
231
"""Total cost in USD.
232
233
The total cost of API calls for this conversation turn. May be None
234
if cost information is not available or tracking is disabled.
235
236
Example: 0.0025 for $0.0025 (0.25 cents)
237
"""
238
239
usage: dict[str, Any] | None = None
240
"""Detailed usage information.
241
242
Token usage and other metrics. Structure varies but typically includes:
243
- input_tokens: Number of input tokens
244
- output_tokens: Number of output tokens
245
- cache_read_tokens: Tokens read from cache
246
- cache_creation_tokens: Tokens written to cache
247
248
Example:
249
{
250
"input_tokens": 1250,
251
"output_tokens": 850,
252
"cache_read_tokens": 500,
253
"cache_creation_tokens": 0
254
}
255
256
May be None if usage tracking is disabled.
257
"""
258
259
result: str | None = None
260
"""Optional result string.
261
262
Additional result information or error message. Content depends
263
on the subtype and completion status.
264
"""
265
```
266
267
### StreamEvent
268
269
Represents a partial message update during streaming.
270
271
```python { .api }
272
@dataclass
273
class StreamEvent:
274
"""
275
Stream event for partial message updates during streaming.
276
277
When include_partial_messages is enabled in ClaudeAgentOptions, the SDK
278
emits StreamEvent messages containing partial content as it's generated
279
in real-time. This enables live updates in UIs.
280
281
Attributes:
282
uuid: Unique event identifier
283
session_id: Session identifier
284
event: Raw Anthropic API stream event
285
parent_tool_use_id: Optional parent tool use ID
286
"""
287
288
uuid: str
289
"""Unique event identifier.
290
291
Each stream event has a unique UUID for tracking and deduplication.
292
"""
293
294
session_id: str
295
"""Session identifier.
296
297
The session this stream event belongs to. Same as ResultMessage.session_id.
298
"""
299
300
event: dict[str, Any]
301
"""Raw Anthropic API stream event.
302
303
The unprocessed stream event from the Anthropic API. Structure follows
304
the Anthropic streaming format with types like:
305
- content_block_start
306
- content_block_delta
307
- content_block_stop
308
- message_start
309
- message_delta
310
- message_stop
311
312
Example:
313
{
314
"type": "content_block_delta",
315
"index": 0,
316
"delta": {"type": "text_delta", "text": "Hello"}
317
}
318
319
See Anthropic's streaming documentation for full event schema.
320
"""
321
322
parent_tool_use_id: str | None = None
323
"""Optional parent tool use ID.
324
325
When set, indicates this stream event is related to a specific
326
tool execution context.
327
"""
328
```
329
330
## Usage Examples
331
332
### Basic Message Handling
333
334
```python
335
from claude_agent_sdk import (
336
query, UserMessage, AssistantMessage, SystemMessage,
337
ResultMessage, TextBlock
338
)
339
340
async for msg in query(prompt="What is Python?"):
341
if isinstance(msg, UserMessage):
342
print(f"User: {msg.content}")
343
344
elif isinstance(msg, AssistantMessage):
345
for block in msg.content:
346
if isinstance(block, TextBlock):
347
print(f"Claude: {block.text}")
348
349
elif isinstance(msg, SystemMessage):
350
print(f"System [{msg.subtype}]: {msg.data}")
351
352
elif isinstance(msg, ResultMessage):
353
print(f"Session: {msg.session_id}")
354
print(f"Cost: ${msg.total_cost_usd:.4f}")
355
print(f"Duration: {msg.duration_ms}ms")
356
```
357
358
### Extracting Text from AssistantMessage
359
360
```python
361
from claude_agent_sdk import query, AssistantMessage, TextBlock
362
363
async for msg in query(prompt="Explain decorators"):
364
if isinstance(msg, AssistantMessage):
365
# Extract all text blocks
366
texts = [
367
block.text
368
for block in msg.content
369
if isinstance(block, TextBlock)
370
]
371
372
full_response = "\n".join(texts)
373
print(full_response)
374
```
375
376
### Collecting Messages
377
378
```python
379
from claude_agent_sdk import query, Message
380
381
# Collect all messages
382
messages: list[Message] = []
383
384
async for msg in query(prompt="Hello"):
385
messages.append(msg)
386
387
print(f"Received {len(messages)} messages")
388
```
389
390
### Handling Tool Uses
391
392
```python
393
from claude_agent_sdk import (
394
query, AssistantMessage, ToolUseBlock, ToolResultBlock,
395
ClaudeAgentOptions
396
)
397
398
options = ClaudeAgentOptions(
399
allowed_tools=["Bash"]
400
)
401
402
async for msg in query(prompt="List files", options=options):
403
if isinstance(msg, AssistantMessage):
404
for block in msg.content:
405
if isinstance(block, ToolUseBlock):
406
print(f"Tool: {block.name}")
407
print(f"Input: {block.input}")
408
409
elif isinstance(block, ToolResultBlock):
410
print(f"Result: {block.content}")
411
if block.is_error:
412
print("(Error occurred)")
413
```
414
415
### Processing Results
416
417
```python
418
from claude_agent_sdk import query, ResultMessage
419
420
result_msg = None
421
422
async for msg in query(prompt="What is 2 + 2?"):
423
if isinstance(msg, ResultMessage):
424
result_msg = msg
425
426
if result_msg:
427
print(f"Session ID: {result_msg.session_id}")
428
print(f"Turns: {result_msg.num_turns}")
429
print(f"Duration: {result_msg.duration_ms}ms")
430
print(f"API time: {result_msg.duration_api_ms}ms")
431
432
if result_msg.total_cost_usd:
433
print(f"Cost: ${result_msg.total_cost_usd:.6f}")
434
435
if result_msg.usage:
436
print(f"Input tokens: {result_msg.usage.get('input_tokens')}")
437
print(f"Output tokens: {result_msg.usage.get('output_tokens')}")
438
439
if result_msg.is_error:
440
print(f"Error: {result_msg.result}")
441
```
442
443
### Streaming Partial Messages
444
445
```python
446
from claude_agent_sdk import query, StreamEvent, ClaudeAgentOptions
447
448
options = ClaudeAgentOptions(
449
include_partial_messages=True
450
)
451
452
async for msg in query(prompt="Write a long story", options=options):
453
if isinstance(msg, StreamEvent):
454
# Handle streaming updates
455
event = msg.event
456
event_type = event.get("type")
457
458
if event_type == "content_block_delta":
459
delta = event.get("delta", {})
460
if delta.get("type") == "text_delta":
461
# Print partial text as it arrives
462
print(delta.get("text", ""), end="", flush=True)
463
464
elif event_type == "message_stop":
465
print("\n[Stream complete]")
466
```
467
468
### Message Type Filtering
469
470
```python
471
from claude_agent_sdk import query, AssistantMessage, ResultMessage
472
473
# Only process assistant messages
474
assistant_messages = []
475
476
async for msg in query(prompt="Explain Python"):
477
if isinstance(msg, AssistantMessage):
478
assistant_messages.append(msg)
479
480
print(f"Claude sent {len(assistant_messages)} responses")
481
482
# Get just the result
483
async for msg in query(prompt="What is 2 + 2?"):
484
if isinstance(msg, ResultMessage):
485
final_result = msg
486
break
487
```
488
489
### Building a Chat History
490
491
```python
492
from claude_agent_sdk import (
493
query, UserMessage, AssistantMessage, TextBlock, ClaudeAgentOptions
494
)
495
496
chat_history = []
497
498
# First message
499
async for msg in query(prompt="What is Python?"):
500
if isinstance(msg, UserMessage):
501
chat_history.append({"role": "user", "content": msg.content})
502
503
elif isinstance(msg, AssistantMessage):
504
texts = [b.text for b in msg.content if isinstance(b, TextBlock)]
505
chat_history.append({"role": "assistant", "content": " ".join(texts)})
506
507
# Continue conversation
508
options = ClaudeAgentOptions(continue_conversation=True)
509
510
async for msg in query(prompt="Can you show an example?", options=options):
511
if isinstance(msg, UserMessage):
512
chat_history.append({"role": "user", "content": msg.content})
513
514
elif isinstance(msg, AssistantMessage):
515
texts = [b.text for b in msg.content if isinstance(b, TextBlock)]
516
chat_history.append({"role": "assistant", "content": " ".join(texts)})
517
518
# Display history
519
for entry in chat_history:
520
print(f"{entry['role']}: {entry['content']}")
521
```
522
523
### Error Detection
524
525
```python
526
from claude_agent_sdk import query, ResultMessage, ToolResultBlock, AssistantMessage
527
528
has_error = False
529
530
async for msg in query(prompt="Delete a non-existent file"):
531
if isinstance(msg, AssistantMessage):
532
for block in msg.content:
533
if isinstance(block, ToolResultBlock) and block.is_error:
534
print(f"Tool error: {block.content}")
535
has_error = True
536
537
elif isinstance(msg, ResultMessage):
538
if msg.is_error:
539
print(f"Result error: {msg.result}")
540
has_error = True
541
542
if has_error:
543
print("Errors occurred during execution")
544
```
545
546
### Session Management with Messages
547
548
```python
549
from claude_agent_sdk import query, ResultMessage, ClaudeAgentOptions
550
551
# Get session ID from result
552
session_id = None
553
554
async for msg in query(prompt="Remember this: my favorite color is blue"):
555
if isinstance(msg, ResultMessage):
556
session_id = msg.session_id
557
print(f"Session ID: {session_id}")
558
559
# Resume the session later
560
if session_id:
561
options = ClaudeAgentOptions(resume=session_id)
562
563
async for msg in query(prompt="What is my favorite color?", options=options):
564
if isinstance(msg, ResultMessage):
565
print(f"Resumed session: {msg.session_id}")
566
```
567
568
### Usage Statistics
569
570
```python
571
from claude_agent_sdk import query, ResultMessage
572
573
async for msg in query(prompt="Explain machine learning"):
574
if isinstance(msg, ResultMessage):
575
if msg.usage:
576
input_tokens = msg.usage.get('input_tokens', 0)
577
output_tokens = msg.usage.get('output_tokens', 0)
578
cache_read = msg.usage.get('cache_read_tokens', 0)
579
total_tokens = input_tokens + output_tokens
580
581
print(f"Total tokens: {total_tokens}")
582
print(f" Input: {input_tokens}")
583
print(f" Output: {output_tokens}")
584
print(f" Cache read: {cache_read}")
585
586
# Approximate cost calculation (example rates)
587
input_cost = (input_tokens / 1_000_000) * 3.00
588
output_cost = (output_tokens / 1_000_000) * 15.00
589
estimated_cost = input_cost + output_cost
590
591
print(f"Estimated cost: ${estimated_cost:.6f}")
592
```
593
594
### Parent Tool Use Context
595
596
```python
597
from claude_agent_sdk import (
598
query, AssistantMessage, UserMessage, ToolUseBlock,
599
ClaudeAgentOptions
600
)
601
602
options = ClaudeAgentOptions(allowed_tools=["Bash"])
603
604
async for msg in query(prompt="Run a command", options=options):
605
if isinstance(msg, AssistantMessage):
606
for block in msg.content:
607
if isinstance(block, ToolUseBlock):
608
print(f"Tool use ID: {block.id}")
609
610
elif isinstance(msg, UserMessage):
611
if msg.parent_tool_use_id:
612
print(f"This message relates to tool use: {msg.parent_tool_use_id}")
613
```
614
615
### Message Count Statistics
616
617
```python
618
from claude_agent_sdk import (
619
query, UserMessage, AssistantMessage, SystemMessage, ResultMessage
620
)
621
622
counts = {
623
"user": 0,
624
"assistant": 0,
625
"system": 0,
626
"result": 0
627
}
628
629
async for msg in query(prompt="Analyze this project"):
630
if isinstance(msg, UserMessage):
631
counts["user"] += 1
632
elif isinstance(msg, AssistantMessage):
633
counts["assistant"] += 1
634
elif isinstance(msg, SystemMessage):
635
counts["system"] += 1
636
elif isinstance(msg, ResultMessage):
637
counts["result"] += 1
638
639
print("Message statistics:")
640
for msg_type, count in counts.items():
641
print(f" {msg_type}: {count}")
642
```
643
644
### Stream Event Processing
645
646
```python
647
from claude_agent_sdk import query, StreamEvent, ClaudeAgentOptions
648
649
options = ClaudeAgentOptions(include_partial_messages=True)
650
651
async for msg in query(prompt="Generate code", options=options):
652
if isinstance(msg, StreamEvent):
653
event = msg.event
654
event_type = event.get("type")
655
656
if event_type == "message_start":
657
print("Message started")
658
659
elif event_type == "content_block_start":
660
print(f"Content block {event.get('index')} started")
661
662
elif event_type == "content_block_delta":
663
delta = event.get("delta", {})
664
print(f"Delta: {delta}")
665
666
elif event_type == "content_block_stop":
667
print(f"Content block {event.get('index')} stopped")
668
669
elif event_type == "message_delta":
670
print(f"Message delta: {event.get('delta')}")
671
672
elif event_type == "message_stop":
673
print("Message complete")
674
```
675