55from dataclasses import dataclass , fields
66from typing import Annotated
77
8- from pydantic import AliasChoices , BeforeValidator , Field
8+ from pydantic import AliasChoices , Field
99from typing_extensions import deprecated , overload
1010
1111from . import _utils
1616
1717@dataclass (repr = False , kw_only = True )
1818class UsageBase :
19- input_tokens : Annotated [int , Field (validation_alias = AliasChoices ('input_tokens' , 'request_tokens' ))] = 0
19+ input_tokens : Annotated [
20+ int ,
21+ # `request_tokens` is deprecated, but we still want to support deserializing model responses stored in a DB before it was changed
22+ Field (validation_alias = AliasChoices ('input_tokens' , 'request_tokens' )),
23+ ] = 0
2024 """Number of input/prompt tokens."""
2125
2226 cache_write_tokens : int = 0
2327 """Number of tokens written to the cache."""
2428 cache_read_tokens : int = 0
2529 """Number of tokens read from the cache."""
2630
27- output_tokens : Annotated [int , Field (validation_alias = AliasChoices ('output_tokens' , 'response_tokens' ))] = 0
31+ output_tokens : Annotated [
32+ int ,
33+ # `response_tokens` is deprecated, but we still want to support deserializing model responses stored in a DB before it was changed
34+ Field (validation_alias = AliasChoices ('output_tokens' , 'response_tokens' )),
35+ ] = 0
2836 """Number of output/completion tokens."""
2937
3038 input_audio_tokens : int = 0
@@ -34,7 +42,7 @@ class UsageBase:
3442 output_audio_tokens : int = 0
3543 """Number of audio output tokens."""
3644
37- details : Annotated [ dict [str , int ], BeforeValidator ( lambda d : d or {})] = dataclasses . field ( default_factory = dict )
45+ details : dict [str , int ] | None = None
3846 """Any extra details returned by the model."""
3947
4048 @property
@@ -140,7 +148,7 @@ class RunUsage(UsageBase):
140148 output_tokens : int = 0
141149 """Total number of text output/completion tokens."""
142150
143- details : dict [str , int ] = dataclasses . field ( default_factory = dict )
151+ details : dict [str , int ] | None = None
144152 """Any extra details returned by the model."""
145153
146154 def incr (self , incr_usage : RunUsage | RequestUsage ) -> None :
@@ -164,22 +172,25 @@ def __add__(self, other: RunUsage | RequestUsage) -> RunUsage:
164172 return new_usage
165173
166174
167- def _incr_usage_tokens (slf : RunUsage | RequestUsage , incr_usage : RunUsage | RequestUsage ) -> None :
175+ def _incr_usage_tokens (self : RunUsage | RequestUsage , incr_usage : RunUsage | RequestUsage ) -> None :
168176 """Increment the usage in place.
169177
170178 Args:
171- slf : The usage to increment.
179+ self : The usage to increment.
172180 incr_usage: The usage to increment by.
173181 """
174- slf .input_tokens += incr_usage .input_tokens
175- slf .cache_write_tokens += incr_usage .cache_write_tokens
176- slf .cache_read_tokens += incr_usage .cache_read_tokens
177- slf .input_audio_tokens += incr_usage .input_audio_tokens
178- slf .cache_audio_read_tokens += incr_usage .cache_audio_read_tokens
179- slf .output_tokens += incr_usage .output_tokens
180-
181- for key , value in incr_usage .details .items ():
182- slf .details [key ] = slf .details .get (key , 0 ) + value
182+ self .input_tokens += incr_usage .input_tokens
183+ self .cache_write_tokens += incr_usage .cache_write_tokens
184+ self .cache_read_tokens += incr_usage .cache_read_tokens
185+ self .input_audio_tokens += incr_usage .input_audio_tokens
186+ self .cache_audio_read_tokens += incr_usage .cache_audio_read_tokens
187+ self .output_tokens += incr_usage .output_tokens
188+
189+ if incr_usage .details is not None :
190+ if self .details is None :
191+ self .details = {}
192+ for key , value in incr_usage .details .items ():
193+ self .details [key ] = self .details .get (key , 0 ) + value
183194
184195
185196@dataclass (repr = False , kw_only = True )
0 commit comments