Modelsanthropicclaude-fable-5
provideranthropic /

claude-fable-5

3500 DZD in 17500 DZD out/ 1M tokens

Claude Fable 5 was Anthropic's most capable widely released model, built for demanding reasoning and long-horizon agentic work. Two things set it apart from everything else in this catalogue. Thinking is permanently on — there is no parameter that disables it, only an effort dial that sets how deep it goes. And it ships with safety classifiers that can decline a request, returning a successful response carrying a refusal rather than an error, which means any integration must inspect why a response ended rather than assuming a 200 means an answer. It holds a million-token context with a 128,000-token output ceiling, and reads text and images.

PublicJSONStreaming
claude-fable-5
Capabilities
ToolsVisionReasoningStructured output
ArchitectureProprietary
Context Window1M

Claude Fable 5

Anthropic's most capable widely released model at launch, aimed at demanding reasoning and long-horizon agentic work. Released June 2026.


Refusals Arrive as Successful Responses

The single most consequential fact for anyone integrating this model, and the easiest to miss.

Fable 5 carries safety classifiers capable of declining a request. When one fires, the Messages API returns HTTP 200 with stop_reason: "refusal". No exception is raised. No error code comes back. The response also names which classifier declined.

So a handler written like this quietly ships a refusal to your user as though it were an answer:

PYTHON
if response.ok:
    return response.content  # a refusal reaches production looking like a result

Check why the response ended, not merely that it arrived:

PYTHON
if response.stop_reason == "refusal":
    # Route to review, retry on a different model, or tell the user plainly.
    handle_declined(response)
else:
    deliver(response.content)

This behaviour is specific to Fable within its tier — the Project Glasswing variant of the same underlying model carries no such classifiers.

Anthropic tunes these conservatively, which means harmless requests are sometimes caught. Their published figure puts the trigger rate at under five percent of sessions on average. Plan a path for that minority rather than discovering it in a support ticket.


A Request May Be Answered by a Different Model

Related, and equally worth knowing before you build.

Anthropic operates a safeguards routing mechanism: queries on certain topics sent to Fable can be served by Claude Opus 5 instead. The request succeeds. The answer is real. It simply came from somewhere else.

Two implications for anything you build on top.

Do not assume the responding model matches the requested one. Read the model field on the response if your logic, logging, or billing depends on which one answered.

Evaluations can drift without explanation. A benchmark suite run against Fable that includes topics the routing catches is measuring a mixture, not a model. Check the responses if a result looks inconsistent with earlier runs.


Thinking Cannot Be Switched Off

Adaptive thinking is always on. There is no disable flag — thinking: {"type": "disabled"} is not supported on this model, unlike Opus-tier models where it is accepted below a certain effort.

The effort parameter is the only control, and it sets depth rather than presence.

Effort defaults to high. Anthropic's guidance is to start there and adjust from your own evaluation results rather than from intuition.

Because the model always reasons, max_tokens must cover thinking plus answer. A ceiling sized for the answer alone truncates the model mid-thought and returns something unusable rather than something shorter.


Specifications

Model IDanthropic/claude-fable-5
Context window1,000,000 tokens — default
Max output128,000 tokens
ThinkingAdaptive, always on
Default efforthigh
Input → outputText and images → text
Reliable knowledge cutoffJanuary 2026
Released9 June 2026
StatusActive (legacy)

The full million-token window carries no surcharge and needs no beta header.

Anthropic publishes no parameter counts, architectural details, or weights for Claude models.


Capabilities

CapabilityValue
input_typestext, image
output_typestext
audio_inputNot supported
video_inputNot supported
context_window1000000
max_output_tokens128000
reasoningAdaptive — permanently enabled
thinking_disableNot supported
safety_classifiersPresent — can return stop_reason: "refusal"
streamingSupported
tool_callingSupported
structured_outputSupported
requires_promptYes — text prompt required, image optional

Where It Sits Now

Anthropic marks this model Active (legacy) and has published a newer release in the same tier, claude-fable-5-1, carrying a knowledge cutoff five months more recent.

That does not make this model a wrong choice. It makes the choice deliberate: pick it when something downstream was tuned against it, when you are reproducing earlier results, or when a migration has a cost you are not ready to pay.

