Content Block
APIDefinition
The structured units that make up Claude's response. Types include: `text` (plain text response), `tool_use` (a request to call a tool with specific inputs), `tool_result` (the caller's response to a tool request), and `thinking` (internal reasoning when extended thinking is enabled). A single response can contain multiple content blocks of mixed types.
Example Usage
Iterate over response.content to process each block: text blocks go to the user, tool_use blocks trigger function calls.
Why It Matters for the CCA-F Exam
The exam tests block type recognition, correct `tool_use` → `tool_result` round-trip mechanics (especially the `tool_use_id` linkage), and proper handling of parallel tool calls within a single response. Candidates should know that `thinking` blocks are present in the content array and count toward context window usage in subsequent turns.
In Depth
Every Claude response is composed of one or more content blocks — typed, structured units inside the response.content array. Rather than treating the response as a flat string, the API requires you to iterate over this array and dispatch based on each block's type field. This design makes tool orchestration, thinking display, and mixed-media responses unambiguous.
Block Types
text — Plain markdown or natural language output. The text field holds the string. Most responses that don't involve tools contain exactly one text block, but there can be multiple (for example, before and after a tool_use block in the same turn).
tool_use — Claude is requesting a function call. Fields: id (unique per block, used for response routing), name (which tool), and input (a JSON object matching the tool's schema). Always parse input as structured JSON — never string-match the serialized form. You must return a tool_result block in the next user message with tool_use_id matching this block's id. For the full round-trip mechanics, see tool_use.
thinking — Present only when extended thinking is enabled via thinking: {type: "adaptive"}. Contains the model's internal reasoning. On claude-fable-5, claude-opus-4-8, and claude-opus-4-7, the default display: "omitted" means this field is empty even though reasoning cost was still incurred. Thinking blocks count toward context window usage in subsequent turns.
tool_result — The block type you construct and send back in a user message to close the tool round-trip. It is not returned by Claude; it is what your code adds to messages.
Processing Pattern
Robust Claude integrations always iterate response.content rather than assuming response.content[0].text is safe. A single response might contain a thinking block followed by a tool_use block with no text block at all.
For parallel tool use, a single response can contain multiple tool_use blocks. You collect all their results and return them in one user message — each as a separate tool_result block. Sending results one at a time breaks the turn structure and causes errors.
Streaming Index Tracking
Content blocks that arrive via streaming carry an index field matching their position in the final content array. Track blocks by index, not by arrival order, when parsing SSE deltas — a content_block_delta event's index tells you which block it extends.
How It Compares
| Block type | Who creates it | Key field | Round-trip requirement |
|---|---|---|---|
text | Claude | text (string) | None |
tool_use | Claude | id, name, input (JSON) | Return tool_result with matching tool_use_id |
thinking | Claude (extended thinking only) | thinking (string) | None — include block as-is when forwarding conversation history |
tool_result | Your code | tool_use_id, content | Sent in user message; not a Claude response type |
Example
Iterating `response.content` by type and returning all `tool_result` blocks in a single user message — the correct pattern for content block handling.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
tools=[
{
"name": "get_weather",
"description": "Get current temperature for a city",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
],
messages=[{"role": "user", "content": "What is the weather in Tokyo?"}]
)
tool_results = []
for block in response.content:
if block.type == "text":
print("Text:", block.text)
elif block.type == "tool_use":
print(f"Tool call: {block.name}({block.input})")
result = {"temperature": "22C", "condition": "Sunny"}
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id, # Must match block.id exactly
"content": str(result)
})
# Return ALL tool results in one user message
if tool_results:
followup = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
tools=response.request.tools,
messages=[
{"role": "user", "content": "What is the weather in Tokyo?"},
{"role": "assistant", "content": response.content},
{"role": "user", "content": tool_results}
]
)
print(followup.content[0].text)Frequently Asked Questions
What happens if I return tool results in separate messages instead of one?
The API expects all `tool_result` blocks for a given assistant turn to arrive in a single user message. Sending them one at a time results in a message structure violation — typically a 400 error or unexpected model behavior where Claude doesn't have all the context it expects.
Does the order of content blocks in the response matter?
Yes, especially for thinking blocks. A `thinking` block always precedes the `text` or `tool_use` block it corresponds to. When streaming, track blocks by their `index` field from `content_block_start` events rather than assuming sequential types.