opentelemetry-instrumentation-openai 0.44.2__tar.gz → 0.45.0__tar.gz
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-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/PKG-INFO +1 -1
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +133 -128
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +39 -34
- opentelemetry_instrumentation_openai-0.45.0/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +326 -0
- opentelemetry_instrumentation_openai-0.45.0/opentelemetry/instrumentation/openai/version.py +1 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/pyproject.toml +1 -1
- opentelemetry_instrumentation_openai-0.44.2/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +0 -318
- opentelemetry_instrumentation_openai-0.44.2/opentelemetry/instrumentation/openai/version.py +0 -1
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/README.md +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/__init__.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/__init__.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/config.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/event_emitter.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/event_models.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/shared/span_utils.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/utils.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/v0/__init__.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/v1/__init__.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +0 -0
- {opentelemetry_instrumentation_openai-0.44.2 → opentelemetry_instrumentation_openai-0.45.0}/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +0 -0
|
@@ -48,6 +48,7 @@ from opentelemetry.semconv_ai import (
|
|
|
48
48
|
SpanAttributes,
|
|
49
49
|
)
|
|
50
50
|
from opentelemetry.trace import SpanKind, Tracer
|
|
51
|
+
from opentelemetry import trace
|
|
51
52
|
from opentelemetry.trace.status import Status, StatusCode
|
|
52
53
|
from wrapt import ObjectProxy
|
|
53
54
|
|
|
@@ -86,75 +87,77 @@ def chat_wrapper(
|
|
|
86
87
|
attributes={SpanAttributes.LLM_REQUEST_TYPE: LLM_REQUEST_TYPE.value},
|
|
87
88
|
)
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
duration_histogram.record(duration, attributes=attributes)
|
|
104
|
-
if exception_counter:
|
|
105
|
-
exception_counter.add(1, attributes=attributes)
|
|
106
|
-
|
|
107
|
-
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
108
|
-
span.record_exception(e)
|
|
109
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
110
|
-
span.end()
|
|
90
|
+
# Use the span as current context to ensure events get proper trace context
|
|
91
|
+
with trace.use_span(span, end_on_exit=False):
|
|
92
|
+
run_async(_handle_request(span, kwargs, instance))
|
|
93
|
+
try:
|
|
94
|
+
start_time = time.time()
|
|
95
|
+
response = wrapped(*args, **kwargs)
|
|
96
|
+
end_time = time.time()
|
|
97
|
+
except Exception as e: # pylint: disable=broad-except
|
|
98
|
+
end_time = time.time()
|
|
99
|
+
duration = end_time - start_time if "start_time" in locals() else 0
|
|
100
|
+
|
|
101
|
+
attributes = {
|
|
102
|
+
"error.type": e.__class__.__name__,
|
|
103
|
+
}
|
|
111
104
|
|
|
112
|
-
|
|
105
|
+
if duration > 0 and duration_histogram:
|
|
106
|
+
duration_histogram.record(duration, attributes=attributes)
|
|
107
|
+
if exception_counter:
|
|
108
|
+
exception_counter.add(1, attributes=attributes)
|
|
113
109
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
span,
|
|
119
|
-
response,
|
|
120
|
-
instance,
|
|
121
|
-
token_counter,
|
|
122
|
-
choice_counter,
|
|
123
|
-
duration_histogram,
|
|
124
|
-
streaming_time_to_first_token,
|
|
125
|
-
streaming_time_to_generate,
|
|
126
|
-
start_time,
|
|
127
|
-
kwargs,
|
|
128
|
-
)
|
|
129
|
-
else:
|
|
130
|
-
return _build_from_streaming_response(
|
|
131
|
-
span,
|
|
132
|
-
response,
|
|
133
|
-
instance,
|
|
134
|
-
token_counter,
|
|
135
|
-
choice_counter,
|
|
136
|
-
duration_histogram,
|
|
137
|
-
streaming_time_to_first_token,
|
|
138
|
-
streaming_time_to_generate,
|
|
139
|
-
start_time,
|
|
140
|
-
kwargs,
|
|
141
|
-
)
|
|
110
|
+
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
111
|
+
span.record_exception(e)
|
|
112
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
113
|
+
span.end()
|
|
142
114
|
|
|
143
|
-
|
|
115
|
+
raise
|
|
144
116
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
117
|
+
if is_streaming_response(response):
|
|
118
|
+
# span will be closed after the generator is done
|
|
119
|
+
if is_openai_v1():
|
|
120
|
+
return ChatStream(
|
|
121
|
+
span,
|
|
122
|
+
response,
|
|
123
|
+
instance,
|
|
124
|
+
token_counter,
|
|
125
|
+
choice_counter,
|
|
126
|
+
duration_histogram,
|
|
127
|
+
streaming_time_to_first_token,
|
|
128
|
+
streaming_time_to_generate,
|
|
129
|
+
start_time,
|
|
130
|
+
kwargs,
|
|
131
|
+
)
|
|
132
|
+
else:
|
|
133
|
+
return _build_from_streaming_response(
|
|
134
|
+
span,
|
|
135
|
+
response,
|
|
136
|
+
instance,
|
|
137
|
+
token_counter,
|
|
138
|
+
choice_counter,
|
|
139
|
+
duration_histogram,
|
|
140
|
+
streaming_time_to_first_token,
|
|
141
|
+
streaming_time_to_generate,
|
|
142
|
+
start_time,
|
|
143
|
+
kwargs,
|
|
144
|
+
)
|
|
154
145
|
|
|
155
|
-
|
|
146
|
+
duration = end_time - start_time
|
|
156
147
|
|
|
157
|
-
|
|
148
|
+
_handle_response(
|
|
149
|
+
response,
|
|
150
|
+
span,
|
|
151
|
+
instance,
|
|
152
|
+
token_counter,
|
|
153
|
+
choice_counter,
|
|
154
|
+
duration_histogram,
|
|
155
|
+
duration,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
span.end()
|
|
159
|
+
|
|
160
|
+
return response
|
|
158
161
|
|
|
159
162
|
|
|
160
163
|
@_with_chat_telemetry_wrapper
|
|
@@ -182,78 +185,80 @@ async def achat_wrapper(
|
|
|
182
185
|
attributes={SpanAttributes.LLM_REQUEST_TYPE: LLM_REQUEST_TYPE.value},
|
|
183
186
|
)
|
|
184
187
|
|
|
185
|
-
|
|
188
|
+
# Use the span as current context to ensure events get proper trace context
|
|
189
|
+
with trace.use_span(span, end_on_exit=False):
|
|
190
|
+
await _handle_request(span, kwargs, instance)
|
|
186
191
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if duration > 0 and duration_histogram:
|
|
202
|
-
duration_histogram.record(duration, attributes=attributes)
|
|
203
|
-
if exception_counter:
|
|
204
|
-
exception_counter.add(1, attributes=attributes)
|
|
205
|
-
|
|
206
|
-
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
207
|
-
span.record_exception(e)
|
|
208
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
209
|
-
span.end()
|
|
192
|
+
try:
|
|
193
|
+
start_time = time.time()
|
|
194
|
+
response = await wrapped(*args, **kwargs)
|
|
195
|
+
end_time = time.time()
|
|
196
|
+
except Exception as e: # pylint: disable=broad-except
|
|
197
|
+
end_time = time.time()
|
|
198
|
+
duration = end_time - start_time if "start_time" in locals() else 0
|
|
199
|
+
|
|
200
|
+
common_attributes = Config.get_common_metrics_attributes()
|
|
201
|
+
attributes = {
|
|
202
|
+
**common_attributes,
|
|
203
|
+
"error.type": e.__class__.__name__,
|
|
204
|
+
}
|
|
210
205
|
|
|
211
|
-
|
|
206
|
+
if duration > 0 and duration_histogram:
|
|
207
|
+
duration_histogram.record(duration, attributes=attributes)
|
|
208
|
+
if exception_counter:
|
|
209
|
+
exception_counter.add(1, attributes=attributes)
|
|
212
210
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
span,
|
|
218
|
-
response,
|
|
219
|
-
instance,
|
|
220
|
-
token_counter,
|
|
221
|
-
choice_counter,
|
|
222
|
-
duration_histogram,
|
|
223
|
-
streaming_time_to_first_token,
|
|
224
|
-
streaming_time_to_generate,
|
|
225
|
-
start_time,
|
|
226
|
-
kwargs,
|
|
227
|
-
)
|
|
228
|
-
else:
|
|
229
|
-
return _abuild_from_streaming_response(
|
|
230
|
-
span,
|
|
231
|
-
response,
|
|
232
|
-
instance,
|
|
233
|
-
token_counter,
|
|
234
|
-
choice_counter,
|
|
235
|
-
duration_histogram,
|
|
236
|
-
streaming_time_to_first_token,
|
|
237
|
-
streaming_time_to_generate,
|
|
238
|
-
start_time,
|
|
239
|
-
kwargs,
|
|
240
|
-
)
|
|
211
|
+
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
212
|
+
span.record_exception(e)
|
|
213
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
214
|
+
span.end()
|
|
241
215
|
|
|
242
|
-
|
|
216
|
+
raise
|
|
243
217
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
218
|
+
if is_streaming_response(response):
|
|
219
|
+
# span will be closed after the generator is done
|
|
220
|
+
if is_openai_v1():
|
|
221
|
+
return ChatStream(
|
|
222
|
+
span,
|
|
223
|
+
response,
|
|
224
|
+
instance,
|
|
225
|
+
token_counter,
|
|
226
|
+
choice_counter,
|
|
227
|
+
duration_histogram,
|
|
228
|
+
streaming_time_to_first_token,
|
|
229
|
+
streaming_time_to_generate,
|
|
230
|
+
start_time,
|
|
231
|
+
kwargs,
|
|
232
|
+
)
|
|
233
|
+
else:
|
|
234
|
+
return _abuild_from_streaming_response(
|
|
235
|
+
span,
|
|
236
|
+
response,
|
|
237
|
+
instance,
|
|
238
|
+
token_counter,
|
|
239
|
+
choice_counter,
|
|
240
|
+
duration_histogram,
|
|
241
|
+
streaming_time_to_first_token,
|
|
242
|
+
streaming_time_to_generate,
|
|
243
|
+
start_time,
|
|
244
|
+
kwargs,
|
|
245
|
+
)
|
|
253
246
|
|
|
254
|
-
|
|
247
|
+
duration = end_time - start_time
|
|
255
248
|
|
|
256
|
-
|
|
249
|
+
_handle_response(
|
|
250
|
+
response,
|
|
251
|
+
span,
|
|
252
|
+
instance,
|
|
253
|
+
token_counter,
|
|
254
|
+
choice_counter,
|
|
255
|
+
duration_histogram,
|
|
256
|
+
duration,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
span.end()
|
|
260
|
+
|
|
261
|
+
return response
|
|
257
262
|
|
|
258
263
|
|
|
259
264
|
@dont_throw
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
3
|
from opentelemetry import context as context_api
|
|
4
|
+
from opentelemetry import trace
|
|
4
5
|
from opentelemetry.instrumentation.openai.shared import (
|
|
5
6
|
_set_client_attributes,
|
|
6
7
|
_set_functions_attributes,
|
|
@@ -55,25 +56,27 @@ def completion_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
|
55
56
|
attributes={SpanAttributes.LLM_REQUEST_TYPE: LLM_REQUEST_TYPE.value},
|
|
56
57
|
)
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
# Use the span as current context to ensure events get proper trace context
|
|
60
|
+
with trace.use_span(span, end_on_exit=False):
|
|
61
|
+
_handle_request(span, kwargs, instance)
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
response = wrapped(*args, **kwargs)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
67
|
+
span.record_exception(e)
|
|
68
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
69
|
+
span.end()
|
|
70
|
+
raise
|
|
71
|
+
|
|
72
|
+
if is_streaming_response(response):
|
|
73
|
+
# span will be closed after the generator is done
|
|
74
|
+
return _build_from_streaming_response(span, kwargs, response)
|
|
75
|
+
else:
|
|
76
|
+
_handle_response(response, span, instance)
|
|
59
77
|
|
|
60
|
-
try:
|
|
61
|
-
response = wrapped(*args, **kwargs)
|
|
62
|
-
except Exception as e:
|
|
63
|
-
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
64
|
-
span.record_exception(e)
|
|
65
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
66
78
|
span.end()
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if is_streaming_response(response):
|
|
70
|
-
# span will be closed after the generator is done
|
|
71
|
-
return _build_from_streaming_response(span, kwargs, response)
|
|
72
|
-
else:
|
|
73
|
-
_handle_response(response, span, instance)
|
|
74
|
-
|
|
75
|
-
span.end()
|
|
76
|
-
return response
|
|
79
|
+
return response
|
|
77
80
|
|
|
78
81
|
|
|
79
82
|
@_with_tracer_wrapper
|
|
@@ -89,25 +92,27 @@ async def acompletion_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
|
89
92
|
attributes={SpanAttributes.LLM_REQUEST_TYPE: LLM_REQUEST_TYPE.value},
|
|
90
93
|
)
|
|
91
94
|
|
|
92
|
-
|
|
95
|
+
# Use the span as current context to ensure events get proper trace context
|
|
96
|
+
with trace.use_span(span, end_on_exit=False):
|
|
97
|
+
_handle_request(span, kwargs, instance)
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
response = await wrapped(*args, **kwargs)
|
|
101
|
+
except Exception as e:
|
|
102
|
+
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
103
|
+
span.record_exception(e)
|
|
104
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
105
|
+
span.end()
|
|
106
|
+
raise
|
|
107
|
+
|
|
108
|
+
if is_streaming_response(response):
|
|
109
|
+
# span will be closed after the generator is done
|
|
110
|
+
return _abuild_from_streaming_response(span, kwargs, response)
|
|
111
|
+
else:
|
|
112
|
+
_handle_response(response, span, instance)
|
|
93
113
|
|
|
94
|
-
try:
|
|
95
|
-
response = await wrapped(*args, **kwargs)
|
|
96
|
-
except Exception as e:
|
|
97
|
-
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
98
|
-
span.record_exception(e)
|
|
99
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
100
114
|
span.end()
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if is_streaming_response(response):
|
|
104
|
-
# span will be closed after the generator is done
|
|
105
|
-
return _abuild_from_streaming_response(span, kwargs, response)
|
|
106
|
-
else:
|
|
107
|
-
_handle_response(response, span, instance)
|
|
108
|
-
|
|
109
|
-
span.end()
|
|
110
|
-
return response
|
|
115
|
+
return response
|
|
111
116
|
|
|
112
117
|
|
|
113
118
|
@dont_throw
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
from opentelemetry import context as context_api
|
|
5
|
+
from opentelemetry import trace
|
|
6
|
+
from opentelemetry.instrumentation.openai.shared import (
|
|
7
|
+
_set_span_attribute,
|
|
8
|
+
model_as_dict,
|
|
9
|
+
)
|
|
10
|
+
from opentelemetry.instrumentation.openai.shared.config import Config
|
|
11
|
+
from opentelemetry.instrumentation.openai.shared.event_emitter import emit_event
|
|
12
|
+
from opentelemetry.instrumentation.openai.shared.event_models import (
|
|
13
|
+
ChoiceEvent,
|
|
14
|
+
MessageEvent,
|
|
15
|
+
)
|
|
16
|
+
from opentelemetry.instrumentation.openai.utils import (
|
|
17
|
+
_with_tracer_wrapper,
|
|
18
|
+
dont_throw,
|
|
19
|
+
should_emit_events,
|
|
20
|
+
)
|
|
21
|
+
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
|
|
22
|
+
from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE
|
|
23
|
+
from opentelemetry.semconv_ai import LLMRequestTypeValues, SpanAttributes
|
|
24
|
+
from opentelemetry.trace import SpanKind, Status, StatusCode
|
|
25
|
+
|
|
26
|
+
from openai._legacy_response import LegacyAPIResponse
|
|
27
|
+
from openai.types.beta.threads.run import Run
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
assistants = {}
|
|
32
|
+
runs = {}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@_with_tracer_wrapper
|
|
36
|
+
def assistants_create_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
37
|
+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
38
|
+
return wrapped(*args, **kwargs)
|
|
39
|
+
|
|
40
|
+
response = wrapped(*args, **kwargs)
|
|
41
|
+
|
|
42
|
+
assistants[response.id] = {
|
|
43
|
+
"model": kwargs.get("model"),
|
|
44
|
+
"instructions": kwargs.get("instructions"),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return response
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@_with_tracer_wrapper
|
|
51
|
+
def runs_create_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
52
|
+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
53
|
+
return wrapped(*args, **kwargs)
|
|
54
|
+
|
|
55
|
+
thread_id = kwargs.get("thread_id")
|
|
56
|
+
instructions = kwargs.get("instructions")
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
response = wrapped(*args, **kwargs)
|
|
60
|
+
response_dict = model_as_dict(response)
|
|
61
|
+
|
|
62
|
+
runs[thread_id] = {
|
|
63
|
+
"start_time": time.time_ns(),
|
|
64
|
+
"assistant_id": kwargs.get("assistant_id"),
|
|
65
|
+
"instructions": instructions,
|
|
66
|
+
"run_id": response_dict.get("id"),
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return response
|
|
70
|
+
except Exception as e:
|
|
71
|
+
runs[thread_id] = {
|
|
72
|
+
"exception": e,
|
|
73
|
+
"end_time": time.time_ns(),
|
|
74
|
+
}
|
|
75
|
+
raise
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@_with_tracer_wrapper
|
|
79
|
+
def runs_retrieve_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
80
|
+
@dont_throw
|
|
81
|
+
def process_response(response):
|
|
82
|
+
if type(response) is LegacyAPIResponse:
|
|
83
|
+
parsed_response = response.parse()
|
|
84
|
+
else:
|
|
85
|
+
parsed_response = response
|
|
86
|
+
assert type(parsed_response) is Run
|
|
87
|
+
|
|
88
|
+
if parsed_response.thread_id in runs:
|
|
89
|
+
thread_id = parsed_response.thread_id
|
|
90
|
+
runs[thread_id]["end_time"] = time.time_ns()
|
|
91
|
+
if parsed_response.usage:
|
|
92
|
+
runs[thread_id]["usage"] = parsed_response.usage
|
|
93
|
+
|
|
94
|
+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
95
|
+
return wrapped(*args, **kwargs)
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
response = wrapped(*args, **kwargs)
|
|
99
|
+
process_response(response)
|
|
100
|
+
return response
|
|
101
|
+
except Exception as e:
|
|
102
|
+
thread_id = kwargs.get("thread_id")
|
|
103
|
+
if thread_id in runs:
|
|
104
|
+
runs[thread_id]["exception"] = e
|
|
105
|
+
runs[thread_id]["end_time"] = time.time_ns()
|
|
106
|
+
raise
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@_with_tracer_wrapper
|
|
110
|
+
def messages_list_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
111
|
+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
112
|
+
return wrapped(*args, **kwargs)
|
|
113
|
+
|
|
114
|
+
id = kwargs.get("thread_id")
|
|
115
|
+
|
|
116
|
+
response = wrapped(*args, **kwargs)
|
|
117
|
+
|
|
118
|
+
response_dict = model_as_dict(response)
|
|
119
|
+
if id not in runs:
|
|
120
|
+
return response
|
|
121
|
+
|
|
122
|
+
run = runs[id]
|
|
123
|
+
messages = sorted(response_dict["data"], key=lambda x: x["created_at"])
|
|
124
|
+
|
|
125
|
+
span = tracer.start_span(
|
|
126
|
+
"openai.assistant.run",
|
|
127
|
+
kind=SpanKind.CLIENT,
|
|
128
|
+
attributes={SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.CHAT.value},
|
|
129
|
+
start_time=run.get("start_time"),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Use the span as current context to ensure events get proper trace context
|
|
133
|
+
with trace.use_span(span, end_on_exit=False):
|
|
134
|
+
if exception := run.get("exception"):
|
|
135
|
+
span.set_attribute(ERROR_TYPE, exception.__class__.__name__)
|
|
136
|
+
span.record_exception(exception)
|
|
137
|
+
span.set_status(Status(StatusCode.ERROR, str(exception)))
|
|
138
|
+
span.end()
|
|
139
|
+
return response
|
|
140
|
+
|
|
141
|
+
prompt_index = 0
|
|
142
|
+
if assistants.get(run["assistant_id"]) is not None or Config.enrich_assistant:
|
|
143
|
+
if Config.enrich_assistant:
|
|
144
|
+
assistant = model_as_dict(
|
|
145
|
+
instance._client.beta.assistants.retrieve(run["assistant_id"])
|
|
146
|
+
)
|
|
147
|
+
assistants[run["assistant_id"]] = assistant
|
|
148
|
+
else:
|
|
149
|
+
assistant = assistants[run["assistant_id"]]
|
|
150
|
+
|
|
151
|
+
_set_span_attribute(
|
|
152
|
+
span,
|
|
153
|
+
SpanAttributes.LLM_SYSTEM,
|
|
154
|
+
"openai",
|
|
155
|
+
)
|
|
156
|
+
_set_span_attribute(
|
|
157
|
+
span,
|
|
158
|
+
SpanAttributes.LLM_REQUEST_MODEL,
|
|
159
|
+
assistant["model"],
|
|
160
|
+
)
|
|
161
|
+
_set_span_attribute(
|
|
162
|
+
span,
|
|
163
|
+
SpanAttributes.LLM_RESPONSE_MODEL,
|
|
164
|
+
assistant["model"],
|
|
165
|
+
)
|
|
166
|
+
if should_emit_events():
|
|
167
|
+
emit_event(MessageEvent(content=assistant["instructions"], role="system"))
|
|
168
|
+
else:
|
|
169
|
+
_set_span_attribute(
|
|
170
|
+
span, f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.role", "system"
|
|
171
|
+
)
|
|
172
|
+
_set_span_attribute(
|
|
173
|
+
span,
|
|
174
|
+
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.content",
|
|
175
|
+
assistant["instructions"],
|
|
176
|
+
)
|
|
177
|
+
prompt_index += 1
|
|
178
|
+
_set_span_attribute(
|
|
179
|
+
span, f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.role", "system"
|
|
180
|
+
)
|
|
181
|
+
_set_span_attribute(
|
|
182
|
+
span,
|
|
183
|
+
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.content",
|
|
184
|
+
run["instructions"],
|
|
185
|
+
)
|
|
186
|
+
if should_emit_events():
|
|
187
|
+
emit_event(MessageEvent(content=run["instructions"], role="system"))
|
|
188
|
+
prompt_index += 1
|
|
189
|
+
|
|
190
|
+
completion_index = 0
|
|
191
|
+
for msg in messages:
|
|
192
|
+
prefix = f"{SpanAttributes.LLM_COMPLETIONS}.{completion_index}"
|
|
193
|
+
content = msg.get("content")
|
|
194
|
+
|
|
195
|
+
message_content = content[0].get("text").get("value")
|
|
196
|
+
message_role = msg.get("role")
|
|
197
|
+
if message_role in ["user", "system"]:
|
|
198
|
+
if should_emit_events():
|
|
199
|
+
emit_event(MessageEvent(content=message_content, role=message_role))
|
|
200
|
+
else:
|
|
201
|
+
_set_span_attribute(
|
|
202
|
+
span,
|
|
203
|
+
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.role",
|
|
204
|
+
message_role,
|
|
205
|
+
)
|
|
206
|
+
_set_span_attribute(
|
|
207
|
+
span,
|
|
208
|
+
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.content",
|
|
209
|
+
message_content,
|
|
210
|
+
)
|
|
211
|
+
prompt_index += 1
|
|
212
|
+
else:
|
|
213
|
+
if should_emit_events():
|
|
214
|
+
emit_event(
|
|
215
|
+
ChoiceEvent(
|
|
216
|
+
index=completion_index,
|
|
217
|
+
message={"content": message_content, "role": message_role},
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
else:
|
|
221
|
+
_set_span_attribute(span, f"{prefix}.role", msg.get("role"))
|
|
222
|
+
_set_span_attribute(span, f"{prefix}.content", message_content)
|
|
223
|
+
_set_span_attribute(
|
|
224
|
+
span, f"gen_ai.response.{completion_index}.id", msg.get("id")
|
|
225
|
+
)
|
|
226
|
+
completion_index += 1
|
|
227
|
+
|
|
228
|
+
if run.get("usage"):
|
|
229
|
+
usage_dict = model_as_dict(run.get("usage"))
|
|
230
|
+
_set_span_attribute(
|
|
231
|
+
span,
|
|
232
|
+
SpanAttributes.LLM_USAGE_COMPLETION_TOKENS,
|
|
233
|
+
usage_dict.get("completion_tokens"),
|
|
234
|
+
)
|
|
235
|
+
_set_span_attribute(
|
|
236
|
+
span,
|
|
237
|
+
SpanAttributes.LLM_USAGE_PROMPT_TOKENS,
|
|
238
|
+
usage_dict.get("prompt_tokens"),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
span.end(run.get("end_time"))
|
|
242
|
+
|
|
243
|
+
return response
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@_with_tracer_wrapper
|
|
247
|
+
def runs_create_and_stream_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
248
|
+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
249
|
+
return wrapped(*args, **kwargs)
|
|
250
|
+
|
|
251
|
+
assistant_id = kwargs.get("assistant_id")
|
|
252
|
+
instructions = kwargs.get("instructions")
|
|
253
|
+
|
|
254
|
+
span = tracer.start_span(
|
|
255
|
+
"openai.assistant.run_stream",
|
|
256
|
+
kind=SpanKind.CLIENT,
|
|
257
|
+
attributes={SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.CHAT.value},
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# Use the span as current context to ensure events get proper trace context
|
|
261
|
+
with trace.use_span(span, end_on_exit=False):
|
|
262
|
+
i = 0
|
|
263
|
+
if assistants.get(assistant_id) is not None or Config.enrich_assistant:
|
|
264
|
+
if Config.enrich_assistant:
|
|
265
|
+
assistant = model_as_dict(
|
|
266
|
+
instance._client.beta.assistants.retrieve(assistant_id)
|
|
267
|
+
)
|
|
268
|
+
assistants[assistant_id] = assistant
|
|
269
|
+
else:
|
|
270
|
+
assistant = assistants[assistant_id]
|
|
271
|
+
|
|
272
|
+
_set_span_attribute(
|
|
273
|
+
span, SpanAttributes.LLM_REQUEST_MODEL, assistants[assistant_id]["model"]
|
|
274
|
+
)
|
|
275
|
+
_set_span_attribute(
|
|
276
|
+
span,
|
|
277
|
+
SpanAttributes.LLM_SYSTEM,
|
|
278
|
+
"openai",
|
|
279
|
+
)
|
|
280
|
+
_set_span_attribute(
|
|
281
|
+
span,
|
|
282
|
+
SpanAttributes.LLM_RESPONSE_MODEL,
|
|
283
|
+
assistants[assistant_id]["model"],
|
|
284
|
+
)
|
|
285
|
+
if should_emit_events():
|
|
286
|
+
emit_event(
|
|
287
|
+
MessageEvent(
|
|
288
|
+
content=assistants[assistant_id]["instructions"], role="system"
|
|
289
|
+
)
|
|
290
|
+
)
|
|
291
|
+
else:
|
|
292
|
+
_set_span_attribute(
|
|
293
|
+
span, f"{SpanAttributes.LLM_PROMPTS}.{i}.role", "system"
|
|
294
|
+
)
|
|
295
|
+
_set_span_attribute(
|
|
296
|
+
span,
|
|
297
|
+
f"{SpanAttributes.LLM_PROMPTS}.{i}.content",
|
|
298
|
+
assistants[assistant_id]["instructions"],
|
|
299
|
+
)
|
|
300
|
+
i += 1
|
|
301
|
+
if should_emit_events():
|
|
302
|
+
emit_event(MessageEvent(content=instructions, role="system"))
|
|
303
|
+
else:
|
|
304
|
+
_set_span_attribute(span, f"{SpanAttributes.LLM_PROMPTS}.{i}.role", "system")
|
|
305
|
+
_set_span_attribute(
|
|
306
|
+
span, f"{SpanAttributes.LLM_PROMPTS}.{i}.content", instructions
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
from opentelemetry.instrumentation.openai.v1.event_handler_wrapper import (
|
|
310
|
+
EventHandleWrapper,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
kwargs["event_handler"] = EventHandleWrapper(
|
|
314
|
+
original_handler=kwargs["event_handler"],
|
|
315
|
+
span=span,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
try:
|
|
319
|
+
response = wrapped(*args, **kwargs)
|
|
320
|
+
return response
|
|
321
|
+
except Exception as e:
|
|
322
|
+
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
323
|
+
span.record_exception(e)
|
|
324
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
325
|
+
span.end()
|
|
326
|
+
raise
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.45.0"
|
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import time
|
|
3
|
-
|
|
4
|
-
from opentelemetry import context as context_api
|
|
5
|
-
from opentelemetry.instrumentation.openai.shared import (
|
|
6
|
-
_set_span_attribute,
|
|
7
|
-
model_as_dict,
|
|
8
|
-
)
|
|
9
|
-
from opentelemetry.instrumentation.openai.shared.config import Config
|
|
10
|
-
from opentelemetry.instrumentation.openai.shared.event_emitter import emit_event
|
|
11
|
-
from opentelemetry.instrumentation.openai.shared.event_models import (
|
|
12
|
-
ChoiceEvent,
|
|
13
|
-
MessageEvent,
|
|
14
|
-
)
|
|
15
|
-
from opentelemetry.instrumentation.openai.utils import (
|
|
16
|
-
_with_tracer_wrapper,
|
|
17
|
-
dont_throw,
|
|
18
|
-
should_emit_events,
|
|
19
|
-
)
|
|
20
|
-
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
|
|
21
|
-
from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE
|
|
22
|
-
from opentelemetry.semconv_ai import LLMRequestTypeValues, SpanAttributes
|
|
23
|
-
from opentelemetry.trace import SpanKind, Status, StatusCode
|
|
24
|
-
|
|
25
|
-
from openai._legacy_response import LegacyAPIResponse
|
|
26
|
-
from openai.types.beta.threads.run import Run
|
|
27
|
-
|
|
28
|
-
logger = logging.getLogger(__name__)
|
|
29
|
-
|
|
30
|
-
assistants = {}
|
|
31
|
-
runs = {}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@_with_tracer_wrapper
|
|
35
|
-
def assistants_create_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
36
|
-
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
37
|
-
return wrapped(*args, **kwargs)
|
|
38
|
-
|
|
39
|
-
response = wrapped(*args, **kwargs)
|
|
40
|
-
|
|
41
|
-
assistants[response.id] = {
|
|
42
|
-
"model": kwargs.get("model"),
|
|
43
|
-
"instructions": kwargs.get("instructions"),
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return response
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@_with_tracer_wrapper
|
|
50
|
-
def runs_create_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
51
|
-
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
52
|
-
return wrapped(*args, **kwargs)
|
|
53
|
-
|
|
54
|
-
thread_id = kwargs.get("thread_id")
|
|
55
|
-
instructions = kwargs.get("instructions")
|
|
56
|
-
|
|
57
|
-
try:
|
|
58
|
-
response = wrapped(*args, **kwargs)
|
|
59
|
-
response_dict = model_as_dict(response)
|
|
60
|
-
|
|
61
|
-
runs[thread_id] = {
|
|
62
|
-
"start_time": time.time_ns(),
|
|
63
|
-
"assistant_id": kwargs.get("assistant_id"),
|
|
64
|
-
"instructions": instructions,
|
|
65
|
-
"run_id": response_dict.get("id"),
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return response
|
|
69
|
-
except Exception as e:
|
|
70
|
-
runs[thread_id] = {
|
|
71
|
-
"exception": e,
|
|
72
|
-
"end_time": time.time_ns(),
|
|
73
|
-
}
|
|
74
|
-
raise
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@_with_tracer_wrapper
|
|
78
|
-
def runs_retrieve_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
79
|
-
@dont_throw
|
|
80
|
-
def process_response(response):
|
|
81
|
-
if type(response) is LegacyAPIResponse:
|
|
82
|
-
parsed_response = response.parse()
|
|
83
|
-
else:
|
|
84
|
-
parsed_response = response
|
|
85
|
-
assert type(parsed_response) is Run
|
|
86
|
-
|
|
87
|
-
if parsed_response.thread_id in runs:
|
|
88
|
-
thread_id = parsed_response.thread_id
|
|
89
|
-
runs[thread_id]["end_time"] = time.time_ns()
|
|
90
|
-
if parsed_response.usage:
|
|
91
|
-
runs[thread_id]["usage"] = parsed_response.usage
|
|
92
|
-
|
|
93
|
-
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
94
|
-
return wrapped(*args, **kwargs)
|
|
95
|
-
|
|
96
|
-
try:
|
|
97
|
-
response = wrapped(*args, **kwargs)
|
|
98
|
-
process_response(response)
|
|
99
|
-
return response
|
|
100
|
-
except Exception as e:
|
|
101
|
-
thread_id = kwargs.get("thread_id")
|
|
102
|
-
if thread_id in runs:
|
|
103
|
-
runs[thread_id]["exception"] = e
|
|
104
|
-
runs[thread_id]["end_time"] = time.time_ns()
|
|
105
|
-
raise
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
@_with_tracer_wrapper
|
|
109
|
-
def messages_list_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
110
|
-
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
111
|
-
return wrapped(*args, **kwargs)
|
|
112
|
-
|
|
113
|
-
id = kwargs.get("thread_id")
|
|
114
|
-
|
|
115
|
-
response = wrapped(*args, **kwargs)
|
|
116
|
-
|
|
117
|
-
response_dict = model_as_dict(response)
|
|
118
|
-
if id not in runs:
|
|
119
|
-
return response
|
|
120
|
-
|
|
121
|
-
run = runs[id]
|
|
122
|
-
messages = sorted(response_dict["data"], key=lambda x: x["created_at"])
|
|
123
|
-
|
|
124
|
-
span = tracer.start_span(
|
|
125
|
-
"openai.assistant.run",
|
|
126
|
-
kind=SpanKind.CLIENT,
|
|
127
|
-
attributes={SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.CHAT.value},
|
|
128
|
-
start_time=run.get("start_time"),
|
|
129
|
-
)
|
|
130
|
-
if exception := run.get("exception"):
|
|
131
|
-
span.set_attribute(ERROR_TYPE, exception.__class__.__name__)
|
|
132
|
-
span.record_exception(exception)
|
|
133
|
-
span.set_status(Status(StatusCode.ERROR, str(exception)))
|
|
134
|
-
span.end(run.get("end_time"))
|
|
135
|
-
|
|
136
|
-
prompt_index = 0
|
|
137
|
-
if assistants.get(run["assistant_id"]) is not None or Config.enrich_assistant:
|
|
138
|
-
if Config.enrich_assistant:
|
|
139
|
-
assistant = model_as_dict(
|
|
140
|
-
instance._client.beta.assistants.retrieve(run["assistant_id"])
|
|
141
|
-
)
|
|
142
|
-
assistants[run["assistant_id"]] = assistant
|
|
143
|
-
else:
|
|
144
|
-
assistant = assistants[run["assistant_id"]]
|
|
145
|
-
|
|
146
|
-
_set_span_attribute(
|
|
147
|
-
span,
|
|
148
|
-
SpanAttributes.LLM_SYSTEM,
|
|
149
|
-
"openai",
|
|
150
|
-
)
|
|
151
|
-
_set_span_attribute(
|
|
152
|
-
span,
|
|
153
|
-
SpanAttributes.LLM_REQUEST_MODEL,
|
|
154
|
-
assistant["model"],
|
|
155
|
-
)
|
|
156
|
-
_set_span_attribute(
|
|
157
|
-
span,
|
|
158
|
-
SpanAttributes.LLM_RESPONSE_MODEL,
|
|
159
|
-
assistant["model"],
|
|
160
|
-
)
|
|
161
|
-
if should_emit_events():
|
|
162
|
-
emit_event(MessageEvent(content=assistant["instructions"], role="system"))
|
|
163
|
-
else:
|
|
164
|
-
_set_span_attribute(
|
|
165
|
-
span, f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.role", "system"
|
|
166
|
-
)
|
|
167
|
-
_set_span_attribute(
|
|
168
|
-
span,
|
|
169
|
-
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.content",
|
|
170
|
-
assistant["instructions"],
|
|
171
|
-
)
|
|
172
|
-
prompt_index += 1
|
|
173
|
-
_set_span_attribute(
|
|
174
|
-
span, f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.role", "system"
|
|
175
|
-
)
|
|
176
|
-
_set_span_attribute(
|
|
177
|
-
span,
|
|
178
|
-
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.content",
|
|
179
|
-
run["instructions"],
|
|
180
|
-
)
|
|
181
|
-
emit_event(MessageEvent(content=run["instructions"], role="system"))
|
|
182
|
-
prompt_index += 1
|
|
183
|
-
|
|
184
|
-
completion_index = 0
|
|
185
|
-
for msg in messages:
|
|
186
|
-
prefix = f"{SpanAttributes.LLM_COMPLETIONS}.{completion_index}"
|
|
187
|
-
content = msg.get("content")
|
|
188
|
-
|
|
189
|
-
message_content = content[0].get("text").get("value")
|
|
190
|
-
message_role = msg.get("role")
|
|
191
|
-
if message_role in ["user", "system"]:
|
|
192
|
-
if should_emit_events():
|
|
193
|
-
emit_event(MessageEvent(content=message_content, role=message_role))
|
|
194
|
-
else:
|
|
195
|
-
_set_span_attribute(
|
|
196
|
-
span,
|
|
197
|
-
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.role",
|
|
198
|
-
message_role,
|
|
199
|
-
)
|
|
200
|
-
_set_span_attribute(
|
|
201
|
-
span,
|
|
202
|
-
f"{SpanAttributes.LLM_PROMPTS}.{prompt_index}.content",
|
|
203
|
-
message_content,
|
|
204
|
-
)
|
|
205
|
-
prompt_index += 1
|
|
206
|
-
else:
|
|
207
|
-
if should_emit_events():
|
|
208
|
-
emit_event(
|
|
209
|
-
ChoiceEvent(
|
|
210
|
-
index=completion_index,
|
|
211
|
-
message={"content": message_content, "role": message_role},
|
|
212
|
-
)
|
|
213
|
-
)
|
|
214
|
-
else:
|
|
215
|
-
_set_span_attribute(span, f"{prefix}.role", msg.get("role"))
|
|
216
|
-
_set_span_attribute(span, f"{prefix}.content", message_content)
|
|
217
|
-
_set_span_attribute(
|
|
218
|
-
span, f"gen_ai.response.{completion_index}.id", msg.get("id")
|
|
219
|
-
)
|
|
220
|
-
completion_index += 1
|
|
221
|
-
|
|
222
|
-
if run.get("usage"):
|
|
223
|
-
usage_dict = model_as_dict(run.get("usage"))
|
|
224
|
-
_set_span_attribute(
|
|
225
|
-
span,
|
|
226
|
-
SpanAttributes.LLM_USAGE_COMPLETION_TOKENS,
|
|
227
|
-
usage_dict.get("completion_tokens"),
|
|
228
|
-
)
|
|
229
|
-
_set_span_attribute(
|
|
230
|
-
span,
|
|
231
|
-
SpanAttributes.LLM_USAGE_PROMPT_TOKENS,
|
|
232
|
-
usage_dict.get("prompt_tokens"),
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
span.end(run.get("end_time"))
|
|
236
|
-
|
|
237
|
-
return response
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
@_with_tracer_wrapper
|
|
241
|
-
def runs_create_and_stream_wrapper(tracer, wrapped, instance, args, kwargs):
|
|
242
|
-
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
|
|
243
|
-
return wrapped(*args, **kwargs)
|
|
244
|
-
|
|
245
|
-
assistant_id = kwargs.get("assistant_id")
|
|
246
|
-
instructions = kwargs.get("instructions")
|
|
247
|
-
|
|
248
|
-
span = tracer.start_span(
|
|
249
|
-
"openai.assistant.run_stream",
|
|
250
|
-
kind=SpanKind.CLIENT,
|
|
251
|
-
attributes={SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.CHAT.value},
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
i = 0
|
|
255
|
-
if assistants.get(assistant_id) is not None or Config.enrich_assistant:
|
|
256
|
-
if Config.enrich_assistant:
|
|
257
|
-
assistant = model_as_dict(
|
|
258
|
-
instance._client.beta.assistants.retrieve(assistant_id)
|
|
259
|
-
)
|
|
260
|
-
assistants[assistant_id] = assistant
|
|
261
|
-
else:
|
|
262
|
-
assistant = assistants[assistant_id]
|
|
263
|
-
|
|
264
|
-
_set_span_attribute(
|
|
265
|
-
span, SpanAttributes.LLM_REQUEST_MODEL, assistants[assistant_id]["model"]
|
|
266
|
-
)
|
|
267
|
-
_set_span_attribute(
|
|
268
|
-
span,
|
|
269
|
-
SpanAttributes.LLM_SYSTEM,
|
|
270
|
-
"openai",
|
|
271
|
-
)
|
|
272
|
-
_set_span_attribute(
|
|
273
|
-
span,
|
|
274
|
-
SpanAttributes.LLM_RESPONSE_MODEL,
|
|
275
|
-
assistants[assistant_id]["model"],
|
|
276
|
-
)
|
|
277
|
-
if should_emit_events():
|
|
278
|
-
emit_event(
|
|
279
|
-
MessageEvent(
|
|
280
|
-
content=assistants[assistant_id]["instructions"], role="system"
|
|
281
|
-
)
|
|
282
|
-
)
|
|
283
|
-
else:
|
|
284
|
-
_set_span_attribute(
|
|
285
|
-
span, f"{SpanAttributes.LLM_PROMPTS}.{i}.role", "system"
|
|
286
|
-
)
|
|
287
|
-
_set_span_attribute(
|
|
288
|
-
span,
|
|
289
|
-
f"{SpanAttributes.LLM_PROMPTS}.{i}.content",
|
|
290
|
-
assistants[assistant_id]["instructions"],
|
|
291
|
-
)
|
|
292
|
-
i += 1
|
|
293
|
-
if should_emit_events():
|
|
294
|
-
emit_event(MessageEvent(content=instructions, role="system"))
|
|
295
|
-
else:
|
|
296
|
-
_set_span_attribute(span, f"{SpanAttributes.LLM_PROMPTS}.{i}.role", "system")
|
|
297
|
-
_set_span_attribute(
|
|
298
|
-
span, f"{SpanAttributes.LLM_PROMPTS}.{i}.content", instructions
|
|
299
|
-
)
|
|
300
|
-
|
|
301
|
-
from opentelemetry.instrumentation.openai.v1.event_handler_wrapper import (
|
|
302
|
-
EventHandleWrapper,
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
kwargs["event_handler"] = EventHandleWrapper(
|
|
306
|
-
original_handler=kwargs["event_handler"],
|
|
307
|
-
span=span,
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
try:
|
|
311
|
-
response = wrapped(*args, **kwargs)
|
|
312
|
-
return response
|
|
313
|
-
except Exception as e:
|
|
314
|
-
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
315
|
-
span.record_exception(e)
|
|
316
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
317
|
-
span.end()
|
|
318
|
-
raise
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.44.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|