diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d445f9..7637d0b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ See [docs/RELEASING.md](docs/RELEASING.md) for the release procedure. ## [Unreleased] ### Added +- Bundled price catalog: `claude-fable-5-1` ($10/$50 per 1M tokens, 1-hour cache + write $20, **cache read $0.25 — 0.025x base input, not the 0.1x every other + Claude model uses**), verified against the official Anthropic pricing page + 2026-09-04; the other Claude entries re-verified at the same date. ([#80]) +- Bundled price catalog: `claude-sonnet-5` ($2/$10 per 1M tokens, cache read + $0.20 / 1-hour cache write $4), verified against the official Anthropic + pricing page 2026-08-24. ([#78]) - Bundled price catalog: `claude-opus-5` ($5/$25 per 1M tokens, cache read $0.50 / 1-hour cache write $10), verified against the official Anthropic pricing page 2026-07-24; the other Claude entries re-verified at the same @@ -644,5 +651,7 @@ Initial release under the **nasde-toolkit** name (rebrand from [#73]: https://github.com/NoesisVision/nasde-toolkit/pull/73 [#74]: https://github.com/NoesisVision/nasde-toolkit/pull/74 [#77]: https://github.com/NoesisVision/nasde-toolkit/pull/77 +[#78]: https://github.com/NoesisVision/nasde-toolkit/pull/78 +[#80]: https://github.com/NoesisVision/nasde-toolkit/pull/80 [#81]: https://github.com/NoesisVision/nasde-toolkit/pull/81 [gh-litellm-2026-04]: https://github.com/BerriAI/litellm/security/advisories/GHSA-xqmj-j6mv-4862 diff --git a/src/nasde_toolkit/pricing.toml b/src/nasde_toolkit/pricing.toml index 1cbfd0cb..fc202bb9 100644 --- a/src/nasde_toolkit/pricing.toml +++ b/src/nasde_toolkit/pricing.toml @@ -15,10 +15,14 @@ # per-step cost accounting on the 2026-07 grid. OpenAI bills no write premium, # so gpt entries omit the field (writes fall back to the base input rate). # -# Claude models re-verified 2026-08-24 against the official pricing page (Fable 5, -# Opus 5, Opus 4.8, Sonnet 4.6 unchanged since 2026-07-13; Sonnet 5 added) — -# CONFIRM before publishing any cost figures. gpt entries not re-checked since -# 2026-06-08. +# Cache reads are 0.1x the base input rate on every Claude model EXCEPT +# Claude Fable 5.1 (and Mythos 5.1), where they are 0.025x — $0.25/MTok on a +# $10/MTok input rate. That is a published per-model exception, not a typo. +# +# Claude models re-verified 2026-09-04 against the official pricing page (Fable 5, +# Opus 5, Opus 4.8, Sonnet 5, Sonnet 4.6 unchanged since 2026-08-24; Fable 5.1 +# added) — CONFIRM before publishing any cost figures. gpt entries not re-checked +# since 2026-06-08. [models."gpt-5.5"] input_per_1m = 5.0 @@ -39,7 +43,7 @@ input_per_1m = 5.0 output_per_1m = 25.0 cached_input_per_1m = 0.50 cache_write_per_1m = 10.0 -as_of = "2026-08-24" +as_of = "2026-09-04" source = "https://platform.claude.com/docs/en/about-claude/pricing" [models."claude-opus-4-8"] @@ -47,7 +51,15 @@ input_per_1m = 5.0 output_per_1m = 25.0 cached_input_per_1m = 0.50 cache_write_per_1m = 10.0 -as_of = "2026-08-24" +as_of = "2026-09-04" +source = "https://platform.claude.com/docs/en/about-claude/pricing" + +[models."claude-fable-5-1"] +input_per_1m = 10.0 +output_per_1m = 50.0 +cached_input_per_1m = 0.25 +cache_write_per_1m = 20.0 +as_of = "2026-09-04" source = "https://platform.claude.com/docs/en/about-claude/pricing" [models."claude-fable-5"] @@ -55,7 +67,7 @@ input_per_1m = 10.0 output_per_1m = 50.0 cached_input_per_1m = 1.0 cache_write_per_1m = 20.0 -as_of = "2026-08-24" +as_of = "2026-09-04" source = "https://platform.claude.com/docs/en/about-claude/pricing" [models."claude-sonnet-5"] @@ -63,7 +75,7 @@ input_per_1m = 2.0 output_per_1m = 10.0 cached_input_per_1m = 0.20 cache_write_per_1m = 4.0 -as_of = "2026-08-24" +as_of = "2026-09-04" source = "https://platform.claude.com/docs/en/about-claude/pricing" [models."claude-sonnet-4-6"] @@ -71,5 +83,5 @@ input_per_1m = 3.0 output_per_1m = 15.0 cached_input_per_1m = 0.30 cache_write_per_1m = 6.0 -as_of = "2026-08-24" +as_of = "2026-09-04" source = "https://platform.claude.com/docs/en/about-claude/pricing" diff --git a/tests/test_evaluator.py b/tests/test_evaluator.py index 16784213..a71871e5 100644 --- a/tests/test_evaluator.py +++ b/tests/test_evaluator.py @@ -282,7 +282,7 @@ def test_assessment_summary_includes_economics(tmp_path: Path) -> None: assert summary.token_usage["total_tokens"] == 1_060_000 # sonnet $3/$15/$0.30 cached (ADR-014): fresh 0.2M*3 + cached 0.8M*0.30 + 0.06M*15 = 1.74 assert summary.cost_usd == pytest.approx(1.74) - assert summary.pricing_as_of == "2026-08-24" + assert summary.pricing_as_of == "2026-09-04" assert not hasattr(summary, "cost_efficiency") # removed: arbitrary zero → use Pareto front assert not hasattr(summary, "token_efficiency") diff --git a/tests/test_pricing.py b/tests/test_pricing.py index de9b20ef..7e889f88 100644 --- a/tests/test_pricing.py +++ b/tests/test_pricing.py @@ -87,6 +87,31 @@ def test_compute_cost_cache_aware_matches_harbor_accounting() -> None: assert cost == pytest.approx(8.841665, abs=0.0005) +def test_compute_cost_cache_aware_matches_harbor_accounting_fable_5_1() -> None: + # Real trial qoVXn7k (claude-fable-5-1, xhigh): Harbor's own per-step total was + # $3.57704175 — it applies the same 0.025x read rate. Pricing reads at 0.1x + # like every other Claude model would land at $4.38 (+22% on this token mix). + cost = compute_cost_usd( + 1_160_418, + 30_522, + "claude-fable-5-1", + load_pricing(), + cache_read_tokens=1_070_967, + cache_write_tokens=88_869, + ) + assert cost == pytest.approx(3.57704175, abs=0.0005) + + +def test_fable_5_1_cache_reads_bill_at_the_published_quarter_rate() -> None: + # Fable 5.1 reads are 0.025x base input ($0.25 on $10), not the 0.1x every + # other Claude model uses — guards the entry against a "consistency" fix. + pricing = load_pricing() + assert pricing["claude-fable-5-1"].cached_input_per_1m == 0.25 + # 1M prompt tokens, all cache reads, 0.1M output: 0.25 + 5.0 + cost = compute_cost_usd(1_000_000, 100_000, "claude-fable-5-1", pricing, cache_read_tokens=1_000_000) + assert cost == pytest.approx(5.25) + + def test_compute_cost_missing_cache_rates_falls_back_to_full_rate(tmp_path: Path) -> None: custom = tmp_path / "pricing.toml" custom.write_text('[models."bare"]\ninput_per_1m = 2.0\noutput_per_1m = 10.0\n') @@ -169,6 +194,7 @@ def test_layered_three_layers_compose(tmp_path: Path, empty_user_layer: Path) -> "gpt-5.5", "gpt-5.4", "claude-opus-5", + "claude-fable-5-1", "claude-fable-5", "claude-opus-4-8", "claude-sonnet-5", diff --git a/tests/test_results_exporter.py b/tests/test_results_exporter.py index f101b1d0..3c0f7339 100644 --- a/tests/test_results_exporter.py +++ b/tests/test_results_exporter.py @@ -174,7 +174,7 @@ def test_export_includes_token_cost_economics(job_dir: Path, tmp_path: Path) -> assert usage["total_tokens"] == 1_060_000 # sonnet $3/$15/$0.30 cached (ADR-014): fresh 0.2M*3 + cached 0.8M*0.30 + 0.06M*15 = 1.74 assert metrics["cost_usd"] == pytest.approx(1.74) - assert metrics["pricing_as_of"] == "2026-08-24" + assert metrics["pricing_as_of"] == "2026-09-04" assert "cost_efficiency" not in metrics # removed: arbitrary zero → use Pareto front assert "token_efficiency" not in metrics assert metrics["reasoning_effort"] == "" # fixture set no override