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
27 changes: 27 additions & 0 deletions internal/cost/cost_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ func TestLookupPrefixAndProviderIDs(t *testing.T) {
"claude-3-5-haiku-20241022": "claude-3-5-haiku",
"CLAUDE-HAIKU-4-5": "claude-haiku-4-5",
"anthropic.claude-opus-4-1-20250805-v1:0": "claude-opus-4-1",
"claude-fable-5-1": "claude-fable-5-1",
"claude-fable-5": "claude-fable-5",
}
for in, want := range cases {
row, ok := tb.Lookup(in)
Expand Down Expand Up @@ -226,3 +228,28 @@ func TestEveryModelHasExactlyOneCurrentPrice(t *testing.T) {
}
}
}

func TestFable51CacheReadsAtItsOwnRate(t *testing.T) {
tb, _ := Embedded()

// Fable 5.1 reads cache at 0.025x input, not the 0.1x every other row
// follows, so the $0.25 looks like a typo of Fable 5's $1.00 and sits one
// character away from a row that would charge four times as much.
for _, tc := range []struct {
model string
want float64
}{
{"claude-fable-5-1", 0.25},
{"claude-mythos-5-1", 0.25},
{"claude-fable-5", 1.0},
} {
got, ok := tb.Price(tc.model, event.TokenDelta{CacheRead: 1_000_000})
if !ok {
t.Errorf("%s has no price", tc.model)
continue
}
if got != tc.want {
t.Errorf("%s: 1M cache-read tokens cost $%.2f, want $%.2f", tc.model, got, tc.want)
}
}
}
24 changes: 22 additions & 2 deletions pricing/pricing.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"version": "2026-09-01.1",
"version": "2026-09-02.1",
"source": "https://platform.claude.com/docs/en/about-claude/pricing",
"fetched_at": "2026-08-18",
"currency": "USD",
"unit": "per_million_tokens",
"notes": [
"First-party Anthropic API prices. Amazon Bedrock and Google Vertex have separate partner pricing (regional endpoints +10%) and are not covered by this table (OQ-02).",
"cache_write_5m = 1.25x input, cache_write_1h = 2x input, cache_read = 0.1x input \u2014 per Anthropic's published multipliers.",
"cache_write_5m = 1.25x input, cache_write_1h = 2x input, cache_read = 0.1x input \u2014 per Anthropic's published multipliers. Claude Fable 5.1 and Claude Mythos 5.1 are the exception and read 0.025x ($0.25 per 1M), so those two rows deliberately break the 0.1x rule; both were read from the pricing page on 2026-09-02.",
"Model ids are matched by prefix against the `model` field observed in transcripts (e.g. claude-opus-5, claude-sonnet-4-5-20250929). Longest prefix wins.",
"context_window is the model's maximum input context in tokens as published; used for the 'context fill %' badge (OQ-07).",
"Non-Anthropic rows are the providers' own published list prices, fetched 2026-08-27: DeepSeek V4 Pro $0.435/$0.87 per 1M (its 75% cut, made permanent); MiniMax M3 $0.30/$1.20 per 1M standard tier with $0.06 cache read (its permanent 50% off). They are priced so a total that includes non-Anthropic usage is a total; Caprock still does not charge for any of it and cannot see a bill.",
Expand All @@ -17,6 +17,26 @@
"gemini-3.1-pro-preview and gemini-2.5-pro are tiered by prompt size; the rate here is the =<200k tier. Prompts over 200k tokens bill at roughly double ($4.00/$18.00 and $2.50/$15.00 respectively) and are therefore under-reported by this table."
],
"models": [
{
"id": "claude-fable-5-1",
"display": "Claude Fable 5.1",
"input": 10.0,
"cache_write_5m": 12.5,
"cache_write_1h": 20.0,
"cache_read": 0.25,
"output": 50.0,
"context_window": 1000000
},
{
"id": "claude-mythos-5-1",
"display": "Claude Mythos 5.1",
"input": 10.0,
"cache_write_5m": 12.5,
"cache_write_1h": 20.0,
"cache_read": 0.25,
"output": 50.0,
"context_window": 1000000
},
{
"id": "claude-fable-5",
"display": "Claude Fable 5",
Expand Down
Loading