Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
30 changes: 21 additions & 9 deletions src/nasde_toolkit/pricing.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -39,37 +43,45 @@ 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"]
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"]
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"]
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"]
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"
2 changes: 1 addition & 1 deletion tests/test_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
26 changes: 26 additions & 0 deletions tests/test_pricing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion tests/test_results_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down