ioa-observe-sdk 1.0.9__py3-none-any.whl → 1.0.10__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.
- ioa_observe/sdk/decorators/__init__.py +22 -9
- ioa_observe/sdk/decorators/base.py +75 -36
- {ioa_observe_sdk-1.0.9.dist-info → ioa_observe_sdk-1.0.10.dist-info}/METADATA +1 -1
- {ioa_observe_sdk-1.0.9.dist-info → ioa_observe_sdk-1.0.10.dist-info}/RECORD +7 -7
- {ioa_observe_sdk-1.0.9.dist-info → ioa_observe_sdk-1.0.10.dist-info}/WHEEL +0 -0
- {ioa_observe_sdk-1.0.9.dist-info → ioa_observe_sdk-1.0.10.dist-info}/licenses/LICENSE.md +0 -0
- {ioa_observe_sdk-1.0.9.dist-info → ioa_observe_sdk-1.0.10.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Copyright AGNTCY Contributors (https://github.com/agntcy)
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
3
|
+
import inspect
|
|
4
4
|
from typing import Optional, Union, TypeVar, Callable, Awaitable
|
|
5
5
|
|
|
6
6
|
from typing_extensions import ParamSpec
|
|
@@ -50,18 +50,31 @@ def workflow(
|
|
|
50
50
|
Union[ObserveSpanKindValues, str]
|
|
51
51
|
] = ObserveSpanKindValues.WORKFLOW,
|
|
52
52
|
) -> Callable[[F], F]:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
def decorator(target):
|
|
54
|
+
# Check if target is a class
|
|
55
|
+
if inspect.isclass(target):
|
|
56
|
+
return entity_class(
|
|
57
|
+
name=name,
|
|
58
|
+
description=description,
|
|
59
|
+
version=version,
|
|
60
|
+
method_name=method_name,
|
|
61
|
+
tlp_span_kind=tlp_span_kind,
|
|
62
|
+
)(target)
|
|
63
|
+
else:
|
|
64
|
+
# Target is a function/method
|
|
65
|
+
return entity_method(
|
|
66
|
+
name=name,
|
|
67
|
+
description=description,
|
|
68
|
+
version=version,
|
|
69
|
+
tlp_span_kind=tlp_span_kind,
|
|
70
|
+
)(target)
|
|
71
|
+
|
|
72
|
+
return decorator
|
|
61
73
|
|
|
62
74
|
|
|
63
75
|
def graph(
|
|
64
76
|
name: Optional[str] = None,
|
|
77
|
+
description: Optional[str] = None,
|
|
65
78
|
version: Optional[int] = None,
|
|
66
79
|
method_name: Optional[str] = None,
|
|
67
80
|
) -> Callable[[F], F]:
|
|
@@ -158,15 +158,41 @@ def _handle_span_input(span, args, kwargs, cls=None):
|
|
|
158
158
|
"""Handles entity input logging in JSON for both sync and async functions"""
|
|
159
159
|
try:
|
|
160
160
|
if _should_send_prompts():
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
# Use a safer serialization approach to avoid recursion
|
|
162
|
+
safe_args = []
|
|
163
|
+
safe_kwargs = {}
|
|
164
|
+
|
|
165
|
+
# Safely convert args
|
|
166
|
+
for arg in args:
|
|
167
|
+
try:
|
|
168
|
+
# Test if the object can be JSON serialized
|
|
169
|
+
json.dumps(arg)
|
|
170
|
+
safe_args.append(arg)
|
|
171
|
+
except (TypeError, ValueError, PydanticSerializationError):
|
|
172
|
+
# If it can't be serialized, use string representation
|
|
173
|
+
safe_args.append(str(arg))
|
|
174
|
+
|
|
175
|
+
# Safely convert kwargs
|
|
176
|
+
for key, value in kwargs.items():
|
|
177
|
+
try:
|
|
178
|
+
# Test if the object can be JSON serialized
|
|
179
|
+
json.dumps(value)
|
|
180
|
+
safe_kwargs[key] = value
|
|
181
|
+
except (TypeError, ValueError, PydanticSerializationError):
|
|
182
|
+
# If it can't be serialized, use string representation
|
|
183
|
+
safe_kwargs[key] = str(value)
|
|
184
|
+
|
|
185
|
+
# Create the JSON without custom encoder to avoid recursion
|
|
186
|
+
json_input = json.dumps({"args": safe_args, "kwargs": safe_kwargs})
|
|
187
|
+
|
|
164
188
|
if _is_json_size_valid(json_input):
|
|
165
189
|
span.set_attribute(
|
|
166
190
|
OBSERVE_ENTITY_INPUT,
|
|
167
191
|
json_input,
|
|
168
192
|
)
|
|
169
|
-
except
|
|
193
|
+
except Exception as e:
|
|
194
|
+
# Log the exception but don't fail the actual function call
|
|
195
|
+
print(f"Warning: Failed to serialize input for span: {e}")
|
|
170
196
|
Telemetry().log_exception(e)
|
|
171
197
|
|
|
172
198
|
|
|
@@ -219,27 +245,32 @@ def _handle_span_output(span, tlp_span_kind, res, cls=None):
|
|
|
219
245
|
"gen_ai.ioa.agent.connection_reliability", reliability
|
|
220
246
|
)
|
|
221
247
|
|
|
222
|
-
|
|
223
|
-
try:
|
|
224
|
-
json_output = json.dumps(res, **({"cls": cls} if cls else {}))
|
|
225
|
-
except (TypeError, PydanticSerializationError):
|
|
226
|
-
# Fallback for objects that can't be directly serialized
|
|
248
|
+
if _should_send_prompts():
|
|
227
249
|
try:
|
|
228
|
-
# Try
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
250
|
+
# Try direct JSON serialization first (without custom encoder)
|
|
251
|
+
json_output = json.dumps(res)
|
|
252
|
+
except (TypeError, PydanticSerializationError, ValueError):
|
|
253
|
+
# Fallback for objects that can't be directly serialized
|
|
254
|
+
try:
|
|
255
|
+
# Try to serialize a string representation
|
|
256
|
+
safe_output = str(res)
|
|
257
|
+
json_output = json.dumps(
|
|
258
|
+
{"__str_representation__": safe_output}
|
|
259
|
+
)
|
|
260
|
+
except Exception:
|
|
261
|
+
# If all serialization fails, skip output attribute
|
|
262
|
+
json_output = None
|
|
263
|
+
|
|
264
|
+
if json_output and _is_json_size_valid(json_output):
|
|
265
|
+
span.set_attribute(
|
|
266
|
+
OBSERVE_ENTITY_OUTPUT,
|
|
267
|
+
json_output,
|
|
268
|
+
)
|
|
269
|
+
TracerWrapper().span_processor_on_ending(
|
|
270
|
+
span
|
|
271
|
+
) # record the response latency
|
|
272
|
+
except Exception as e:
|
|
273
|
+
print(f"Warning: Failed to serialize output for span: {e}")
|
|
243
274
|
Telemetry().log_exception(e)
|
|
244
275
|
|
|
245
276
|
|
|
@@ -286,7 +317,7 @@ def entity_method(
|
|
|
286
317
|
entity_name,
|
|
287
318
|
tlp_span_kind,
|
|
288
319
|
version,
|
|
289
|
-
description
|
|
320
|
+
description,
|
|
290
321
|
)
|
|
291
322
|
_handle_span_input(span, args, kwargs, cls=JSONEncoder)
|
|
292
323
|
|
|
@@ -307,8 +338,12 @@ def entity_method(
|
|
|
307
338
|
entity_name,
|
|
308
339
|
tlp_span_kind,
|
|
309
340
|
version,
|
|
310
|
-
description
|
|
341
|
+
description,
|
|
311
342
|
)
|
|
343
|
+
|
|
344
|
+
# Handle case where span setup failed
|
|
345
|
+
if span is None:
|
|
346
|
+
return fn(*args, **kwargs)
|
|
312
347
|
_handle_span_input(span, args, kwargs, cls=JSONEncoder)
|
|
313
348
|
success = False
|
|
314
349
|
try:
|
|
@@ -399,9 +434,13 @@ def entity_method(
|
|
|
399
434
|
entity_name,
|
|
400
435
|
tlp_span_kind,
|
|
401
436
|
version,
|
|
402
|
-
description
|
|
437
|
+
description,
|
|
403
438
|
)
|
|
404
439
|
|
|
440
|
+
# Handle case where span setup failed
|
|
441
|
+
if span is None:
|
|
442
|
+
return fn(*args, **kwargs)
|
|
443
|
+
|
|
405
444
|
_handle_span_input(span, args, kwargs, cls=JSONEncoder)
|
|
406
445
|
_handle_agent_span(span, entity_name, description, tlp_span_kind)
|
|
407
446
|
success = False
|
|
@@ -571,15 +610,15 @@ def _handle_agent_failure_event(res, span, tlp_span_kind):
|
|
|
571
610
|
# Skip if span is already ended
|
|
572
611
|
return
|
|
573
612
|
if tlp_span_kind == ObserveSpanKindValues.AGENT:
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
)
|
|
613
|
+
attributes = {}
|
|
614
|
+
attributes["failure_reason"] = res
|
|
615
|
+
|
|
616
|
+
if "observe.workflow.name" in span.attributes:
|
|
617
|
+
attributes["agent_name"] = span.attributes["observe.workflow.name"]
|
|
618
|
+
elif "traceloop.workflow.name" in span.attributes:
|
|
619
|
+
attributes["agent_name"] = span.attributes["traceloop.workflow.name"]
|
|
620
|
+
|
|
621
|
+
TracerWrapper().failing_agents_counter.add(1, attributes=attributes)
|
|
583
622
|
|
|
584
623
|
|
|
585
624
|
def _handle_execution_result(span, success):
|
|
@@ -9,8 +9,8 @@ ioa_observe/sdk/client/http.py,sha256=LdLYSQPFIhKN5BTB-N78jLO7ITl7jGjA0-qpewEIvO
|
|
|
9
9
|
ioa_observe/sdk/config/__init__.py,sha256=8aVNaw0yRNLFPxlf97iOZLlJVcV81ivSDnudH2m1OIo,572
|
|
10
10
|
ioa_observe/sdk/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
ioa_observe/sdk/connectors/slim.py,sha256=NwbKEV7d5NIOqmG8zKqtgGigSJl7kf3QJ65z2gxpsY8,8498
|
|
12
|
-
ioa_observe/sdk/decorators/__init__.py,sha256=
|
|
13
|
-
ioa_observe/sdk/decorators/base.py,sha256=
|
|
12
|
+
ioa_observe/sdk/decorators/__init__.py,sha256=Lv5EbouBazvWaYB0N82v26pqKtj2FAqlwfLKEh5e8Q0,3251
|
|
13
|
+
ioa_observe/sdk/decorators/base.py,sha256=vZuF9bsaMhH0BAJjPvmPA-cvdgaXucRuSvGHhvc_8tc,28483
|
|
14
14
|
ioa_observe/sdk/decorators/util.py,sha256=WMkzmwD7Js0g1BbId9_qR4pwhnaIJdW588zVc5dpqdQ,25399
|
|
15
15
|
ioa_observe/sdk/instrumentations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
ioa_observe/sdk/instrumentations/a2a.py,sha256=ov_9ckkymf_qFXG0iXVWfxlW-3kFcP-knrM_t-Cf72w,4414
|
|
@@ -38,8 +38,8 @@ ioa_observe/sdk/utils/const.py,sha256=GwbHakKPjBL4wLqAVkDrSoKB-8p18EUrbaqPuRuV_x
|
|
|
38
38
|
ioa_observe/sdk/utils/in_memory_span_exporter.py,sha256=H_4TRaThMO1H6vUQ0OpQvzJk_fZH0OOsRAM1iZQXsR8,2112
|
|
39
39
|
ioa_observe/sdk/utils/json_encoder.py,sha256=g4NQ0tTqgWssY6I1D7r4zo0G6PiUo61jhofTAw5-jno,639
|
|
40
40
|
ioa_observe/sdk/utils/package_check.py,sha256=1d1MjxhwoEZIx9dumirT2pRsEWgn-m-SI4npDeEalew,576
|
|
41
|
-
ioa_observe_sdk-1.0.
|
|
42
|
-
ioa_observe_sdk-1.0.
|
|
43
|
-
ioa_observe_sdk-1.0.
|
|
44
|
-
ioa_observe_sdk-1.0.
|
|
45
|
-
ioa_observe_sdk-1.0.
|
|
41
|
+
ioa_observe_sdk-1.0.10.dist-info/licenses/LICENSE.md,sha256=55VjUfgjWOS4vv3Cf55gfq-RxjPgRIO2vlgYPUuC5lA,11362
|
|
42
|
+
ioa_observe_sdk-1.0.10.dist-info/METADATA,sha256=eNDXQNsig6-m56PqwvFuYH6XUtYG8konoqFk2UUHW9w,7747
|
|
43
|
+
ioa_observe_sdk-1.0.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
44
|
+
ioa_observe_sdk-1.0.10.dist-info/top_level.txt,sha256=Yt-6Y1olZEDqCs2REeqI30WjYx0pLGQSVqzYmDd67N8,12
|
|
45
|
+
ioa_observe_sdk-1.0.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|