refactor(cost_calc): move the fireworks cache-read default under litellm/llms

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
kerry 2026-09-19 01:18:09 +00:00
parent 1b305cd6b9
commit c9cd666b36
4 changed files with 98 additions and 48 deletions

View file

@ -14,11 +14,11 @@ from typing_extensions import ReadOnly
import litellm
from litellm._internal_context import current_billing_time
from litellm._logging import verbose_logger
from litellm.constants import FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO
from litellm.litellm_core_utils.llm_cost_calc.tiered_pricing import (
select_tier_for_input,
tier_rate,
)
from litellm.llms.fireworks_ai.cache_pricing import with_default_cache_read_rate
from litellm.types.utils import (
CacheCreationTokenDetails,
CallTypes,
@ -74,31 +74,12 @@ 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:
"""Apply provider-specific defaults for cache-read pricing."""
if custom_llm_provider != "fireworks_ai":
return model_info
input_rate: Final = 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})
return cast(
ModelInfo,
{
**model_info,
"cache_read_input_token_cost": cache_read_rate,
"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
else cache_read_rate
),
},
},
)
"""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
def _get_token_detail_value(details: object, key: str) -> int | None:

View file

@ -0,0 +1,38 @@
"""
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
)
from litellm.constants import FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO
from litellm.types.utils import ModelInfo
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")
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})
return cast(
ModelInfo,
{
**model_info,
"cache_read_input_token_cost": cache_read_rate,
"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
else cache_read_rate
),
},
},
)

View file

@ -98,36 +98,17 @@ def test_generic_cost_per_token_bills_cache_reads_at_input_rate_when_no_cache_re
assert completion_cost == pytest.approx(380 * 9.7e-7)
def test_apply_provider_cache_read_default_preserves_identity_and_input_data() -> None:
def test_apply_provider_cache_read_default_only_derives_a_rate_for_fireworks() -> None:
openai_info: ModelInfo = {"input_cost_per_token": 2e-6}
explicit_fireworks_info: ModelInfo = {
"input_cost_per_token": 2e-6,
"cache_read_input_token_cost": 1e-6,
}
fireworks_info: ModelInfo = {
"input_cost_per_token": 2e-6,
"off_peak_pricing": {
"hours_utc": "14:00-00:00",
"input_cost_per_token": 1e-6,
"output_cost_per_token": 3e-6,
},
}
original_fireworks_info: ModelInfo = deepcopy(fireworks_info)
fireworks_info: ModelInfo = {"input_cost_per_token": 2e-6}
assert apply_provider_cache_read_default(openai_info, "openai") is openai_info
assert apply_provider_cache_read_default(explicit_fireworks_info, "fireworks_ai") is explicit_fireworks_info
assert apply_provider_cache_read_default(openai_info, None) is openai_info
processed_fireworks_info = apply_provider_cache_read_default(fireworks_info, "fireworks_ai")
assert fireworks_info == original_fireworks_info
assert processed_fireworks_info is not fireworks_info
assert processed_fireworks_info["cache_read_input_token_cost"] == pytest.approx(2e-6 * 0.5)
assert processed_fireworks_info["off_peak_pricing"] == {
"hours_utc": "14:00-00:00",
"input_cost_per_token": 1e-6,
"output_cost_per_token": 3e-6,
"cache_read_input_token_cost": 1e-6 * 0.5,
}
def test_generic_cost_per_token_prefers_audio_per_second_rate() -> None:

View file

@ -0,0 +1,50 @@
from copy import deepcopy
import pytest
from litellm.constants import FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO
from litellm.llms.fireworks_ai.cache_pricing import with_default_cache_read_rate
from litellm.types.utils import ModelInfo
def test_explicit_cache_read_rate_and_missing_input_rate_keep_the_entry_untouched() -> None:
explicit_info: ModelInfo = {"input_cost_per_token": 2e-6, "cache_read_input_token_cost": 1e-6}
no_input_rate_info: ModelInfo = {"output_cost_per_token": 3e-6}
assert with_default_cache_read_rate(explicit_info) is explicit_info
assert with_default_cache_read_rate(no_input_rate_info) is no_input_rate_info
def test_missing_cache_read_rate_is_derived_for_standard_and_off_peak_without_mutating_the_entry() -> 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,
"output_cost_per_token": 3e-6,
},
}
original: ModelInfo = deepcopy(model_info)
derived = with_default_cache_read_rate(model_info)
assert model_info == original
assert derived is not model_info
assert derived["cache_read_input_token_cost"] == pytest.approx(2e-6 * FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO)
assert derived["off_peak_pricing"] == {
"hours_utc": "14:00-00:00",
"input_cost_per_token": 1e-6,
"output_cost_per_token": 3e-6,
"cache_read_input_token_cost": 1e-6 * FIREWORKS_AI_DEFAULT_CACHE_READ_RATE_RATIO,
}
def test_off_peak_window_without_its_own_input_rate_reuses_the_standard_derived_rate() -> None:
model_info: ModelInfo = {
"input_cost_per_token": 2e-6,
"off_peak_pricing": {"hours_utc": "14:00-00:00", "output_cost_per_token": 3e-6},
}
derived = with_default_cache_read_rate(model_info)
assert derived["off_peak_pricing"]["cache_read_input_token_cost"] == derived["cache_read_input_token_cost"]