fix(fireworks_ai): account for cache read/creation tokens in cost calculator

The Fireworks AI cost_per_token function only calculated costs using
prompt_tokens * input_cost_per_token, ignoring cache_read_input_tokens
and cache_creation_input_tokens from the Usage object. This caused
incorrect cost reporting when prompt caching was active.

Now adjusts the prompt cost by applying the differential between the
cache-specific rate and the standard input rate for cached tokens.

Fixes #24774

Signed-off-by: GopalGB <67310594+GopalGB@users.noreply.github.com>
This commit is contained in:
GopalGB 2026-05-07 20:23:04 +05:30
parent 50ef2d51a2
commit 73112c87ac
2 changed files with 69 additions and 1 deletions

View file

@ -77,8 +77,28 @@ def cost_per_token(model: str, usage: Usage) -> Tuple[float, float]:
)
## CALCULATE INPUT COST
input_cost_per_token = model_info["input_cost_per_token"]
prompt_cost: float = usage["prompt_tokens"] * input_cost_per_token
prompt_cost: float = usage["prompt_tokens"] * model_info["input_cost_per_token"]
## ADJUST FOR CACHE READ TOKENS
cache_read_input_tokens = usage.get("cache_read_input_tokens", None) or 0
cache_read_cost = model_info.get("cache_read_input_token_cost", None)
if cache_read_input_tokens > 0 and cache_read_cost is not None:
# Cache read tokens were already counted at the full input rate above.
# Subtract the full-price portion and add the discounted cache rate.
prompt_cost += cache_read_input_tokens * (
cache_read_cost - input_cost_per_token
)
## ADJUST FOR CACHE CREATION TOKENS
cache_creation_input_tokens = (
usage.get("cache_creation_input_tokens", None) or 0
)
cache_creation_cost = model_info.get("cache_creation_input_token_cost", None)
if cache_creation_input_tokens > 0 and cache_creation_cost is not None:
prompt_cost += cache_creation_input_tokens * (
cache_creation_cost - input_cost_per_token
)
## CALCULATE OUTPUT COST
completion_cost = usage["completion_tokens"] * model_info["output_cost_per_token"]

View file

@ -1196,6 +1196,54 @@ def test_completion_cost_fireworks_ai(model):
cost = completion_cost(completion_response=resp)
def test_fireworks_ai_cache_token_pricing():
"""Test that Fireworks AI cost calculator accounts for cache read/creation tokens.
Regression test for https://github.com/BerriAI/litellm/issues/24774
"""
from litellm.llms.fireworks_ai.cost_calculator import cost_per_token
from litellm.types.utils import Usage
# Simulate usage with cache read tokens
usage_with_cache = Usage(
prompt_tokens=1000,
completion_tokens=500,
cache_read_input_tokens=800,
cache_creation_input_tokens=0,
)
# Simulate usage without cache tokens
usage_no_cache = Usage(
prompt_tokens=1000,
completion_tokens=500,
)
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
litellm.model_cost = litellm.get_model_cost_map(url="")
prompt_cost_cached, completion_cost_cached = cost_per_token(
model="fireworks_ai/llama-v3p3-70b-instruct", usage=usage_with_cache
)
prompt_cost_no_cache, completion_cost_no_cache = cost_per_token(
model="fireworks_ai/llama-v3p3-70b-instruct", usage=usage_no_cache
)
# Completion cost should be the same regardless of cache
assert completion_cost_cached == completion_cost_no_cache
# If the model has cache pricing, the prompt cost with cache should differ
# from the prompt cost without cache (cache read rate is cheaper)
model_info = litellm.get_model_info(
model="fireworks_ai/llama-v3p3-70b-instruct",
custom_llm_provider="fireworks_ai",
)
if model_info.get("cache_read_input_token_cost") is not None:
assert prompt_cost_cached < prompt_cost_no_cache, (
"Prompt cost with 800 cache-read tokens should be less than "
"full-price for the same total prompt tokens"
)
def test_cost_azure_openai_prompt_caching():
from litellm.utils import Choices, Message, ModelResponse, Usage
from litellm.types.utils import (