Merge pull request #41736 from BerriAI/litellm_mistral_cache_read_pricing

fix(model_prices): add cache-read pricing to Mistral chat models missing it
This commit is contained in:
kerry-berri 2026-09-17 19:35:26 -07:00 committed by GitHub
commit db37977307
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 0 deletions

View file

@ -36785,6 +36785,7 @@
"supports_tool_choice": true
},
"mistral/codestral-mamba-latest": {
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_token": 2.5e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,
@ -36842,6 +36843,7 @@
"supports_tool_choice": true
},
"mistral/devstral-small-latest": {
"cache_read_input_token_cost": 1e-08,
"input_cost_per_token": 1e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,
@ -36871,6 +36873,7 @@
"supports_tool_choice": true
},
"mistral/devstral-latest": {
"cache_read_input_token_cost": 4e-08,
"input_cost_per_token": 4e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,
@ -36885,6 +36888,7 @@
"supports_tool_choice": true
},
"mistral/devstral-medium-latest": {
"cache_read_input_token_cost": 4e-08,
"input_cost_per_token": 4e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,
@ -36986,6 +36990,7 @@
"source": "https://docs.mistral.ai/models/mistral-embed-23-12"
},
"mistral/mistral-medium-3": {
"cache_read_input_token_cost": 1.5e-07,
"input_cost_per_token": 1.5e-06,
"litellm_provider": "mistral",
"max_input_tokens": 262144,
@ -37034,6 +37039,7 @@
"supports_audio_output": true
},
"mistral/voxtral-small-2507": {
"cache_read_input_token_cost": 1e-08,
"input_cost_per_second": 6.666666666666667e-05,
"input_cost_per_token": 1e-07,
"litellm_provider": "mistral",
@ -37049,6 +37055,7 @@
"supports_tool_choice": true
},
"mistral/voxtral-small-latest": {
"cache_read_input_token_cost": 1e-08,
"input_cost_per_second": 6.666666666666667e-05,
"input_cost_per_token": 1e-07,
"litellm_provider": "mistral",
@ -37554,6 +37561,7 @@
"supports_vision": true
},
"mistral/mistral-small": {
"cache_read_input_token_cost": 1e-08,
"input_cost_per_token": 1e-07,
"litellm_provider": "mistral",
"max_input_tokens": 32000,
@ -37680,6 +37688,7 @@
"supports_vision": true
},
"mistral/mistral-tiny": {
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_token": 2.5e-07,
"litellm_provider": "mistral",
"max_input_tokens": 32000,
@ -37718,6 +37727,7 @@
"supports_tool_choice": true
},
"mistral/open-mistral-nemo": {
"cache_read_input_token_cost": 3e-08,
"input_cost_per_token": 3e-07,
"litellm_provider": "mistral",
"max_input_tokens": 128000,
@ -37803,6 +37813,7 @@
"supports_vision": true
},
"mistral/pixtral-large-latest": {
"cache_read_input_token_cost": 2e-07,
"input_cost_per_token": 2e-06,
"litellm_provider": "mistral",
"max_input_tokens": 128000,
@ -62790,6 +62801,7 @@
"supports_tool_choice": true
},
"mistral/mistral-code-agent-latest": {
"cache_read_input_token_cost": 4e-08,
"input_cost_per_token": 4e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,

View file

@ -36785,6 +36785,7 @@
"supports_tool_choice": true
},
"mistral/codestral-mamba-latest": {
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_token": 2.5e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,
@ -36842,6 +36843,7 @@
"supports_tool_choice": true
},
"mistral/devstral-small-latest": {
"cache_read_input_token_cost": 1e-08,
"input_cost_per_token": 1e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,
@ -36871,6 +36873,7 @@
"supports_tool_choice": true
},
"mistral/devstral-latest": {
"cache_read_input_token_cost": 4e-08,
"input_cost_per_token": 4e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,
@ -36885,6 +36888,7 @@
"supports_tool_choice": true
},
"mistral/devstral-medium-latest": {
"cache_read_input_token_cost": 4e-08,
"input_cost_per_token": 4e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,
@ -36986,6 +36990,7 @@
"source": "https://docs.mistral.ai/models/mistral-embed-23-12"
},
"mistral/mistral-medium-3": {
"cache_read_input_token_cost": 1.5e-07,
"input_cost_per_token": 1.5e-06,
"litellm_provider": "mistral",
"max_input_tokens": 262144,
@ -37034,6 +37039,7 @@
"supports_audio_output": true
},
"mistral/voxtral-small-2507": {
"cache_read_input_token_cost": 1e-08,
"input_cost_per_second": 6.666666666666667e-05,
"input_cost_per_token": 1e-07,
"litellm_provider": "mistral",
@ -37049,6 +37055,7 @@
"supports_tool_choice": true
},
"mistral/voxtral-small-latest": {
"cache_read_input_token_cost": 1e-08,
"input_cost_per_second": 6.666666666666667e-05,
"input_cost_per_token": 1e-07,
"litellm_provider": "mistral",
@ -37554,6 +37561,7 @@
"supports_vision": true
},
"mistral/mistral-small": {
"cache_read_input_token_cost": 1e-08,
"input_cost_per_token": 1e-07,
"litellm_provider": "mistral",
"max_input_tokens": 32000,
@ -37680,6 +37688,7 @@
"supports_vision": true
},
"mistral/mistral-tiny": {
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_token": 2.5e-07,
"litellm_provider": "mistral",
"max_input_tokens": 32000,
@ -37718,6 +37727,7 @@
"supports_tool_choice": true
},
"mistral/open-mistral-nemo": {
"cache_read_input_token_cost": 3e-08,
"input_cost_per_token": 3e-07,
"litellm_provider": "mistral",
"max_input_tokens": 128000,
@ -37803,6 +37813,7 @@
"supports_vision": true
},
"mistral/pixtral-large-latest": {
"cache_read_input_token_cost": 2e-07,
"input_cost_per_token": 2e-06,
"litellm_provider": "mistral",
"max_input_tokens": 128000,
@ -62790,6 +62801,7 @@
"supports_tool_choice": true
},
"mistral/mistral-code-agent-latest": {
"cache_read_input_token_cost": 4e-08,
"input_cost_per_token": 4e-07,
"litellm_provider": "mistral",
"max_input_tokens": 256000,

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import importlib.util
import json
import re
from collections.abc import Mapping
from pathlib import Path
from types import MappingProxyType
from typing import Final
@ -274,3 +275,42 @@ def test_every_bedrock_openai_gpt_row_advertises_xhigh(prices: dict):
and "xhigh" not in (resolve_supported_reasoning_efforts(entry, deployment_is_mapped=True) or ())
]
assert missing == []
def is_active_priced_mistral_chat_row(name: str, entry: Mapping[str, object]) -> bool:
input_cost: Final = entry.get("input_cost_per_token")
return (
name.startswith("mistral/")
and entry.get("mode") == "chat"
and entry.get("deprecation_date") is None
and isinstance(input_cost, (int, float))
and input_cost > 0
)
def cache_read_is_tenth_of_input(entry: Mapping[str, object]) -> bool:
cache_read: Final = entry.get("cache_read_input_token_cost")
input_cost: Final = entry.get("input_cost_per_token")
return (
isinstance(cache_read, float)
and isinstance(input_cost, (int, float))
and 0 < cache_read < input_cost
and cache_read == pytest.approx(input_cost / 10)
)
@pytest.mark.parametrize("path", (PRICES_PATH, BACKUP_PRICES_PATH), ids=("main", "backup"))
def test_active_mistral_chat_rows_price_cache_reads_below_input(path: Path):
"""A Mistral chat row without a cache-read rate bills cached prompt tokens at zero, so every
active priced row must carry one, and it must be cheaper than a fresh input token. Mistral
bills cached tokens at 10% of the input price for every model (docs.mistral.ai/studio/
conversations/advanced/prompt-caching, read 2026-09-18), so the ratio is checked as well."""
rows: Mapping[str, object] = json.loads(path.read_text())
drifted: Final = [
f"{name}: cache_read={entry.get('cache_read_input_token_cost')} input={entry.get('input_cost_per_token')}"
for name, entry in rows.items()
if isinstance(entry, dict)
and is_active_priced_mistral_chat_row(name, entry)
and not cache_read_is_tenth_of_input(entry)
]
assert drifted == []