fix(cost_calc): coerce string fireworks rates and drop the match fall-through

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
kerry 2026-09-19 01:33:41 +00:00
parent 8836410c4c
commit 05cefb1480
3 changed files with 31 additions and 15 deletions

View file

@ -74,12 +74,9 @@ def _uses_inclusive_token_thresholds(custom_llm_provider: str | None) -> bool:
def apply_provider_cache_read_default(model_info: ModelInfo, custom_llm_provider: str | None) -> ModelInfo:
"""Dispatch to the provider's cache-read pricing default; providers without one keep their entry as is."""
match custom_llm_provider:
case "fireworks_ai":
return with_default_cache_read_rate(model_info)
case _:
return model_info
if custom_llm_provider == "fireworks_ai":
return with_default_cache_read_rate(model_info)
return model_info
def _get_token_detail_value(details: object, key: str) -> int | None:

View file

@ -1,7 +1,3 @@
"""
Fireworks AI serverless cache-read pricing defaults.
"""
from typing import (
Final,
cast, # noqa: TID251 # the derived entry is a dict copy of a ReadOnly TypedDict; no cast-free way to retype it
@ -11,16 +7,24 @@ from litellm.constants import FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO
from litellm.types.utils import ModelInfo
def _as_rate(value: object) -> float | None:
if isinstance(value, bool) or not isinstance(value, (int, float, str)):
return None
try:
return float(value)
except ValueError:
return None
def with_default_cache_read_rate(model_info: ModelInfo) -> ModelInfo:
"""Entries without a cache-read rate get the documented discount off the input rate; the shared map is
never mutated, so a copy carries it."""
input_rate: Final = model_info.get("input_cost_per_token")
input_rate: Final = _as_rate(model_info.get("input_cost_per_token"))
if model_info.get("cache_read_input_token_cost") is not None or input_rate is None:
return model_info
cache_read_rate: Final = input_rate * FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO
off_peak: Final = model_info.get("off_peak_pricing")
if off_peak is None or "cache_read_input_token_cost" in off_peak:
return cast(ModelInfo, {**model_info, "cache_read_input_token_cost": cache_read_rate})
off_peak_input_rate: Final = _as_rate(off_peak.get("input_cost_per_token"))
return cast(
ModelInfo,
{
@ -29,8 +33,8 @@ def with_default_cache_read_rate(model_info: ModelInfo) -> ModelInfo:
"off_peak_pricing": {
**off_peak,
"cache_read_input_token_cost": (
off_peak["input_cost_per_token"] * FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO
if "input_cost_per_token" in off_peak
off_peak_input_rate * FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO
if off_peak_input_rate is not None
else cache_read_rate
),
},

View file

@ -48,3 +48,18 @@ def test_off_peak_window_without_its_own_input_rate_reuses_the_standard_derived_
derived = with_default_cache_read_rate(model_info)
assert derived["off_peak_pricing"]["cache_read_input_token_cost"] == derived["cache_read_input_token_cost"]
def test_string_rates_from_config_are_coerced_before_the_discount_is_applied() -> None:
model_info: ModelInfo = {
"input_cost_per_token": "2e-6",
"off_peak_pricing": {
"hours_utc": "14:00-00:00",
"input_cost_per_token": "1e-6",
},
}
derived = with_default_cache_read_rate(model_info)
assert derived["cache_read_input_token_cost"] == pytest.approx(1e-6)
assert derived["off_peak_pricing"]["cache_read_input_token_cost"] == pytest.approx(5e-7)