Three changes are breaking if you move to the newer release, so a migration is more than a model string:

  • Forced tool use returns an error — only auto and none are accepted for tool_choice
  • Earlier models cannot read its thinking blocks
  • Editing earlier turns invalidates thinking blocks

Anthropic's own routing advice is worth repeating: for most workloads they suggest starting with Claude Opus 5, and reaching for this tier when evaluations at higher effort on Opus still fall short.


Using Claude Fable 5 on DEVUP AI

Base URL: https://api.devupai.com/v1 · Model ID: anthropic/claude-fable-5

First request — cURL

BASH
curl https://api.devupai.com/v1/chat/completions \
  -H "Authorization: Bearer $DEVUP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-fable-5",
    "messages": [
      {
        "role": "user",
        "content": "Our reconciliation job double-counts refunds issued in the same minute as the original charge, but only under load. Rank the mechanisms that could produce that, and say which one the timing detail points to."
      }
    ],
    "max_tokens": 32768
  }'

Handling refusals properly — Python

The integration pattern this model requires.

PYTHON
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEVUP_API_KEY"],
    base_url="https://api.devupai.com/v1",
)


def ask(prompt: str, *, max_tokens: int = 32768):
    """Send a request and distinguish a real answer from a declined one."""
    reply = client.chat.completions.create(
        model="anthropic/claude-fable-5",
        messages=[{"role": "user", "content": prompt}],
        max_tokens=max_tokens,
    )

    choice = reply.choices[0]

    # A decline arrives as a successful response, not an exception.
    if getattr(choice, "finish_reason", None) == "refusal":
        return {"declined": True, "content": None}

    # The answering model is not guaranteed to be the one requested.
    if reply.model and reply.model != "anthropic/claude-fable-5":
        logger.info("served by %s", reply.model)

    return {"declined": False, "content": choice.message.content}

Both checks earn their place. The first stops a refusal from reaching a user dressed as an answer. The second tells you when routing sent the request elsewhere, which matters for logs, evaluations, and anything that reasons about which model produced what.

Sizing the output budget — Python

PYTHON
reply = client.chat.completions.create(
    model="anthropic/claude-fable-5",
    messages=[{"role": "user", "content": hard_question}],
    max_tokens=64000,  # reasoning and answer share this
)

usage = reply.usage
print(f"in {usage.prompt_tokens} · out {usage.completion_tokens}")

Thinking runs on every request and consumes output tokens. Watch the completion count on a few real requests before settling on a ceiling — a budget that worked on a model where reasoning was optional will not transfer.

A long-horizon agent — Python

The workload this tier exists for.

PYTHON
import json

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "query_ledger",
            "description": "Run a read-only query against the accounting ledger.",
            "parameters": {
                "type": "object",
                "properties": {"sql": {"type": "string"}},
                "required": ["sql"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "fetch_statement",
            "description": "Retrieve a bank statement for a given month.",
            "parameters": {
                "type": "object",
                "properties": {"month": {"type": "string"}},
                "required": ["month"],
            },
        },
    },
]


def query_ledger(sql: str) -> dict:
    """Replace with your real, read-only data layer."""
    raise NotImplementedError


def fetch_statement(month: str) -> dict:
    """Replace with your real statement source."""
    raise NotImplementedError


HANDLERS = {"query_ledger": query_ledger, "fetch_statement": fetch_statement}

thread = [
    {
        "role": "system",
        "content": (
            "You are reconciling accounts. Cite the query or statement behind every figure you "
            "report. Where two sources disagree, show both and explain the discrepancy rather "
            "than picking one."
        ),
    },
    {"role": "user", "content": "Reconcile January against the bank statement and explain every variance above 1000 DZD."},
]

CEILING = 30

for step in range(CEILING):
    reply = client.chat.completions.create(
        model="anthropic/claude-fable-5",
        messages=thread,
        tools=TOOLS,
        max_tokens=32768,
    )

    choice = reply.choices[0]

    if getattr(choice, "finish_reason", None) == "refusal":
        print("Request declined by a safety classifier.")
        break

    message = choice.message
    thread.append(message)

    if not message.tool_calls:
        print(message.content)
        break

    for call in message.tool_calls:
        handler = HANDLERS.get(call.function.name)
        if handler is None:
            result = {"error": "unknown tool", "name": call.function.name}
        else:
            try:
                result = handler(**json.loads(call.function.arguments or "{}"))
            except Exception as exc:
                # Describe the failure. The model works with it; an exception ends the session.
                result = {"error": type(exc).__name__, "detail": str(exc)}

        thread.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})
