diff --git a/agent/usage_pricing.py b/agent/usage_pricing.py index e1763046ff0f..caae20bee270 100644 --- a/agent/usage_pricing.py +++ b/agent/usage_pricing.py @@ -446,36 +446,41 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = { pricing_version="anthropic-pricing-2026-05", ), # DeepSeek + # Snapshot of https://api-docs.deepseek.com/quick_start/pricing (2026-07). + # deepseek-chat / deepseek-reasoner are deprecated 2026-07-24 and now alias + # deepseek-v4-flash's non-thinking / thinking modes — same rates. ( "deepseek", "deepseek-chat", ): PricingEntry( input_cost_per_million=Decimal("0.14"), output_cost_per_million=Decimal("0.28"), + cache_read_cost_per_million=Decimal("0.0028"), source="official_docs_snapshot", source_url="https://api-docs.deepseek.com/quick_start/pricing", - pricing_version="deepseek-pricing-2026-03-16", + pricing_version="deepseek-pricing-2026-07", ), ( "deepseek", "deepseek-reasoner", ): PricingEntry( - input_cost_per_million=Decimal("0.55"), - output_cost_per_million=Decimal("2.19"), + input_cost_per_million=Decimal("0.14"), + output_cost_per_million=Decimal("0.28"), + cache_read_cost_per_million=Decimal("0.0028"), source="official_docs_snapshot", source_url="https://api-docs.deepseek.com/quick_start/pricing", - pricing_version="deepseek-pricing-2026-03-16", + pricing_version="deepseek-pricing-2026-07", ), ( "deepseek", "deepseek-v4-pro", ): PricingEntry( - input_cost_per_million=Decimal("1.74"), - output_cost_per_million=Decimal("3.48"), - cache_read_cost_per_million=Decimal("0.0145"), + input_cost_per_million=Decimal("0.435"), + output_cost_per_million=Decimal("0.87"), + cache_read_cost_per_million=Decimal("0.003625"), source="official_docs_snapshot", source_url="https://api-docs.deepseek.com/quick_start/pricing", - pricing_version="deepseek-pricing-2026-05-12", + pricing_version="deepseek-pricing-2026-07", ), ( "deepseek", @@ -486,7 +491,7 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = { cache_read_cost_per_million=Decimal("0.0028"), source="official_docs_snapshot", source_url="https://api-docs.deepseek.com/quick_start/pricing", - pricing_version="deepseek-pricing-2026-05-12", + pricing_version="deepseek-pricing-2026-07", ), # Google Gemini ( diff --git a/tests/agent/test_usage_pricing.py b/tests/agent/test_usage_pricing.py index 4b1d9f7e55dd..6458a9b0d3f8 100644 --- a/tests/agent/test_usage_pricing.py +++ b/tests/agent/test_usage_pricing.py @@ -223,7 +223,8 @@ def test_deepseek_v4_pro_pricing_entry_exists(): Before this fix, deepseek-v4-pro sessions showed as unknown cost in hermes insights because the _OFFICIAL_DOCS_PRICING table had no - entry for that model. See #24218. + entry for that model. See #24218. Rates track the 2026-07 price cut + ($1.74/$3.48 → $0.435/$0.87). """ entry = get_pricing_entry( "deepseek-v4-pro", @@ -233,9 +234,9 @@ def test_deepseek_v4_pro_pricing_entry_exists(): assert entry is not None assert entry.input_cost_per_million is not None assert entry.output_cost_per_million is not None - assert float(entry.input_cost_per_million) == 1.74 - assert float(entry.output_cost_per_million) == 3.48 - assert float(entry.cache_read_cost_per_million) == 0.0145 + assert float(entry.input_cost_per_million) == 0.435 + assert float(entry.output_cost_per_million) == 0.87 + assert float(entry.cache_read_cost_per_million) == 0.003625 def test_deepseek_v4_pro_estimate_usage_cost(): @@ -248,8 +249,39 @@ def test_deepseek_v4_pro_estimate_usage_cost(): assert result.status == "estimated" assert result.amount_usd is not None - # 1M input × $1.74/M + 500K output × $3.48/M = $1.74 + $1.74 = $3.48 - assert float(result.amount_usd) == 3.48 + # 1M input × $0.435/M + 500K output × $0.87/M = $0.435 + $0.435 = $0.87 + assert float(result.amount_usd) == 0.87 + + +def test_deepseek_deprecated_aliases_price_as_v4_flash(): + """Invariant: deepseek-chat / deepseek-reasoner are deprecated aliases for + deepseek-v4-flash's non-thinking / thinking modes (deprecation 2026-07-24) + — they must bill at identical rates to the flash entry, or sessions on the + legacy names over/under-report cost.""" + flash = get_pricing_entry("deepseek-v4-flash", provider="deepseek") + assert flash is not None + for alias in ("deepseek-chat", "deepseek-reasoner"): + entry = get_pricing_entry(alias, provider="deepseek") + assert entry is not None, alias + assert entry.input_cost_per_million == flash.input_cost_per_million, alias + assert entry.output_cost_per_million == flash.output_cost_per_million, alias + assert ( + entry.cache_read_cost_per_million == flash.cache_read_cost_per_million + ), alias + + +def test_deepseek_rows_all_carry_cache_read_pricing(): + """Invariant: DeepSeek publishes a cache-hit rate for every current model; + every deepseek snapshot row must carry cache_read < input so cached + sessions estimate correctly instead of billing reads at full price.""" + from agent.usage_pricing import _OFFICIAL_DOCS_PRICING + + ds_rows = [k for k in _OFFICIAL_DOCS_PRICING if k[0] == "deepseek"] + assert ds_rows, "expected at least one deepseek pricing row" + for key in ds_rows: + entry = _OFFICIAL_DOCS_PRICING[key] + assert entry.cache_read_cost_per_million is not None, key + assert entry.cache_read_cost_per_million < entry.input_cost_per_million, key def test_bedrock_claude_rows_all_carry_cache_pricing():