mirror of
https://github.com/anthropics/skills.git
synced 2026-08-02 13:05:28 +08:00
Update claude-api skill: per-SDK doc split, code_execution_20260521, platform-availability, onboarding streamline (#1363)
This commit is contained in:
@@ -19,7 +19,7 @@ For the latest, authoritative version (with code samples in every supported lang
|
||||
| Opus 4.7 Migration Checklist | The required vs optional items for 4.7, tagged `[BLOCKS]` / `[TUNE]` |
|
||||
| Migrating to Opus 4.8 | Migrating to Opus 4.8 (no new breaking changes; mid-session system prompts; behavioral re-tuning) |
|
||||
| Opus 4.8 Migration Checklist | The required vs optional items for 4.8, tagged `[BLOCKS]` / `[TUNE]` |
|
||||
| Migrating to Claude Fable 5 | Migrating to Claude Fable 5 or Claude Mythos 5 (always-on protected thinking, new tokenizer, refusal handling, data retention, behavioral shifts + prompting guidance) |
|
||||
| Migrating to Claude Fable 5 | Migrating to Claude Fable 5 or Claude Mythos 5 (always-on thinking, raw chain of thought never returned, refusal handling, data retention, behavioral shifts + prompting guidance) |
|
||||
| Claude Fable 5 Migration Checklist | The required vs optional items for Claude Fable 5, tagged `[BLOCKS]` / `[TUNE]` |
|
||||
| Verify the Migration | After edits — runtime spot-check |
|
||||
|
||||
@@ -69,7 +69,7 @@ Not every file that contains the old model ID is a **caller** of the API. Before
|
||||
| 1 | **Calls the API/SDK** | `client.messages.create(model=…)`, `anthropic.Anthropic()`, request payloads | Swap the model ID **and** apply the breaking-change checklist for the target version (below). |
|
||||
| 2 | **Defines or serves the model** | Model registries, OpenAPI specs, routing/queue configs, model-policy enums, generated catalogs | The old entry **stays** (the model is still served). Ask whether to (a) add the new model alongside, (b) leave alone, or (c) retire the old model — never blind-replace. **If you can't ask, default to (a): add the new model alongside and flag it** — replacing would de-register a model that's still in production. |
|
||||
| 3 | **References the ID as an opaque string** | UI fallback constants, capability-gate substring checks, generic test fixtures, label parsers, env defaults | Usually swap the string and verify any parser/regex/substring match handles the new ID — but check the sub-cases below first. |
|
||||
| 4 | **Suffixed variant ID** | `claude-<model>-<suffix>` like `-fast`, `-1024k`, `-200k`, `[1m]`, dated snapshots | These are deployment/routing identifiers, not the public model ID. **Do not assume a new-model equivalent exists.** Verify in the registry first; if absent, leave the string alone and flag it. |
|
||||
| 4 | **Suffixed variant ID** | `claude-<model>-<suffix>` like `-fast`, `-1024k`, `-200k`, `[1m]`, dated snapshots | These are deployment/routing identifiers, not the public model ID. **Do not assume a new-model equivalent exists.** Verify in the registry first; if absent, leave the string alone and flag it. **Exception: `-fast` strings (e.g. `claude-opus-4-6-fast`) are handled by the Fast Mode section below**, which rewrites them to Opus 4.8 plus `speed="fast"` and the `fast-mode-2026-02-01` beta rather than leaving them in place. |
|
||||
|
||||
**Bucket 3 sub-cases — before swapping a string reference, check:**
|
||||
|
||||
@@ -403,7 +403,7 @@ Legacy tool versions are not supported on 4+. **Both the `type` and the `name` f
|
||||
| Old | New |
|
||||
| ------------------------------------------------- | ------------------------------------------------------- |
|
||||
| `text_editor_20250124` + `str_replace_editor` | `text_editor_20250728` + `str_replace_based_edit_tool` |
|
||||
| `code_execution_*` (earlier versions) | `code_execution_20250825` |
|
||||
| `code_execution_*` (earlier versions) | `code_execution_20260521` |
|
||||
| `undo_edit` command | *(no longer supported — delete call sites)* |
|
||||
|
||||
```python
|
||||
@@ -502,7 +502,7 @@ If the code uses the `AnthropicBedrockMantle` client (Python `anthropic[bedrock]
|
||||
|
||||
When migrating a Bedrock file, apply the same rename-table row as first-party, then keep/add the `anthropic.` prefix. Do **not** generate a first-party `claude-*` ID for a Bedrock client — it will 400.
|
||||
|
||||
**Skip for Bedrock:** the `code_execution_*` tool-version checklist item and the **Task Budgets** section — both are first-party-only features (Bedrock does not support server-side Anthropic tools or the `task-budgets-2026-03-13` beta). Everything else in this guide — `effort`, adaptive/extended thinking, `output_config.format`, `thinking.display`, fine-grained tool streaming, token counting — is available on Bedrock.
|
||||
**Skip for Bedrock:** the `code_execution_*` tool-version checklist item and the **Task Budgets** section — neither is available on Bedrock (see `shared/platform-availability.md` for the per-feature table). Everything else in this guide — `effort`, adaptive/extended thinking, `output_config.format`, `thinking.display`, fine-grained tool streaming, token counting — is available on Bedrock.
|
||||
|
||||
> **Out of scope:** the legacy Amazon Bedrock integration (`InvokeModel` / `Converse` APIs with ARN-versioned IDs like `anthropic.claude-3-5-sonnet-20241022-v2:0`) uses a different request shape and model-ID format. This guide does not cover it; WebFetch the Bedrock page in `shared/live-sources.md` if the user is migrating between the two Bedrock integrations.
|
||||
|
||||
@@ -533,7 +533,7 @@ For each file that calls `messages.create()` / equivalent SDK method:
|
||||
- [ ] **[BLOCKS]** Remove either `temperature` or `top_p` (passing both 400s on Claude 4+)
|
||||
- [ ] **[BLOCKS]** Update text-editor tool `type` to `text_editor_20250728`
|
||||
- [ ] **[BLOCKS]** Update text-editor tool `name` to `str_replace_based_edit_tool` — **changing only the `type` and keeping `name: "str_replace_editor"` returns a 400**
|
||||
- [ ] **[BLOCKS]** Update code-execution tool to `code_execution_20250825`
|
||||
- [ ] **[BLOCKS]** Update code-execution tool to `code_execution_20260521`
|
||||
- [ ] **[BLOCKS]** Delete any `undo_edit` command call sites
|
||||
- [ ] **[TUNE]** Add handling for `stop_reason == "refusal"`
|
||||
- [ ] **[TUNE]** Add handling for `stop_reason == "model_context_window_exceeded"` (4.5+)
|
||||
@@ -681,18 +681,22 @@ Beyond resolution, Opus 4.7 also improves on low-level perception (pointing, mea
|
||||
|
||||
Requests that involve prohibited or high-risk topics may lead to refusals.
|
||||
|
||||
### Fast Mode: not available on Opus 4.7
|
||||
### Fast Mode: Opus 4.8 / 4.7 only
|
||||
|
||||
Opus 4.7 does not have a Fast Mode variant. **Opus 4.6 Fast remains supported**. Only surface this if the caller's code actually uses a Fast Mode model string (e.g. `claude-opus-4-6-fast`); if the word "fast" does not appear in the code, say nothing about Fast Mode.
|
||||
Fast mode is available on Opus 4.8 and Opus 4.7. Only surface this if the caller's code actually uses fast mode (e.g. `model="claude-opus-4-6-fast"`, or `speed="fast"` on an unsupported model); if the word "fast" does not appear in the code, say nothing about Fast Mode.
|
||||
|
||||
When you see `model="claude-opus-4-6-fast"` (or similar), **the migration edit is**:
|
||||
When you see `model="claude-opus-4-6-fast"` (or any retired `-fast` model string), **the migration edit is** to move the fast-mode traffic onto Opus 4.8, the durable fast-capable tier:
|
||||
|
||||
```python
|
||||
# Opus 4.7 has no Fast Mode — keeping on 4.6 Fast (caller's choice to switch to standard Opus 4.7).
|
||||
model="claude-opus-4-6-fast",
|
||||
# Request fast mode on Opus 4.8.
|
||||
client.beta.messages.create(
|
||||
model="claude-opus-4-8", max_tokens=4096,
|
||||
speed="fast", betas=["fast-mode-2026-02-01"],
|
||||
messages=[...],
|
||||
)
|
||||
```
|
||||
|
||||
That is: leave the model string **unchanged**, add the comment above it, and tell the user their two options — (a) stay on Opus 4.6 Fast, which remains supported, or (b) move latency-tolerant traffic to standard Opus 4.7 for the intelligence gain. Do **not** rewrite the model string to `claude-opus-4-7` yourself; that silently trades latency for intelligence, which is the caller's decision.
|
||||
That is: switch the model to Opus 4.8 and request fast mode the supported way, using the beta `client.beta.messages.…` endpoint, the `fast-mode-2026-02-01` beta flag, and `speed="fast"` as a top-level request parameter (per-language form in SKILL.md § Fast Mode). Opus 4.7 also supports fast mode today, but it is itself being sunset (fast mode removed by default around Jul 25, 2026), so target Opus 4.8 as the durable choice rather than landing on a tier that is about to lose fast mode. Do **not** leave the code on a retired `-fast` model string — the failure mode differs by version: `claude-opus-4-6-fast` is already retired and the API **silently falls back** to standard Opus 4.6 (no error — the caller loses fast-mode speed without noticing); `claude-opus-4-7-fast`, once removed, will instead return an **API error** (hard failure — requests break outright rather than degrading). Either way, migrate to Opus 4.8 fast mode now.
|
||||
|
||||
### Behavioral shifts (prompt-tunable)
|
||||
|
||||
@@ -822,7 +826,7 @@ messages=[
|
||||
]
|
||||
```
|
||||
|
||||
Phrase these as **context, not commands**. State the fact and let Claude act on it; avoid override-style language ("ignore what the user said", "regardless of the user's request", "disregard the previous instruction"). Claude is trained to protect users from instructions that appear to work against them, and that protection applies to the system role too. This is a beta (`anthropic-beta: mid-conversation-system-2026-04-07`) and is available from Opus 4.7 onward, not 4.8-exclusive. For cache-placement details and the older-model `<system-reminder>` fallback, see `shared/prompt-caching.md` and `shared/agent-design.md`.
|
||||
Phrase these as **context, not commands**. State the fact and let Claude act on it; avoid override-style language ("ignore what the user said", "regardless of the user's request", "disregard the previous instruction"). Claude is trained to protect users from instructions that appear to work against them, and that protection applies to the system role too. No beta header is required; available on Claude Opus 4.8. For cache-placement details and the older-model `<system-reminder>` fallback, see `shared/prompt-caching.md` and `shared/agent-design.md`.
|
||||
|
||||
### Capability improvements
|
||||
|
||||
@@ -882,7 +886,7 @@ For a caller **already on Opus 4.7**, only the first item is required; everythin
|
||||
- [ ] **[TUNE]** Writing voice: re-evaluate style prompts added to counter 4.7's directness — 4.8 is warmer and less hedged by default; re-baseline before keeping them
|
||||
- [ ] **[TUNE]** Code-review harnesses: keep the report-everything-filter-downstream pattern (4.8 follows "only high-severity" / "be conservative" filters literally, which can depress measured recall)
|
||||
- [ ] **[TUNE]** Thinking-disabled paths: add a final-answer-only instruction if reasoning leaks into the visible response
|
||||
- [ ] **[TUNE]** Consider mid-session system messages (`role:"system"` in `messages`, beta `mid-conversation-system-2026-04-07`) for context the app learns mid-session, instead of rebuilding the top-level system prompt and invalidating the cache
|
||||
- [ ] **[TUNE]** Consider mid-session system messages (`role:"system"` in `messages`; no beta header) for context the app learns mid-session, instead of rebuilding the top-level system prompt and invalidating the cache
|
||||
|
||||
---
|
||||
|
||||
@@ -892,7 +896,7 @@ For a caller **already on Opus 4.7**, only the first item is required; everythin
|
||||
|
||||
Claude Fable 5 is Anthropic's most capable widely released model — for the most demanding reasoning and long-horizon agentic work. **Claude Mythos 5** (`claude-mythos-5`) offers the same capabilities, pricing, and API behavior through Project Glasswing (participation is the only way to access it), and succeeds the invitation-only **Claude Mythos Preview** (`claude-mythos-preview`). Everything in this section applies to both models — only the ID differs. Mythos Preview migrators in Project Glasswing target `claude-mythos-5`; everyone else targets `claude-fable-5`. 1M token context window by default (the maximum is also the default), up to 128K output tokens per request.
|
||||
|
||||
**Migrate to Claude Fable 5 only when the user explicitly chose it.** It is not the default Opus upgrade path — pricing is above Opus-tier and the new tokenizer changes cost baselines. For "upgrade to the latest model" requests, the target remains `claude-opus-4-8`.
|
||||
**Migrate to Claude Fable 5 only when the user explicitly chose it.** It is not the default Opus upgrade path — pricing is above Opus-tier. For "upgrade to the latest model" requests, the target remains `claude-opus-4-8`.
|
||||
|
||||
### Breaking changes (vs Opus-tier and Mythos Preview)
|
||||
|
||||
@@ -920,28 +924,28 @@ Claude Fable 5 is Anthropic's most capable widely released model — for the mos
|
||||
|
||||
3. **Interleaved scratchpad is not supported** (Mythos Preview migrators only). Inter-tool reasoning is returned in thinking blocks instead, which adaptive thinking produces automatically between tool calls.
|
||||
|
||||
### Protected thinking — always encrypted, model-specific
|
||||
### Thinking output on Claude Fable 5 and Claude Mythos 5
|
||||
|
||||
Claude Fable 5's `protected_thinking` policy protects the **raw chain of thought** — it is never exposed in responses. What you receive are **regular `thinking` blocks**, not encrypted blobs or `redacted_thinking`: `display: "summarized"` returns a readable summary of the reasoning, and with `"omitted"` — the default, same as Opus 4.8/4.7 — responses still include `thinking` blocks but the `thinking` field is an empty string. `display` controls visibility only; thinking happens and is billed the same under every setting. What's stricter on Claude Fable 5 is **replay**: pass thinking blocks back to the API **unchanged** when continuing a conversation on the same model (the standard multi-turn pattern; dropping or editing them breaks the turn).
|
||||
On Claude Fable 5 and Claude Mythos 5, the raw chain of thought is never returned. What you receive are **regular `thinking` blocks**, not encrypted blobs or `redacted_thinking`: `display: "summarized"` returns a readable summary of the reasoning, and with `"omitted"` — the default, same as Opus 4.8/4.7 — responses still include `thinking` blocks but the `thinking` field is an empty string. `display` controls visibility only; thinking happens and is billed the same under every setting. When continuing a conversation on the same model, pass thinking blocks back to the API **unchanged** (the standard multi-turn pattern; dropping or editing them breaks the turn).
|
||||
|
||||
When continuing on the same model, pass each thinking block back **exactly as received — including blocks whose `thinking` text is empty**. The API rejects blocks whose content has been *modified*, not blocks you have read; displaying the summary is fine, editing or reconstructing blocks is not.
|
||||
|
||||
Thinking blocks are tied to the model that produced them, but cross-model replay is forgiving: other models **silently ignore** them rather than rejecting the request (early-access builds returned `invalid_request_error`; that was reverted before launch). Ignored blocks still bill input tokens, though — so when switching models for good, e.g. after a classifier refusal, strip `thinking`/`redacted_thinking` blocks from prior assistant turns to avoid paying for dead weight. Two exceptions: fallback-credit retries must echo the refused body **unchanged**, and `fallback` blocks from a mid-output fallback stay where they appeared.
|
||||
Regular thinking blocks aren't origin-locked — they replay across models fine (the server renders them into the target model's prompt). Claude Fable 5/Claude Mythos 5 thinking is the exception: a thinking block from these models replayed to a different model is **dropped from the prompt** rather than rendered — typically silently (early-access builds hard-rejected with `invalid_request_error`; that broke workflows and was reverted before launch, but the new behavior is still rolling out, so don't build logic that depends on either outcome). The drop happens before the prompt is priced, so a dropped block **lowers `usage.input_tokens`** — you aren't billed for it, and there's nothing to strip for cost. Don't strip *regular* thinking blocks either: removing them can trigger ordering/signature 400s. Two rules for replay bodies stand regardless: fallback-credit retries must echo the refused body **unchanged**, and `fallback` blocks from a mid-output fallback stay where they appeared.
|
||||
|
||||
Related: a request that tries to elicit the model's internal reasoning *in the response text* can be refused with `stop_details.category: "reasoning_extraction"` — applications needing reasoning visibility should read the summarized `thinking` blocks instead of prompting for reasoning.
|
||||
|
||||
### New tokenizer — re-baseline tokens and cost
|
||||
### Tokenizer — unchanged from Opus 4.8
|
||||
|
||||
Claude Fable 5 uses a new tokenizer. The same content tokenizes to **roughly 30% more tokens** than on Opus-tier and older models (varies by content and workload shape). Billing is per token, so an unchanged workload can cost more after migration even before the per-token price difference.
|
||||
Claude Fable 5 uses the **same tokenizer as Claude Opus 4.8** (the tokenizer introduced with Opus 4.7). Token counts are roughly unchanged when migrating from Opus 4.7/4.8 or from `claude-mythos-preview`; per-token pricing differs.
|
||||
|
||||
- Coming **from `claude-mythos-preview`**: token counts are roughly unchanged (same tokenizer family).
|
||||
- Coming **from Opus/Sonnet/Haiku**: do not reuse token counts, context-window budgets, or `max_tokens` settings measured on the old model.
|
||||
- Coming **from Opus 4.7/4.8 or `claude-mythos-preview`**: token counts are roughly unchanged. Re-baseline cost and latency on your own workloads for the per-token price difference.
|
||||
- Coming **from Opus 4.6, Sonnet, Haiku, or older**: the Opus 4.7 tokenizer tokenizes the same content to roughly 1×–1.35× as many tokens (varies by content and workload shape). Do not reuse token counts, context-window budgets, or `max_tokens` settings measured on the old model; re-baseline with `count_tokens`.
|
||||
|
||||
The token counting endpoint returns counts under **both** tokenizers when you pass `model: "claude-fable-5"` — `input_tokens` (new tokenizer, what you're billed) plus `input_tokens_prior_tokenizer` (the same request under the prior-generation tokenizer) — so you can measure the delta on your own prompts before switching.
|
||||
To measure the difference on your own prompts, call `count_tokens` once with your current model and once with `model: "claude-fable-5"`, and compare the two `input_tokens` values.
|
||||
|
||||
### `refusal` stop reason — handle before reading content
|
||||
|
||||
Claude Fable 5 runs safety classifiers on incoming requests, targeting research biology and most cybersecurity content (Claude Fable 5 is not intended for those domains); benign adjacent work — security tooling, life-sciences tasks — can occasionally trigger false positives, which is why the fallback patterns below matter even for legitimate workloads. (Most Claude consumer surfaces ship with built-in Opus 4.8 fallbacks; API callers configure their own.) A declined request returns a **successful HTTP 200** with `stop_reason: "refusal"`, plus a `stop_details` object with the policy category (`"cyber"`, `"bio"`, `"reasoning_extraction"`, or `null` — treat `null` as a permanent valid state). **Branch on `stop_reason`, never on `stop_details`** — `stop_details` is informational and can be `null` even on a refusal, and `explanation` is not guaranteed present. Note that classifier blocks and ordinary model refusals (the model itself declining) both surface as `stop_reason: "refusal"`; `stop_details.category` tells you which class you're handling, and therefore whether retrying on a fallback model is the right response. The classifier can fire **before any output** (empty `content` array; not billed at all — no input or output tokens, no rate-limit consumption) or **mid-stream** after partial output (already-streamed output is billed at normal rates — discard the partial output rather than treating it as complete). Code that reads `response.content[0]` unconditionally will break — check `stop_reason` first:
|
||||
Claude Fable 5 runs safety classifiers on incoming requests, targeting research biology and most cybersecurity content (Claude Fable 5 is not intended for those domains); benign adjacent work — security tooling, life-sciences tasks — can occasionally trigger false positives, which is why the fallback patterns below matter even for legitimate workloads. (Most Claude consumer surfaces ship with built-in Opus 4.8 fallbacks; API callers configure their own.) A declined request returns a **successful HTTP 200** with `stop_reason: "refusal"`, plus a `stop_details` object with the policy category (values such as `"cyber"`, `"bio"`, `"reasoning_extraction"`, `"frontier_llm"`, or `null` — treat `null` as a permanent valid state; see the refusal category table in the public docs for the full set). **Branch on `stop_reason`, never on `stop_details`** — `stop_details` is informational and can be `null` even on a refusal, and `explanation` is not guaranteed present. Note that classifier blocks and ordinary model refusals (the model itself declining) both surface as `stop_reason: "refusal"`; `stop_details.category` tells you which class you're handling, and therefore whether retrying on a fallback model is the right response. The classifier can fire **before any output** (empty `content` array; not billed at all — no input or output tokens, no rate-limit consumption) or **mid-stream** after partial output (already-streamed output is billed at normal rates — discard the partial output rather than treating it as complete). Code that reads `response.content[0]` unconditionally will break — check `stop_reason` first:
|
||||
|
||||
```python
|
||||
response = client.messages.create(model="claude-fable-5", max_tokens=1024, messages=[...])
|
||||
@@ -952,6 +956,8 @@ else:
|
||||
print(response.content[0].text)
|
||||
```
|
||||
|
||||
**Default to opting in.** Fallbacks are not automatic on the API — a request without them simply stops on a refusal. Migrated and new Claude Fable 5 code should ship with pattern 1 below (pattern 2 on providers without server-side support) from day one, not as a later hardening step: emit the opt-in in the code, tell the user it's there, and remove it only if they decline.
|
||||
|
||||
Three ways to retry a refused request on another model, in order of preference:
|
||||
|
||||
**1. Server-side `fallbacks` parameter (beta: Claude API and Claude Platform on AWS) — preferred.** One round trip, a plain client, no client-side logic. Name substitute models (the only supported fallback target at launch is `claude-opus-4-8`, expansion expected); on a policy decline the API runs the next model on the same request and returns its answer, with credit-style repricing applied automatically. A `stop_reason: "refusal"` on the final response means the whole chain refused.
|
||||
@@ -970,23 +976,26 @@ for block in response.content:
|
||||
if block.type == "fallback":
|
||||
print(f"{block.from_.model} declined; {block.to.model} continued")
|
||||
|
||||
# Served-by signal: covers every fallback-served turn, INCLUDING sticky turns
|
||||
# (sticky-served turns carry no fallback block — nothing declined this turn)
|
||||
iterations = getattr(response.usage, "iterations", None) or []
|
||||
if any(entry.type == "fallback_message" for entry in iterations):
|
||||
# Served-by signal: a fallback_message in usage.iterations means a fallback model
|
||||
# ran; pair it with stop_reason to confirm the fallback served the response
|
||||
# (a fallback model can also refuse). Covers sticky turns too.
|
||||
fallback_ran = any(
|
||||
entry.type == "fallback_message" for entry in response.usage.iterations or []
|
||||
)
|
||||
if fallback_ran and response.stop_reason != "refusal":
|
||||
print(f"Served by {response.model}")
|
||||
```
|
||||
|
||||
Key semantics:
|
||||
|
||||
- **Header must be exactly `server-side-fallback-2026-06-01`** — other `server-side-fallback-*` values reject the `fallbacks` param with a 400. The current header carries the *earliest* date of the series (`-2026-06-09` and `-2026-06-02` were earlier previews) — do not "correct" it to a newer-looking date. Rejected on the Batches API; not available on Bedrock/Vertex (use pattern 2 there — the SDK middleware). Entries may override `max_tokens` per hop (bounding that attempt's own output independently of the top-level `max_tokens`); `thinking`, `output_config`, and `speed` overrides are rolling out (`speed` additionally requires its beta) — until your requests accept them, include only `model` and `max_tokens` in each entry. Entries must be distinct and must be in the requested model's `allowed_fallback_models` (visible on `/v1/models` under the beta). The request *with an entry's overrides merged in* must be valid as a direct request to that entry's model.
|
||||
- **Header must be exactly `server-side-fallback-2026-06-01`** — other `server-side-fallback-*` values reject the `fallbacks` param with a 400. The current header carries the *earliest* date of the series (`-2026-06-09` and `-2026-06-02` were earlier previews) — do not "correct" it to a newer-looking date. Rejected on the Batches API; not available on Amazon Bedrock, Vertex AI, or Microsoft Foundry (use pattern 2 there — the SDK middleware). Entries may override `max_tokens` per hop (bounding that attempt's own output independently of the top-level `max_tokens`); `thinking`, `output_config`, and `speed` overrides are rolling out (`speed` additionally requires its beta) — until your requests accept them, include only `model` and `max_tokens` in each entry. Entries must be distinct and must be in the requested model's `allowed_fallback_models` (published on `/v1/models` when the `server-side-fallback-2026-06-01` beta header is set — not yet visible under the `fallback-credit-*` header alone, and not exposed on Amazon Bedrock, Vertex AI, or Microsoft Foundry). The request *with an entry's overrides merged in* must be valid as a direct request to that entry's model.
|
||||
- **Triggers on policy declines only** — rate limits, overloads, and server errors on the requested model are returned as-is, never falling back.
|
||||
- **Reading the response:** a `fallback` content block (`{"type": "fallback", "from": {"model": ...}, "to": {"model": ...}}`) marks each switch point in `content`; the served-by signal is a `fallback_message` entry in `usage.iterations` (don't rely on the block — sticky-served turns have none). Top-level `model` names the model that produced the message.
|
||||
- **Billing:** `usage.iterations` is the per-attempt source of truth; top-level `usage` covers only the attempt that produced the returned message. Declined-before-output attempts are reported but not billed; fallback attempts bill at the fallback model's rates. Each attempt claims the rate limits of the model that ran it — if the fallback model is rate-limited or overloaded, the refusal is returned instead with `stop_details.recommended_model` naming the canonical model ID to retry directly (populated only when the request included `fallbacks` and the attempt couldn't be made) — size fallback-model limits for expected refusal volume.
|
||||
- **Billing:** `usage.iterations` is the per-attempt source of truth; top-level `usage` covers only the attempt that produced the returned message. Declined-before-output attempts are reported but not billed; fallback attempts bill at the fallback model's rates. Each attempt claims the rate limits of the model that ran it — if the fallback model is rate-limited or overloaded, the fallback attempt is not made and the preceding refusal is returned instead with `stop_details.recommended_model` naming a model to retry directly (the recommendation is a hint, not a guarantee, and is `null` when no recommendation is available) — size fallback-model limits for expected refusal volume.
|
||||
- **Sticky routing:** once a conversation falls back, later non-streaming requests with `fallbacks` are served directly by the fallback model for ~1 hour (best-effort; org-scoped content-hash record, not message content; not recorded for ZDR orgs). Handle the requested model being tried again at any time.
|
||||
- **Echoing fallback turns back:** after a mid-output fallback, omit `thinking`, `redacted_thinking`, and `tool_use` blocks — plus any `server_tool_use` block without its matching `server_tool_result`, and any other unrecognized model-internal block type — that appear *before* the final `fallback` block; text blocks, paired server-tool blocks, and everything after the boundary echo normally. The `fallback` block itself is an ignored audit marker (keep or drop). Streaming: the retry happens on the same stream and already-received content is never invalidated — a pre-output block is seamless (`message_start` names the fallback model; the `fallback` block arrives as an ordinary `content_block_start`, first in `content` — there is no special SSE event type; note `message_start` arrives only after the declined attempt, so time-to-first-byte includes it), and a mid-stream block keeps the partial, marks the boundary with the block, and continues — only the partial's `text` blocks are passed to the fallback model as continuation context (other block types stay in `content` but aren't part of it). Sticky routing is **not consulted on streaming requests** in the initial release, so on streams the `fallback` block check is the complete signal; non-streaming mid-output declines omit the declined partial entirely.
|
||||
|
||||
**2. SDK client-side middleware — for providers without server-side fallbacks (Bedrock, Vertex).** Register it on the client and every `client.beta.messages` request (streaming included) retries refusals automatically, splicing the fallback model's events onto the open stream in the same wire shape as pattern 1 (a `fallback` content block at each boundary, per-hop `usage.iterations`). It is also a beta surface: the middleware sends the `fallback-credit-2026-06-01` header by default so retries are repriced via credit tokens (override with its `betas` option). `BetaFallbackState` pins follow-up turns to the model that accepted (the client-side analog of sticky routing) — reuse one state object per conversation:
|
||||
**2. SDK client-side middleware — for providers without server-side fallbacks (Amazon Bedrock, Vertex AI, Microsoft Foundry).** Register it on the client and every `client.beta.messages` request (streaming included) retries refusals automatically, splicing the fallback model's events onto the open stream in the same wire shape as pattern 1 (a `fallback` content block at each boundary, per-hop `usage.iterations`). It is also a beta surface: the middleware sends the `fallback-credit-2026-06-01` header by default so retries are repriced via credit tokens (override with its `betas` option). `BetaFallbackState` pins follow-up turns to the model that accepted (the client-side analog of sticky routing) — reuse one state object per conversation:
|
||||
|
||||
```python
|
||||
from anthropic import Anthropic, BetaFallbackState, BetaRefusalFallbackMiddleware
|
||||
@@ -1005,7 +1014,7 @@ Create **one state per conversation** — it is the pinning scope; sharing one a
|
||||
|
||||
For languages not listed (Java, Ruby, PHP) — or for a full runnable program in any language — each public SDK repo ships a fallbacks example under `examples/` (e.g. `examples/fallbacks.py`, `examples/refusal-fallback/`): WebFetch the repo from `shared/live-sources.md` § SDK Repositories rather than improvising the binding.
|
||||
|
||||
**3. Hand-rolled retry + fallback credit (raw HTTP, or SDKs without the middleware).** Detect the refusal via `stop_reason` and re-send the conversation as-is on a model with broader availability such as `claude-opus-4-8` (Claude Fable 5's protected thinking blocks are silently ignored by other models — no stripping required); keep using the fallback model for subsequent turns. **Fallback credit** (beta: Claude API, Bedrock, Vertex) makes those retries cheaper. Prompt caches are per-model, so a plain retry pays cold cache-writes on the new model. With the `fallback-credit-2026-06-01` beta header (send it on both the original request and the retry), a refusal's `stop_details` carries `fallback_credit_token` (opaque; `null` when unavailable) and `fallback_has_prefill_claim`. Echo the token as the top-level `fallback_credit_token` request parameter on the retry (typed in the GA SDKs; on a pre-GA SDK pass it via `extra_body`) and the previously-cached span bills at cache-read rates — the retry costs what it would have if the conversation had been on that model all along. Rules: the retry body must match the refused request **exactly** in every prompt-shaping field (`system`, `messages`, `tools`, `tool_choice`, `thinking` — do **not** strip thinking blocks when redeeming a credit — the server handles them); the retry model must be in the refused model's `allowed_fallback_models`; the token expires in 5 minutes; Batches results carry no tokens. If `fallback_has_prefill_claim` is `true`, append one assistant message echoing the refused response's `content` — the retry model continues from where the refused model stopped (and completed server-tool work isn't re-run). When echoing, strip trailing whitespace from a final `text` block (the prefill validator rejects it; the credit match tolerates that edit), after omitting any unpaired `tool_use` blocks. On a 400, fall back to the unchanged body with the token; on a 400 naming `fallback_credit_token`, retry without it (credit forfeited).
|
||||
**3. Hand-rolled retry + fallback credit (raw HTTP, or SDKs without the middleware).** Detect the refusal via `stop_reason` and re-send the conversation as-is on a model with broader availability such as `claude-opus-4-8` (Claude Fable 5's thinking blocks are silently ignored by other models — no stripping required); keep using the fallback model for subsequent turns. **Fallback credit** (beta: Claude API, Claude Platform on AWS, Amazon Bedrock, Vertex AI, and Microsoft Foundry) makes those retries cheaper. Prompt caches are per-model, so a plain retry pays cold cache-writes on the new model. With the `fallback-credit-2026-06-01` beta header (send it on both the original request and the retry), a refusal's `stop_details` carries `fallback_credit_token` (opaque; `null` when unavailable) and `fallback_has_prefill_claim`. Echo the token as the top-level `fallback_credit_token` request parameter on the retry (typed in the GA SDKs; on a pre-GA SDK pass it via `extra_body`) and the previously-cached span bills at cache-read rates — the retry costs what it would have if the conversation had been on that model all along. Rules: the retry body must match the refused request **exactly** in every prompt-shaping field (`system`, `messages`, `tools`, `tool_choice`, `thinking` — do **not** strip thinking blocks when redeeming a credit — the server handles them); the retry model must be in the refused model's `allowed_fallback_models`; the token expires in 5 minutes; Batches results carry no tokens. If `fallback_has_prefill_claim` is `true`, append one assistant message echoing the refused response's `content` — the retry model continues from where the refused model stopped (and completed server-tool work isn't re-run). When echoing, strip trailing whitespace from a final `text` block (the prefill validator rejects it; the credit match tolerates that edit), after omitting any unpaired `tool_use` blocks. On a 400, fall back to the unchanged body with the token; on a 400 naming `fallback_credit_token`, retry without it (credit forfeited).
|
||||
|
||||
**Migrating code built on the v1 preview.** If the code you're editing carries any of these markers, it targets the discontinued early-access surface — migrate it to the v2 shapes above, and ship the header and parameter changes together (the v1 parameter shape under the v2 header is a 400):
|
||||
|
||||
@@ -1096,7 +1105,7 @@ None of these are API-breaking, but they're where migrated workloads feel differ
|
||||
}
|
||||
```
|
||||
|
||||
For agents that only narrate routine progress, default summaries are typically adequate without this tool.
|
||||
For agents that only narrate routine progress, the model's default progress narration is typically adequate without this tool.
|
||||
|
||||
### Claude Fable 5 Migration Checklist
|
||||
|
||||
@@ -1105,9 +1114,10 @@ For agents that only narrate routine progress, default summaries are typically a
|
||||
- [ ] **[BLOCKS]** Replace assistant prefill with structured outputs or system prompt instructions
|
||||
- [ ] **[BLOCKS]** Confirm the org meets the 30-day data-retention requirement (ZDR orgs get `400 invalid_request_error` on every request)
|
||||
- [ ] **[BLOCKS]** Remove all other `thinking` configuration (`{type: "enabled", budget_tokens: N}` returns a 400, same as on Opus 4.7/4.8); control depth with `output_config.effort` instead
|
||||
- [ ] **[TUNE]** Re-baseline token counts, context budgets, `max_tokens`, and cost — ~30% more tokens vs Opus-tier (roughly unchanged from Mythos Preview); use `count_tokens` with `model: "claude-fable-5"` to measure
|
||||
- [ ] **[TUNE]** Add `stop_reason == "refusal"` handling before reading `response.content` (pre-output: empty + unbilled; mid-stream: partial output billed — discard); pick a retry strategy — client-side (replay history as-is; other models ignore Fable's thinking blocks), fallback credit (`fallback-credit-2026-06-01`, exact body), or server-side `fallbacks` (`server-side-fallback-2026-06-01`, Claude API and Claude Platform on AWS)
|
||||
- [ ] **[TUNE]** If you surfaced thinking text to users, plan for protected (encrypted) thinking — pass blocks back unchanged on the same model, never render or cross-model them
|
||||
- [ ] **[BLOCKS]** If thinking content is surfaced to users or stored in logs: add `thinking: {type: "adaptive", display: "summarized"}` (the default is `"omitted"` — otherwise the rendered text is empty)
|
||||
- [ ] **[TUNE]** Re-baseline cost and latency on your own workloads — token counts are roughly unchanged from Opus 4.7/4.8 and Mythos Preview (same tokenizer); per-token pricing differs. Coming from Opus 4.6, Sonnet, Haiku, or older, token counts differ — use `count_tokens` with each model to compare
|
||||
- [ ] **[TUNE]** Add `stop_reason == "refusal"` handling before reading `response.content` (pre-output: empty + unbilled; mid-stream: partial output billed — discard); opt into a fallback by default — server-side `fallbacks` (`server-side-fallback-2026-06-01`, Claude API and Claude Platform on AWS) where available, otherwise the SDK middleware or fallback credit (`fallback-credit-2026-06-01`, exact body); a bare client-side replay (history as-is; other models drop Fable's thinking blocks) is the floor, not the recommendation
|
||||
- [ ] **[TUNE]** If you surfaced thinking text to users, plan for the thinking output change — the raw chain of thought is never returned; render the `display: "summarized"` summary (per the [BLOCKS] item above); pass blocks back unchanged on the same model; other models drop them from the prompt (unbilled)
|
||||
- [ ] **[TUNE]** Plan for minutes-long turns: timeouts, streaming, async check-ins, progress UX (see Behavior changes above)
|
||||
- [ ] **[TUNE]** Run an effort sweep including low/medium for routine workloads; add the no-tidying instruction if higher effort produces unrequested refactors
|
||||
- [ ] **[TUNE]** A/B with prior-model scaffolding removed — over-prescriptive prompts/skills reduce Claude Fable 5 output quality
|
||||
|
||||
Reference in New Issue
Block a user