Merge pull request #18799 from BerriAI/litellm_fix_claude_usage_object

Fix: Incomplete usage in response object passed
This commit is contained in:
Sameer Kankute 2026-01-08 15:29:26 +05:30 • committed by GitHub
commit e0662d53a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 66 additions and 7 deletions

View file

@ -1265,14 +1265,15 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
cache_creation_tokens=cache_creation_input_tokens,
cache_creation_token_details=cache_creation_token_details,
)
completion_token_details = (
CompletionTokensDetailsWrapper(
reasoning_tokens=token_counter(
text=reasoning_content, count_response_tokens=True
)
)
# Always populate completion_token_details, not just when there's reasoning_content
reasoning_tokens = (
token_counter(text=reasoning_content, count_response_tokens=True)
if reasoning_content
else None
else 0
)
completion_token_details = CompletionTokensDetailsWrapper(
reasoning_tokens=reasoning_tokens if reasoning_tokens > 0 else None,
text_tokens=completion_tokens - reasoning_tokens if reasoning_tokens > 0 else completion_tokens,
)
total_tokens = prompt_tokens + completion_tokens

View file

@ -1754,3 +1754,61 @@ def test_transform_request_respects_user_max_tokens():
)
assert result["max_tokens"] == 1000
def test_calculate_usage_completion_tokens_details_always_populated():
"""
Test that completion_tokens_details is always populated in Usage object,
not just when there's reasoning_content.
Fixes: https://github.com/BerriAI/litellm/issues/18772
Bug: completion_tokens_details was None for regular Claude responses without reasoning
"""
config = AnthropicConfig()
# Test without reasoning_content - completion_tokens_details should still be populated
usage_object = {
"input_tokens": 37,
"output_tokens": 248,
}
usage = config.calculate_usage(usage_object=usage_object, reasoning_content=None)
# completion_tokens_details should NOT be None
assert usage.completion_tokens_details is not None
assert usage.completion_tokens_details.reasoning_tokens is None
assert usage.completion_tokens_details.text_tokens == 248
assert usage.completion_tokens == 248
assert usage.prompt_tokens == 37
assert usage.total_tokens == 285
def test_calculate_usage_completion_tokens_details_with_reasoning():
"""
Test that completion_tokens_details correctly splits text_tokens and reasoning_tokens
when reasoning_content is present.
Fixes: https://github.com/BerriAI/litellm/issues/18772
"""
config = AnthropicConfig()
# Test with reasoning_content - should split tokens correctly
usage_object = {
"input_tokens": 100,
"output_tokens": 500,
}
# Simulating reasoning content that would count as ~50 tokens
reasoning_content = "Let me think about this step by step. " * 10 # Roughly 50 tokens
usage = config.calculate_usage(
usage_object=usage_object,
reasoning_content=reasoning_content
)
# completion_tokens_details should be populated with both reasoning and text tokens
assert usage.completion_tokens_details is not None
assert usage.completion_tokens_details.reasoning_tokens is not None
assert usage.completion_tokens_details.reasoning_tokens > 0
# text_tokens should be total minus reasoning
expected_text_tokens = 500 - usage.completion_tokens_details.reasoning_tokens
assert usage.completion_tokens_details.text_tokens == expected_text_tokens
assert usage.completion_tokens == 500