Correct current Anthropic cost estimates

Price Anthropic Opus 4.5 through 5 at the current first-party rates while preserving legacy Opus pricing. Correct Haiku 4.5 in the same version-sensitive table and add regression coverage for current and legacy aliases.\n\nFixes #1789
This commit is contained in:
pulse-triage[bot]
2026-08-28 08:08:22 +01:00
parent 7e3c624900
commit bf1b81700b
3 changed files with 70 additions and 0 deletions
@@ -6627,6 +6627,16 @@ uses the provider resolved by Patrol readiness, even when the configured
OpenRouter model is an unprefixed slash route such as
`anthropic/claude-sonnet-5`; scorer replay persists and reuses that resolved
provider so the same captured report prices deterministically.
First-party Anthropic cost estimation is version-sensitive even within one
model family. Standard API calls for Opus 4.5, 4.6, 4.7, 4.8, and 5 use the
reviewed $5 input / $25 output per-million-token rates, while Opus 4, 4.1, and
3 retain the legacy $15 / $75 rates. Haiku 4.5 similarly uses $1 / $5 rather
than the Haiku 3 fallback. These version-specific rows must precede broad
family fallbacks because pricing lookup is first-match prefix-based, and
dated model aliases must resolve to the same row as their base version. The
30-day runtime budget recalculates retained usage through this table, so a
stale higher fallback must not disable Assistant or Patrol before estimated
first-party spend reaches the configured limit.
After a non-interactive Patrol finding lifecycle write succeeds, the structured
tool result is authoritative and investigation remains closed. Watch first
offers a bounded lifecycle-completion request containing only report and
+10
View File
@@ -51,8 +51,18 @@ var providerPrices = map[string][]modelPrice{
flatPrice("gpt-4o*", 5.00, 15.00),
},
"anthropic": {
// Anthropic first-party standard API prices, checked from
// https://platform.claude.com/docs/en/about-claude/pricing on 2026-08-28.
// Keep version-specific rows before the legacy family fallbacks because
// lookupPrice returns the first matching prefix.
flatPriceAsOf("claude-opus-5*", 5.00, 25.00, "2026-08-28"),
flatPriceAsOf("claude-opus-4-8*", 5.00, 25.00, "2026-08-28"),
flatPriceAsOf("claude-opus-4-7*", 5.00, 25.00, "2026-08-28"),
flatPriceAsOf("claude-opus-4-6*", 5.00, 25.00, "2026-08-28"),
flatPriceAsOf("claude-opus-4-5*", 5.00, 25.00, "2026-08-28"),
flatPrice("claude-opus*", 15.00, 75.00),
flatPrice("claude-sonnet*", 3.00, 15.00),
flatPriceAsOf("claude-haiku-4-5*", 1.00, 5.00, "2026-08-28"),
flatPrice("claude-haiku*", 0.25, 1.25),
},
"deepseek": {
@@ -0,0 +1,50 @@
package cost
import "testing"
func TestLookupPriceUsesCurrentAnthropicOpusPricing(t *testing.T) {
tests := []struct {
model string
input float64
output float64
asOf string
}{
{model: "claude-opus-5", input: 5.00, output: 25.00, asOf: "2026-08-28"},
{model: "claude-opus-5-20260801", input: 5.00, output: 25.00, asOf: "2026-08-28"},
{model: "claude-opus-4-8", input: 5.00, output: 25.00, asOf: "2026-08-28"},
{model: "claude-opus-4-7", input: 5.00, output: 25.00, asOf: "2026-08-28"},
{model: "claude-opus-4-6", input: 5.00, output: 25.00, asOf: "2026-08-28"},
{model: "claude-opus-4-5-20251101", input: 5.00, output: 25.00, asOf: "2026-08-28"},
{model: "claude-opus-4-1-20250805", input: 15.00, output: 75.00, asOf: pricingAsOf},
{model: "claude-opus-4-20250514", input: 15.00, output: 75.00, asOf: pricingAsOf},
{model: "claude-opus-20240229", input: 15.00, output: 75.00, asOf: pricingAsOf},
}
for _, test := range tests {
t.Run(test.model, func(t *testing.T) {
price, ok := lookupPrice("anthropic", test.model, 50_000)
if !ok {
t.Fatal("expected Anthropic Opus pricing to resolve")
}
if price.InputUSDPerMTok != test.input || price.OutputUSDPerMTok != test.output {
t.Fatalf("unexpected Anthropic Opus price: %+v", price)
}
if price.AsOf != test.asOf {
t.Fatalf("Anthropic Opus pricing date = %q, want %q", price.AsOf, test.asOf)
}
})
}
}
func TestLookupPriceUsesCurrentAnthropicHaiku45Pricing(t *testing.T) {
price, ok := lookupPrice("anthropic", "claude-haiku-4-5-20251001", 50_000)
if !ok {
t.Fatal("expected Anthropic Haiku 4.5 pricing to resolve")
}
if price.InputUSDPerMTok != 1.00 || price.OutputUSDPerMTok != 5.00 {
t.Fatalf("unexpected Anthropic Haiku 4.5 price: %+v", price)
}
if price.AsOf != "2026-08-28" {
t.Fatalf("Anthropic Haiku 4.5 pricing date = %q, want 2026-08-28", price.AsOf)
}
}