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

content-blocks.mddocs/

0

# Content Blocks

1

2

Content blocks are the building blocks of messages in conversations with Claude. They represent different types of content including text, thinking, tool uses, and tool results.

3

4

## Capabilities

5

6

### ContentBlock Union Type

7

8

Union of all possible content block types.

9

10

```python { .api }

11

ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock

12

"""

13

Union of all content block types.

14

15

Content blocks appear in AssistantMessage and UserMessage objects to

16

represent different types of content:

17

18

- TextBlock: Normal text output from Claude

19

- ThinkingBlock: Extended thinking content (when enabled)

20

- ToolUseBlock: Request to execute a tool

21

- ToolResultBlock: Result from tool execution

22

23

Use isinstance() to determine the specific block type and access

24

type-specific fields.

25

"""

26

```

27

28

### TextBlock

29

30

Plain text content from Claude or user.

31

32

```python { .api }

33

@dataclass

34

class TextBlock:

35

"""

36

Text content block.

37

38

Represents plain text in a message. This is the most common content

39

block type for normal conversation text.

40

41

Attributes:

42

text: The text content

43

"""

44

45

text: str

46

"""Text content.

47

48

The plain text content of this block. Can be a single word, sentence,

49

paragraph, or longer text.

50

51

Examples:

52

"Hello, how can I help you?"

53

"To solve this problem, we need to..."

54

"The result is 42."

55

"""

56

```

57

58

### ThinkingBlock

59

60

Extended thinking content from Claude.

61

62

```python { .api }

63

@dataclass

64

class ThinkingBlock:

65

"""

66

Thinking content block.

67

68

Represents extended thinking from Claude when using models with

69

thinking capabilities (like Claude Opus with extended thinking enabled).

70

This shows Claude's internal reasoning process.

71

72

Attributes:

73

thinking: The thinking content

74

signature: Digital signature for the thinking block

75

"""

76

77

thinking: str

78

"""Thinking content.

79

80

Claude's internal reasoning and thought process. This text shows how

81

Claude is analyzing the problem, considering options, and planning

82

its response.

83

84

Example:

85

"Let me think through this step by step. First, I need to

86

understand what the user is asking. They want to know about...

87

I should consider... The best approach would be..."

88

"""

89

90

signature: str

91

"""Digital signature.

92

93

Cryptographic signature that verifies the authenticity of the thinking

94

content. Ensures the thinking wasn't modified after generation.

95

"""

96

```

97

98

### ToolUseBlock

99

100

Request from Claude to execute a tool.

101

102

```python { .api }

103

@dataclass

104

class ToolUseBlock:

105

"""

106

Tool use content block.

107

108

Represents a request from Claude to execute a tool. When Claude needs

109

to perform an action like reading a file or running a command, it

110

generates a ToolUseBlock with the tool name and input parameters.

111

112

The SDK or CLI handles executing the tool and providing results back

113

to Claude via ToolResultBlock.

114

115

Attributes:

116

id: Unique identifier for this tool use

117

name: Name of the tool to execute

118

input: Input parameters for the tool

119

"""

120

121

id: str

122

"""Unique tool use identifier.

123

124

A unique ID for this specific tool execution. Used to match tool

125

uses with their results (ToolResultBlock.tool_use_id).

126

127

Example: "toolu_01A2B3C4D5E6F7G8H9I0J1K2"

128

"""

129

130

name: str

131

"""Tool name.

132

133

The name of the tool Claude wants to execute. This matches tool

134

names from the allowed_tools configuration or MCP server tools.

135

136

Examples:

137

"Read" - Read a file

138

"Write" - Write a file

139

"Bash" - Execute a bash command

140

"Grep" - Search files

141

"custom_tool" - Your custom MCP tool

142

"""

143

144

input: dict[str, Any]

145

"""Tool input parameters.

146

147

Dictionary of parameters to pass to the tool. Structure varies by

148

tool type.

149

150

Examples:

151

{"file_path": "/home/user/file.txt"} # Read tool

152

{"command": "ls -la"} # Bash tool

153

{"pattern": "TODO", "path": "./src"} # Grep tool

154

"""

155

```

156

157

### ToolResultBlock

158

159

Result from executing a tool.

160

161

