opentelemetry-instrumentation-openai 0.45.5__py3-none-any.whl → 0.46.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of opentelemetry-instrumentation-openai might be problematic. Click here for more details.

@@ -285,6 +285,14 @@ async def _handle_request(span, kwargs, instance):
285
285
  if Config.enable_trace_context_propagation:
286
286
  propagate_trace_context(span, kwargs)
287
287
 
288
+ # Reasoning request attributes
289
+ reasoning_effort = kwargs.get("reasoning_effort")
290
+ _set_span_attribute(
291
+ span,
292
+ SpanAttributes.LLM_REQUEST_REASONING_EFFORT,
293
+ reasoning_effort or ()
294
+ )
295
+
288
296
 
289
297
  @dont_throw
290
298
  def _handle_response(
@@ -316,6 +324,28 @@ def _handle_response(
316
324
  # span attributes
317
325
  _set_response_attributes(span, response_dict)
318
326
 
327
+ # Reasoning usage attributes
328
+ usage = response_dict.get("usage")
329
+ reasoning_tokens = None
330
+ if usage:
331
+ # Support both dict-style and object-style `usage`
332
+ tokens_details = (
333
+ usage.get("completion_tokens_details") if isinstance(usage, dict)
334
+ else getattr(usage, "completion_tokens_details", None)
335
+ )
336
+
337
+ if tokens_details:
338
+ reasoning_tokens = (
339
+ tokens_details.get("reasoning_tokens", None) if isinstance(tokens_details, dict)
340
+ else getattr(tokens_details, "reasoning_tokens", None)
341
+ )
342
+
343
+ _set_span_attribute(
344
+ span,
345
+ SpanAttributes.LLM_USAGE_REASONING_TOKENS,
346
+ reasoning_tokens or 0,
347
+ )
348
+
319
349
  if should_emit_events():
320
350
  if response.choices is not None:
321
351
  for choice in response.choices:
@@ -5,6 +5,7 @@ import threading
5
5
  import traceback
6
6
  from contextlib import asynccontextmanager
7
7
  from importlib.metadata import version
8
+ from packaging import version as pkg_version
8
9
 
9
10
  from opentelemetry import context as context_api
10
11
  from opentelemetry._events import EventLogger
@@ -18,7 +19,15 @@ TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT"
18
19
 
19
20
 
20
21
  def is_openai_v1():
21
- return _OPENAI_VERSION >= "1.0.0"
22
+ return pkg_version.parse(_OPENAI_VERSION) >= pkg_version.parse("1.0.0")
23
+
24
+
25
+ def is_reasoning_supported():
26
+ # Reasoning has been introduced in OpenAI API on Dec 17, 2024
27
+ # as per https://platform.openai.com/docs/changelog.
28
+ # The updated OpenAI library version is 1.58.0
29
+ # as per https://pypi.org/project/openai/.
30
+ return pkg_version.parse(_OPENAI_VERSION) >= pkg_version.parse("1.58.0")
22
31
 
23
32
 
24
33
  def is_azure_openai(instance):
@@ -132,6 +132,11 @@ class TracedData(pydantic.BaseModel):
132
132
  request_model: Optional[str] = pydantic.Field(default=None)
133
133
  response_model: Optional[str] = pydantic.Field(default=None)
134
134
 
135
+ # Reasoning attributes
136
+ request_reasoning_summary: Optional[str] = pydantic.Field(default=None)
137
+ request_reasoning_effort: Optional[str] = pydantic.Field(default=None)
138
+ response_reasoning_effort: Optional[str] = pydantic.Field(default=None)
139
+
135
140
 
136
141
  responses: dict[str, TracedData] = {}
137
142
 
@@ -197,7 +202,46 @@ def set_data_attributes(traced_response: TracedData, span: Span):
197
202
  SpanAttributes.LLM_USAGE_CACHE_READ_INPUT_TOKENS,
198
203
  usage.input_tokens_details.cached_tokens,
199
204
  )
200
- # TODO: add reasoning tokens in output token details
205
+
206
+ # Usage - count of reasoning tokens
207
+ reasoning_tokens = None
208
+ # Support both dict-style and object-style `usage`
209
+ tokens_details = (
210
+ usage.get("output_tokens_details") if isinstance(usage, dict)
211
+ else getattr(usage, "output_tokens_details", None)
212
+ )
213
+
214
+ if tokens_details:
215
+ reasoning_tokens = (
216
+ tokens_details.get("reasoning_tokens", None) if isinstance(tokens_details, dict)
217
+ else getattr(tokens_details, "reasoning_tokens", None)
218
+ )
219
+
220
+ _set_span_attribute(
221
+ span,
222
+ SpanAttributes.LLM_USAGE_REASONING_TOKENS,
223
+ reasoning_tokens or 0,
224
+ )
225
+
226
+ # Reasoning attributes
227
+ # Request - reasoning summary
228
+ _set_span_attribute(
229
+ span,
230
+ f"{SpanAttributes.LLM_REQUEST_REASONING_SUMMARY}",
231
+ traced_response.request_reasoning_summary or (),
232
+ )
233
+ # Request - reasoning effort
234
+ _set_span_attribute(
235
+ span,
236
+ f"{SpanAttributes.LLM_REQUEST_REASONING_EFFORT}",
237
+ traced_response.request_reasoning_effort or (),
238
+ )
239
+ # Response - reasoning effort
240
+ _set_span_attribute(
241
+ span,
242
+ f"{SpanAttributes.LLM_RESPONSE_REASONING_EFFORT}",
243
+ traced_response.response_reasoning_effort or (),
244
+ )
201
245
 
202
246
  if should_send_prompts():
203
247
  prompt_index = 0
@@ -416,6 +460,18 @@ def responses_get_or_create_wrapper(tracer: Tracer, wrapped, instance, args, kwa
416
460
  "model", existing_data.get("request_model", "")
417
461
  ),
418
462
  response_model=existing_data.get("response_model", ""),
463
+ # Reasoning attributes
464
+ request_reasoning_summary=(
465
+ kwargs.get("reasoning", {}).get(
466
+ "summary", existing_data.get("request_reasoning_summary")
467
+ )
468
+ ),
469
+ request_reasoning_effort=(
470
+ kwargs.get("reasoning", {}).get(
471
+ "effort", existing_data.get("request_reasoning_effort")
472
+ )
473
+ ),
474
+ response_reasoning_effort=kwargs.get("reasoning", {}).get("effort"),
419
475
  )
