Update claude-api skill: Claude Opus 5 (#1476)

* Update claude-api skill: Claude Opus 5

- Add Claude Opus 5 (`claude-opus-5`) as the default model across all
  SDK examples, model tables, pricing, and migration guidance.
- Add an Opus 5 migration section covering the API changes that come
  with it, and move Opus 4.8 into the previous-generation slot.
- Drop the Opus 4.7 fast-mode guidance, which no longer applies.
- Scope the server-side fallbacks beta header to the current version.

* Update claude-api skill: Opus 5 fast-follow corrections

- Server-side refusal fallbacks are available on Claude Platform on AWS,
  not just the Claude API. Correct the availability statements in
  SKILL.md, the migration guide, and the platform-availability table.
- Simplify the effort guidance: start at `high` (the API default) and
  sweep down, rather than starting at `xhigh` for coding work.
- Add a time-to-first-token section with the prompt instruction that
  reduces pre-answer thinking on latency-sensitive routes.
- Replace the two separate thinking-disabled mitigations with the single
  combined instruction that covers both failure modes.
This commit is contained in:
Lance Martin
2026-07-24 13:12:34 -07:00
committed by GitHub
parent 1f630fdf92
commit b29e7cf65e
50 changed files with 608 additions and 278 deletions
+22 -21
View File
@@ -33,7 +33,7 @@ Use `with_options()` to override client settings for a single call without mutat
```python
client.with_options(timeout=5.0, max_retries=5).messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
@@ -90,7 +90,7 @@ Set `ANTHROPIC_LOG=debug` (or `info`) to enable SDK logging via the standard `lo
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[
{"role": "user", "content": "What is the capital of France?"}
@@ -109,7 +109,7 @@ for block in response.content:
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
system="You are a helpful coding assistant. Always provide examples in Python.",
messages=[{"role": "user", "content": "How do I read a JSON file?"}]
@@ -145,7 +145,7 @@ with open("image.png", "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode("utf-8")
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -168,7 +168,7 @@ response = client.messages.create(
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -198,7 +198,7 @@ Use top-level `cache_control` to automatically cache the last cacheable block in
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
cache_control={"type": "ephemeral"}, # auto-caches the last cacheable block
system="You are an expert on this large document...",
@@ -212,7 +212,7 @@ For fine-grained control, add `cache_control` to specific content blocks:
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
system=[{
"type": "text",
@@ -224,7 +224,7 @@ response = client.messages.create(
# With explicit TTL (time-to-live)
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
system=[{
"type": "text",
@@ -249,16 +249,17 @@ If `cache_read_input_tokens` is zero across repeated identical-prefix requests,
## Extended Thinking
> **Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6:** Use adaptive thinking. `budget_tokens` is removed on Fable 5, Opus 4.8, and 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6.
> **Fable 5, Claude Opus 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6:** Use adaptive thinking. `budget_tokens` is removed on Fable 5, Claude Opus 5, Opus 4.8, and 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6.
> **Claude Opus 5:** thinking is on by default — omitting `thinking` runs adaptive (`{"type": "adaptive"}` is equivalent), unlike Opus 4.8/4.7 where omitting it meant no thinking. `{"type": "disabled"}` is accepted only at effort `high` or lower; pairing it with `xhigh`/`max` returns a 400.
> **Older models:** Use `thinking: {type: "enabled", budget_tokens: N}` (must be < `max_tokens`, min 1024).
```python
# Fable 5 / Opus 4.8 / 4.7 / 4.6: adaptive thinking (recommended)
# Fable 5 / Claude Opus 5 / Opus 4.8 / 4.7 / 4.6: adaptive thinking (recommended)
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
thinking={"type": "adaptive", "display": "summarized"}, # display opt-in: default is omitted (empty thinking text) on Fable 5 / Mythos 5 / Opus 4.8 / 4.7
output_config={"effort": "high"}, # low | medium | high | max
thinking={"type": "adaptive", "display": "summarized"}, # display opt-in: default is omitted (empty thinking text) on Fable 5 / Mythos 5 / Claude Opus 5 / Opus 4.8 / 4.7
output_config={"effort": "high"}, # low | medium | high | xhigh | max
messages=[{"role": "user", "content": "Solve this step by step..."}]
)
@@ -316,7 +317,7 @@ To access raw headers or other response metadata, use `.with_raw_response`:
```python
raw = client.messages.with_raw_response.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
@@ -362,7 +363,7 @@ class ConversationManager:
# Usage
conversation = ConversationManager(
client=anthropic.Anthropic(),
model="claude-opus-4-8",
model="claude-opus-5",
system="You are a helpful assistant."
)
@@ -380,7 +381,7 @@ response2 = conversation.send("What's my name?") # Claude remembers "Alice"
### Compaction (long conversations)
> **Beta, Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6.** When conversations approach the 200K context window, compaction automatically summarizes earlier context server-side. The API returns a `compaction` block; you must pass it back on subsequent requests — append `response.content`, not just the text.
> **Beta, Fable 5, Claude Opus 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6.** When conversations approach the 200K context window, compaction automatically summarizes earlier context server-side. The API returns a `compaction` block; you must pass it back on subsequent requests — append `response.content`, not just the text.
```python
import anthropic
@@ -393,7 +394,7 @@ def chat(user_message: str) -> str:
response = client.beta.messages.create(
betas=["compact-2026-01-12"],
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=messages,
context_management={
@@ -464,7 +465,7 @@ if fallback_ran and response.stop_reason != "refusal":
print(f"Served by {response.model}")
```
A `stop_reason: "refusal"` on the final response means the whole chain refused. The header must be exactly `server-side-fallback-2026-06-01`; the parameter is rejected on the Batches API and unavailable on Amazon Bedrock, Vertex AI, and Microsoft Foundry — register the client-side `BetaRefusalFallbackMiddleware` on the client there instead. Full semantics (sticky routing, billing, streaming, echoing fallback turns back): `shared/model-migration.md` → Migrating to Claude Fable 5 → `refusal` stop reason.
A `stop_reason: "refusal"` on the final response means the whole chain refused. The header must be exactly `server-side-fallback-2026-06-01` **for this array form**; the newer `fallbacks: "default"` scalar form uses `server-side-fallback-2026-07-01` instead (see `shared/model-migration.md` → Migrating to Claude Opus 5 → New API features), and pairing either header with the other form returns a 400. The parameter is rejected on the Batches API and unavailable on Amazon Bedrock, Vertex AI, and Microsoft Foundry — register the client-side `BetaRefusalFallbackMiddleware` on the client there instead. Full semantics (sticky routing, billing, streaming, echoing fallback turns back): `shared/model-migration.md` → Migrating to Claude Fable 5 → `refusal` stop reason.
---
@@ -475,7 +476,7 @@ A `stop_reason: "refusal"` on the final response means the whole chain refused.
```python
# Automatic caching (simplest — caches the last cacheable block)
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
cache_control={"type": "ephemeral"},
system=large_document_text, # e.g., 50KB of context
@@ -491,7 +492,7 @@ response = client.messages.create(
```python
# Default to Opus for most tasks
response = client.messages.create(
model="claude-opus-4-8", # $5.00/$25.00 per 1M tokens
model="claude-opus-5", # $5.00/$25.00 per 1M tokens
max_tokens=16000,
messages=[{"role": "user", "content": "Explain quantum computing"}]
)
@@ -515,7 +516,7 @@ simple_response = client.messages.create(
```python
count_response = client.messages.count_tokens(
model="claude-opus-4-8",
model="claude-opus-5",
messages=messages,
system=system
)
@@ -26,7 +26,7 @@ message_batch = client.messages.batches.create(
Request(
custom_id="request-1",
params=MessageCreateParamsNonStreaming(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Summarize climate change impacts"}]
)
@@ -34,7 +34,7 @@ message_batch = client.messages.batches.create(
Request(
custom_id="request-2",
params=MessageCreateParamsNonStreaming(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Explain quantum computing basics"}]
)
@@ -130,7 +130,7 @@ message_batch = client.messages.batches.create(
Request(
custom_id=f"analysis-{i}",
params=MessageCreateParamsNonStreaming(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
system=shared_system,
messages=[{"role": "user", "content": question}]
@@ -40,7 +40,7 @@ print(f"Size: {uploaded.size_bytes} bytes")
```python
response = client.beta.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -69,7 +69,7 @@ image_file = client.beta.files.upload(
)
response = client.beta.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -147,7 +147,7 @@ questions = [
for question in questions:
response = client.beta.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -4,7 +4,7 @@
```python
with client.messages.stream(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=64000,
messages=[{"role": "user", "content": "Write a story"}]
) as stream:
@@ -16,7 +16,7 @@ with client.messages.stream(
```python
async with async_client.messages.stream(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=64000,
messages=[{"role": "user", "content": "Write a story"}]
) as stream:
@@ -30,7 +30,7 @@ async with async_client.messages.stream(
```python
for event in client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=64000,
messages=[{"role": "user", "content": "Write a story"}],
stream=True,
@@ -46,13 +46,13 @@ No final-message accumulation is done for you in this form.
Claude may return text, thinking blocks, or tool use. Handle each appropriately:
> **Fable 5 / Opus 4.8 / Opus 4.7 / Opus 4.6:** Use `thinking: {type: "adaptive"}`. On older models, use `thinking: {type: "enabled", budget_tokens: N}` instead.
> **Fable 5 / Claude Opus 5 / Opus 4.8 / Opus 4.7 / Opus 4.6:** Use `thinking: {type: "adaptive"}`. On Claude Opus 5 adaptive is also what you get by omitting `thinking` entirely. On older models, use `thinking: {type: "enabled", budget_tokens: N}` instead.
```python
with client.messages.stream(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=64000,
thinking={"type": "adaptive", "display": "summarized"}, # display opt-in: default is omitted (empty thinking text) on Fable 5 / Mythos 5 / Opus 4.8 / 4.7
thinking={"type": "adaptive", "display": "summarized"}, # display opt-in: default is omitted (empty thinking text) on Fable 5 / Mythos 5 / Claude Opus 5 / Opus 4.8 / 4.7
messages=[{"role": "user", "content": "Analyze this problem"}]
) as stream:
for event in stream:
@@ -77,7 +77,7 @@ The Python tool runner supports streaming: pass `stream=True` to `client.beta.me
```python
with client.messages.stream(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=64000,
tools=tools,
messages=messages
@@ -95,7 +95,7 @@ with client.messages.stream(
```python
with client.messages.stream(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=64000,
messages=[{"role": "user", "content": "Hello"}]
) as stream:
@@ -142,7 +142,7 @@ def stream_with_progress(client, **kwargs):
```python
try:
with client.messages.stream(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=64000,
messages=[{"role": "user", "content": "Write a story"}]
) as stream:
+20 -20
View File
@@ -27,7 +27,7 @@ def get_weather(location: str, unit: str = "celsius") -> str:
# The tool runner handles the agentic loop automatically
runner = client.beta.messages.tool_runner(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
tools=[get_weather],
messages=[{"role": "user", "content": "What's the weather in Paris?"}],
@@ -60,7 +60,7 @@ max_restarts = 5 # cap pause_turn restarts, mirroring max_continuations advice
restarts = 0
while True:
runner = client.beta.messages.tool_runner(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
tools=tools, # may mix @beta_tool functions and server-tool definitions
messages=messages,
@@ -109,7 +109,7 @@ async with stdio_client(StdioServerParameters(command="mcp-server")) as (read, w
tools_result = await mcp_client.list_tools()
# tool_runner is sync — returns the runner, not a coroutine
runner = client.beta.messages.tool_runner(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Use the available tools"}],
tools=[async_mcp_tool(t, mcp_client) for t in tools_result.tools],
@@ -127,7 +127,7 @@ from anthropic.lib.tools.mcp import mcp_message
prompt = await mcp_client.get_prompt(name="my-prompt")
response = await client.beta.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[mcp_message(m) for m in prompt.messages],
)
@@ -140,7 +140,7 @@ from anthropic.lib.tools.mcp import mcp_resource_to_content
resource = await mcp_client.read_resource(uri="file:///path/to/doc.txt")
response = await client.beta.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -181,7 +181,7 @@ messages = [{"role": "user", "content": user_input}]
# Agentic loop: keep going until Claude stops calling tools
while True:
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
tools=tools,
messages=messages
@@ -228,7 +228,7 @@ final_text = next(b.text for b in response.content if b.type == "text")
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
tools=tools,
messages=[{"role": "user", "content": "What's the weather in Paris?"}]
@@ -243,7 +243,7 @@ for block in response.content:
result = execute_tool(tool_name, tool_input)
followup = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
tools=tools,
messages=[
@@ -280,7 +280,7 @@ for block in response.content:
# Send all results back at once
if tool_results:
followup = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
tools=tools,
messages=[
@@ -310,7 +310,7 @@ tool_result = {
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
tools=tools,
tool_choice={"type": "tool", "name": "get_weather"}, # Force specific tool
@@ -330,7 +330,7 @@ import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -358,7 +358,7 @@ uploaded = client.beta.files.upload(file=open("sales_data.csv", "rb"))
# 2. Pass to code execution via container_upload block
# Code execution is GA; Files API is still beta (pass via extra_headers)
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
extra_headers={"anthropic-beta": "files-api-2025-04-14"},
messages=[{
@@ -403,7 +403,7 @@ for block in response.content:
```python
# First request: set up environment
response1 = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Install tabulate and create data.json with sample data"}],
tools=[{"type": "code_execution_20260120", "name": "code_execution"}]
@@ -415,7 +415,7 @@ container_id = response1.container.id
# Second request: reuse the same container
response2 = client.messages.create(
container=container_id,
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Read data.json and display as a formatted table"}],
tools=[{"type": "code_execution_20260120", "name": "code_execution"}]
@@ -455,7 +455,7 @@ import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Remember that my preferred language is Python."}],
tools=[{"type": "memory_20250818", "name": "memory"}],
@@ -481,7 +481,7 @@ memory = MyMemoryTool()
# Use with tool runner
runner = client.beta.messages.tool_runner(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
tools=[memory],
messages=[{"role": "user", "content": "Remember my preferences"}],
@@ -516,7 +516,7 @@ class ContactInfo(BaseModel):
client = anthropic.Anthropic()
response = client.messages.parse(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -535,7 +535,7 @@ print(contact.interests) # ["API", "SDKs"]
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{
"role": "user",
@@ -569,7 +569,7 @@ data = json.loads(text)
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Book a flight to Tokyo for 2 passengers on March 15"}],
tools=[{
@@ -594,7 +594,7 @@ response = client.messages.create(
```python
response = client.messages.create(
model="claude-opus-4-8",
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Plan a trip to Paris next month"}],
output_config={
@@ -51,7 +51,7 @@ print(environment.id) # env_...
# 1. Create the agent (reusable, versioned)
agent = client.beta.agents.create(
name="Coding Assistant",
model="claude-opus-4-8",
model="claude-opus-5",
tools=[{"type": "agent_toolset_20260401", "default_config": {"enabled": True}}],
)
@@ -71,7 +71,7 @@ import os
agent = client.beta.agents.create(
name="Code Reviewer",
model="claude-opus-4-8",
model="claude-opus-5",
system="You are a senior code reviewer.",
tools=[
{"type": "agent_toolset_20260401"},
@@ -314,7 +314,7 @@ client.beta.sessions.archive(session_id="sesn_011CZxAbc123Def456")
# Agent declares MCP server (no auth here — auth goes in a vault)
agent = client.beta.agents.create(
name="MCP Agent",
model="claude-opus-4-8",
model="claude-opus-5",
mcp_servers=[
{"type": "url", "name": "my-tools", "url": "https://my-mcp-server.example.com/sse"},
],