preserved-thinking changedbuild-with-claude/preserved-thinking
Nearest release: v2.1.304, published under an hour after 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+25added
Lines−224removed
From line
457
where the diff opens
First seen
1 Sep 2026
this site's first read of the page
Recorded edits29to this page, all time
The whole hunk
from line 457, old and new numbered
/
from line 457
457457
458458Then confirm against the API. Add the `thinking-binding-controls-2026-08-01` beta header, set `prefix_mismatch_behavior` to `"drop_block"`, and run a normal multi-turn session through your integration on claude-fable-5-1. The following example runs two turns the way your integration should: `messages` only grows, each assistant turn goes back exactly as the API returned it, `thinking` blocks included, and `block_binding` is set on every request. After each turn it prints the number of `thinking` blocks in the response and the number of dropped blocks:
459459
460<CodeGroup>
461 ```bash cURL
462 # Counts the thinking blocks in a response and the blocks the API dropped
463 COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
464 "dropped: \(.input_transformations | length)"'
460<CodeGroup exclude="shell:cURL, shell:CLI">
461 <CodeGroupItem language="cURL">
462 This workflow needs more logic than a single shell command. Use the [Claude SDK](https://platform.claude.com/docs/en/cli-sdks-libraries/overview) to run it.
463 </CodeGroupItem>
465464
466 FIRST=$(curl -s https://api.anthropic.com/v1/messages \
467 -H "content-type: application/json" \
468 -H "x-api-key: $ANTHROPIC_API_KEY" \
469 -H "anthropic-version: 2023-06-01" \
470 -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
471 -d '{
472 "model": "claude-fable-5-1",
473 "max_tokens": 16000,
474 "thinking": {
475 "type": "adaptive",
476 "block_binding": { "prefix_mismatch_behavior": "drop_block" }
477 },
478 "messages": [
479 {
480 "role": "user",
481 "content": "How many positive integers below 500 have exactly 6 positive divisors?"
482 }
483 ]
484 }')
485 echo "$FIRST" | jq -r "$COUNTS"
465 <CodeGroupItem language="CLI">
466 This workflow needs more logic than a single shell command. Use the [Claude SDK](https://platform.claude.com/docs/en/cli-sdks-libraries/overview) to run it.
467 </CodeGroupItem>
486468
487 # Turn 2: the assistant turn goes back exactly as returned, then the next user message
488 MESSAGES=$(jq -n --argjson first "$FIRST" '[
489 {
490 role: "user",
491 content: "How many positive integers below 500 have exactly 6 positive divisors?"
492 },
493 { role: "assistant", content: $first.content },
494 { role: "user", content: "How many of those are odd?" }
495 ]')
496
497 jq -n --argjson messages "$MESSAGES" '{
498 model: "claude-fable-5-1",
499 max_tokens: 16000,
500 thinking: {
501 type: "adaptive",
502 block_binding: { prefix_mismatch_behavior: "drop_block" }
503 },
504 messages: $messages
505 }' | curl -s https://api.anthropic.com/v1/messages \
506 -H "content-type: application/json" \
507 -H "x-api-key: $ANTHROPIC_API_KEY" \
508 -H "anthropic-version: 2023-06-01" \
509 -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
510 -d @- | jq -r "$COUNTS"
511 ```
512
513 ```bash CLI
514 # Counts the thinking blocks in a response and the blocks the API dropped
515 COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
516 "dropped: \(.input_transformations | length)"'
517
518 FIRST=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
519 --format json <<'YAML'
520 model: claude-fable-5-1
521 max_tokens: 16000
522 thinking:
523 type: adaptive
524 block_binding:
525 prefix_mismatch_behavior: drop_block
526 messages:
527 - role: user
528 content: How many positive integers below 500 have exactly 6 positive divisors?
529 YAML
530 )
531 echo "$FIRST" | jq -r "$COUNTS"
532
533 # Turn 2: the assistant turn goes back exactly as returned, then the next user message
534 ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
535 --format json <<YAML | jq -r "$COUNTS"
536 model: claude-fable-5-1
537 max_tokens: 16000
538 thinking:
539 type: adaptive
540 block_binding:
541 prefix_mismatch_behavior: drop_block
542 messages:
543 - role: user
544 content: How many positive integers below 500 have exactly 6 positive divisors?
545 - role: assistant
546 content: $(echo "$FIRST" | jq -c .content)
547 - role: user
548 content: How many of those are odd?
549 YAML
550 ```
551
552469 ```python Python
553470 client = anthropic.Anthropic()
554471
from line 736
819736* **`reason: "model_binding_mismatch"`:** the conversation moved to a model that can't read the earlier model's blocks. This isn't a prefix edit. See [Switching models mid-conversation](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#switching-models).
820737* **`reason: "organization_binding_mismatch"`:** the block came from another account. See [Thinking blocks stay with the account that produced them](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#account-bound-thinking).
821738
822To see a failure on purpose, send a third turn from the earlier example and add a `system` prompt to that request only, so that it differs from the first two requests, which had none. With `"drop_block"`, the dropped count is no longer 0: the response has one entry for each thinking block in the history, each with `reason: "prefix_binding_mismatch"`. With `"error"`, the request returns the 400 described in [What the API does with an invalid block](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#mismatch-behavior), and its last sentence names the `system` prompt. In the cURL and CLI tabs, remove the `jq` filter to see the error body. If the count is still 0, there was nothing to check: confirm that the model is claude-fable-5-1, that the request sets `block_binding`, that the history you sent contains `thinking` blocks, and that the first two requests had no `system` prompt.
739To see a failure on purpose, send a third turn from the earlier example and add a `system` prompt to that request only, so that it differs from the first two requests, which had none. With `"drop_block"`, the dropped count is no longer 0: the response has one entry for each thinking block in the history, each with `reason: "prefix_binding_mismatch"`. With `"error"`, the request returns the 400 described in [What the API does with an invalid block](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#mismatch-behavior), and its last sentence names the `system` prompt. If the count is still 0, there was nothing to check: confirm that the model is claude-fable-5-1, that the request sets `block_binding`, that the history you sent contains `thinking` blocks, and that the first two requests had no `system` prompt.
823740
824741Two plain turns rarely show the problem. Run a session through each of the following, with `"error"` set so that a regression fails your CI:
825742
from line 763
846763
847764Run the following example from an [older account](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#enforcement), because a newer account rejects its third request with the 400. It sends the header without `block_binding` and extends the earlier session with a third request that adds a system prompt, which changes the prefix on purpose. After each turn it prints the number of `thinking` blocks and flagged blocks:
848765
849<CodeGroup>
850 ```bash cURL
851 # Counts the thinking blocks in a response and the blocks that failed the prefix check
852 COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
853 "flagged: \([.input_transformations[] |
854 select(.type == "thinking_mismatch_allowed")] | length)"'
766<CodeGroup exclude="shell:cURL, shell:CLI">
767 <CodeGroupItem language="cURL">
768 This workflow needs more logic than a single shell command. Use the [Claude SDK](https://platform.claude.com/docs/en/cli-sdks-libraries/overview) to run it.
769 </CodeGroupItem>
855770
856 FIRST=$(curl -s https://api.anthropic.com/v1/messages \
857 -H "content-type: application/json" \
858 -H "x-api-key: $ANTHROPIC_API_KEY" \
859 -H "anthropic-version: 2023-06-01" \
860 -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
861 -d '{
862 "model": "claude-fable-5-1",
863 "max_tokens": 16000,
864 "thinking": { "type": "adaptive" },
865 "messages": [
866 {
867 "role": "user",
868 "content": "How many positive integers below 500 have exactly 6 positive divisors?"
869 }
870 ]
871 }')
872 echo "$FIRST" | jq -r "$COUNTS"
771 <CodeGroupItem language="CLI">
772 This workflow needs more logic than a single shell command. Use the [Claude SDK](https://platform.claude.com/docs/en/cli-sdks-libraries/overview) to run it.
773 </CodeGroupItem>
873774
874 # Turn 2: the assistant turn goes back exactly as returned, then the next user message
875 MESSAGES=$(jq -n --argjson first "$FIRST" '[
876 {
877 role: "user",
878 content: "How many positive integers below 500 have exactly 6 positive divisors?"
879 },
880 { role: "assistant", content: $first.content },
881 { role: "user", content: "How many of those are odd?" }
882 ]')
883
884 SECOND=$(jq -n --argjson messages "$MESSAGES" '{
885 model: "claude-fable-5-1",
886 max_tokens: 16000,
887 thinking: { type: "adaptive" },
888 messages: $messages
889 }' | curl -s https://api.anthropic.com/v1/messages \
890 -H "content-type: application/json" \
891 -H "x-api-key: $ANTHROPIC_API_KEY" \
892 -H "anthropic-version: 2023-06-01" \
893 -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
894 -d @-)
895 echo "$SECOND" | jq -r "$COUNTS"
896
897 # Turn 3: only this request adds a system prompt, which changes the prefix on purpose
898 jq -n --argjson messages "$MESSAGES" --argjson second "$SECOND" '{
899 model: "claude-fable-5-1",
900 max_tokens: 16000,
901 thinking: { type: "adaptive" },
902 system: "Answer briefly.",
903 messages: ($messages + [
904 { role: "assistant", content: $second.content },
905 { role: "user", content: "And how many of the odd ones are below 100?" }
906 ])
907 }' | curl -s https://api.anthropic.com/v1/messages \
908 -H "content-type: application/json" \
909 -H "x-api-key: $ANTHROPIC_API_KEY" \
910 -H "anthropic-version: 2023-06-01" \
911 -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
912 -d @- | jq -r "$COUNTS"
913 ```
914
915 ```bash CLI
916 # Counts the thinking blocks in a response and the blocks that failed the prefix check
917 COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
918 "flagged: \([.input_transformations[] |
919 select(.type == "thinking_mismatch_allowed")] | length)"'
920
921 FIRST=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
922 --format json <<'YAML'
923 model: claude-fable-5-1
924 max_tokens: 16000
925 thinking:
926 type: adaptive
927 messages:
928 - role: user
929 content: How many positive integers below 500 have exactly 6 positive divisors?
930 YAML
931 )
932 echo "$FIRST" | jq -r "$COUNTS"
933
934 # Turn 2: the assistant turn goes back exactly as returned, then the next user message
935 SECOND=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
936 --format json <<YAML
937 model: claude-fable-5-1
938 max_tokens: 16000
939 thinking:
940 type: adaptive
941 messages:
942 - role: user
943 content: How many positive integers below 500 have exactly 6 positive divisors?
944 - role: assistant
945 content: $(echo "$FIRST" | jq -c .content)
946 - role: user
947 content: How many of those are odd?
948 YAML
949 )
950 echo "$SECOND" | jq -r "$COUNTS"
951
952 # Turn 3: only this request adds a system prompt, which changes the prefix on purpose
953 ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
954 --format json <<YAML | jq -r "$COUNTS"
955 model: claude-fable-5-1
956 max_tokens: 16000
957 thinking:
958 type: adaptive
959 system: Answer briefly.
960 messages:
961 - role: user
962 content: How many positive integers below 500 have exactly 6 positive divisors?
963 - role: assistant
964 content: $(echo "$FIRST" | jq -c .content)
965 - role: user
966 content: How many of those are odd?
967 - role: assistant
968 content: $(echo "$SECOND" | jq -c .content)
969 - role: user
970 content: And how many of the odd ones are below 100?
971 YAML
972 ```
973
974775 ```python Python
975776 client = anthropic.Anthropic()
976777
from line 1295
14941295 -H "x-api-key: $ANTHROPIC_API_KEY" \
14951296 -H "anthropic-version: 2023-06-01" \
14961297 -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
1497 -d "{
1498 \"model\": \"claude-fable-5-1\",
1499 \"max_tokens\": 16000,
1500 \"thinking\": {
1501 \"type\": \"adaptive\",
1502 \"block_binding\": { \"prefix_mismatch_behavior\": \"drop_block\" }
1298 -d '{
1299 "model": "claude-fable-5-1",
1300 "max_tokens": 16000,
1301 "thinking": {
1302 "type": "adaptive",
1303 "block_binding": { "prefix_mismatch_behavior": "drop_block" }
15031304 },
1504 \"messages\": $COMPACTED_MESSAGES
1505 }"
1305 "messages": '"$COMPACTED_MESSAGES"'
1306 }'
15061307 ```
15071308
15081309 ```bash CLI
No line in this hunk matches that.