420
476
  except Exception:
421
477
  traced_data = None
@@ -467,6 +523,18 @@ def responses_get_or_create_wrapper(tracer: Tracer, wrapped, instance, args, kwa
467
523
  output_text=existing_data.get("output_text", parsed_response_output_text),
468
524
  request_model=existing_data.get("request_model", kwargs.get("model")),
469
525
  response_model=existing_data.get("response_model", parsed_response.model),
526
+ # Reasoning attributes
527
+ request_reasoning_summary=(
528
+ kwargs.get("reasoning", {}).get(
529
+ "summary", existing_data.get("request_reasoning_summary")
530
+ )
531
+ ),
532
+ request_reasoning_effort=(
533
+ kwargs.get("reasoning", {}).get(
534
+ "effort", existing_data.get("request_reasoning_effort")
535
+ )
536
+ ),
537
+ response_reasoning_effort=kwargs.get("reasoning", {}).get("effort"),
470
538
  )
471
539
  responses[parsed_response.id] = traced_data
472
540
  except Exception:
@@ -518,6 +586,18 @@ async def async_responses_get_or_create_wrapper(
518
586
  output_text=kwargs.get("output_text", existing_data.get("output_text")),
519
587
  request_model=kwargs.get("model", existing_data.get("request_model")),
520
588
  response_model=existing_data.get("response_model"),
589
+ # Reasoning attributes
590
+ request_reasoning_summary=(
591
+ kwargs.get("reasoning", {}).get(
592
+ "summary", existing_data.get("request_reasoning_summary")
593
+ )
594
+ ),
595
+ request_reasoning_effort=(
596
+ kwargs.get("reasoning", {}).get(
597
+ "effort", existing_data.get("request_reasoning_effort")
598
+ )
599
+ ),
600
+ response_reasoning_effort=kwargs.get("reasoning", {}).get("effort"),
521
601
  )
