fix: keep video fallback for usage without prompt tokens

This commit is contained in:
pragnyanramtha 2026-05-20 22:01:02 +00:00
parent 069c2ad449
commit e9469f9b7c
2 changed files with 77 additions and 12 deletions

View file

@ -375,26 +375,28 @@ def _get_max_input_tokens_for_cost_fallback(
return None
def _usage_has_token_counts(usage_object: Optional[Usage]) -> bool:
def _usage_has_prompt_token_counts(usage_object: Optional[Usage]) -> bool:
if usage_object is None:
return False
for attr in ("prompt_tokens", "completion_tokens", "total_tokens"):
if _is_positive_finite_number(getattr(usage_object, attr, 0)):
return True
if _is_positive_finite_number(getattr(usage_object, "prompt_tokens", 0)):
return True
prompt_details = getattr(usage_object, "prompt_tokens_details", None)
if prompt_details is not None:
for attr in ("audio_tokens", "cached_tokens", "text_tokens"):
for attr in (
"audio_tokens",
"cached_tokens",
"cache_creation_tokens",
"character_count",
"image_count",
"image_tokens",
"text_tokens",
"video_length_seconds",
):
if _is_positive_finite_number(getattr(prompt_details, attr, 0)):
return True
completion_details = getattr(usage_object, "completion_tokens_details", None)
if completion_details is not None:
for attr in ("audio_tokens", "reasoning_tokens", "text_tokens"):
if _is_positive_finite_number(getattr(completion_details, attr, 0)):
return True
return False
@ -1684,7 +1686,7 @@ def completion_cost( # noqa: PLR0915
if (
call_type in _CHAT_COMPLETION_CALL_TYPES
and not _usage_has_token_counts(cost_per_token_usage_object)
and not _usage_has_prompt_token_counts(cost_per_token_usage_object)
):
# Video metadata is client-provided. When provider usage is
# missing, keep spend reconciliation conservative.

View file

@ -1031,6 +1031,69 @@ def test_completion_cost_uses_conservative_video_fallback_without_usage():
assert cost == pytest.approx(max_input_tokens * input_cost_per_token)
@pytest.mark.parametrize(
"usage,expected_completion_tokens",
[
({"total_tokens": 5}, 0),
({"completion_tokens": 3, "total_tokens": 3}, 3),
],
)
def test_completion_cost_uses_video_fallback_without_prompt_usage(
usage,
expected_completion_tokens,
):
model = "openai/test-video-cost-fallback-no-prompt-usage"
input_cost_per_token = 0.25
output_cost_per_token = 0.5
max_input_tokens = 16
litellm.register_model(
model_cost={
model: {
"input_cost_per_token": input_cost_per_token,
"output_cost_per_token": output_cost_per_token,
"max_tokens": max_input_tokens,
"max_input_tokens": max_input_tokens,
"max_output_tokens": 4,
"litellm_provider": "openai",
"mode": "chat",
}
}
)
messages = [
{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {
"url": "https://example.com/video.mp4",
"video_metadata": {
"duration_seconds": 0,
"fps": 0,
"has_audio": False,
},
},
}
],
}
]
try:
cost = completion_cost(
completion_response={"model": model, "usage": usage},
model=model,
messages=messages,
custom_llm_provider="openai",
)
finally:
litellm.model_cost.pop(model, None)
assert cost == pytest.approx(
(max_input_tokens * input_cost_per_token)
+ (expected_completion_tokens * output_cost_per_token)
)
@pytest.mark.parametrize("metadata_key", ["metadata", "litellm_metadata"])
def test_completion_cost_ignores_client_metadata_for_video_fallback_limit(
metadata_key,