File tree Expand file tree Collapse file tree 2 files changed +32
-0
lines changed Expand file tree Collapse file tree 2 files changed +32
-0
lines changed Original file line number Diff line number Diff line change @@ -60,6 +60,16 @@ class Usage:
6060 cost calculation or context window management.
6161 """
6262
63+ def __post_init__ (self ) -> None :
64+ # Some providers don't populate optional token detail fields
65+ # (cached_tokens, reasoning_tokens), and the OpenAI SDK's generated
66+ # code can bypass Pydantic validation (e.g., via model_construct),
67+ # allowing None values. We normalize these to 0 to prevent TypeErrors.
68+ if self .input_tokens_details .cached_tokens is None :
69+ self .input_tokens_details = InputTokensDetails (cached_tokens = 0 )
70+ if self .output_tokens_details .reasoning_tokens is None :
71+ self .output_tokens_details = OutputTokensDetails (reasoning_tokens = 0 )
72+
6373 def add (self , other : "Usage" ) -> None :
6474 """Add another Usage object to this one, aggregating all fields.
6575
Original file line number Diff line number Diff line change @@ -267,3 +267,25 @@ def test_anthropic_cost_calculation_scenario():
267267 for req in usage .request_usage_entries :
268268 assert req .input_tokens < 200_000
269269 assert req .output_tokens < 200_000
270+
271+
272+ def test_usage_normalizes_none_token_details ():
273+ # Some providers don't populate optional fields, resulting in None values
274+ input_details = InputTokensDetails (cached_tokens = 0 )
275+ input_details .__dict__ ["cached_tokens" ] = None
276+
277+ output_details = OutputTokensDetails (reasoning_tokens = 0 )
278+ output_details .__dict__ ["reasoning_tokens" ] = None
279+
280+ usage = Usage (
281+ requests = 1 ,
282+ input_tokens = 100 ,
283+ input_tokens_details = input_details ,
284+ output_tokens = 50 ,
285+ output_tokens_details = output_details ,
286+ total_tokens = 150 ,
287+ )
288+
289+ # __post_init__ should normalize None to 0
290+ assert usage .input_tokens_details .cached_tokens == 0
291+ assert usage .output_tokens_details .reasoning_tokens == 0
You can’t perform that action at this time.
0 commit comments