522
602
  except Exception:
523
603
  traced_data = None
@@ -570,6 +650,18 @@ async def async_responses_get_or_create_wrapper(
570
650
  output_text=existing_data.get("output_text", parsed_response_output_text),
571
651
  request_model=existing_data.get("request_model", kwargs.get("model")),
572
652
  response_model=existing_data.get("response_model", parsed_response.model),
653
+ # Reasoning attributes
654
+ request_reasoning_summary=(
655
+ kwargs.get("reasoning", {}).get(
656
+ "summary", existing_data.get("request_reasoning_summary")
657
+ )
658
+ ),
659
+ request_reasoning_effort=(
660
+ kwargs.get("reasoning", {}).get(
661
+ "effort", existing_data.get("request_reasoning_effort")
662
+ )
663
+ ),
664
+ response_reasoning_effort=kwargs.get("reasoning", {}).get("effort"),
573
665
  )
574
666
  responses[parsed_response.id] = traced_data
575
667
  except Exception:
@@ -1 +1 @@
1
- __version__ = "0.45.5"
1
+ __version__ = "0.46.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: opentelemetry-instrumentation-openai
3
- Version: 0.45.5
3
+ Version: 0.46.0
4
4
  Summary: OpenTelemetry OpenAI instrumentation
5
5
  License: Apache-2.0
6
6
  Author: Gal Kleinman
@@ -17,7 +17,7 @@ Provides-Extra: instruments
17
17
  Requires-Dist: opentelemetry-api (>=1.28.0,<2.0.0)
18
18
  Requires-Dist: opentelemetry-instrumentation (>=0.50b0)
19
19
  Requires-Dist: opentelemetry-semantic-conventions (>=0.50b0)
20
- Requires-Dist: opentelemetry-semantic-conventions-ai (>=0.4.12,<0.5.0)
20
+ Requires-Dist: opentelemetry-semantic-conventions-ai (>=0.4.13,<0.5.0)
21
21
  Project-URL: Repository, https://github.com/traceloop/openllmetry/tree/main/packages/opentelemetry-instrumentation-openai
22
22
  Description-Content-Type: text/markdown
23
23
 
@@ -1,6 +1,6 @@
1
1
  opentelemetry/instrumentation/openai/__init__.py,sha256=Mx_nwMl0TlhUjrQOR4qdx6MEhBUKp5cuUIIXFzi3mXo,2093
2
2
  opentelemetry/instrumentation/openai/shared/__init__.py,sha256=Ba429tv5NPuQN7RoLzaj00K9oj88BaUBdPmUUsZ-7ic,12346
3
- opentelemetry/instrumentation/openai/shared/chat_wrappers.py,sha256=whdVqpTBFyWXITuY2pJYzVx1PF7kt5pQXvG7Z0nZV8Y,39325
3
+ opentelemetry/instrumentation/openai/shared/chat_wrappers.py,sha256=Wi6I_J4s-Xe29NKMmU5hoD7Oi1S2aS-H9nXXJuhK7J0,40271
4
4
  opentelemetry/instrumentation/openai/shared/completion_wrappers.py,sha256=600McQXNCPFaifeD4yFq00beZ9XjGEbYT_3XVojHQT4,9244