else:
    print(f"Reached the {CEILING}-step ceiling without concluding.")

The refusal check sits inside the loop deliberately. A classifier can fire on any turn, not only the first, and a loop that ignores it will keep iterating on a response that contains no tool call and no useful content.

CEILING is what ends a run that does not end itself.

Reading documents and charts — Python

PYTHON
import base64

with open("annual_report_page.png", "rb") as handle:
    encoded = base64.b64encode(handle.read()).decode("utf-8")

reply = client.chat.completions.create(
    model="anthropic/claude-fable-5",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{encoded}"}},
                {
                    "type": "text",
                    "text": (
                        "Report every figure on this page with its label and unit. Separate values "
                        "printed in the document from values you inferred by reading a chart axis, "
                        "and mark anything illegible as such."
                    ),
                },
            ],
        }
    ],
    max_tokens=16384,
)

Separating printed figures from axis-read estimates is a small ask with a large payoff. One category belongs in a spreadsheet unchecked; the other does not, and they look identical once transcribed.

Node.js — DEVUP AI SDK

BASH
npm install devupai
JAVASCRIPT
import DevupAI from "devupai";

const client = new DevupAI({
  apiKey: process.env.DEVUP_API_KEY,
});

const reply = await client.chat.completions.create({
  model: "anthropic/claude-fable-5",
  messages: [
    {
      role: "system",
      content:
        "Assess this architecture against a two-engineer team with no platform specialist. " +
        "Say what you would rule out and why before saying what you would choose.",
    },
    { role: "user", content: proposal },
  ],
  max_tokens: 32768,
});

const choice = reply.choices[0];

if (choice.finish_reason === "refusal") {
  console.warn("Declined by a safety classifier.");
} else {
  console.log(choice.message?.content);
}

Streaming

PYTHON
stream = client.chat.completions.create(
    model="anthropic/claude-fable-5",
    messages=[{"role": "user", "content": "Design an idempotency scheme for a payment callback that may arrive twice."}],
    max_tokens=32768,
    stream=True,
)

for chunk in stream:
    if not chunk.choices:
        if getattr(chunk, "usage", None):
            print(f"\n\nin {chunk.usage.prompt_tokens} · out {chunk.usage.completion_tokens}")
        continue

    piece = chunk.choices[0].delta
    if getattr(piece, "content", None):
        print(piece.content, end="", flush=True)

The model reasons before anything becomes visible, and at high effort that gap is real. Raise client timeouts before deploying — a value tuned for a non-reasoning model expires while this one is still working, and the reasoning it performed is already spent.


Prompting Notes

Ask for the argument alongside the conclusion. At this tier the reasoning is frequently the more useful half, and it is what makes a conclusion something you can disagree with intelligently.

Supply your constraints up front — team size, timeline, existing stack, what is already ruled out. A deep analysis that ignores your real limits is a well-made answer to somebody else's question.

Send one substantial question rather than several small ones. Splitting a problem across requests discards the cross-cutting reasoning that justifies reaching for this tier.

Iterate on a faster model, then run the final question here. A model that thinks at length is not a model you develop prompts against.


Limitations

A refusal is a successful response. Inspect stop_reason on every call, or a declined request reaches your users looking like an answer.

The responding model may differ from the requested one. Safeguards routing can serve a Fable request from Opus 5 — infrequently, but not never.

Thinking cannot be disabled. There is no fast path; the effort dial changes depth only.

Reasoning shares the output ceiling. Size max_tokens for both, or requests truncate mid-thought.

Knowledge ends January 2026. Later facts require retrieval or a search tool, and the newer release in this tier reaches five months further.

Text and images only. No audio, no video, no image generation.

Marked legacy by Anthropic, with a current release available in the same tier. Migration there is not a model-string swap: three documented behaviours change.

Internals are undisclosed — no parameter count, no architecture, no weights.

A well-argued answer is not a verified one. Extended reasoning improves the argument, not the premises. Check anything you intend to act on.