Skip to content

feat: add Claude Fable 5.1 support — pricing (75% cache-read reduction), capability parity with Fable 5 - #112

Merged
Salil Das (sadlilas) merged 5 commits into
mainfrom
resolve/amplifier-module-provider-anthropic-e2f0540e
Sep 2, 2026
Merged

feat: add Claude Fable 5.1 support — pricing (75% cache-read reduction), capability parity with Fable 5#112
Salil Das (sadlilas) merged 5 commits into
mainfrom
resolve/amplifier-module-provider-anthropic-e2f0540e

Conversation

@kenotron-ms

@kenotron-ms Ken Chau (kenotron-ms) commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds support for Claude Fable 5.1 (claude-fable-5-1), announced September 2026. Fable 5.1 is generally available; its Mythos 5.1 counterpart is trusted-access only and is deliberately out of scope here (see Not In Scope).

Fable 5.1 is the same capability shape as Fable 5 — the change is almost entirely pricing. Anthropic's headline for 5.1 is a cost reduction delivered specifically through cache reads, which is the one rate that moves.

Key changes:

  • _RATES entry for claude-fable-5-1: $10.00 / $50.00 input/output, cache read $0.25/MTok — a 75% reduction from Fable 5's $1.00, cache write $12.50/MTok (unchanged)
  • No new capability flags required — _detect_family("claude-fable-5-1") already returns "fable" and the fable capability branch is version-agnostic, so 5.1 inherits the full Fable 5 profile automatically
  • 15 new tests: 8 covering registration/capabilities/family+version detection, 7 covering the pricing table
  • Docstring update in __init__.py to name Fable 5.1 alongside Fable 5

What's New in Fable 5.1 (API-Level)

Pricing — the only substantive change. Anthropic states Fable 5.1 "will cost an estimated 25% less than Fable 5 for typical workloads… because we're reducing our pricing on cache reads," and up to ~45% for highly agentic work. Input, output, and cache-write rates are unchanged from Fable 5; cache_read_per_m drops $1.00 → $0.25.

No new or changed request parameters. Confirmed against the announcement and the model docs. Effort tiers (low/medium/high/xhigh/max) already exist in this module and are unchanged — the announcement's note that Fable 5.1 defaults to High effort in Claude Code and Medium elsewhere is a client default, not a provider-level API change.

No dated snapshot ID published. The docs list only the alias claude-fable-5-1. If a dated snapshot appears later it will need a separate _RATES entry, as with previous models.

Capability Profile for claude-fable-5-1

Identical to claude-fable-5 — asserted as whole-object equality (assert caps51 == caps5) in test_fable51_capabilities_match_fable5, covering all 21 ModelCapabilities fields.

Attribute Value
Context window 1M tokens
Max output 128k tokens
Thinking mode Adaptive (always on, cannot be disabled)
Effort levels low, medium, high, xhigh, max
Speed mode Not supported
Cache support 5-min and 1-hour write; read access
Inline system message Supported
Sampling Not supported

Implementation Details

1. Pricing (_cost.py)

claude-fable-5-1 added to _RATES, with the source URLs and the cache-read delta recorded inline as a comment.

2. Capabilities (__init__.py)

No functional change needed. _detect_family returns "fable", _detect_version returns (5, 1), and the fable branch of _get_capabilities is version-agnostic. Only the docstring changed, to name Fable 5.1 explicitly. This is worth a reviewer's eye: the tests assert the inheritance holds rather than assuming it.

3. Tests

  • tests/test_fable51_support.py (8) — family detection, version detection, capability matrix, capability parity with Fable 5, _RATES registration, cache-read rate, fallback target, cost_usd stamping
  • tests/test_cost.py (+7) — input, output, cache-read, cache-write costs; cache read cheaper than Fable 5; not fast-mode eligible; input/output identical to Fable 5

Verification

Live API call against the real model, executed in the Resolve worker (not mocked):

text: fable51ok
finish_reason: end_turn
usage.input_tokens: 16
usage.output_tokens: 7
usage.cost_usd: 0.00051

