81
81
"method" : "stream" ,
82
82
"span_name" : "anthropic.chat" ,
83
83
},
84
- # # Beta API methods (regular Anthropic SDK)
85
- # {
86
- # "package": "anthropic.resources.beta.messages.messages",
87
- # "object": "Messages",
88
- # "method": "create",
89
- # "span_name": "anthropic.chat",
90
- # },
91
- # {
92
- # "package": "anthropic.resources.beta.messages.messages",
93
- # "object": "Messages",
94
- # "method": "stream",
95
- # "span_name": "anthropic.chat",
96
- # },
97
- # # Beta API methods (Bedrock SDK)
98
- # {
99
- # "package": "anthropic.lib.bedrock._beta_messages",
100
- # "object": "Messages",
101
- # "method": "create",
102
- # "span_name": "anthropic.chat",
103
- # },
104
- # {
105
- # "package": "anthropic.lib.bedrock._beta_messages",
106
- # "object": "Messages",
107
- # "method": "stream",
108
- # "span_name": "anthropic.chat",
109
- # },
84
+ # Beta API methods (regular Anthropic SDK)
85
+ {
86
+ "package" : "anthropic.resources.beta.messages.messages" ,
87
+ "object" : "Messages" ,
88
+ "method" : "create" ,
89
+ "span_name" : "anthropic.chat" ,
90
+ },
91
+ {
92
+ "package" : "anthropic.resources.beta.messages.messages" ,
93
+ "object" : "Messages" ,
94
+ "method" : "stream" ,
95
+ "span_name" : "anthropic.chat" ,
96
+ },
97
+ # Beta API methods (Bedrock SDK)
98
+ {
99
+ "package" : "anthropic.lib.bedrock._beta_messages" ,
100
+ "object" : "Messages" ,
101
+ "method" : "create" ,
102
+ "span_name" : "anthropic.chat" ,
103
+ },
104
+ {
105
+ "package" : "anthropic.lib.bedrock._beta_messages" ,
106
+ "object" : "Messages" ,
107
+ "method" : "stream" ,
108
+ "span_name" : "anthropic.chat" ,
109
+ },
110
110
]
111
111
112
112
WRAPPED_AMETHODS = [
122
122
"method" : "create" ,
123
123
"span_name" : "anthropic.chat" ,
124
124
},
125
- # # Beta API async methods (regular Anthropic SDK)
126
- # {
127
- # "package": "anthropic.resources.beta.messages.messages",
128
- # "object": "AsyncMessages",
129
- # "method": "create",
130
- # "span_name": "anthropic.chat",
131
- # },
132
- # {
133
- # "package": "anthropic.resources.beta.messages.messages",
134
- # "object": "AsyncMessages",
135
- # "method": "stream",
136
- # "span_name": "anthropic.chat",
137
- # },
138
- # # Beta API async methods (Bedrock SDK)
139
- # {
140
- # "package": "anthropic.lib.bedrock._beta_messages",
141
- # "object": "AsyncMessages",
142
- # "method": "create",
143
- # "span_name": "anthropic.chat",
144
- # },
145
- # {
146
- # "package": "anthropic.lib.bedrock._beta_messages",
147
- # "object": "AsyncMessages",
148
- # "method": "stream",
149
- # "span_name": "anthropic.chat",
150
- # },
125
+ # Beta API async methods (regular Anthropic SDK)
126
+ {
127
+ "package" : "anthropic.resources.beta.messages.messages" ,
128
+ "object" : "AsyncMessages" ,
129
+ "method" : "create" ,
130
+ "span_name" : "anthropic.chat" ,
131
+ },
132
+ {
133
+ "package" : "anthropic.resources.beta.messages.messages" ,
134
+ "object" : "AsyncMessages" ,
135
+ "method" : "stream" ,
136
+ "span_name" : "anthropic.chat" ,
137
+ },
138
+ # Beta API async methods (Bedrock SDK)
139
+ {
140
+ "package" : "anthropic.lib.bedrock._beta_messages" ,
141
+ "object" : "AsyncMessages" ,
142
+ "method" : "create" ,
143
+ "span_name" : "anthropic.chat" ,
144
+ },
145
+ {
146
+ "package" : "anthropic.lib.bedrock._beta_messages" ,
147
+ "object" : "AsyncMessages" ,
148
+ "method" : "stream" ,
149
+ "span_name" : "anthropic.chat" ,
150
+ },
151
151
]
152
152
153
153
@@ -182,14 +182,35 @@ async def _aset_token_usage(
182
182
token_histogram : Histogram = None ,
183
183
choice_counter : Counter = None ,
184
184
):
185
- from opentelemetry .instrumentation .anthropic .utils import _aextract_response_data
185
+ import inspect
186
+
187
+ # If we get a coroutine, await it
188
+ if inspect .iscoroutine (response ):
189
+ try :
190
+ response = await response
191
+ except Exception as e :
192
+ import logging
193
+ logger = logging .getLogger (__name__ )
194
+ logger .debug (f"Failed to await coroutine response: { e } " )
195
+ return
196
+
197
+ # Handle with_raw_response wrapped responses first
198
+ if response and hasattr (response , "parse" ) and callable (response .parse ):
199
+ try :
200
+ response = response .parse ()
201
+ except Exception as e :
202
+ import logging
203
+ logger = logging .getLogger (__name__ )
204
+ logger .debug (f"Failed to parse with_raw_response: { e } " )
205
+ return
186
206
187
- response = await _aextract_response_data (response )
207
+ # Safely get usage attribute without extracting the whole object
208
+ usage = getattr (response , "usage" , None ) if response else None
188
209
189
- if usage := response . get ( "usage" ) :
190
- prompt_tokens = usage . input_tokens
191
- cache_read_tokens = dict (usage ). get ( "cache_read_input_tokens" , 0 ) or 0
192
- cache_creation_tokens = dict (usage ). get ( "cache_creation_input_tokens" , 0 ) or 0
210
+ if usage :
211
+ prompt_tokens = getattr ( usage , " input_tokens" , 0 )
212
+ cache_read_tokens = getattr (usage , "cache_read_input_tokens" , 0 ) or 0
213
+ cache_creation_tokens = getattr (usage , "cache_creation_input_tokens" , 0 ) or 0
193
214
else :
194
215
prompt_tokens = await acount_prompt_tokens_from_request (anthropic , request )
195
216
cache_read_tokens = 0
@@ -206,18 +227,18 @@ async def _aset_token_usage(
206
227
},
207
228
)
208
229
209
- if usage := response . get ( "usage" ) :
210
- completion_tokens = usage . output_tokens
230
+ if usage :
231
+ completion_tokens = getattr ( usage , " output_tokens" , 0 )
211
232
else :
212
233
completion_tokens = 0
213
234
if hasattr (anthropic , "count_tokens" ):
214
- if response .get ("completion" ):
235
+ completion_attr = getattr (response , "completion" , None )
236
+ content_attr = getattr (response , "content" , None )
237
+ if completion_attr :
238
+ completion_tokens = await anthropic .count_tokens (completion_attr )
239
+ elif content_attr and len (content_attr ) > 0 :
215
240
completion_tokens = await anthropic .count_tokens (
216
- response .get ("completion" )
217
- )
218
- elif response .get ("content" ):
219
- completion_tokens = await anthropic .count_tokens (
220
- response .get ("content" )[0 ].text
241
+ content_attr [0 ].text
221
242
)
222
243
223
244
if (
@@ -236,17 +257,19 @@ async def _aset_token_usage(
236
257
total_tokens = input_tokens + completion_tokens
237
258
238
259
choices = 0
239
- if isinstance (response .get ("content" ), list ):
240
- choices = len (response .get ("content" ))
241
- elif response .get ("completion" ):
260
+ content_attr = getattr (response , "content" , None )
261
+ completion_attr = getattr (response , "completion" , None )
262
+ if isinstance (content_attr , list ):
263
+ choices = len (content_attr )
264
+ elif completion_attr :
242
265
choices = 1
243
266
244
267
if choices > 0 and choice_counter :
245
268
choice_counter .add (
246
269
choices ,
247
270
attributes = {
248
271
** metric_attributes ,
249
- SpanAttributes .LLM_RESPONSE_STOP_REASON : response . get ( "stop_reason" ),
272
+ SpanAttributes .LLM_RESPONSE_STOP_REASON : getattr ( response , "stop_reason" , None ),
250
273
},
251
274
)
252
275
@@ -276,14 +299,32 @@ def _set_token_usage(
276
299
token_histogram : Histogram = None ,
277
300
choice_counter : Counter = None ,
278
301
):
279
- from opentelemetry .instrumentation .anthropic .utils import _extract_response_data
302
+ import inspect
303
+
304
+ # If we get a coroutine, we cannot process it in sync context
305
+ if inspect .iscoroutine (response ):
306
+ import logging
307
+ logger = logging .getLogger (__name__ )
308
+ logger .warning (f"_set_token_usage received coroutine { response } - token usage processing skipped" )
309
+ return
310
+
311
+ # Handle with_raw_response wrapped responses first
312
+ if response and hasattr (response , "parse" ) and callable (response .parse ):
313
+ try :
314
+ response = response .parse ()
315
+ except Exception as e :
316
+ import logging
317
+ logger = logging .getLogger (__name__ )
318
+ logger .debug (f"Failed to parse with_raw_response: { e } " )
319
+ return
280
320
281
- response = _extract_response_data (response )
321
+ # Safely get usage attribute without extracting the whole object
322
+ usage = getattr (response , "usage" , None ) if response else None
282
323
283
- if usage := response . get ( "usage" ) :
284
- prompt_tokens = usage . input_tokens
285
- cache_read_tokens = dict (usage ). get ( "cache_read_input_tokens" , 0 ) or 0
286
- cache_creation_tokens = dict (usage ). get ( "cache_creation_input_tokens" , 0 ) or 0
324
+ if usage :
325
+ prompt_tokens = getattr ( usage , " input_tokens" , 0 )
326
+ cache_read_tokens = getattr (usage , "cache_read_input_tokens" , 0 ) or 0
327
+ cache_creation_tokens = getattr (usage , "cache_creation_input_tokens" , 0 ) or 0
287
328
else :
288
329
prompt_tokens = count_prompt_tokens_from_request (anthropic , request )
289
330
cache_read_tokens = 0
@@ -300,16 +341,18 @@ def _set_token_usage(
300
341
},
301
342
)
302
343
303
- if usage := response . get ( "usage" ) :
304
- completion_tokens = usage . output_tokens
344
+ if usage :
345
+ completion_tokens = getattr ( usage , " output_tokens" , 0 )
305
346
else :
306
347
completion_tokens = 0
307
348
if hasattr (anthropic , "count_tokens" ):
308
- if response .get ("completion" ):
309
- completion_tokens = anthropic .count_tokens (response .get ("completion" ))
310
- elif response .get ("content" ):
349
+ completion_attr = getattr (response , "completion" , None )
350
+ content_attr = getattr (response , "content" , None )
351
+ if completion_attr :
352
+ completion_tokens = anthropic .count_tokens (completion_attr )
353
+ elif content_attr and len (content_attr ) > 0 :
311
354
completion_tokens = anthropic .count_tokens (
312
- response . get ( "content" ) [0 ].text
355
+ content_attr [0 ].text
313
356
)
314
357
315
358
if (
@@ -328,17 +371,19 @@ def _set_token_usage(
328
371
total_tokens = input_tokens + completion_tokens
329
372
330
373
choices = 0
331
- if isinstance (response .get ("content" ), list ):
332
- choices = len (response .get ("content" ))
333
- elif response .get ("completion" ):
374
+ content_attr = getattr (response , "content" , None )
375
+ completion_attr = getattr (response , "completion" , None )
376
+ if isinstance (content_attr , list ):
377
+ choices = len (content_attr )
378
+ elif completion_attr :
334
379
choices = 1
335
380
336
381
if choices > 0 and choice_counter :
337
382
choice_counter .add (
338
383
choices ,
339
384
attributes = {
340
385
** metric_attributes ,
341
- SpanAttributes .LLM_RESPONSE_STOP_REASON : response . get ( "stop_reason" ),
386
+ SpanAttributes .LLM_RESPONSE_STOP_REASON : getattr ( response , "stop_reason" , None ),
342
387
},
343
388
)
344
389
0 commit comments