```python { .api }

162

@dataclass

163

class ToolResultBlock:

164

"""

165

Tool result content block.

166

167

Contains the result of a tool execution. After Claude requests a tool

168

use via ToolUseBlock, the SDK executes the tool and provides results

169

back to Claude in a ToolResultBlock.

170

171

Attributes:

172

tool_use_id: ID of the tool use this is a result for

173

content: The result content

174

is_error: Whether the tool execution resulted in an error

175

"""

176

177

tool_use_id: str

178

"""Tool use identifier.

179

180

The ID of the ToolUseBlock this result corresponds to. Used to match

181

results with their requests.

182

183

Example: "toolu_01A2B3C4D5E6F7G8H9I0J1K2"

184

"""

185

186

content: str | list[dict[str, Any]] | None = None

187

"""Result content.

188

189

The output from the tool execution. Can be:

190

- A string for simple text results

191

- A list of content dictionaries for rich content

192

- None if the tool produced no output

193

194

Examples:

195

"File contents: Hello World"

196

[{"type": "text", "text": "Success"}]

197

None

198

"""

199

200

is_error: bool | None = None

201

"""Error flag.

202

203

Indicates whether the tool execution resulted in an error:

204

- True: Tool execution failed

205

- False: Tool execution succeeded

206

- None: Error status not specified (usually means success)

207

208

When True, the content typically contains error details.

209

"""

210

```

211

212

## Usage Examples

213

214

### Extracting Text from Messages

215

216

```python

217

from claude_agent_sdk import query, AssistantMessage, TextBlock

218

219

async for msg in query(prompt="Explain Python"):

220

if isinstance(msg, AssistantMessage):

221

for block in msg.content:

222

if isinstance(block, TextBlock):

223

print(block.text)

224

```

225

226

### Handling All Block Types

227

228

```python

229

from claude_agent_sdk import (

230

query, AssistantMessage, TextBlock, ThinkingBlock,

231

ToolUseBlock, ToolResultBlock, ClaudeAgentOptions

232

)

233

234

options = ClaudeAgentOptions(allowed_tools=["Read", "Bash"])

235

236

async for msg in query(prompt="Analyze this project", options=options):

237

if isinstance(msg, AssistantMessage):

238

for block in msg.content:

239

if isinstance(block, TextBlock):

240

print(f"[Text] {block.text}")

241

242

elif isinstance(block, ThinkingBlock):

243

print(f"[Thinking] {block.thinking}")

244

245

elif isinstance(block, ToolUseBlock):

246

print(f"[Tool Use] {block.name}: {block.input}")

247

248

elif isinstance(block, ToolResultBlock):

249

error_status = " (ERROR)" if block.is_error else ""

250

print(f"[Tool Result{error_status}] {block.content}")

251

```

252

253

### Collecting Text Content

254

255

```python

256

from claude_agent_sdk import query, AssistantMessage, TextBlock

257

258

all_text = []

259

260

async for msg in query(prompt="Write a story"):

261

if isinstance(msg, AssistantMessage):

262

for block in msg.content:

263

if isinstance(block, TextBlock):

264

all_text.append(block.text)

265

266

full_response = "\n".join(all_text)

267

print(full_response)

268

```

269

270

### Monitoring Tool Usage

271

272

```python

273

from claude_agent_sdk import (

274

query, AssistantMessage, ToolUseBlock, ClaudeAgentOptions

275

)

276

277

options = ClaudeAgentOptions(allowed_tools=["Read", "Write", "Bash"])

278

279

tools_used = []

280

281

async for msg in query(prompt="Build a web server", options=options):

282

if isinstance(msg, AssistantMessage):

283

for block in msg.content:

284

if isinstance(block, ToolUseBlock):

285

tools_used.append({

286

"id": block.id,

287

"name": block.name,

288

"input": block.input

289

})

290

291

print(f"Claude used {len(tools_used)} tools:")

292

for tool in tools_used:

293

print(f" - {tool['name']}: {tool['input']}")

294

```

295

296

### Detecting Tool Errors

297

298

```python

299

from claude_agent_sdk import (

300

query, AssistantMessage, ToolResultBlock, ClaudeAgentOptions

301

)

302

303

options = ClaudeAgentOptions(allowed_tools=["Bash"])

304

305

async for msg in query(prompt="Run an invalid command", options=options):

306

if isinstance(msg, AssistantMessage):

307

for block in msg.content:

308

if isinstance(block, ToolResultBlock):

309

if block.is_error:

310

print(f"Error in tool {block.tool_use_id}:")

311

print(f" {block.content}")

312

```

313

314

### Building a Conversation Log

315

316

