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-and-content.mddocs/

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