opentelemetry-instrumentation-openai 0.45.6__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.
- opentelemetry/instrumentation/openai/shared/chat_wrappers.py +30 -0
- opentelemetry/instrumentation/openai/utils.py +10 -1
- opentelemetry/instrumentation/openai/v1/responses_wrappers.py +93 -1
- opentelemetry/instrumentation/openai/version.py +1 -1
- {opentelemetry_instrumentation_openai-0.45.6.dist-info → opentelemetry_instrumentation_openai-0.46.0.dist-info}/METADATA +2 -2
- {opentelemetry_instrumentation_openai-0.45.6.dist-info → opentelemetry_instrumentation_openai-0.46.0.dist-info}/RECORD +8 -8
- {opentelemetry_instrumentation_openai-0.45.6.dist-info → opentelemetry_instrumentation_openai-0.46.0.dist-info}/WHEEL +0 -0
- {opentelemetry_instrumentation_openai-0.45.6.dist-info → opentelemetry_instrumentation_openai-0.46.0.dist-info}/entry_points.txt +0 -0
|
@@ -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
|
-
|
|
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.
|
|
1
|
+
__version__ = "0.46.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: opentelemetry-instrumentation-openai
|
|
3
|
-
Version: 0.
|
|
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.
|
|
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=
|
|
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
|
|
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=
|
|
17
|
-
opentelemetry/instrumentation/openai/version.py,sha256=
|
|
18
|
-
opentelemetry_instrumentation_openai-0.
|
|
19
|
-
opentelemetry_instrumentation_openai-0.
|
|
20
|
-
opentelemetry_instrumentation_openai-0.
|
|
21
|
-
opentelemetry_instrumentation_openai-0.
|
|
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,,
|
|
File without changes
|