mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-08 22:21:35 +00:00
fix: cleanup cache_write_tokens when None + add unit test
- PromptTokensDetailsWrapper.__init__: delete cache_write_tokens when None, matching the cleanup pattern used by all other optional extension fields (character_count, image_count, web_search_requests, etc.) so it doesn't appear as null in model_dump() for non-OpenRouter callers - tests/test_litellm/types/test_types_utils.py: add test_usage_openrouter_cache_tokens_from_prompt_tokens_details covering the happy path (cached_tokens + cache_write_tokens → private fields), Anthropic-native precedence, and absence of cache_write_tokens in serialised output when not provided Made-with: Cursor
This commit is contained in:
parent
e44128c68c
commit
af4ea96f67
2 changed files with 51 additions and 0 deletions
|
|
@ -1493,6 +1493,8 @@ class PromptTokensDetailsWrapper(
|
|||
del self.cache_creation_tokens
|
||||
if self.cache_creation_token_details is None:
|
||||
del self.cache_creation_token_details
|
||||
if self.cache_write_tokens is None:
|
||||
del self.cache_write_tokens
|
||||
|
||||
|
||||
class ServerToolUse(BaseModel):
|
||||
|
|
|
|||
|
|
@ -304,3 +304,52 @@ def test_delta_maps_reasoning_to_reasoning_content():
|
|||
# When neither is present, reasoning_content is not set (OpenAI spec)
|
||||
delta4 = Delta(content="hello")
|
||||
assert not hasattr(delta4, "reasoning_content")
|
||||
|
||||
|
||||
def test_usage_openrouter_cache_tokens_from_prompt_tokens_details():
|
||||
"""OpenRouter returns cache token counts in prompt_tokens_details (OpenAI format).
|
||||
Usage.__init__ must map them to the Anthropic-style private fields so that cost
|
||||
calculations and the Anthropic pass-through streaming adapter see correct values."""
|
||||
from litellm.types.utils import PromptTokensDetailsWrapper, Usage
|
||||
|
||||
# Simulate what OpenRouter sends in the final streaming chunk
|
||||
usage = Usage(
|
||||
prompt_tokens=18500,
|
||||
completion_tokens=120,
|
||||
total_tokens=18620,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(
|
||||
cached_tokens=17000,
|
||||
cache_write_tokens=400,
|
||||
),
|
||||
)
|
||||
|
||||
# Private Anthropic-style fields must be populated from prompt_tokens_details
|
||||
assert usage._cache_read_input_tokens == 17000
|
||||
assert usage._cache_creation_input_tokens == 400
|
||||
|
||||
# When Anthropic native params are provided they must take precedence over
|
||||
# prompt_tokens_details so existing callers are not broken.
|
||||
usage_native = Usage(
|
||||
prompt_tokens=18500,
|
||||
completion_tokens=120,
|
||||
total_tokens=18620,
|
||||
cache_read_input_tokens=999,
|
||||
cache_creation_input_tokens=888,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(
|
||||
cached_tokens=17000,
|
||||
cache_write_tokens=400,
|
||||
),
|
||||
)
|
||||
assert usage_native._cache_read_input_tokens == 999
|
||||
assert usage_native._cache_creation_input_tokens == 888
|
||||
|
||||
# cache_write_tokens must not appear in serialised output when absent
|
||||
usage_no_writes = Usage(
|
||||
prompt_tokens=100,
|
||||
completion_tokens=10,
|
||||
total_tokens=110,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(cached_tokens=50),
|
||||
)
|
||||
dumped = usage_no_writes.model_dump()
|
||||
ptd = dumped.get("prompt_tokens_details", {})
|
||||
assert "cache_write_tokens" not in ptd
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue