()
| 4 | |
| 5 | |
| 6 | def main() -> None: |
| 7 | # Server-side fallbacks (preferred): the API retries a refusal itself — one |
| 8 | # request, a plain client, no client-side logic. Use this when talking to |
| 9 | # the API directly. |
| 10 | client = Anthropic() |
| 11 | message = client.beta.messages.create( |
| 12 | max_tokens=1024, |
| 13 | model="claude-fable-5", |
| 14 | messages=[{"role": "user", "content": "Some prompt that triggers a refusal"}], |
| 15 | fallbacks=[{"model": "claude-opus-4-8"}], |
| 16 | betas=["server-side-fallback-2026-06-01"], |
| 17 | ) |
| 18 | print("server-side:", message.model) |
| 19 | |
| 20 | # If your provider doesn't support server-side fallbacks, register the |
| 21 | # client-side middleware instead: |
| 22 | fallback_client = Anthropic( |
| 23 | middleware=[BetaRefusalFallbackMiddleware([{"model": "claude-opus-4-8"}])], |
| 24 | ) |
| 25 | state = BetaFallbackState() # pins follow-ups to the model that accepted |
| 26 | |
| 27 | # Streaming: on a refusal the middleware retries and splices the fallback's |
| 28 | # events onto the open stream — one continuous message, with a `fallback` |
| 29 | # content block marking the model boundary. |
| 30 | messages: list[BetaMessageParam] = [{"role": "user", "content": "Some prompt that triggers a refusal"}] |
| 31 | with state, fallback_client.beta.messages.stream( |
| 32 | max_tokens=1024, |
| 33 | model="claude-fable-5", |
| 34 | messages=messages, |
| 35 | ) as stream: |
| 36 | for event in stream: |
| 37 | if event.type == "text": |
| 38 | print(event.text, end="", flush=True) |
| 39 | elif event.type == "content_block_start" and event.content_block.type == "fallback": |
| 40 | block = event.content_block |
| 41 | print(f"\n--- fell back: {block.from_.model} -> {block.to.model} ---") |
| 42 | streamed = stream.get_final_message() |
| 43 | print("\nstreaming:", streamed.model) |
| 44 | messages.append({"role": "assistant", "content": streamed.content}) |
| 45 | |
| 46 | # Non-streaming: reusing the state keeps the conversation pinned. |
| 47 | messages.append({"role": "user", "content": "what did I just ask you?"}) |
| 48 | with state: |
| 49 | follow_up = fallback_client.beta.messages.create( |
| 50 | max_tokens=1024, |
| 51 | model="claude-fable-5", |
| 52 | messages=messages, |
| 53 | ) |
| 54 | print("non-streaming:", follow_up.model) |
| 55 | |
| 56 | |
| 57 | main() |
no test coverage detected