From bb34eec409303a26ef22d41eae00ec0e60223563 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 14 Aug 2026 16:04:53 +0100 Subject: [PATCH] Recognize reviewed OpenRouter free route pricing --- .../v6/internal/subsystems/ai-runtime.md | 5 ++++- internal/ai/cost/pricing.go | 3 ++- internal/ai/cost/store_extended_test.go | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/release-control/v6/internal/subsystems/ai-runtime.md b/docs/release-control/v6/internal/subsystems/ai-runtime.md index d87d9ed25..9d5754066 100644 --- a/docs/release-control/v6/internal/subsystems/ai-runtime.md +++ b/docs/release-control/v6/internal/subsystems/ai-runtime.md @@ -6272,7 +6272,10 @@ than silently borrowing a direct-provider family price. Reviewed OpenRouter routes use exact model IDs and model-specific review dates from the public OpenRouter Models API; aliases, fast variants, routers, and other unreviewed routes remain unknown and therefore fail any non-zero qualification cost -budget until their actual route price is explicitly recorded. Live scoring +budget until their actual route price is explicitly recorded. An exact +OpenRouter `:free` route may be recorded at zero only after that route's public +catalog entry is reviewed; the suffix alone never makes other free aliases +known. Live scoring 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 diff --git a/internal/ai/cost/pricing.go b/internal/ai/cost/pricing.go index 0dc5d661d..cb6c132d5 100644 --- a/internal/ai/cost/pricing.go +++ b/internal/ai/cost/pricing.go @@ -63,12 +63,13 @@ var providerPrices = map[string][]modelPrice{ }, "openrouter": { // OpenRouter model-catalog list prices, checked from the public Models API - // (https://openrouter.ai/api/v1/model/:author/:slug) on 2026-07-14. + // (https://openrouter.ai/api/v1/models) on the per-route review date. // Keep these route-specific: OpenRouter aliases, variants, and provider // routing can have different prices and must remain unknown until reviewed. flatPriceAsOf("anthropic/claude-opus-4.8", 5.00, 25.00, "2026-07-14"), flatPriceAsOf("anthropic/claude-sonnet-5", 2.00, 10.00, "2026-07-14"), flatPriceAsOf("deepseek/deepseek-v4-flash", 0.09, 0.18, "2026-07-14"), + flatPriceAsOf("nvidia/nemotron-3-super-120b-a12b:free", 0, 0, "2026-08-14"), }, "gemini": { // Gemini Developer API standard paid-tier pricing, checked from diff --git a/internal/ai/cost/store_extended_test.go b/internal/ai/cost/store_extended_test.go index a087d5e92..aaf22475e 100644 --- a/internal/ai/cost/store_extended_test.go +++ b/internal/ai/cost/store_extended_test.go @@ -137,6 +137,23 @@ func TestEstimateUSD_OllamaFree(t *testing.T) { } } +func TestEstimateUSD_ReviewedOpenRouterFreeRoute(t *testing.T) { + usd, ok, price := EstimateUSD("openrouter", "nvidia/nemotron-3-super-120b-a12b:free", 1_000_000, 1_000_000) + if !ok { + t.Fatal("reviewed OpenRouter free-route pricing should be known") + } + if usd != 0 || price.InputUSDPerMTok != 0 || price.OutputUSDPerMTok != 0 { + t.Fatalf("reviewed OpenRouter free route should estimate $0, got usd=%f price=%+v", usd, price) + } + if price.AsOf != "2026-08-14" { + t.Fatalf("reviewed OpenRouter free-route date = %q, want 2026-08-14", price.AsOf) + } + + if _, known, _ := EstimateUSD("openrouter", "nvidia/nemotron-3.5-lightning:free", 1_000, 1_000); known { + t.Fatal("an unreviewed OpenRouter free route must remain unknown") + } +} + func TestEstimateUSD_AnthropicModels(t *testing.T) { tests := []struct { model string