fix(cost): tier-aware fallback for Gemini image tokens; avoid double-billing per-second audio/video

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
shivam 2026-07-16 01:03:52 +00:00
parent ca5bcfc8a8
commit e6ec88b1b7
2 changed files with 22 additions and 18 deletions

View file

@ -581,29 +581,30 @@ def _calculate_input_cost(
### AUDIO COST
if prompt_tokens_details["audio_tokens"]:
audio_cost_key = _get_service_tier_cost_key("input_cost_per_audio_token", service_tier)
if model_info.get(audio_cost_key) is None:
prompt_cost += float(prompt_tokens_details["audio_tokens"]) * prompt_base_cost
else:
if model_info.get(audio_cost_key) is not None:
prompt_cost += calculate_cost_component(model_info, audio_cost_key, prompt_tokens_details["audio_tokens"])
elif model_info.get("input_cost_per_audio_per_second") is None:
prompt_cost += float(prompt_tokens_details["audio_tokens"]) * prompt_base_cost
### IMAGE TOKEN COST
if prompt_tokens_details["image_tokens"]:
# For image token costs:
# First check if input_cost_per_image_token is available. If not, default to generic input_cost_per_token.
image_token_cost_key = "input_cost_per_image_token"
if model_info.get(image_token_cost_key) is None:
image_token_cost_key = "input_cost_per_token"
prompt_cost += calculate_cost_component(model_info, image_token_cost_key, prompt_tokens_details["image_tokens"])
if model_info.get(image_token_cost_key) is not None:
prompt_cost += calculate_cost_component(
model_info, image_token_cost_key, prompt_tokens_details["image_tokens"]
)
else:
prompt_cost += float(prompt_tokens_details["image_tokens"]) * prompt_base_cost
### VIDEO TOKEN COST
if prompt_tokens_details["video_tokens"]:
video_token_cost_key = "input_cost_per_video_token"
if model_info.get(video_token_cost_key) is None:
prompt_cost += float(prompt_tokens_details["video_tokens"]) * prompt_base_cost
else:
if model_info.get(video_token_cost_key) is not None:
prompt_cost += calculate_cost_component(
model_info, video_token_cost_key, prompt_tokens_details["video_tokens"]
)
elif model_info.get("input_cost_per_video_per_second") is None:
prompt_cost += float(prompt_tokens_details["video_tokens"]) * prompt_base_cost
### CACHE WRITING COST - Now uses tiered pricing
if (

View file

@ -379,12 +379,12 @@ def test_audio_input_tokens_gemini_priced_at_text_rate():
)
def test_audio_video_input_tokens_gemini_use_above_200k_tier():
"""Regression for LIT-4474: audio/video fallbacks must honor the >200k long-context tier.
def test_audio_video_image_input_tokens_gemini_use_above_200k_tier():
"""Regression for LIT-4474: audio/video/image fallbacks must honor the >200k long-context tier.
Falling back to the raw un-tiered input_cost_per_token undercounts when the request crosses
the 200k boundary; audio and video should be priced at input_cost_per_token_above_200k_tokens
like text.
the 200k boundary; audio, video and image tokens should be priced at
input_cost_per_token_above_200k_tokens like text.
"""
model = "gemini-3-pro-preview"
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
@ -393,11 +393,13 @@ def test_audio_video_input_tokens_gemini_use_above_200k_tier():
model_cost_map = litellm.model_cost[f"gemini/{model}"]
hi_rate = model_cost_map["input_cost_per_token_above_200k_tokens"]
assert hi_rate != model_cost_map["input_cost_per_token"]
assert model_cost_map.get("input_cost_per_image_token") is None
text_tokens = 100000
audio_tokens = 60000
video_tokens = 80000
prompt_tokens = text_tokens + audio_tokens + video_tokens
audio_tokens = 40000
video_tokens = 60000
image_tokens = 40000
prompt_tokens = text_tokens + audio_tokens + video_tokens + image_tokens
usage = Usage(
completion_tokens=0,
prompt_tokens=prompt_tokens,
@ -406,6 +408,7 @@ def test_audio_video_input_tokens_gemini_use_above_200k_tier():
text_tokens=text_tokens,
audio_tokens=audio_tokens,
video_tokens=video_tokens,
image_tokens=image_tokens,
),
)