@@ -72,29 +72,47 @@ def _capture_exception(exc: "Any") -> None:
7272 sentry_sdk .capture_event (event , hint = hint )
7373
7474
75- def _get_token_usage (result : "Messages" ) -> "tuple[int, int]" :
75+ def _get_token_usage (result : "Messages" ) -> "tuple[int, int, int, int ]" :
7676 """
7777 Get token usage from the Anthropic response.
78+ Returns: (input_tokens, output_tokens, cache_read_input_tokens, cache_write_input_tokens)
7879 """
7980 input_tokens = 0
8081 output_tokens = 0
82+ cache_read_input_tokens = 0
83+ cache_write_input_tokens = 0
8184 if hasattr (result , "usage" ):
8285 usage = result .usage
8386 if hasattr (usage , "input_tokens" ) and isinstance (usage .input_tokens , int ):
8487 input_tokens = usage .input_tokens
8588 if hasattr (usage , "output_tokens" ) and isinstance (usage .output_tokens , int ):
8689 output_tokens = usage .output_tokens
87-
88- return input_tokens , output_tokens
90+ if hasattr (usage , "cache_read_input_tokens" ) and isinstance (
91+ usage .cache_read_input_tokens , int
92+ ):
93+ cache_read_input_tokens = usage .cache_read_input_tokens
94+ if hasattr (usage , "cache_creation_input_tokens" ) and isinstance (
95+ usage .cache_creation_input_tokens , int
96+ ):
97+ cache_write_input_tokens = usage .cache_creation_input_tokens
98+
99+ return (
100+ input_tokens ,
101+ output_tokens ,
102+ cache_read_input_tokens ,
103+ cache_write_input_tokens ,
104+ )
89105
90106
91107def _collect_ai_data (
92108 event : "MessageStreamEvent" ,
93109 model : "str | None" ,
94110 input_tokens : int ,
95111 output_tokens : int ,
112+ cache_read_input_tokens : int ,
113+ cache_write_input_tokens : int ,
96114 content_blocks : "list[str]" ,
97- ) -> "tuple[str | None, int, int, list[str]]" :
115+ ) -> "tuple[str | None, int, int, int, int, list[str]]" :
98116 """
99117 Collect model information, token usage, and collect content blocks from the AI streaming response.
100118 """
@@ -104,6 +122,14 @@ def _collect_ai_data(
104122 usage = event .message .usage
105123 input_tokens += usage .input_tokens
106124 output_tokens += usage .output_tokens
125+ if hasattr (usage , "cache_read_input_tokens" ) and isinstance (
126+ usage .cache_read_input_tokens , int
127+ ):
128+ cache_read_input_tokens += usage .cache_read_input_tokens
129+ if hasattr (usage , "cache_creation_input_tokens" ) and isinstance (
130+ usage .cache_creation_input_tokens , int
131+ ):
132+ cache_write_input_tokens += usage .cache_creation_input_tokens
107133 model = event .message .model or model
108134 elif event .type == "content_block_start" :
109135 pass
@@ -117,7 +143,14 @@ def _collect_ai_data(
117143 elif event .type == "message_delta" :
118144 output_tokens += event .usage .output_tokens
119145
120- return model , input_tokens , output_tokens , content_blocks
146+ return (
147+ model ,
148+ input_tokens ,
149+ output_tokens ,
150+ cache_read_input_tokens ,
151+ cache_write_input_tokens ,
152+ content_blocks ,
153+ )
121154
122155
123156def _set_input_data (
@@ -219,6 +252,8 @@ def _set_output_data(
219252 model : "str | None" ,
220253 input_tokens : "int | None" ,
221254 output_tokens : "int | None" ,
255+ cache_read_input_tokens : "int | None" ,
256+ cache_write_input_tokens : "int | None" ,
222257 content_blocks : "list[Any]" ,
223258 finish_span : bool = False ,
224259) -> None :
@@ -254,6 +289,8 @@ def _set_output_data(
254289 span ,
255290 input_tokens = input_tokens ,
256291 output_tokens = output_tokens ,
292+ input_tokens_cached = cache_read_input_tokens ,
293+ input_tokens_cache_write = cache_write_input_tokens ,
257294 )
258295
259296 if finish_span :
@@ -288,7 +325,12 @@ def _sentry_patched_create_common(f: "Any", *args: "Any", **kwargs: "Any") -> "A
288325
289326 with capture_internal_exceptions ():
290327 if hasattr (result , "content" ):
291- input_tokens , output_tokens = _get_token_usage (result )
328+ (
329+ input_tokens ,
330+ output_tokens ,
331+ cache_read_input_tokens ,
332+ cache_write_input_tokens ,
333+ ) = _get_token_usage (result )
292334
293335 content_blocks = []
294336 for content_block in result .content :
@@ -305,6 +347,8 @@ def _sentry_patched_create_common(f: "Any", *args: "Any", **kwargs: "Any") -> "A
305347 model = getattr (result , "model" , None ),
306348 input_tokens = input_tokens ,
307349 output_tokens = output_tokens ,
350+ cache_read_input_tokens = cache_read_input_tokens ,
351+ cache_write_input_tokens = cache_write_input_tokens ,
308352 content_blocks = content_blocks ,
309353 finish_span = True ,
310354 )
@@ -317,13 +361,26 @@ def new_iterator() -> "Iterator[MessageStreamEvent]":
317361 model = None
318362 input_tokens = 0
319363 output_tokens = 0
364+ cache_read_input_tokens = 0
365+ cache_write_input_tokens = 0
320366 content_blocks : "list[str]" = []
321367
322368 for event in old_iterator :
323- model , input_tokens , output_tokens , content_blocks = (
324- _collect_ai_data (
325- event , model , input_tokens , output_tokens , content_blocks
326- )
369+ (
370+ model ,
371+ input_tokens ,
372+ output_tokens ,
373+ cache_read_input_tokens ,
374+ cache_write_input_tokens ,
375+ content_blocks ,
376+ ) = _collect_ai_data (
377+ event ,
378+ model ,
379+ input_tokens ,
380+ output_tokens ,
381+ cache_read_input_tokens ,
382+ cache_write_input_tokens ,
383+ content_blocks ,
327384 )
328385 yield event
329386
@@ -333,6 +390,8 @@ def new_iterator() -> "Iterator[MessageStreamEvent]":
333390 model = model ,
334391 input_tokens = input_tokens ,
335392 output_tokens = output_tokens ,
393+ cache_read_input_tokens = cache_read_input_tokens ,
394+ cache_write_input_tokens = cache_write_input_tokens ,
336395 content_blocks = [{"text" : "" .join (content_blocks ), "type" : "text" }],
337396 finish_span = True ,
338397 )
@@ -341,13 +400,26 @@ async def new_iterator_async() -> "AsyncIterator[MessageStreamEvent]":
341400 model = None
342401 input_tokens = 0
343402 output_tokens = 0
403+ cache_read_input_tokens = 0
404+ cache_write_input_tokens = 0
344405 content_blocks : "list[str]" = []
345406
346407 async for event in old_iterator :
347- model , input_tokens , output_tokens , content_blocks = (
348- _collect_ai_data (
349- event , model , input_tokens , output_tokens , content_blocks
350- )
408+ (
409+ model ,
410+ input_tokens ,
411+ output_tokens ,
412+ cache_read_input_tokens ,
413+ cache_write_input_tokens ,
414+ content_blocks ,
415+ ) = _collect_ai_data (
416+ event ,
417+ model ,
418+ input_tokens ,
419+ output_tokens ,
420+ cache_read_input_tokens ,
421+ cache_write_input_tokens ,
422+ content_blocks ,
351423 )
352424 yield event
353425
@@ -357,6 +429,8 @@ async def new_iterator_async() -> "AsyncIterator[MessageStreamEvent]":
357429 model = model ,
358430 input_tokens = input_tokens ,
359431 output_tokens = output_tokens ,
432+ cache_read_input_tokens = cache_read_input_tokens ,
433+ cache_write_input_tokens = cache_write_input_tokens ,
360434 content_blocks = [{"text" : "" .join (content_blocks ), "type" : "text" }],
361435 finish_span = True ,
362436 )
0 commit comments