Cost arithmetic checks out end-to-end: 16 × $10/MTok + 7 × $50/MTok = $0.00016 + $0.00035 = $0.00051. This confirms the identifier resolves, the model responds, and the new _RATES entry is actually wired into cost stamping.

Suite: uv run pytest --tb=short770 passed. No new lint errors versus main (the two pre-existing ruff findings in the touched files are unchanged — see reviewer note 1).

Research Sources

Fact Value Source
API model identifier claude-fable-5-1 model docs
Context window 1M tokens model docs
Max output tokens 128K tokens model docs
Input / Output price $10 / $50 per MTok pricing
Cache read price $0.25/MTok (−75% vs Fable 5) pricing + announcement
Cache write price $12.50/MTok (unchanged) pricing
New/changed API params None published announcement
Dated snapshot ID None published model docs

Not In Scope

  • Mythos 5.1 — trusted-access only and unavailable to this account: models.list() returns no Mythos models at all. No Mythos identifiers added, tested, or referenced. (Not citing fix: descope Mythos-5, add refusal-fallback-to-opus (follow-up to #58) #67 as precedent — that PR did descope Mythos 5, but main has since re-added Mythos across capability detection, the fallback ladder, and the README, so the precedent no longer holds. The reason here is simply no access.)
  • Dated snapshot IDs (none published yet)
  • Any change to the effort-tier or thinking machinery — Fable 5.1 introduces no new knobs

Reviewer notes — two things to look at

  1. _PER_M and an import blank line were changed as ruff auto-fixes. Reverted — this repo has no [tool.ruff] config, ruff isn't a dev dependency, and CI runs only pytest, so neither rule is actually enforced here. Both lines are byte-identical to main again.
  2. This PR carried 9 .ai/* scratch files from the automation that produced it. Resolved — stripped in chore: drop .ai/ pipeline scratch from the PR. The diff is now 5 files: __init__.py, _cost.py, README.md, and the two test files. The pipeline-side cause is fixed in amplifier-resolver-dot-graph#142 so it stops recurring.

Provenance

Authored by an automated Amplifier Resolve goal run (instance e2f0540e3ae2). The verification above is the run's own captured output, reproduced here rather than summarized. The pricing figures were taken from Anthropic's published pages at the time of the run and should be spot-checked by a reviewer before merge.


Review round 1 — findings applied (4d68b1a)

An adversarial review against the five-check framework (Necessity · Layer fit · Pattern · Correctness · Calibration) returned CHANGES_REQUESTED. All six findings are fixed:

# Finding Fix
B1 The 1M-context model list is enumerated in three places; only one was updated Added Fable 5.1 to __init__.py:980 and README.md:275
B2 _cost.py:40 states cache_read ≈ 10 % of input_per_m — 19 of 20 rows obey it; this PR added the first exception (2.5%) without amending it Invariant now names its exception; the Fable 5 "2× Opus 4.8" note gained a don't-over-generalize pointer
B3 test_fable51_fallback_target_is_opus couldn't fail for a Fable-5.1 reason — claude-fable-banana also returns claude-opus-5 Asserts the concrete target; mutation-verified (repointing the opus rung passes the old assert, fails the new one)
N1 The parity test hand-compared 16 fields; ModelCapabilities has 21 Replaced with assert caps51 == caps5 — 21 fields, 15 lines shorter, mutation-verified against all 5 previously-blind fields
N2 A local named expected held a ratio that coincidentally equalled the expected dollar value Renamed ratio_of_fable5
N3 Two unrelated ride-along edits justified by lint rules this repo doesn't enforce Reverted, byte-identical to main

Suite still 770 passed.

Filed separately — not fixed here

Verification surfaced a pre-existing discrepancy on an untouched row: _cost.py:65-77 encodes claude-sonnet-5 at $3/$15, treating the published $2/$10 as an introductory discount expiring 2026-08-31. That date has passed and the published price is still $2/$10, which would mean the repo's default model over-reports cost by 50%. Entirely outside this diff and deliberately not bolted on — it needs its own verification and its own change.


Review round 2 — five-check rubric (branch tip 4d68b1a)

Protocol followed: diff read to orient; all 5 changed files read in full; callers, tests, and related surfaces read; five checks applied; sibling-model sweep performed.

Five checks

1. Necessity — The claude-fable-5-1 entry in _RATES is required: without it compute_cost("claude-fable-5-1", ...) returns None, silently breaking cost tracking for any user of Fable 5.1. The capability detection works automatically via _detect_family returning "fable" — no new capability branch needed. The implementation is minimal and correct. PASS

2. Layer fit — Change is in amplifier_module_provider_anthropic, the Anthropic provider module. Model pricing and capability registration belong here. PASS

3. Pattern_RATES entry follows the exact same 4-key pattern as all other models (input_per_m, output_per_m, cache_read_per_m, cache_write_per_m). Comment style matches. Tests follow the same pattern as existing model tests. PASS

4. Correctness — Pricing verified directly against https://www.anthropic.com/pricing (2026-09-02): Input $10/MTok, Output $50/MTok, Cache Read $0.25/MTok, Cache Write $12.50/MTok — all match _cost.py:166-171. Version detection: _detect_version("claude-fable-5-1", "fable") returns (5, 1) via the fable-(\d+)-(\d{1,2})(?:-|$) pattern; the 2-digit minor guard prevents a hypothetical dated snapshot claude-fable-5-20260901 from being mis-parsed as (5, 20). Capabilities: _get_capabilities fable branch is version-agnostic; caps51 == caps5 confirmed. Fallback: _fallback_target_for_model("claude-fable-5-1") == "claude-opus-5" confirmed. PASS

5. Calibration — Sibling-model sweep: every surface where claude-fable-5 appears was checked for whether claude-fable-5-1 also needed to appear. Surfaces checked:

  • _RATES — ✓ present (_cost.py:166)
  • __init__.py comment at line 980 — ✓ updated (Fable 5/5.1)
  • __init__.py docstring at line 1662 — ✓ updated (Fable 5 / Fable 5.1)
  • README.md:276 — ✓ updated (Fable 5/5.1)
  • _FAST_ELIGIBLE_MODELS — ✓ NOT added (Fable has no speed mode; test guards this)
  • _FALLBACK_NEXT_FAMILY — ✓ NOT added (family-level map; fable->opus covers all fable models)
  • _STATIC_FALLBACK_MODELS — ✓ NOT added (values are targets, not sources; fable never appears as a value)
  • _INERT_CONFIG_KEY_MESSAGES — ✓ no model-specific entries
  • docs/, scripts/ — ✓ no fable references

No missing surface found. PASS

Mutation verification

Cache-read rate guard: setting cache_read_per_m to Decimal("0.50") caused test_fable51_cache_read_rate, test_fable51_cache_read_cost, and test_fable51_cache_read_cheaper_than_fable5 to fail as expected. Restored.

Capability parity guard: adding a version gate (max_output_tokens=64000 if (major, minor) == (5, 1) else 128000) caused test_fable51_capabilities_match_fable5 and test_fable51_capabilities_correct to fail as expected. Restored.

Suite

uv run pytest tests/ --tb=short
770 passed in 60.03s (0:01:00)

No regressions. Count at or above pre-work baseline (770 passed before this PR; 770 passed now, with 15 new tests added by this PR).

No blocking findings

All five checks pass. No new findings.

VERDICT: PASS

Amplifier Resolve added 3 commits September 2, 2026 00:49
Registers claude-fable-5-1 in the provider module:

- _cost.py: add claude-fable-5-1 to _RATES with the new cache read price
  ($0.25/MTok, 75% reduction from Fable 5's $1.00/MTok). Input/output/
  cache-write rates are unchanged ($10/$50/$12.50 per MTok).
- __init__.py: update _get_capabilities docstring to mention Fable 5.1.
  The fable branch already handles all fable models generically -- no
  version-gating needed since 5.1 has identical capabilities to 5.
- tests/test_cost.py: add pricing tests for claude-fable-5-1 (input,
  output, cache_read, cache_write, comparative vs Fable 5).
- tests/test_fable51_support.py: new test file covering family/version
  detection, capabilities, _RATES registration, cache read rate,
  fallback target, and cost_usd stamping.

Also auto-fixes a pre-existing ruff FURB157 lint issue in _cost.py
(_PER_M = Decimal(1_000_000) instead of Decimal("1_000_000")) and
import-sort in tests/test_cost.py.

Facts sourced from:
- API model identifier: claude-fable-5-1
  Source: https://docs.anthropic.com/en/docs/about-claude/models/overview
- Context window: 1M tokens (same as Fable 5)
  Source: https://docs.anthropic.com/en/docs/about-claude/models/overview
- Max output tokens: 128K tokens (same as Fable 5)
  Source: https://docs.anthropic.com/en/docs/about-claude/models/overview
- Pricing: $10/$50/$0.25/$12.50 per MTok (input/output/cache_read/cache_write)
  Source: https://www.anthropic.com/pricing
          https://www.anthropic.com/claude-fable-and-mythos-5-1
- No new or changed API request parameters
  Source: https://www.anthropic.com/claude-fable-and-mythos-5-1

Live API validation (2026-09-02, resolve worker environment):
  Model: claude-fable-5-1
  Request: {messages: [{role: user, content: 'Say: fable51ok'}], max_tokens: 20}
  Response: text='fable51ok', finish_reason='end_turn',
            usage.input_tokens=16, usage.output_tokens=7,
            usage.cost_usd=0.00051
@kenotron-ms Ken Chau (kenotron-ms) changed the title Automated implementation via the implement pipeline feat: add Claude Fable 5.1 support — pricing (75% cache-read reduction), capability parity with Fable 5 Sep 2, 2026
Ken and others added 2 commits September 2, 2026 04:12
These 9 files are working state from the automation that produced this
branch (goal_journal.md, goal_verdict.json, goal_condition.md, ...), not
part of the Fable 5.1 change. Only 4 files are the real diff.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Addresses the CHANGES_REQUESTED findings from the adversarial review.

BLOCKING
- B1: the 1M-context model list is enumerated by explicit version in three
  places; the PR had updated only one. Add Fable 5.1 to the other two --
  __init__.py:980 (comment) and README.md:275 (user-facing). The code
  already sets supports_1m=True for it, so both were simply stale.
- B2: _cost.py's "cache_read ~= 10 % of input_per_m" invariant held for
  19 of 20 rate rows; claude-fable-5-1 is the first exception at 2.5 %
  (Anthropic cut Fable 5.1 cache reads 75 %). Note it inline. Also add a
  pointer on the Fable 5 "exactly 2x Opus 4.8" comment so it is not
  over-generalised to the fable family. test_fable5_exact_2x_opus48 is
  correct for Fable 5 itself and is left untouched.
- B3: test_fable51_fallback_target_is_opus had no discriminating power --
  _fallback_target_for_model branches only on _detect_family, so the
  family-level assertion also held for "claude-fable-banana". Assert the
  concrete target ("claude-opus-5"), which catches a regression in the
  _STATIC_FALLBACK_MODELS backstop. Verified by mutation: pointing the
  opus rung at claude-opus-4-8 passes the old assert, fails the new one.

NON-BLOCKING
- N1: replace 16 hand-rolled field comparisons with whole-object equality.
  ModelCapabilities has 21 fields; the list silently omitted 5. The test is
  kept -- the sibling mythos branch IS version-gated, so a future fable
  version gate is a real regression this guards -- with that rationale
  moved into the docstring.
- N2: a local named `expected` held a dimensionless RATIO (0.25) that
  collided with the expected DOLLAR value ($0.25). Renamed.
- N3: revert two unrelated ride-along style edits back to origin/main.
  They were attributed to ruff FURB157/I001, but this repo has no
  [tool.ruff] config, ruff is not a dev dependency, CI runs only
  `uv run pytest -q`, and neither rule is in ruff's default set.

Out of scope, deliberately untouched: the claude-sonnet-5 durable-vs-intro
rate question (pre-existing, filed separately) and Mythos 5.1.

Verified: uv run pytest -q -> 770 passed (baseline unchanged).

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
@sadlilas
Salil Das (sadlilas) merged commit 6abfcff into main Sep 2, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants