ragaai-catalyst 2.1.3b0__py3-none-any.whl → 2.1.4__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.
- ragaai_catalyst/tracers/agentic_tracing/data/data_structure.py +37 -11
- ragaai_catalyst/tracers/agentic_tracing/tracers/agent_tracer.py +240 -81
- ragaai_catalyst/tracers/agentic_tracing/tracers/base.py +632 -114
- ragaai_catalyst/tracers/agentic_tracing/tracers/custom_tracer.py +316 -0
- ragaai_catalyst/tracers/agentic_tracing/tracers/langgraph_tracer.py +0 -0
- ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py +229 -82
- ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py +214 -59
- ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py +16 -14
- ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py +147 -28
- ragaai_catalyst/tracers/agentic_tracing/tracers/user_interaction_tracer.py +88 -2
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py +9 -51
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_trace_metric.py +83 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/create_dataset_schema.py +26 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/get_user_trace_metrics.py +28 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +45 -15
- ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +2520 -2152
- ragaai_catalyst/tracers/agentic_tracing/utils/span_attributes.py +59 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py +23 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/zip_list_of_unique_files.py +284 -15
- ragaai_catalyst/tracers/llamaindex_callback.py +5 -5
- ragaai_catalyst/tracers/tracer.py +83 -10
- ragaai_catalyst/tracers/upload_traces.py +1 -1
- ragaai_catalyst-2.1.4.dist-info/METADATA +431 -0
- {ragaai_catalyst-2.1.3b0.dist-info → ragaai_catalyst-2.1.4.dist-info}/RECORD +26 -20
- ragaai_catalyst-2.1.3b0.dist-info/METADATA +0 -43
- {ragaai_catalyst-2.1.3b0.dist-info → ragaai_catalyst-2.1.4.dist-info}/WHEEL +0 -0
- {ragaai_catalyst-2.1.3b0.dist-info → ragaai_catalyst-2.1.4.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
|
|
1
|
+
import os
|
1
2
|
import functools
|
2
3
|
import uuid
|
3
4
|
from datetime import datetime
|
@@ -7,6 +8,15 @@ from ..utils.unique_decorator import mydecorator, generate_unique_hash_simple
|
|
7
8
|
import contextvars
|
8
9
|
import asyncio
|
9
10
|
from ..utils.file_name_tracker import TrackName
|
11
|
+
from ..utils.span_attributes import SpanAttributes
|
12
|
+
import logging
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
logging_level = (
|
16
|
+
logger.setLevel(logging.DEBUG)
|
17
|
+
if os.getenv("DEBUG")
|
18
|
+
else logger.setLevel(logging.INFO)
|
19
|
+
)
|
10
20
|
|
11
21
|
|
12
22
|
class AgentTracerMixin:
|
@@ -16,42 +26,91 @@ class AgentTracerMixin:
|
|
16
26
|
self.current_agent_id = contextvars.ContextVar("agent_id", default=None)
|
17
27
|
self.current_agent_name = contextvars.ContextVar("agent_name", default=None)
|
18
28
|
self.agent_children = contextvars.ContextVar("agent_children", default=[])
|
19
|
-
self.component_network_calls = contextvars.ContextVar(
|
20
|
-
|
21
|
-
|
29
|
+
self.component_network_calls = contextvars.ContextVar(
|
30
|
+
"component_network_calls", default={}
|
31
|
+
)
|
32
|
+
self.component_user_interaction = contextvars.ContextVar(
|
33
|
+
"component_user_interaction", default={}
|
34
|
+
)
|
35
|
+
self.version = contextvars.ContextVar("version", default=None)
|
22
36
|
self.agent_type = contextvars.ContextVar("agent_type", default="generic")
|
23
37
|
self.capabilities = contextvars.ContextVar("capabilities", default=[])
|
24
38
|
self.start_time = contextvars.ContextVar("start_time", default=None)
|
25
39
|
self.input_data = contextvars.ContextVar("input_data", default=None)
|
26
40
|
self.gt = None
|
27
41
|
|
42
|
+
self.span_attributes_dict = {}
|
43
|
+
|
44
|
+
# Add auto instrument flags
|
45
|
+
self.auto_instrument_agent = False
|
46
|
+
self.auto_instrument_user_interaction = False
|
47
|
+
self.auto_instrument_network = False
|
48
|
+
|
49
|
+
def trace_agent(
|
50
|
+
self,
|
51
|
+
name: str,
|
52
|
+
agent_type: str = None,
|
53
|
+
version: str = None,
|
54
|
+
capabilities: List[str] = None,
|
55
|
+
tags: List[str] = [],
|
56
|
+
metadata: Dict[str, Any] = {},
|
57
|
+
metrics: List[Dict[str, Any]] = [],
|
58
|
+
feedback: Optional[Any] = None,
|
59
|
+
):
|
60
|
+
if name not in self.span_attributes_dict:
|
61
|
+
self.span_attributes_dict[name] = SpanAttributes(name)
|
62
|
+
if tags:
|
63
|
+
self.span(name).add_tags(tags)
|
64
|
+
if metadata:
|
65
|
+
self.span(name).add_metadata(metadata)
|
66
|
+
if metrics:
|
67
|
+
if isinstance(metrics, dict):
|
68
|
+
metrics = [metrics]
|
69
|
+
try:
|
70
|
+
for metric in metrics:
|
71
|
+
self.span(name).add_metrics(
|
72
|
+
name=metric["name"],
|
73
|
+
score=metric["score"],
|
74
|
+
reasoning=metric.get("reasoning", ""),
|
75
|
+
cost=metric.get("cost", None),
|
76
|
+
latency=metric.get("latency", None),
|
77
|
+
metadata=metric.get("metadata", {}),
|
78
|
+
config=metric.get("config", {}),
|
79
|
+
)
|
80
|
+
except ValueError as e:
|
81
|
+
logger.error(f"Validation Error: {e}")
|
82
|
+
except Exception as e:
|
83
|
+
logger.error(f"Error adding metric: {e}")
|
84
|
+
if feedback:
|
85
|
+
self.span(name).add_feedback(feedback)
|
28
86
|
|
29
|
-
def trace_agent(self, name: str, agent_type: str = None, version: str = None, capabilities: List[str] = None):
|
30
87
|
def decorator(target):
|
31
88
|
# Check if target is a class
|
32
89
|
is_class = isinstance(target, type)
|
33
90
|
tracer = self # Store reference to tracer instance
|
34
|
-
top_level_hash_id = generate_unique_hash_simple(
|
91
|
+
top_level_hash_id = generate_unique_hash_simple(
|
92
|
+
target
|
93
|
+
) # Generate hash based on the decorated target code
|
35
94
|
self.version.set(version)
|
36
95
|
self.agent_type.set(agent_type)
|
37
96
|
self.capabilities.set(capabilities)
|
38
|
-
|
97
|
+
|
39
98
|
if is_class:
|
40
99
|
# Store original __init__
|
41
100
|
original_init = target.__init__
|
42
|
-
|
101
|
+
|
43
102
|
def wrapped_init(self, *args, **kwargs):
|
44
|
-
self.gt = kwargs.get(
|
103
|
+
self.gt = kwargs.get("gt", None) if kwargs else None
|
45
104
|
# Set agent context before initializing
|
46
105
|
component_id = str(uuid.uuid4())
|
47
106
|
hash_id = top_level_hash_id
|
48
|
-
|
107
|
+
|
49
108
|
# Store the component ID in the instance
|
50
109
|
self._agent_component_id = component_id
|
51
|
-
|
110
|
+
|
52
111
|
# Get parent agent ID if exists
|
53
112
|
parent_agent_id = tracer.current_agent_id.get()
|
54
|
-
|
113
|
+
|
55
114
|
# Create agent component
|
56
115
|
agent_component = tracer.create_agent_component(
|
57
116
|
component_id=component_id,
|
@@ -60,19 +119,19 @@ class AgentTracerMixin:
|
|
60
119
|
agent_type=agent_type,
|
61
120
|
version=version,
|
62
121
|
capabilities=capabilities or [],
|
63
|
-
start_time=datetime.now(),
|
122
|
+
start_time=datetime.now().astimezone().isoformat(),
|
64
123
|
memory_used=0,
|
65
124
|
input_data=tracer._sanitize_input(args, kwargs),
|
66
125
|
output_data=None,
|
67
126
|
children=[],
|
68
|
-
parent_id=parent_agent_id
|
127
|
+
parent_id=parent_agent_id,
|
69
128
|
)
|
70
|
-
|
129
|
+
|
71
130
|
# Store component for later updates
|
72
|
-
if not hasattr(tracer,
|
131
|
+
if not hasattr(tracer, "_agent_components"):
|
73
132
|
tracer._agent_components = {}
|
74
133
|
tracer._agent_components[component_id] = agent_component
|
75
|
-
|
134
|
+
|
76
135
|
# If this is a nested agent, add it to parent's children
|
77
136
|
if parent_agent_id:
|
78
137
|
parent_children = tracer.agent_children.get()
|
@@ -81,61 +140,82 @@ class AgentTracerMixin:
|
|
81
140
|
else:
|
82
141
|
# Only add to root components if no parent
|
83
142
|
tracer.add_component(agent_component)
|
84
|
-
|
143
|
+
|
85
144
|
# Call original __init__ with this agent as current
|
86
145
|
token = tracer.current_agent_id.set(component_id)
|
87
146
|
try:
|
88
147
|
original_init(self, *args, **kwargs)
|
89
148
|
finally:
|
90
149
|
tracer.current_agent_id.reset(token)
|
91
|
-
|
150
|
+
|
92
151
|
# Wrap all public methods to track execution
|
93
152
|
for attr_name in dir(target):
|
94
|
-
if not attr_name.startswith(
|
153
|
+
if not attr_name.startswith("_"):
|
95
154
|
attr_value = getattr(target, attr_name)
|
96
155
|
if callable(attr_value):
|
156
|
+
|
97
157
|
def wrap_method(method):
|
98
158
|
@self.file_tracker.trace_decorator
|
99
159
|
@functools.wraps(method)
|
100
160
|
def wrapped_method(self, *args, **kwargs):
|
101
|
-
self.gt = kwargs.get(
|
161
|
+
self.gt = kwargs.get("gt", None) if kwargs else None
|
102
162
|
# Set this agent as current during method execution
|
103
|
-
token = tracer.current_agent_id.set(
|
104
|
-
|
163
|
+
token = tracer.current_agent_id.set(
|
164
|
+
self._agent_component_id
|
165
|
+
)
|
166
|
+
|
105
167
|
# Store parent's children before setting new empty list
|
106
168
|
parent_children = tracer.agent_children.get()
|
107
169
|
children_token = tracer.agent_children.set([])
|
108
|
-
|
170
|
+
|
109
171
|
try:
|
110
|
-
start_time = datetime.now()
|
172
|
+
start_time = datetime.now().astimezone().isoformat()
|
111
173
|
result = method(self, *args, **kwargs)
|
112
|
-
|
174
|
+
|
113
175
|
# Update agent component with method result
|
114
|
-
if hasattr(tracer,
|
115
|
-
component = tracer._agent_components.get(
|
176
|
+
if hasattr(tracer, "_agent_components"):
|
177
|
+
component = tracer._agent_components.get(
|
178
|
+
self._agent_component_id
|
179
|
+
)
|
116
180
|
if component:
|
117
|
-
component[
|
118
|
-
|
119
|
-
|
120
|
-
|
181
|
+
component["data"]["output"] = (
|
182
|
+
tracer._sanitize_output(result)
|
183
|
+
)
|
184
|
+
component["data"]["input"] = (
|
185
|
+
tracer._sanitize_input(args, kwargs)
|
186
|
+
)
|
187
|
+
component["start_time"] = (
|
188
|
+
start_time
|
189
|
+
)
|
190
|
+
|
121
191
|
# Get children accumulated during method execution
|
122
192
|
children = tracer.agent_children.get()
|
123
193
|
if children:
|
124
|
-
if
|
125
|
-
|
126
|
-
|
127
|
-
|
194
|
+
if (
|
195
|
+
"children"
|
196
|
+
not in component["data"]
|
197
|
+
):
|
198
|
+
component["data"][
|
199
|
+
"children"
|
200
|
+
] = []
|
201
|
+
component["data"][
|
202
|
+
"children"
|
203
|
+
].extend(children)
|
204
|
+
|
128
205
|
# Add this component as a child to parent's children list
|
129
206
|
parent_children.append(component)
|
130
|
-
tracer.agent_children.set(
|
207
|
+
tracer.agent_children.set(
|
208
|
+
parent_children
|
209
|
+
)
|
131
210
|
return result
|
132
211
|
finally:
|
133
212
|
tracer.current_agent_id.reset(token)
|
134
213
|
tracer.agent_children.reset(children_token)
|
214
|
+
|
135
215
|
return wrapped_method
|
136
|
-
|
216
|
+
|
137
217
|
setattr(target, attr_name, wrap_method(attr_value))
|
138
|
-
|
218
|
+
|
139
219
|
# Replace __init__ with wrapped version
|
140
220
|
target.__init__ = wrapped_init
|
141
221
|
return target
|
@@ -143,17 +223,40 @@ class AgentTracerMixin:
|
|
143
223
|
# For function decorators, use existing sync/async tracing
|
144
224
|
is_async = asyncio.iscoroutinefunction(target)
|
145
225
|
if is_async:
|
226
|
+
|
146
227
|
async def wrapper(*args, **kwargs):
|
147
|
-
return await self._trace_agent_execution(
|
228
|
+
return await self._trace_agent_execution(
|
229
|
+
target,
|
230
|
+
name,
|
231
|
+
agent_type,
|
232
|
+
version,
|
233
|
+
capabilities,
|
234
|
+
top_level_hash_id,
|
235
|
+
*args,
|
236
|
+
**kwargs,
|
237
|
+
)
|
238
|
+
|
148
239
|
return wrapper
|
149
240
|
else:
|
241
|
+
|
150
242
|
def wrapper(*args, **kwargs):
|
151
|
-
return self._trace_sync_agent_execution(
|
243
|
+
return self._trace_sync_agent_execution(
|
244
|
+
target,
|
245
|
+
name,
|
246
|
+
agent_type,
|
247
|
+
version,
|
248
|
+
capabilities,
|
249
|
+
*args,
|
250
|
+
**kwargs,
|
251
|
+
)
|
252
|
+
|
152
253
|
return wrapper
|
153
254
|
|
154
255
|
return decorator
|
155
256
|
|
156
|
-
def _trace_sync_agent_execution(
|
257
|
+
def _trace_sync_agent_execution(
|
258
|
+
self, func, name, agent_type, version, capabilities, *args, **kwargs
|
259
|
+
):
|
157
260
|
# Generate a unique hash_id for this execution context
|
158
261
|
hash_id = str(uuid.uuid4())
|
159
262
|
|
@@ -161,18 +264,21 @@ class AgentTracerMixin:
|
|
161
264
|
if not self.is_active:
|
162
265
|
return func(*args, **kwargs)
|
163
266
|
|
164
|
-
|
267
|
+
if not self.auto_instrument_agent:
|
268
|
+
return func(*args, **kwargs)
|
269
|
+
|
270
|
+
start_time = datetime.now().astimezone().isoformat()
|
165
271
|
self.start_time = start_time
|
166
272
|
self.input_data = self._sanitize_input(args, kwargs)
|
167
273
|
start_memory = psutil.Process().memory_info().rss
|
168
274
|
component_id = str(uuid.uuid4())
|
169
275
|
|
170
276
|
# Extract ground truth if present
|
171
|
-
ground_truth = kwargs.pop(
|
277
|
+
ground_truth = kwargs.pop("gt", None) if kwargs else None
|
172
278
|
|
173
279
|
# Get parent agent ID if exists
|
174
280
|
parent_agent_id = self.current_agent_id.get()
|
175
|
-
|
281
|
+
|
176
282
|
# Set the current agent context
|
177
283
|
agent_token = self.current_agent_id.set(component_id)
|
178
284
|
agent_name_token = self.current_agent_name.set(name)
|
@@ -180,7 +286,7 @@ class AgentTracerMixin:
|
|
180
286
|
# Initialize empty children list for this agent
|
181
287
|
parent_children = self.agent_children.get()
|
182
288
|
children_token = self.agent_children.set([])
|
183
|
-
|
289
|
+
|
184
290
|
# Start tracking network calls for this component
|
185
291
|
self.start_component(component_id)
|
186
292
|
|
@@ -211,12 +317,12 @@ class AgentTracerMixin:
|
|
211
317
|
input_data=self.input_data,
|
212
318
|
output_data=self._sanitize_output(result),
|
213
319
|
children=children,
|
214
|
-
parent_id=parent_agent_id
|
320
|
+
parent_id=parent_agent_id,
|
215
321
|
)
|
216
322
|
# Add ground truth to component data if present
|
217
323
|
if ground_truth is not None:
|
218
324
|
agent_component["data"]["gt"] = ground_truth
|
219
|
-
|
325
|
+
|
220
326
|
# Add this component as a child to parent's children list
|
221
327
|
parent_children.append(agent_component)
|
222
328
|
self.agent_children.set(parent_children)
|
@@ -231,19 +337,19 @@ class AgentTracerMixin:
|
|
231
337
|
"code": 500,
|
232
338
|
"type": type(e).__name__,
|
233
339
|
"message": str(e),
|
234
|
-
"details": {}
|
340
|
+
"details": {},
|
235
341
|
}
|
236
|
-
|
342
|
+
|
237
343
|
# Get children even in case of error
|
238
344
|
children = self.agent_children.get()
|
239
|
-
|
345
|
+
|
240
346
|
# Set parent_id for all children
|
241
347
|
for child in children:
|
242
348
|
child["parent_id"] = component_id
|
243
|
-
|
349
|
+
|
244
350
|
# End tracking network calls for this component
|
245
351
|
self.end_component(component_id)
|
246
|
-
|
352
|
+
|
247
353
|
agent_component = self.create_agent_component(
|
248
354
|
component_id=component_id,
|
249
355
|
hash_id=hash_id,
|
@@ -257,39 +363,45 @@ class AgentTracerMixin:
|
|
257
363
|
output_data=None,
|
258
364
|
error=error_component,
|
259
365
|
children=children,
|
260
|
-
parent_id=parent_agent_id # Add parent ID if exists
|
366
|
+
parent_id=parent_agent_id, # Add parent ID if exists
|
261
367
|
)
|
262
368
|
# If this is a nested agent, add it to parent's children
|
263
369
|
if parent_agent_id:
|
264
370
|
parent_component = self._agent_components.get(parent_agent_id)
|
265
371
|
if parent_component:
|
266
|
-
if
|
267
|
-
parent_component[
|
268
|
-
parent_component[
|
372
|
+
if "children" not in parent_component["data"]:
|
373
|
+
parent_component["data"]["children"] = []
|
374
|
+
parent_component["data"]["children"].append(agent_component)
|
269
375
|
else:
|
270
376
|
# Only add to root components if no parent
|
271
377
|
self.add_component(agent_component)
|
378
|
+
|
272
379
|
raise
|
273
380
|
finally:
|
274
381
|
self.current_agent_id.reset(agent_token)
|
275
382
|
self.current_agent_name.reset(agent_name_token)
|
276
383
|
self.agent_children.reset(children_token)
|
277
384
|
|
278
|
-
async def _trace_agent_execution(
|
385
|
+
async def _trace_agent_execution(
|
386
|
+
self, func, name, agent_type, version, capabilities, hash_id, *args, **kwargs
|
387
|
+
):
|
279
388
|
"""Asynchronous version of agent tracing"""
|
280
389
|
if not self.is_active:
|
281
390
|
return await func(*args, **kwargs)
|
282
391
|
|
283
|
-
|
392
|
+
if not self.auto_instrument_agent:
|
393
|
+
return await func(*args, **kwargs)
|
394
|
+
|
395
|
+
start_time = datetime.now().astimezone().isoformat()
|
284
396
|
start_memory = psutil.Process().memory_info().rss
|
285
397
|
component_id = str(uuid.uuid4())
|
286
398
|
|
287
399
|
# Extract ground truth if present
|
288
|
-
ground_truth = kwargs.pop(
|
400
|
+
ground_truth = kwargs.pop("gt", None) if kwargs else None
|
289
401
|
|
290
402
|
# Get parent agent ID if exists
|
291
403
|
parent_agent_id = self.current_agent_id.get()
|
292
|
-
|
404
|
+
|
293
405
|
# Set the current agent context
|
294
406
|
agent_token = self.current_agent_id.set(component_id)
|
295
407
|
agent_name_token = self.current_agent_name.set(name)
|
@@ -297,6 +409,7 @@ class AgentTracerMixin:
|
|
297
409
|
# Initialize empty children list for this agent
|
298
410
|
parent_children = self.agent_children.get()
|
299
411
|
children_token = self.agent_children.set([])
|
412
|
+
self.start_component(component_id)
|
300
413
|
|
301
414
|
try:
|
302
415
|
# Execute the agent
|
@@ -309,6 +422,8 @@ class AgentTracerMixin:
|
|
309
422
|
# Get children components collected during execution
|
310
423
|
children = self.agent_children.get()
|
311
424
|
|
425
|
+
self.end_component(component_id)
|
426
|
+
|
312
427
|
# Create agent component with children and parent if exists
|
313
428
|
agent_component = self.create_agent_component(
|
314
429
|
component_id=component_id,
|
@@ -322,7 +437,7 @@ class AgentTracerMixin:
|
|
322
437
|
input_data=self._sanitize_input(args, kwargs),
|
323
438
|
output_data=self._sanitize_output(result),
|
324
439
|
children=children,
|
325
|
-
parent_id=parent_agent_id
|
440
|
+
parent_id=parent_agent_id,
|
326
441
|
)
|
327
442
|
|
328
443
|
# Add ground truth to component data if present
|
@@ -343,19 +458,19 @@ class AgentTracerMixin:
|
|
343
458
|
"code": 500,
|
344
459
|
"type": type(e).__name__,
|
345
460
|
"message": str(e),
|
346
|
-
"details": {}
|
461
|
+
"details": {},
|
347
462
|
}
|
348
|
-
|
463
|
+
|
349
464
|
# Get children even in case of error
|
350
465
|
children = self.agent_children.get()
|
351
|
-
|
466
|
+
|
352
467
|
# Set parent_id for all children
|
353
468
|
for child in children:
|
354
469
|
child["parent_id"] = component_id
|
355
|
-
|
470
|
+
|
356
471
|
# End tracking network calls for this component
|
357
472
|
self.end_component(component_id)
|
358
|
-
|
473
|
+
|
359
474
|
agent_component = self.create_agent_component(
|
360
475
|
component_id=component_id,
|
361
476
|
hash_id=hash_id,
|
@@ -369,19 +484,20 @@ class AgentTracerMixin:
|
|
369
484
|
output_data=None,
|
370
485
|
error=error_component,
|
371
486
|
children=children,
|
372
|
-
parent_id=parent_agent_id # Add parent ID if exists
|
487
|
+
parent_id=parent_agent_id, # Add parent ID if exists
|
373
488
|
)
|
374
|
-
|
489
|
+
|
375
490
|
# If this is a nested agent, add it to parent's children
|
376
491
|
if parent_agent_id:
|
377
492
|
parent_component = self._agent_components.get(parent_agent_id)
|
378
493
|
if parent_component:
|
379
|
-
if
|
380
|
-
parent_component[
|
381
|
-
parent_component[
|
494
|
+
if "children" not in parent_component["data"]:
|
495
|
+
parent_component["data"]["children"] = []
|
496
|
+
parent_component["data"]["children"].append(agent_component)
|
382
497
|
else:
|
383
498
|
# Only add to root components if no parent
|
384
499
|
self.add_component(agent_component)
|
500
|
+
|
385
501
|
raise
|
386
502
|
finally:
|
387
503
|
# Reset context variables
|
@@ -391,14 +507,42 @@ class AgentTracerMixin:
|
|
391
507
|
|
392
508
|
def create_agent_component(self, **kwargs):
|
393
509
|
"""Create an agent component according to the data structure"""
|
510
|
+
network_calls = []
|
511
|
+
if self.auto_instrument_network:
|
512
|
+
network_calls = self.component_network_calls.get(kwargs["component_id"], [])
|
513
|
+
interactions = []
|
514
|
+
if self.auto_instrument_user_interaction:
|
515
|
+
interactions = self.component_user_interaction.get(
|
516
|
+
kwargs["component_id"], []
|
517
|
+
)
|
394
518
|
start_time = kwargs["start_time"]
|
519
|
+
|
520
|
+
# Get tags, metrics
|
521
|
+
name = kwargs["name"]
|
522
|
+
# tags
|
523
|
+
tags = []
|
524
|
+
if name in self.span_attributes_dict:
|
525
|
+
tags = self.span_attributes_dict[name].tags or []
|
526
|
+
|
527
|
+
# metrics
|
528
|
+
metrics = []
|
529
|
+
if name in self.span_attributes_dict:
|
530
|
+
raw_metrics = self.span_attributes_dict[name].metrics or []
|
531
|
+
for metric in raw_metrics:
|
532
|
+
base_metric_name = metric["name"]
|
533
|
+
counter = sum(1 for x in self.visited_metrics if x.startswith(base_metric_name))
|
534
|
+
metric_name = f'{base_metric_name}_{counter}' if counter > 0 else base_metric_name
|
535
|
+
self.visited_metrics.append(metric_name)
|
536
|
+
metric["name"] = metric_name
|
537
|
+
metrics.append(metric)
|
538
|
+
|
395
539
|
component = {
|
396
540
|
"id": kwargs["component_id"],
|
397
541
|
"hash_id": kwargs["hash_id"],
|
398
542
|
"source_hash_id": None,
|
399
543
|
"type": "agent",
|
400
544
|
"name": kwargs["name"],
|
401
|
-
"start_time": start_time
|
545
|
+
"start_time": start_time,
|
402
546
|
"end_time": datetime.now().astimezone().isoformat(),
|
403
547
|
"error": kwargs.get("error"),
|
404
548
|
"parent_id": kwargs.get("parent_id"),
|
@@ -406,20 +550,25 @@ class AgentTracerMixin:
|
|
406
550
|
"agent_type": kwargs["agent_type"],
|
407
551
|
"version": kwargs["version"],
|
408
552
|
"capabilities": kwargs["capabilities"],
|
409
|
-
"memory_used": kwargs["memory_used"]
|
553
|
+
"memory_used": kwargs["memory_used"],
|
554
|
+
"tags": tags,
|
410
555
|
},
|
411
556
|
"data": {
|
412
557
|
"input": kwargs["input_data"],
|
413
558
|
"output": kwargs["output_data"],
|
414
|
-
"children": kwargs.get("children", [])
|
559
|
+
"children": kwargs.get("children", []),
|
415
560
|
},
|
416
|
-
"
|
417
|
-
"
|
561
|
+
"metrics": metrics,
|
562
|
+
"network_calls": network_calls,
|
563
|
+
"interactions": interactions,
|
418
564
|
}
|
419
565
|
|
420
|
-
if self.gt:
|
566
|
+
if self.gt:
|
421
567
|
component["data"]["gt"] = self.gt
|
422
568
|
|
569
|
+
# Reset the SpanAttributes context variable
|
570
|
+
self.span_attributes_dict[kwargs["name"]] = SpanAttributes(kwargs["name"])
|
571
|
+
|
423
572
|
return component
|
424
573
|
|
425
574
|
def start_component(self, component_id):
|
@@ -438,21 +587,22 @@ class AgentTracerMixin:
|
|
438
587
|
|
439
588
|
def _sanitize_input(self, args: tuple, kwargs: dict) -> str:
|
440
589
|
"""Convert input arguments to text format.
|
441
|
-
|
590
|
+
|
442
591
|
Args:
|
443
592
|
args: Input arguments tuple
|
444
593
|
kwargs: Input keyword arguments dict
|
445
|
-
|
594
|
+
|
446
595
|
Returns:
|
447
596
|
str: Text representation of the input arguments
|
448
597
|
"""
|
598
|
+
|
449
599
|
def _sanitize_value(value):
|
450
600
|
if isinstance(value, dict):
|
451
601
|
return str({k: _sanitize_value(v) for k, v in value.items()})
|
452
602
|
elif isinstance(value, (list, tuple)):
|
453
603
|
return str([_sanitize_value(item) for item in value])
|
454
604
|
return str(value)
|
455
|
-
|
605
|
+
|
456
606
|
sanitized_args = [_sanitize_value(arg) for arg in args]
|
457
607
|
sanitized_kwargs = {k: _sanitize_value(v) for k, v in kwargs.items()}
|
458
608
|
return str({"args": sanitized_args, "kwargs": sanitized_kwargs})
|
@@ -461,4 +611,13 @@ class AgentTracerMixin:
|
|
461
611
|
"""Sanitize and format output data"""
|
462
612
|
if isinstance(output, (int, float, bool, str, list, dict)):
|
463
613
|
return output
|
464
|
-
return str(output)
|
614
|
+
return str(output)
|
615
|
+
|
616
|
+
def instrument_agent_calls(self):
|
617
|
+
self.auto_instrument_agent = True
|
618
|
+
|
619
|
+
def instrument_user_interaction_calls(self):
|
620
|
+
self.auto_instrument_user_interaction = True
|
621
|
+
|
622
|
+
def instrument_network_calls(self):
|
623
|
+
self.auto_instrument_network = True
|