Sweep 22 Sep 2026 · 17:19Z Build v2.1.280 501 read Stable v2.1.267 Latest v2.1.280 Next v2.1.280 Feeds RSS JSON llms.txt Unofficial
One change · api

thinking changed

build-with-claude/thinking

Nearest release: v2.1.261, published under an hour before this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Recorded here
Lines+13added
Lines−348removed
From line 1,006 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits11to this page, all time

### Only for the model that produced it, or a newer one ### Only in the conversation that produced it ### Controls for blocks that aren't preserved (beta)

The whole hunk

from line 1006, old and new numbered
/
lines
from line 1006
10061006 
10071007## Preserved thinking
10081008 
1009Claude preserves a thinking block, keeping it usable on later turns, only under the conditions it was created in. Starting with Claude Fable 5.1 and Claude Mythos 5.1, a `thinking` or `redacted_thinking` block is preserved only:
1009[Preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking) decides whether the model can use a thinking block that you send back from an earlier turn. Starting with Claude Fable 5.1, the API checks the `signature` of every `thinking` or `redacted_thinking` block in a request for two things:
10101010 
1011* **For the model that produced it, or a newer one.** An earlier model can't use the block, and the API drops it from that request. See [Only for the model that produced it, or a newer one](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-for-model).
1012* **In the conversation that produced it (Claude Fable 5.1 only).** If the `system` prompt, the `tools`, or any earlier message changes, the block is no longer valid, and the API rejects the request or drops the block. See [Only in the conversation that produced it](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-in-conversation).
1011* **The model that produced it.** A model reads its own thinking blocks and those of earlier models, never those of a newer model. Claude Fable 5.1 reads blocks from Claude Opus 5, but Claude Opus 5 can't read blocks from Claude Fable 5.1. The API drops a block the current model can't read, without an error and without billing it. See [Switching models mid-conversation](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#switching-models).
1012* **Everything sent before it.** A block stays valid only while the top-level `system` prompt, the `tools`, and the messages before it are unchanged. If any of them changes, that block and every later thinking block are invalid, and the API rejects the request with a 400 error or drops the invalid blocks, whichever you choose. See [Keeping the prefix unchanged](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#prefix-check).
10131013 
1014The block's `signature` records both conditions on both models. The API checks it whenever the block comes back in a later request, including a request to a different model; Claude Mythos 5.1 checks only the model condition.
1014The model check applies to every account. The API enforces the prefix check by default for accounts created on or after August 31, 2026, 00:00 UTC. On older accounts it enforces the check only on requests that set `thinking.block_binding.prefix_mismatch_behavior`. Later models will enforce it for all accounts, so make your integration append-only now.
10151015 
1016**Pass blocks back unchanged.** Send every assistant turn exactly as you received it, thinking blocks included, and let the API decide which blocks the model can use.
1016To keep thinking valid, send every assistant turn back exactly as you received it and add new messages only at the end of `messages`. If your code builds the `messages` array itself, the Preserved thinking page covers:
10171017 
1018### Only for the model that produced it, or a newer one
1019 
1020This condition is one-way: Claude Fable 5.1 and Claude Mythos 5.1 read earlier models' thinking blocks, and no earlier model reads theirs.
1021 
1022* **A conversation that moves onto Claude Fable 5.1 or Claude Mythos 5.1 keeps its reasoning.** The earlier model's thinking blocks stay readable, so the model thinks as usual from the first turn after the switch.
1023* **A conversation that moves from them to any earlier model loses it.** The earlier model can't read their blocks, the API drops them for that request, and the earlier model reasons again from the visible messages. If the conversation later returns to Claude Fable 5.1 with the same history, its own blocks are readable again.
1024 
1025In full, Claude Fable 5.1 and Claude Mythos 5.1 read thinking blocks produced by each other, by Claude Opus 5, Claude Fable 5, and Claude Mythos 5, and by Claude Opus 4.8 and earlier Opus models, Claude Sonnet models, and Claude Haiku 4.5. No model other than these two can read a block produced by Claude Fable 5.1 or Claude Mythos 5.1.
1026 
1027**A block the receiving model can't read is dropped.** The API removes it before the prompt reaches the model. It doesn't count toward `input_tokens` and isn't billed. When you fall back from Claude Fable 5.1 to an older model mid-conversation, for example after a [classifier refusal fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback), the older model reasons again from the visible conversation. With the [controls beta header](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-thinking-controls) the drop is reported in `input_transformations` as `model_binding_mismatch`. Without it the drop is silent. A [server-side fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#server-side-fallback) drops unreadable blocks the same way.
1028 
1029### Only in the conversation that produced it
1030 
1031A thinking block from Claude Fable 5.1 is preserved only while the conversation prefix it was produced from stays unchanged. Its `signature` covers the `system` prompt, the `tools`, and the messages that preceded the block. Claude Mythos 5.1 records the same `signature` but doesn't run this check.
1032 
1033This check is enforced for new accounts created on or after August 31, 2026. For accounts created earlier, the API records the condition in the signature but doesn't act on a mismatch unless the request sets [`thinking.block_binding.prefix_mismatch_behavior`](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-thinking-controls), which opts into enforcement. Anthropic plans to enforce this condition for every organization on future models. If your account was created earlier, make your application compatible now: the same append-only patterns keep the [prompt cache](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) warm, and you can test against the check by sending `prefix_mismatch_behavior: "error"`. If you ship a tool or framework that people run with their own API key, test that way: your users on new accounts are enforced before you are. [Preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking) has the integration checklist: how to tell whether your code edits history, and the API feature that replaces each kind of edit.
1034 
1035Where the check is enforced, a request that replays a block against a changed prefix is rejected with a 400 `invalid_request_error`:
1036 
1037```text wrap
1038messages.5.content.0: Invalid `signature` in `thinking` block. The block is bound to a different conversation. Remove the block, or set `thinking.block_binding.prefix_mismatch_behavior` to "drop_block". That setting requires the `thinking-binding-controls-2026-08-01` value in the `anthropic-beta` header.
1039```
1040 
1041The last sentence appears only when the request didn't send the beta header. The message can end with one more sentence naming the first message that changed. Retrying the same request body fails the same way. To continue without the invalidated reasoning instead, send the `thinking-binding-controls-2026-08-01` beta header and set `prefix_mismatch_behavior` to `"drop_block"`. The API then drops the failing block and every thinking block after it in the conversation, and reports each one in `input_transformations` as `prefix_binding_mismatch`. The [token counting](https://platform.claude.com/docs/en/build-with-claude/token-counting) endpoint runs the same check and returns the same 400.
1042 
1043What invalidates later thinking blocks:
1044 
1045* Editing, reordering, or removing an earlier message, including removing a per-turn reminder you injected into an earlier user turn.
1046* Changing the content of the top-level `system` prompt, or adding, removing, or editing a tool in the `tools` array, between requests.
1047* Client-side compaction or truncation that keeps recent assistant turns verbatim, thinking included, while rewriting the turns before them.
1048* An image or document URL in an earlier turn that serves different bytes on a later request. The check covers the bytes, not the URL string, so a rotating signed URL for the same file is fine. For content you reference across turns, upload it once with the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) and send the `file_id`, or send base64.
1049 
1050What doesn't:
1051 
1052* Removing a leading run of thinking blocks, oldest first: the first thinking block in the conversation (or the first one after the most recent compaction block), then the next, and so on. Removing a thinking block from anywhere else invalidates every thinking block after it, in that turn and in every later turn.
1053* Changing `output_config.effort`, `max_tokens`, or other sampling settings between requests.
1054* `cache_control` markers, wherever you place or move them.
1055* Server-side [compaction](https://platform.claude.com/docs/en/build-with-claude/compaction) and [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing): they don't count as edits, because the check compares the conversation as you sent it, not the server's edited copy. After a compaction, the checked prefix starts from the compaction block.
1056 
1057Patterns that keep thinking blocks valid:
1058 
1059* **Append only.** Add new messages at the end of `messages` and leave earlier turns byte-for-byte unchanged.
1060* **Use [mid-conversation system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages)** and mid-conversation tool changes to add instructions or change tool availability partway through, instead of editing the top-level `system` field or `tools` array. For a reminder that should apply to one turn only, send it as a [turn-scoped system message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages) and leave it in the history rather than deleting it later. This also preserves the prompt cache.
1061* **Use server-side context management** rather than trimming history yourself.
1062* **If a request is rejected for a prefix mismatch and you can't repair the history,** resend it with the beta header and `prefix_mismatch_behavior: "drop_block"`, or strip every `thinking` and `redacted_thinking` block from the history and retry once.
1063 
1064When earlier thinking is dropped, the model answers that turn without those blocks. A client that repeatedly invalidates its own history restarts the prompt cache each time, which raises cost.
1065 
1066**Client-side compaction.** This check doesn't rule out compacting on the client. The rule is narrower: don't keep a thinking block behind a prefix you've rewritten. Server-side [compaction](https://platform.claude.com/docs/en/build-with-claude/compaction) is the simplest way to satisfy it. If you compact on the client, use one of these shapes:
1067 
1068* **Simple compaction (recommended):** summarize the conversation into one message and start the next request with that summary plus the new user turn, replaying no earlier turns and no earlier thinking blocks. No earlier thinking remains, so nothing fails, and the model thinks afresh on the compacted conversation. Claude models are trained on long-horizon tasks with this scheme, and it performs comparably to more elaborate ones for most workloads. It resets the prompt cache, as any compaction does.
1069* **Keep-tail compaction:** summarize older turns and keep the most recent turns verbatim. The kept turns' thinking blocks were produced against the full history and fail behind the summary. Strip `thinking` and `redacted_thinking` from every turn you carry across (their text and tool calls can stay), or set `prefix_mismatch_behavior: "drop_block"` and let the API discard them.
1070* **Background compaction:** build the summary off the critical path and swap it in while the conversation continues. Every turn produced in the meantime has thinking that predates the swap. Send `"drop_block"` on every request that still carries thinking blocks produced before the swap (or strip those blocks yourself; `input_transformations` on the first response after the swap lists exactly which ones), or compact synchronously.
1071 
1072Snipping individual turns out of the middle of the transcript invalidates every thinking block after them, and no client-side shape avoids that. Use a mid-conversation system message for the instruction change you were making, or server-side [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing) for selective removal.
1073 
1074### Controls for blocks that aren't preserved (beta)
1075 
1076Send the [beta header](https://platform.claude.com/docs/en/api/beta-headers) `thinking-binding-controls-2026-08-01` to get two things: an `input_transformations` array on every response that lists any thinking blocks the API dropped, and a `block_binding` object on the thinking configuration with one field.
1077 
1078| Field | Type | Default | Description |
1079| -------------------------- | --------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1080| `prefix_mismatch_behavior` | `"error"` or `"drop_block"` | `"error"` | What the API does with a thinking block that fails the [conversation check](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-in-conversation). `"error"` rejects the request with a 400 error. `"drop_block"` removes the block and every later thinking block in the conversation, reports each in `input_transformations`, and continues. Neither value changes the model check, which always drops. |
1081 
1082`block_binding` is accepted alongside `thinking.type: "adaptive"` and `thinking.type: "enabled"`. Sending it without the beta header returns a 400 error. Models that don't run the conversation check accept the object and report only model-check drops, so one request body works across models. On Amazon Bedrock and Google Cloud, pass beta names as described in [Beta headers](https://platform.claude.com/docs/en/api/beta-headers).
1083 
1084The following request opts into dropping rather than rejecting. On a first turn there is nothing to replay, so `input_transformations` comes back empty:
1085 
1086<CodeGroup>
1087 ```bash cURL
1088 curl https://api.anthropic.com/v1/messages \
1089 -H "x-api-key: $ANTHROPIC_API_KEY" \
1090 -H "anthropic-version: 2023-06-01" \
1091 -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
1092 -H "content-type: application/json" \
1093 -d '{
1094 "model": "claude-fable-5-1",
1095 "max_tokens": 16000,
1096 "thinking": {
1097 "type": "adaptive",
1098 "block_binding": {
1099 "prefix_mismatch_behavior": "drop_block"
1100 }
1101 },
1102 "messages": [
1103 {
1104 "role": "user",
1105 "content": "What is the greatest common divisor of 1071 and 462?"
1106 }
1107 ]
1108 }'
1109 ```
1110 
1111 ```bash CLI
1112 ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
1113 --transform '{content.#(type=="text")#.text,input_transformations}' \
1114 --format yaml <<'YAML'
1115 model: claude-fable-5-1
1116 max_tokens: 16000
1117 thinking:
1118 type: adaptive
1119 block_binding:
1120 prefix_mismatch_behavior: drop_block
1121 messages:
1122 - role: user
1123 content: What is the greatest common divisor of 1071 and 462?
1124 YAML
1125 ```
1126 
1127 ```python Python
1128 client = anthropic.Anthropic()
1129 
1130 response = client.beta.messages.create(
1131 model="claude-fable-5-1",
1132 max_tokens=16000,
1133 thinking={
1134 "type": "adaptive",
1135 "block_binding": {"prefix_mismatch_behavior": "drop_block"},
1136 },
1137 messages=[
1138 {
1139 "role": "user",
1140 "content": "What is the greatest common divisor of 1071 and 462?",
1141 }
1142 ],
1143 betas=["thinking-binding-controls-2026-08-01"],
1144 )
1145 
1146 for block in response.content:
1147 if block.type == "text":
1148 print(block.text)
1149 
1150 print(f"Input transformations: {len(response.input_transformations or [])}")
1151 ```
1152 
1153 ```typescript TypeScript
1154 const client = new Anthropic();
1155 
1156 const response = await client.beta.messages.create({
1157 model: "claude-fable-5-1",
1158 max_tokens: 16000,
1159 thinking: {
1160 type: "adaptive",
1161 block_binding: { prefix_mismatch_behavior: "drop_block" }
1162 },
1163 messages: [
1164 { role: "user", content: "What is the greatest common divisor of 1071 and 462?" }
1165 ],
1166 betas: ["thinking-binding-controls-2026-08-01"]
1167 });
1168 
1169 for (const block of response.content) {
1170 if (block.type === "text") {
1171 console.log(block.text);
1172 }
1173 }
1174 console.log(`Input transformations: ${response.input_transformations?.length ?? 0}`);
1175 ```
1176 
1177 ```csharp C#
1178 
1179 AnthropicClient client = new();
1180 
1181 var response = await client.Beta.Messages.Create(
1182 new()
1183 {
1184 Model = "claude-fable-5-1",
1185 MaxTokens = 16000,
1186 Thinking = new BetaThinkingConfigAdaptive
1187 {
1188 BlockBinding = new()
1189 {
1190 PrefixMismatchBehavior = BetaThinkingPrefixMismatchBehavior.DropBlock,
1191 },
1192 },
1193 Messages =
1194 [
1195 new()
1196 {
1197 Role = Role.User,
1198 Content = "What is the greatest common divisor of 1071 and 462?",
1199 },
1200 ],
1201 Betas = [AnthropicBeta.ThinkingBindingControls2026_08_01],
1202 }
1203 );
1204 
1205 foreach (var block in response.Content)
1206 {
1207 if (block.TryPickText(out var textBlock))
1208 {
1209 Console.WriteLine(textBlock.Text);
1210 }
1211 }
1212 
1213 Console.WriteLine($"Input transformations: {response.InputTransformations?.Count ?? 0}");
1214 ```
1215 
1216 ```go Go
1217 client := anthropic.NewClient()
1218 
1219 response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
1220 Model: "claude-fable-5-1",
1221 MaxTokens: 16000,
1222 Thinking: anthropic.BetaThinkingConfigParamUnion{
1223 OfAdaptive: &anthropic.BetaThinkingConfigAdaptiveParam{
1224 BlockBinding: anthropic.BetaThinkingBlockBindingParam{
1225 PrefixMismatchBehavior: anthropic.BetaThinkingPrefixMismatchBehaviorDropBlock,
1226 },
1227 },
1228 },
1229 Messages: []anthropic.BetaMessageParam{
1230 anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("What is the greatest common divisor of 1071 and 462?")),
1231 },
1232 Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaThinkingBindingControls2026_08_01},
1233 })
1234 if err != nil {
1235 log.Fatal(err)
1236 }
1237 
1238 for _, block := range response.Content {
1239 if textBlock, ok := block.AsAny().(anthropic.BetaTextBlock); ok {
1240 fmt.Println(textBlock.Text)
1241 }
1242 }
1243 fmt.Printf("Input transformations: %d\n", len(response.InputTransformations))
1244 ```
1245 
1246 ```java Java
1247 import com.anthropic.models.beta.AnthropicBeta;
1248 import com.anthropic.models.beta.messages.BetaMessage;
1249 import com.anthropic.models.beta.messages.BetaThinkingBlockBinding;
1250 import com.anthropic.models.beta.messages.BetaThinkingConfigAdaptive;
1251 import com.anthropic.models.beta.messages.BetaThinkingPrefixMismatchBehavior;
1252 import com.anthropic.models.beta.messages.MessageCreateParams;
1253 
1254 void main() {
1255 AnthropicClient client = AnthropicOkHttpClient.fromEnv();
1256 
1257 MessageCreateParams params = MessageCreateParams.builder()
1258 .model("claude-fable-5-1")
1259 .maxTokens(16000L)
1260 .addBeta(AnthropicBeta.THINKING_BINDING_CONTROLS_2026_08_01)
1261 .thinking(BetaThinkingConfigAdaptive.builder()
1262 .blockBinding(BetaThinkingBlockBinding.builder()
1263 .prefixMismatchBehavior(BetaThinkingPrefixMismatchBehavior.DROP_BLOCK)
1264 .build())
1265 .build())
1266 .addUserMessage("What is the greatest common divisor of 1071 and 462?")
1267 .build();
1268 
1269 BetaMessage response = client.beta().messages().create(params);
1270 
1271 response.content().stream()
1272 .flatMap(block -> block.text().stream())
1273 .forEach(textBlock -> IO.println(textBlock.text()));
1274 IO.println("Input transformations: "
1275 + response.inputTransformations().map(List::size).orElse(0));
1276 }
1277 ```
1278 
1279 ```php PHP
1280 use Anthropic\Beta\AnthropicBeta;
1281 use Anthropic\Beta\Messages\BetaThinkingBlockBinding;
1282 use Anthropic\Beta\Messages\BetaThinkingConfigAdaptive;
1283 use Anthropic\Beta\Messages\BetaThinkingPrefixMismatchBehavior;
1284 use Anthropic\Client;
1285 
1286 $client = new Client();
1287 
1288 $response = $client->beta->messages->create(
1289 model: 'claude-fable-5-1',
1290 maxTokens: 16000,
1291 thinking: BetaThinkingConfigAdaptive::with(
1292 blockBinding: BetaThinkingBlockBinding::with(
1293 prefixMismatchBehavior: BetaThinkingPrefixMismatchBehavior::DROP_BLOCK,
1294 ),
1295 ),
1296 messages: [
1297 ['role' => 'user', 'content' => 'What is the greatest common divisor of 1071 and 462?'],
1298 ],
1299 betas: [AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01],
1300 );
1301 
1302 foreach ($response->content as $block) {
1303 if ($block->type === 'text') {
1304 echo $block->text, PHP_EOL;
1305 }
1306 }
1307 
1308 echo 'Input transformations: ', count($response->inputTransformations ?? []), PHP_EOL;
1309 ```
1310 
1311 ```ruby Ruby
1312 client = Anthropic::Client.new
1313 
1314 response = client.beta.messages.create(
1315 model: "claude-fable-5-1",
1316 max_tokens: 16_000,
1317 thinking: {
1318 type: "adaptive",
1319 block_binding: {prefix_mismatch_behavior: "drop_block"}
1320 },
1321 messages: [
1322 {role: "user", content: "What is the greatest common divisor of 1071 and 462?"}
1323 ],
1324 betas: [Anthropic::AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01]
1325 )
1326 
1327 response.content.each do |block|
1328 puts block.text if block.type == :text
1329 end
1330 
1331 puts "Input transformations: #{response.input_transformations&.length || 0}"
1332 ```
1333</CodeGroup>
1334 
1335```text Output wrap
1336The greatest common divisor of 1071 and 462 is 21.
1337Input transformations: 0
1338```
1339 
1340**Dropped blocks are reported in `input_transformations`.** Under the beta header, every response from a thinking-capable model carries this top-level array. It's empty when nothing was dropped and never `null`. Each entry names the position of a dropped block and the check it failed:
1341 
1342```json
1343{
1344 "input_transformations": [
1345 {
1346 "type": "thinking_dropped",
1347 "path": "messages.1.content.0",
1348 "reason": "model_binding_mismatch"
1349 }
1350 ]
1351}
1352```
1353 
1354The `reason` field is `model_binding_mismatch` or `prefix_binding_mismatch`. Ignore entries whose `type` or `reason` you don't recognize, because later checks add values. When [streaming](https://platform.claude.com/docs/en/build-with-claude/streaming), `input_transformations` arrives on the `message` object in the `message_start` event. After a mid-stream server-side fallback, the final `message_delta` event carries the array again with the serving model's entries. Without the beta header the field is absent.
1355 
1356A tampered or undecryptable signature is a different failure: it always returns a 400 (``Invalid `signature` in `thinking` block``, with no reason clause) and `prefix_mismatch_behavior` doesn't apply to it. In a [message batch](https://platform.claude.com/docs/en/build-with-claude/batch-processing), an item whose block fails the conversation check under `"error"` resolves as `errored`.
1018* [What counts as an edit](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#what-counts-as-an-edit), and [how to check whether your code makes one](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#how-to-tell-whether-your-integration-is-impacted).
1019* [The API feature that replaces each common edit](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#replace-prefix-edits): mid-conversation system messages for new instructions and per-turn reminders, `tool_addition` and `tool_removal` blocks for tool changes, per-message `output_config` for effort changes, and server-side compaction and context editing for trimming.
1020* [Client-side compaction](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#custom-compaction-on-the-client): which patterns keep thinking valid and which don't.
1021* [The `thinking-binding-controls-2026-08-01` beta header](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#preserved-thinking-controls). It adds an `input_transformations` array to every response that lists the blocks the API dropped, and a `block_binding.prefix_mismatch_behavior` field on the thinking configuration that accepts `"error"` or `"drop_block"`.
13571022 
13581023## Thinking and prompt caching
13591024