diff --git a/pilot/cost_model.py b/pilot/cost_model.py index e0df5c3..0ea16b9 100644 --- a/pilot/cost_model.py +++ b/pilot/cost_model.py @@ -82,6 +82,15 @@ PRICES: dict[str, Price] = { "gpt-5.6-sol": Price("GPT-5.6 Sol", 5.00, 30.00, 5.00, 0.50), "gpt-5.6-terra": Price("GPT-5.6 Terra", 2.00, 12.00, 2.00, 0.20), "gpt-5.6-luna": Price("GPT-5.6 Luna", 0.20, 1.20, 0.20, 0.02), + # OpenAI — cached_input 0.1x, no separate cache_write + "gpt-5": Price("GPT-5", 1.25, 10.00, 1.25, 0.125), + "gpt-5-mini": Price("GPT-5 mini", 0.25, 2.00, 0.25, 0.025), + # Google Gemini — cache_write = input + "gemini-2.5-pro": Price("Gemini 2.5 Pro", 1.875, 12.50, 1.875, 0.1875), + "gemini-2.5-flash": Price("Gemini 2.5 Flash", 0.30, 2.50, 0.30, 0.03), + # xAI Grok — cache_write = input + "grok-4.5": Price("Grok 4.5", 2.00, 6.00, 2.00, 0.30), + "grok-4.3": Price("Grok 4.3", 1.25, 2.50, 1.25, 0.20), } diff --git a/tests/pilot/test_cost_model.py b/tests/pilot/test_cost_model.py index 841b54a..d575b0a 100644 --- a/tests/pilot/test_cost_model.py +++ b/tests/pilot/test_cost_model.py @@ -244,3 +244,39 @@ def test_model_is_within_an_order_of_magnitude_of_the_measurement(): predicted = cm.tier_usage(modelled, FACTORY, caching=False).total_input measured = run["input"] assert 0.4 < predicted / measured < 2.5, (predicted, measured) + + +# --------------------------------------------------------------------------- +# PRICES — the multi-provider table (GPT / Gemini / Grok) +# --------------------------------------------------------------------------- + + +NEW_KEYS = ("gpt-5", "gpt-5-mini", "gemini-2.5-pro", + "gemini-2.5-flash", "grok-4.5", "grok-4.3") + + +def test_prices_contains_new_providers(): + for k in NEW_KEYS: + assert k in cm.PRICES, k + + +def test_cost_matches_published_gpt5(): + # $1.25 in / $10.00 out / cached $0.125; cache_write = input + u = cm.Usage(uncached_input=1_000_000, cached_input=1_000_000, + cache_writes=1_000_000, output=1_000_000) + assert abs(cm.cost(u, cm.PRICES["gpt-5"]) - (1.25 + 0.125 + 1.25 + 10.00)) < 1e-9 + + +def test_cost_matches_published_gemini_flash(): + # $0.30 in / $2.50 out / cached $0.03; cache_write = input + u = cm.Usage(uncached_input=2_000_000, cached_input=0, + cache_writes=0, output=500_000) + expected = 2.00 * 0.30 + 0.50 * 2.50 # $0.60 + $1.25 + assert abs(cm.cost(u, cm.PRICES["gemini-2.5-flash"]) - expected) < 1e-9 + + +def test_cost_matches_published_grok45(): + # $2.00 in / $6.00 out / cached $0.30; cache_write = input + u = cm.Usage(uncached_input=1_000_000, cached_input=1_000_000, + cache_writes=1_000_000, output=1_000_000) + assert abs(cm.cost(u, cm.PRICES["grok-4.5"]) - (2.00 + 0.30 + 2.00 + 6.00)) < 1e-9