```python

317

from claude_agent_sdk import (

318

query, AssistantMessage, TextBlock, ToolUseBlock,

319

ToolResultBlock, ClaudeAgentOptions

320

)

321

322

options = ClaudeAgentOptions(allowed_tools=["Read"])

323

324

log = []

325

326

async for msg in query(prompt="Read config.json", options=options):

327

if isinstance(msg, AssistantMessage):

328

for block in msg.content:

329

if isinstance(block, TextBlock):

330

log.append({"type": "text", "content": block.text})

331

332

elif isinstance(block, ToolUseBlock):

333

log.append({

334

"type": "tool_use",

335

"tool": block.name,

336

"input": block.input

337

})

338

339

elif isinstance(block, ToolResultBlock):

340

log.append({

341

"type": "tool_result",

342

"content": block.content,

343

"error": block.is_error

344

})

345

346

# Display log

347

for entry in log:

348

print(f"{entry['type']}: {entry.get('content', entry.get('tool', ''))}")

349

```

350

351

### Filtering by Block Type

352

353

```python

354

from claude_agent_sdk import (

355

query, AssistantMessage, TextBlock, ToolUseBlock

356

)

357

358

text_blocks = []

359

tool_blocks = []

360

361

async for msg in query(prompt="Analyze files"):

362

if isinstance(msg, AssistantMessage):

363

text_blocks.extend([b for b in msg.content if isinstance(b, TextBlock)])

364

tool_blocks.extend([b for b in msg.content if isinstance(b, ToolUseBlock)])

365

366

print(f"Text blocks: {len(text_blocks)}")

367

print(f"Tool blocks: {len(tool_blocks)}")

368

```

369

370

### Extracting Thinking Content

371

372

```python

373

from claude_agent_sdk import (

374

query, AssistantMessage, ThinkingBlock, ClaudeAgentOptions

375

)

376

377

# Note: Thinking blocks require extended thinking enabled

378

options = ClaudeAgentOptions(

379

model="claude-opus-4-20250514" # Model with extended thinking

380

)

381

382

async for msg in query(prompt="Solve this complex problem", options=options):

383

if isinstance(msg, AssistantMessage):

384

for block in msg.content:

385

if isinstance(block, ThinkingBlock):

386

print("=== Claude's Thinking Process ===")

387

print(block.thinking)

388

print(f"Signature: {block.signature[:50]}...")

389

```

390

391

### Tool Use Chain Analysis

392

393

```python

394

from claude_agent_sdk import (

395

query, AssistantMessage, ToolUseBlock, ToolResultBlock,

396

ClaudeAgentOptions

397

)

398

399

options = ClaudeAgentOptions(allowed_tools=["Read", "Write", "Bash"])

400

401

tool_chain = []

402

403

async for msg in query(prompt="Create and test a script", options=options):

404

if isinstance(msg, AssistantMessage):

405

for block in msg.content:

406

if isinstance(block, ToolUseBlock):

407

tool_chain.append({

408

"id": block.id,

409

"type": "use",

410

"name": block.name,

411

"input": block.input

412

})

413

414

elif isinstance(block, ToolResultBlock):

415

# Find the matching tool use

416

for entry in tool_chain:

417

if entry["id"] == block.tool_use_id and entry["type"] == "use":

418

entry["result"] = block.content

419

entry["error"] = block.is_error

420

break

421

422

# Display tool chain

423

print("Tool Execution Chain:")

424

for i, entry in enumerate(tool_chain, 1):

425

if entry["type"] == "use":

426

status = "ERROR" if entry.get("error") else "SUCCESS"

427

print(f"{i}. {entry['name']} [{status}]")

428

print(f" Input: {entry['input']}")

429

if "result" in entry:

430

result_preview = str(entry["result"])[:100]

431

print(f" Result: {result_preview}...")

432

```

433

434

### Content Block Statistics

435

436

```python

437

from claude_agent_sdk import (

438

query, AssistantMessage, TextBlock, ThinkingBlock,

439

ToolUseBlock, ToolResultBlock

440

)

441

442

stats = {

443

"text": 0,

444

"thinking": 0,

445

"tool_use": 0,

446

"tool_result": 0

447

}

448

449

async for msg in query(prompt="Complex task"):

450

if isinstance(msg, AssistantMessage):

451

for block in msg.content:

452

if isinstance(block, TextBlock):

453

stats["text"] += 1

454

elif isinstance(block, ThinkingBlock):

455

stats["thinking"] += 1

456

elif isinstance(block, ToolUseBlock):

457

stats["tool_use"] += 1

458

elif isinstance(block, ToolResultBlock):

459

stats["tool_result"] += 1

460

461

print("Content Block Statistics:")

462

for block_type, count in stats.items():

463

print(f" {block_type}: {count}")

464

```

