or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

agent-definitions.mdagents.mdclient.mdconfiguration-options.mdcontent-blocks.mdcore-query-interface.mdcustom-tools.mderror-handling.mderrors.mdhook-system.mdhooks.mdindex.mdmcp-config.mdmcp-server-configuration.mdmessages-and-content.mdmessages.mdoptions.mdpermission-control.mdpermissions.mdquery.mdtransport.md
COMPLETION_SUMMARY.md

messages.mddocs/

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