diff --git a/rust/src/core/cost_pricing.rs b/rust/src/core/cost_pricing.rs index d220c6b8f8..2c522cb78a 100755 --- a/rust/src/core/cost_pricing.rs +++ b/rust/src/core/cost_pricing.rs @@ -620,11 +620,18 @@ impl CostUsagePricing { return Self::CODEX_UNATTRIBUTED_MODEL.to_string(); } - // Remove "openai/" prefix - if let Some(rest) = trimmed.strip_prefix("openai/") { + // Remove the provider-qualified OpenAI prefix. + if let Some((prefix, rest)) = trimmed.split_once('/') + && prefix.eq_ignore_ascii_case("openai") + { trimmed = rest.to_string(); } + // Codex uses this alias for the Luna reserve quota bucket. + if trimmed.eq_ignore_ascii_case("gpt-reserve") { + return "gpt-5.6-luna".to_string(); + } + // Check if base model (without -codex suffix) exists in pricing if let Some(idx) = trimmed.find("-codex") { let base = &trimmed[..idx]; diff --git a/rust/src/core/cost_pricing_tests.rs b/rust/src/core/cost_pricing_tests.rs index 9984061644..e3ae70328a 100644 --- a/rust/src/core/cost_pricing_tests.rs +++ b/rust/src/core/cost_pricing_tests.rs @@ -20,6 +20,30 @@ fn test_normalize_codex_model() { CostUsagePricing::normalize_codex_model("unknown"), CostUsagePricing::CODEX_UNATTRIBUTED_MODEL ); + assert_eq!( + CostUsagePricing::normalize_codex_model("gpt-reserve"), + "gpt-5.6-luna" + ); + assert_eq!( + CostUsagePricing::normalize_codex_model(" GPT-RESERVE "), + "gpt-5.6-luna" + ); + assert_eq!( + CostUsagePricing::normalize_codex_model("openai/gpt-reserve"), + "gpt-5.6-luna" + ); + assert_eq!( + CostUsagePricing::normalize_codex_model("OPENAI/GPT-RESERVE"), + "gpt-5.6-luna" + ); + assert_eq!( + CostUsagePricing::normalize_codex_model("gpt-reserve-preview"), + "gpt-reserve-preview" + ); + assert_eq!( + CostUsagePricing::normalize_codex_model("my-gpt-reserve"), + "my-gpt-reserve" + ); } #[test] @@ -168,6 +192,22 @@ fn test_gpt56_standard_pricing() { } } +#[test] +fn gpt_reserve_alias_uses_luna_pricing() { + let luna = + CostUsagePricing::codex_cost_usd("gpt-5.6-luna", 1_000, 400, 1_000).expect("Luna pricing"); + for model in [ + "gpt-reserve", + " GPT-RESERVE ", + "openai/gpt-reserve", + "OPENAI/GPT-RESERVE", + ] { + let reserve = + CostUsagePricing::codex_cost_usd(model, 1_000, 400, 1_000).expect("reserve pricing"); + assert!((reserve - luna).abs() < 1e-10, "{model}"); + } +} + #[test] fn test_gpt56_long_context_pricing() { for (model, expected) in [