465

466

### Rich Content Handling

467

468

```python

469

from claude_agent_sdk import query, AssistantMessage, ToolResultBlock

470

471

async for msg in query(prompt="Task with rich output"):

472

if isinstance(msg, AssistantMessage):

473

for block in msg.content:

474

if isinstance(block, ToolResultBlock):

475

content = block.content

476

477

# Handle different content types

478

if isinstance(content, str):

479

print(f"Text result: {content}")

480

481

elif isinstance(content, list):

482

print("Rich content result:")

483

for item in content:

484

if isinstance(item, dict):

485

item_type = item.get("type", "unknown")

486

print(f" - Type: {item_type}")

487

if item_type == "text":

488

print(f" Text: {item.get('text', '')}")

489

490

elif content is None:

491

print("No output from tool")

492

```

493

494

### Tool Input Analysis

495

496

```python

497

from claude_agent_sdk import (

498

query, AssistantMessage, ToolUseBlock, ClaudeAgentOptions

499

)

500

501

options = ClaudeAgentOptions(allowed_tools=["Bash", "Read", "Write"])

502

503

tool_inputs = {}

504

505

async for msg in query(prompt="Work on this project", options=options):

506

if isinstance(msg, AssistantMessage):

507

for block in msg.content:

508

if isinstance(block, ToolUseBlock):

509

if block.name not in tool_inputs:

510

tool_inputs[block.name] = []

511

512

tool_inputs[block.name].append(block.input)

513

514

print("Tool Input Analysis:")

515

for tool_name, inputs in tool_inputs.items():

516

print(f"\n{tool_name} ({len(inputs)} uses):")

517

for i, input_data in enumerate(inputs, 1):

518

print(f" {i}. {input_data}")

519

```

520

521

### Separating Text and Actions

522

523

```python

524

from claude_agent_sdk import (

525

query, AssistantMessage, TextBlock, ToolUseBlock,

526

ClaudeAgentOptions

527

)

528

529

options = ClaudeAgentOptions(allowed_tools=["Read", "Write"])

530

531

explanations = []

532

actions = []

533

534

async for msg in query(prompt="Fix this bug", options=options):

535

if isinstance(msg, AssistantMessage):

536

for block in msg.content:

537

if isinstance(block, TextBlock):

538

explanations.append(block.text)

539

540

elif isinstance(block, ToolUseBlock):

541

actions.append(f"{block.name}: {block.input}")

542

543

print("=== What Claude Said ===")

544

print("\n".join(explanations))

545

546

print("\n=== What Claude Did ===")

547

print("\n".join(actions))

548

```

549

550

### Error Recovery Pattern

551

552

```python

553

from claude_agent_sdk import (

554

query, AssistantMessage, ToolUseBlock, ToolResultBlock,

555

ClaudeAgentOptions

556

)

557

558

options = ClaudeAgentOptions(allowed_tools=["Bash"])

559

560

current_tool_use = None

561

562

async for msg in query(prompt="Try a command", options=options):

563

if isinstance(msg, AssistantMessage):

564

for block in msg.content:

565

if isinstance(block, ToolUseBlock):

566

current_tool_use = block

567

print(f"Attempting: {block.name} with {block.input}")

568

569

elif isinstance(block, ToolResultBlock):

570

if block.is_error and current_tool_use:

571

print(f"Failed: {current_tool_use.name}")

572

print(f"Error: {block.content}")

573

print("Claude will likely try an alternative...")

574

elif current_tool_use:

575

print(f"Success: {current_tool_use.name}")

576

577

current_tool_use = None

578

```

579

580

### Block Type Distribution

581

582

```python

583

from claude_agent_sdk import (

584

query, AssistantMessage, TextBlock, ThinkingBlock,

585

ToolUseBlock, ToolResultBlock

586

)

587

588

def get_block_type_name(block):

589

if isinstance(block, TextBlock):

590

return "text"

591

elif isinstance(block, ThinkingBlock):

592

return "thinking"

593

elif isinstance(block, ToolUseBlock):

594

return "tool_use"

595

elif isinstance(block, ToolResultBlock):

596

return "tool_result"

597

else:

598

return "unknown"

599

600

block_sequence = []

601

602

async for msg in query(prompt="Multi-step task"):

603

if isinstance(msg, AssistantMessage):

604

for block in msg.content:

605

block_sequence.append(get_block_type_name(block))

606

607

print("Block sequence:")

608

print(" -> ".join(block_sequence))

609

```

610