Read Thinking Blocks
What Comes Back When Claude Thinks
When thinking is enabled, a response contains more than text. Its content list holds thinking blocks before the text, and sometimes before the tool calls too. Each thinking block carries the reasoning Claude produced, along with a signature, a value that identifies the block and lets the API verify it later. Reading these blocks correctly is the difference between an application that shows users a clean answer and one that breaks the moment a tool is involved.
This lesson explains the structure of a thinking block, the two display settings that control what text it contains, how to separate thinking from answers in code, and why the blocks must be passed back unchanged. The rule about passing blocks back is the one that breaks most often, so it gets the most attention.
The Shape of a Thinking Block
A thinking block is an object with a type and two main fields:
{
"type": "thinking",
"thinking": "The user asks whether 1,001 is prime. 1,001 = 7 × 11 × 13...",
"signature": "EqQBCgIYAhIM...",
}
| Field | Meaning |
|---|---|
type | Always "thinking" for reasoning blocks |
thinking | The reasoning text, or a summary of it, depending on the display setting |
signature | An opaque value that authenticates the block, and must be preserved |
The signature is not for display or for your logic. Its only purpose is to let the API confirm that a thinking block is genuine when it is returned in a later request. A block whose signature is missing or altered cannot be used in a continuation, and this is why the rule about passing blocks back is strict.
Two Display Settings
Thinking text can be returned in more than one form, controlled by the display setting inside the thinking object:
| Display | What the thinking block contains | When to use it |
|---|---|---|
summarized | A summary of the reasoning | Showing reasoning to people, or logging it for review |
omitted | An empty thinking field, with only the signature | Keeping the signature for continuations, without exposing the reasoning text |
The omitted form keeps everything the API needs, and drops the text. An application that never shows reasoning, but must continue tool conversations, can use it to reduce the amount of text it stores and transmits. The documentation describes the exact default for each model, and that default should be confirmed rather than assumed.
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
thinking={"type": "adaptive", "display": "summarized"},
messages=[{"role": "user", "content": "Is 1,001 prime?"}],
)
Separating Reasoning from Answers
Because thinking blocks come first, the simplest mistake is to take the first block and assume it is text. The correct approach selects blocks by type, as Lesson 42 recommended. The helper below separates a content list into its parts, and reports how many thinking blocks it found:
"""thinking_blocks.py: separate reasoning, text, and tool calls from a response's content."""
def split_content(content: list[dict]) -> dict:
parts = {"thinking": [], "text": [], "tool_use": [], "signatures": []}
for block in content:
kind = block.get("type")
if kind == "thinking":
parts["thinking"].append(block.get("thinking", ""))
parts["signatures"].append(block.get("signature"))
elif kind == "text":
parts["text"].append(block.get("text", ""))
elif kind == "tool_use":
parts["tool_use"].append(block.get("name"))
return parts
if __name__ == "__main__":
content = [
{"type": "thinking", "thinking": "1,001 = 7 x 11 x 13, so it is not prime.",
"signature": "sig-a"},
{"type": "text", "text": "No, 1,001 is not prime."},
]
parts = split_content(content)
print("thinking blocks:", len(parts["thinking"]))
print("answer:", "".join(parts["text"]))
print("signatures kept:", parts["signatures"])
Output:
thinking blocks: 1
answer: No, 1,001 is not prime.
signatures kept: ['sig-a']
How It Works
- Blocks are selected by type, not by position. The thinking block is first in the list, but the code would find the text correctly even if the order changed.
- The reasoning and the signature are kept separately. The text can be logged or displayed, and the signature is retained for any later continuation.
- The answer is assembled from text blocks only, which is what the user should see. The reasoning is not mixed into the reply.
- The function returns a dictionary of lists, so a response with several thinking blocks, which can occur around tool calls, is handled without special cases.
Passing Blocks Back Unchanged
The rule that matters most is this: when a conversation continues after a tool call, the assistant's thinking blocks must be sent back exactly as they were received. The documentation is explicit that thinking blocks carry the reasoning behind tool calls, and that they should be returned unmodified, with their signatures intact.
messages.append({"role": "assistant", "content": response.content}) # The whole content, untouched
messages.append({"role": "user", "content": [tool_result_block]})
The mistake to avoid is rebuilding the assistant message from its text alone, or editing the thinking text, or dropping the blocks to save tokens. Each of those changes the content the API verified, and the continuation fails or behaves unpredictably. The safe pattern appends the response's content as received, which is the same practice Lesson 88 introduced for tool loops.
The documentation also notes that thinking is interleaved with tool use automatically on adaptive thinking, so a single assistant turn can contain thinking blocks around several tool calls. Passing the full content back preserves that structure.
Thinking and Caching
Thinking blocks interact with prompt caching in two ways. They cannot be marked with a cache breakpoint directly, but they can be cached as part of earlier assistant turns in a conversation. When a cached thinking block is read back, it counts as input tokens, so it contributes to cost like any other input. Changing the thinking configuration between requests invalidates cached message prefixes, as Lesson 127 described, so a conversation should keep its thinking settings steady.
Keeping Reasoning Private
Reasoning text can contain material that should not reach every user, such as internal notes, sensitive data that Claude considered, or wording that is confusing out of context. Displaying the summarized reasoning is a product decision, and the safest default is to show only the answer. When reasoning is shown, the application should label it as reasoning and present it with the same care as any other model output, and it should be logged according to the policy in Lesson 147.
Summary
A thinking block carries reasoning text, controlled by the display setting, and a signature that the API uses to verify it. Blocks come before the text, so code must select them by type. The display setting trades visibility of reasoning against the size of stored content, while the signature must always survive. Passing the assistant's content back unchanged is the rule that keeps tool conversations valid. The next lesson moves to a tool that changes how Claude finds the tools it needs.