5
5
  opentelemetry/instrumentation/openai/shared/config.py,sha256=nQfVXiznVUIv2_BHSUQpaoCnxysG3XpaYpIZdxi0mxM,477
6
6
  opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py,sha256=oRHghd4vSDJ6fNHjL9G8QfKnPnp_NkZfVmTDSgZScVU,9251
@@ -8,14 +8,14 @@ opentelemetry/instrumentation/openai/shared/event_emitter.py,sha256=iXUoyEHbC9Dq
8
8
  opentelemetry/instrumentation/openai/shared/event_models.py,sha256=PCfCGxrrArwZqR-4wFcXrhwQq0sBMAxmSrpC4PUMtaM,876
9
9
  opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py,sha256=y_jN9oqjiOCoht3z-L1vuxaYehZRcpqUB4x3FyoqdrI,2120
10
10
  opentelemetry/instrumentation/openai/shared/span_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- opentelemetry/instrumentation/openai/utils.py,sha256=-0ugLRCR50v25KncuOq4tXHHPzdsH5PjS4Qd_8PP0TQ,4684
11
+ opentelemetry/instrumentation/openai/utils.py,sha256=3I37q_2uDJ_g3tSg_YH-wTTb9RL8-VpVnffvd4DanE0,5105
12
12
  opentelemetry/instrumentation/openai/v0/__init__.py,sha256=FhpVbP8NqjN2We_srppZ_U-0-Vbk-A15VSQp3zUnW3k,6353
13
13
  opentelemetry/instrumentation/openai/v1/__init__.py,sha256=oLst4xav77tTteZKXo59uyb-2IWqw_xOafaSMzTxq9g,13255
14
14
  opentelemetry/instrumentation/openai/v1/assistant_wrappers.py,sha256=oa5xYEDELFN9luvSn3y1xhSs37yRYY_Pwh6htqOs8gc,11297
15
15
  opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py,sha256=AT-eDZOFP-K_mm-ecdgQaILoIsEiItZmtwzwAuse86Q,4350
16
- opentelemetry/instrumentation/openai/v1/responses_wrappers.py,sha256=NSty_lrL5HJVt88d_keV-wQ17-4XGVzc9ukMLaITAug,24471
17
- opentelemetry/instrumentation/openai/version.py,sha256=6u4HbbMFHsa1nACy9zwQghY_pk7CDWVvNHRk0nDg70Y,23
18
- opentelemetry_instrumentation_openai-0.45.5.dist-info/METADATA,sha256=_CK5n5Xj26JNENhv-xlqQTdWz-ZHgGW3cO4MyTSJtvQ,2157
19
- opentelemetry_instrumentation_openai-0.45.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
20
- opentelemetry_instrumentation_openai-0.45.5.dist-info/entry_points.txt,sha256=vTBfiX5yXji5YHikuJHEOoBZ1TFdPQ1EI4ctd2pZSeE,93
21
- opentelemetry_instrumentation_openai-0.45.5.dist-info/RECORD,,
16
+ opentelemetry/instrumentation/openai/v1/responses_wrappers.py,sha256=AIvpkGC0yTdRRPVzjRDuRo8oAJD1_lBKvsSSxFbPqJs,28124
17
+ opentelemetry/instrumentation/openai/version.py,sha256=VTDTPpzZ6KwzjCPZhHgalFxPlpuy4ZGRkHB_n3WGwYs,23
18
+ opentelemetry_instrumentation_openai-0.46.0.dist-info/METADATA,sha256=NGxtNrpsFYwIOvM0uk_iLoaINHoauLTQAH61Xruoick,2157
19
+ opentelemetry_instrumentation_openai-0.46.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
20
+ opentelemetry_instrumentation_openai-0.46.0.dist-info/entry_points.txt,sha256=vTBfiX5yXji5YHikuJHEOoBZ1TFdPQ1EI4ctd2pZSeE,93
21
+ opentelemetry_instrumentation_openai-0.46.0.dist-info/RECORD,,