ragaai-catalyst 2.2.4b5__py3-none-any.whl → 2.2.5b2__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/__init__.py +0 -2
- ragaai_catalyst/dataset.py +59 -1
- ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py +5 -285
- ragaai_catalyst/tracers/agentic_tracing/utils/__init__.py +0 -2
- ragaai_catalyst/tracers/agentic_tracing/utils/create_dataset_schema.py +1 -1
- ragaai_catalyst/tracers/exporters/__init__.py +1 -2
- ragaai_catalyst/tracers/exporters/file_span_exporter.py +0 -1
- ragaai_catalyst/tracers/exporters/ragaai_trace_exporter.py +23 -1
- ragaai_catalyst/tracers/tracer.py +6 -186
- {ragaai_catalyst-2.2.4b5.dist-info → ragaai_catalyst-2.2.5b2.dist-info}/METADATA +1 -1
- {ragaai_catalyst-2.2.4b5.dist-info → ragaai_catalyst-2.2.5b2.dist-info}/RECORD +14 -45
- ragaai_catalyst/experiment.py +0 -486
- ragaai_catalyst/tracers/agentic_tracing/tests/FinancialAnalysisSystem.ipynb +0 -536
- ragaai_catalyst/tracers/agentic_tracing/tests/GameActivityEventPlanner.ipynb +0 -134
- ragaai_catalyst/tracers/agentic_tracing/tests/TravelPlanner.ipynb +0 -563
- ragaai_catalyst/tracers/agentic_tracing/tests/__init__.py +0 -0
- ragaai_catalyst/tracers/agentic_tracing/tests/ai_travel_agent.py +0 -197
- ragaai_catalyst/tracers/agentic_tracing/tests/unique_decorator_test.py +0 -172
- ragaai_catalyst/tracers/agentic_tracing/tracers/agent_tracer.py +0 -687
- ragaai_catalyst/tracers/agentic_tracing/tracers/base.py +0 -1319
- ragaai_catalyst/tracers/agentic_tracing/tracers/custom_tracer.py +0 -347
- ragaai_catalyst/tracers/agentic_tracing/tracers/langgraph_tracer.py +0 -0
- ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py +0 -1182
- ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py +0 -288
- ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py +0 -557
- ragaai_catalyst/tracers/agentic_tracing/tracers/user_interaction_tracer.py +0 -129
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_local_metric.py +0 -74
- ragaai_catalyst/tracers/agentic_tracing/utils/api_utils.py +0 -21
- ragaai_catalyst/tracers/agentic_tracing/utils/generic.py +0 -32
- ragaai_catalyst/tracers/agentic_tracing/utils/get_user_trace_metrics.py +0 -28
- ragaai_catalyst/tracers/agentic_tracing/utils/span_attributes.py +0 -133
- ragaai_catalyst/tracers/agentic_tracing/utils/supported_llm_provider.toml +0 -34
- ragaai_catalyst/tracers/exporters/raga_exporter.py +0 -467
- ragaai_catalyst/tracers/langchain_callback.py +0 -821
- ragaai_catalyst/tracers/llamaindex_callback.py +0 -361
- ragaai_catalyst/tracers/llamaindex_instrumentation.py +0 -424
- ragaai_catalyst/tracers/upload_traces.py +0 -170
- ragaai_catalyst/tracers/utils/convert_langchain_callbacks_output.py +0 -62
- ragaai_catalyst/tracers/utils/convert_llama_instru_callback.py +0 -69
- ragaai_catalyst/tracers/utils/extraction_logic_llama_index.py +0 -74
- ragaai_catalyst/tracers/utils/langchain_tracer_extraction_logic.py +0 -82
- ragaai_catalyst/tracers/utils/rag_trace_json_converter.py +0 -403
- {ragaai_catalyst-2.2.4b5.dist-info → ragaai_catalyst-2.2.5b2.dist-info}/WHEEL +0 -0
- {ragaai_catalyst-2.2.4b5.dist-info → ragaai_catalyst-2.2.5b2.dist-info}/licenses/LICENSE +0 -0
- {ragaai_catalyst-2.2.4b5.dist-info → ragaai_catalyst-2.2.5b2.dist-info}/top_level.txt +0 -0
@@ -1,687 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import functools
|
3
|
-
import uuid
|
4
|
-
from datetime import datetime
|
5
|
-
import psutil
|
6
|
-
from typing import Optional, Any, Dict, List
|
7
|
-
from ..utils.unique_decorator import mydecorator, generate_unique_hash_simple
|
8
|
-
import contextvars
|
9
|
-
import asyncio
|
10
|
-
from ..utils.file_name_tracker import TrackName
|
11
|
-
from ..utils.span_attributes import SpanAttributes
|
12
|
-
from .base import BaseTracer
|
13
|
-
import logging
|
14
|
-
|
15
|
-
logger = logging.getLogger(__name__)
|
16
|
-
logging_level = (
|
17
|
-
logger.setLevel(logging.DEBUG)
|
18
|
-
if os.getenv("DEBUG")
|
19
|
-
else logger.setLevel(logging.INFO)
|
20
|
-
)
|
21
|
-
|
22
|
-
|
23
|
-
class AgentTracerMixin:
|
24
|
-
def __init__(self, *args, **kwargs):
|
25
|
-
super().__init__(*args, **kwargs)
|
26
|
-
self.file_tracker = TrackName()
|
27
|
-
self.current_agent_id = contextvars.ContextVar("agent_id", default=None)
|
28
|
-
self.current_agent_name = contextvars.ContextVar("agent_name", default=None)
|
29
|
-
self.agent_children = contextvars.ContextVar("agent_children", default=[])
|
30
|
-
self.component_network_calls = contextvars.ContextVar(
|
31
|
-
"component_network_calls", default={}
|
32
|
-
)
|
33
|
-
self.component_user_interaction = contextvars.ContextVar(
|
34
|
-
"component_user_interaction", default={}
|
35
|
-
)
|
36
|
-
self.version = contextvars.ContextVar("version", default=None)
|
37
|
-
self.agent_type = contextvars.ContextVar("agent_type", default="generic")
|
38
|
-
self.capabilities = contextvars.ContextVar("capabilities", default=[])
|
39
|
-
self.start_time = contextvars.ContextVar("start_time", default=None)
|
40
|
-
self.input_data = contextvars.ContextVar("input_data", default=None)
|
41
|
-
self.gt = None
|
42
|
-
|
43
|
-
self.span_attributes_dict = {}
|
44
|
-
|
45
|
-
# Add auto instrument flags
|
46
|
-
self.auto_instrument_agent = False
|
47
|
-
self.auto_instrument_user_interaction = False
|
48
|
-
self.auto_instrument_file_io = False
|
49
|
-
self.auto_instrument_network = False
|
50
|
-
|
51
|
-
def trace_agent(
|
52
|
-
self,
|
53
|
-
name: str,
|
54
|
-
agent_type: str = None,
|
55
|
-
version: str = None,
|
56
|
-
capabilities: List[str] = None,
|
57
|
-
tags: List[str] = [],
|
58
|
-
metadata: Dict[str, Any] = {},
|
59
|
-
metrics: List[Dict[str, Any]] = [],
|
60
|
-
feedback: Optional[Any] = None,
|
61
|
-
):
|
62
|
-
if name not in self.span_attributes_dict:
|
63
|
-
self.span_attributes_dict[name] = SpanAttributes(name)
|
64
|
-
if tags:
|
65
|
-
self.span(name).add_tags(tags)
|
66
|
-
if metadata:
|
67
|
-
self.span(name).add_metadata(metadata)
|
68
|
-
if metrics:
|
69
|
-
if isinstance(metrics, dict):
|
70
|
-
metrics = [metrics]
|
71
|
-
try:
|
72
|
-
for metric in metrics:
|
73
|
-
self.span(name).add_metrics(
|
74
|
-
name=metric["name"],
|
75
|
-
score=metric["score"],
|
76
|
-
reasoning=metric.get("reasoning", ""),
|
77
|
-
cost=metric.get("cost", None),
|
78
|
-
latency=metric.get("latency", None),
|
79
|
-
metadata=metric.get("metadata", {}),
|
80
|
-
config=metric.get("config", {}),
|
81
|
-
)
|
82
|
-
except ValueError as e:
|
83
|
-
logger.error(f"Validation Error: {e}")
|
84
|
-
except Exception as e:
|
85
|
-
logger.error(f"Error adding metric: {e}")
|
86
|
-
if feedback:
|
87
|
-
self.span(name).add_feedback(feedback)
|
88
|
-
|
89
|
-
def decorator(target):
|
90
|
-
# Check if target is a class
|
91
|
-
is_class = isinstance(target, type)
|
92
|
-
tracer = self # Store reference to tracer instance
|
93
|
-
top_level_hash_id = generate_unique_hash_simple(
|
94
|
-
target
|
95
|
-
) # Generate hash based on the decorated target code
|
96
|
-
self.version.set(version)
|
97
|
-
self.agent_type.set(agent_type)
|
98
|
-
self.capabilities.set(capabilities)
|
99
|
-
|
100
|
-
if is_class:
|
101
|
-
# Store original __init__
|
102
|
-
original_init = target.__init__
|
103
|
-
|
104
|
-
def wrapped_init(self, *args, **kwargs):
|
105
|
-
gt = kwargs.get("gt") if kwargs else None
|
106
|
-
if gt is not None:
|
107
|
-
span = self.span(name)
|
108
|
-
span.add_gt(gt)
|
109
|
-
|
110
|
-
if not hasattr(self, '_agent_component_id'):
|
111
|
-
component_id = str(uuid.uuid4())
|
112
|
-
self._agent_component_id = component_id
|
113
|
-
|
114
|
-
# Get parent agent ID if exists
|
115
|
-
parent_agent_id = tracer.current_agent_id.get()
|
116
|
-
|
117
|
-
agent_component = tracer.create_agent_component(
|
118
|
-
component_id=component_id,
|
119
|
-
hash_id=top_level_hash_id,
|
120
|
-
name=name,
|
121
|
-
agent_type=agent_type,
|
122
|
-
version=version,
|
123
|
-
capabilities=capabilities or [],
|
124
|
-
start_time=datetime.now().astimezone().isoformat(),
|
125
|
-
memory_used=0,
|
126
|
-
input_data=tracer._sanitize_input(args, kwargs),
|
127
|
-
output_data=None,
|
128
|
-
children=[],
|
129
|
-
parent_id=parent_agent_id,
|
130
|
-
)
|
131
|
-
|
132
|
-
if not hasattr(tracer, "_agent_components"):
|
133
|
-
tracer._agent_components = {}
|
134
|
-
tracer._agent_components[component_id] = agent_component
|
135
|
-
|
136
|
-
# For class agents, only add to parent's children if parent exists
|
137
|
-
if parent_agent_id and parent_agent_id in tracer._agent_components:
|
138
|
-
parent_component = tracer._agent_components[parent_agent_id]
|
139
|
-
if not hasattr(parent_component, "children"):
|
140
|
-
parent_component["children"] = []
|
141
|
-
if component_id not in parent_component["children"]:
|
142
|
-
parent_component["children"].append(component_id)
|
143
|
-
|
144
|
-
token = tracer.current_agent_id.set(self._agent_component_id)
|
145
|
-
try:
|
146
|
-
original_init(self, *args, **kwargs)
|
147
|
-
finally:
|
148
|
-
tracer.current_agent_id.reset(token)
|
149
|
-
|
150
|
-
# Wrap all public methods to track execution
|
151
|
-
for attr_name in dir(target):
|
152
|
-
if not attr_name.startswith("_"):
|
153
|
-
attr_value = getattr(target, attr_name)
|
154
|
-
if callable(attr_value):
|
155
|
-
|
156
|
-
def wrap_method(method):
|
157
|
-
@functools.wraps(method)
|
158
|
-
def wrapped_method(self, *args, **kwargs):
|
159
|
-
gt = kwargs.get("gt") if kwargs else None
|
160
|
-
if gt is not None:
|
161
|
-
span = tracer.span(name)
|
162
|
-
span.add_gt(gt)
|
163
|
-
# Set this agent as current during method execution
|
164
|
-
token = tracer.current_agent_id.set(
|
165
|
-
self._agent_component_id
|
166
|
-
)
|
167
|
-
|
168
|
-
# Store parent's children before setting new empty list
|
169
|
-
parent_children = tracer.agent_children.get()
|
170
|
-
children_token = tracer.agent_children.set([])
|
171
|
-
|
172
|
-
try:
|
173
|
-
start_time = datetime.now().astimezone().isoformat()
|
174
|
-
result = method(self, *args, **kwargs)
|
175
|
-
|
176
|
-
# Update agent component with method result
|
177
|
-
if hasattr(tracer, "_agent_components"):
|
178
|
-
component = tracer._agent_components.get(
|
179
|
-
self._agent_component_id
|
180
|
-
)
|
181
|
-
if component:
|
182
|
-
component["data"]["output"] = (
|
183
|
-
tracer._sanitize_output(result)
|
184
|
-
)
|
185
|
-
component["data"]["input"] = (
|
186
|
-
tracer._sanitize_input(args, kwargs)
|
187
|
-
)
|
188
|
-
component["start_time"] = (
|
189
|
-
start_time
|
190
|
-
)
|
191
|
-
|
192
|
-
# Get children accumulated during method execution
|
193
|
-
children = tracer.agent_children.get()
|
194
|
-
if children:
|
195
|
-
if (
|
196
|
-
"children"
|
197
|
-
not in component["data"]
|
198
|
-
):
|
199
|
-
component["data"][
|
200
|
-
"children"
|
201
|
-
] = []
|
202
|
-
component["data"][
|
203
|
-
"children"
|
204
|
-
].extend(children)
|
205
|
-
|
206
|
-
# Add this component as a child to parent's children list
|
207
|
-
parent_children.append(component)
|
208
|
-
tracer.agent_children.set(
|
209
|
-
parent_children
|
210
|
-
)
|
211
|
-
return result
|
212
|
-
finally:
|
213
|
-
tracer.current_agent_id.reset(token)
|
214
|
-
tracer.agent_children.reset(children_token)
|
215
|
-
|
216
|
-
return wrapped_method
|
217
|
-
|
218
|
-
setattr(target, attr_name, wrap_method(attr_value))
|
219
|
-
|
220
|
-
# Replace __init__ with wrapped version
|
221
|
-
|
222
|
-
target.__init__ = wrapped_init
|
223
|
-
|
224
|
-
# Wrap all methods to maintain parent-child relationship
|
225
|
-
for attr_name, attr_value in target.__dict__.items():
|
226
|
-
if callable(attr_value) and not attr_name.startswith('__'):
|
227
|
-
original_method = attr_value
|
228
|
-
|
229
|
-
def create_wrapper(method):
|
230
|
-
@self.file_tracker.trace_decorator
|
231
|
-
@functools.wraps(method)
|
232
|
-
def method_wrapper(self, *args, **kwargs):
|
233
|
-
gt = kwargs.get("gt") if kwargs else None
|
234
|
-
if gt is not None:
|
235
|
-
span = tracer.span(name)
|
236
|
-
span.add_gt(gt)
|
237
|
-
# Use the class instance's agent ID as parent
|
238
|
-
parent_id = getattr(self, '_agent_component_id', None)
|
239
|
-
if parent_id:
|
240
|
-
if asyncio.iscoroutinefunction(method):
|
241
|
-
return tracer._trace_agent_execution(
|
242
|
-
method.__get__(self, type(self)),
|
243
|
-
name,
|
244
|
-
agent_type,
|
245
|
-
version,
|
246
|
-
capabilities,
|
247
|
-
top_level_hash_id,
|
248
|
-
*args,
|
249
|
-
**kwargs,
|
250
|
-
)
|
251
|
-
else:
|
252
|
-
return tracer._trace_sync_agent_execution(
|
253
|
-
method.__get__(self, type(self)),
|
254
|
-
name,
|
255
|
-
agent_type,
|
256
|
-
version,
|
257
|
-
capabilities,
|
258
|
-
top_level_hash_id,
|
259
|
-
*args,
|
260
|
-
**kwargs,
|
261
|
-
)
|
262
|
-
else:
|
263
|
-
return method(self, *args, **kwargs)
|
264
|
-
return method_wrapper
|
265
|
-
|
266
|
-
setattr(target, attr_name, create_wrapper(original_method))
|
267
|
-
|
268
|
-
return target
|
269
|
-
else:
|
270
|
-
# For non-class targets (e.g., functions), use existing function wrapping logic
|
271
|
-
@functools.wraps(target)
|
272
|
-
def wrapper(*args, **kwargs):
|
273
|
-
if asyncio.iscoroutinefunction(target):
|
274
|
-
return tracer._trace_agent_execution(
|
275
|
-
target,
|
276
|
-
name,
|
277
|
-
agent_type,
|
278
|
-
version,
|
279
|
-
capabilities,
|
280
|
-
top_level_hash_id,
|
281
|
-
*args,
|
282
|
-
**kwargs,
|
283
|
-
)
|
284
|
-
else:
|
285
|
-
return tracer._trace_sync_agent_execution(
|
286
|
-
target,
|
287
|
-
name,
|
288
|
-
agent_type,
|
289
|
-
version,
|
290
|
-
capabilities,
|
291
|
-
top_level_hash_id,
|
292
|
-
*args,
|
293
|
-
**kwargs,
|
294
|
-
)
|
295
|
-
return wrapper
|
296
|
-
|
297
|
-
return decorator
|
298
|
-
|
299
|
-
def _trace_sync_agent_execution(
|
300
|
-
self, func, name, agent_type, version, capabilities, top_level_hash_id, *args, **kwargs
|
301
|
-
):
|
302
|
-
"""Synchronous version of agent tracing"""
|
303
|
-
if not self.is_active:
|
304
|
-
return func(*args, **kwargs)
|
305
|
-
|
306
|
-
if not self.auto_instrument_agent:
|
307
|
-
return func(*args, **kwargs)
|
308
|
-
|
309
|
-
start_time = datetime.now().astimezone().isoformat()
|
310
|
-
self.start_time = start_time
|
311
|
-
self.input_data = self._sanitize_input(args, kwargs)
|
312
|
-
start_memory = psutil.Process().memory_info().rss
|
313
|
-
component_id = str(uuid.uuid4())
|
314
|
-
|
315
|
-
# Extract ground truth if present
|
316
|
-
ground_truth = kwargs.pop("gt", None) if kwargs else None
|
317
|
-
if ground_truth is not None:
|
318
|
-
span = self.span(name)
|
319
|
-
span.add_gt(ground_truth)
|
320
|
-
|
321
|
-
# Get parent agent ID if exists
|
322
|
-
parent_agent_id = self.current_agent_id.get()
|
323
|
-
|
324
|
-
# Set the current agent context
|
325
|
-
agent_token = self.current_agent_id.set(component_id)
|
326
|
-
agent_name_token = self.current_agent_name.set(name)
|
327
|
-
|
328
|
-
# Initialize empty children list for this agent
|
329
|
-
parent_children = self.agent_children.get()
|
330
|
-
children_token = self.agent_children.set([])
|
331
|
-
|
332
|
-
# Start tracking network calls for this component
|
333
|
-
self.start_component(component_id)
|
334
|
-
|
335
|
-
try:
|
336
|
-
# Execute the agent
|
337
|
-
result = func(*args, **kwargs)
|
338
|
-
|
339
|
-
# Calculate resource usage
|
340
|
-
end_memory = psutil.Process().memory_info().rss
|
341
|
-
memory_used = max(0, end_memory - start_memory)
|
342
|
-
|
343
|
-
# Get children components collected during execution
|
344
|
-
children = self.agent_children.get()
|
345
|
-
|
346
|
-
# End tracking network calls for this component
|
347
|
-
self.end_component(component_id)
|
348
|
-
|
349
|
-
# Create agent component with children and parent if exists
|
350
|
-
agent_component = self.create_agent_component(
|
351
|
-
component_id=component_id,
|
352
|
-
hash_id=top_level_hash_id,
|
353
|
-
name=name,
|
354
|
-
agent_type=agent_type,
|
355
|
-
version=version,
|
356
|
-
capabilities=capabilities or [],
|
357
|
-
start_time=start_time,
|
358
|
-
memory_used=memory_used,
|
359
|
-
input_data=self.input_data,
|
360
|
-
output_data=self._sanitize_output(result),
|
361
|
-
children=children,
|
362
|
-
parent_id=parent_agent_id,
|
363
|
-
)
|
364
|
-
|
365
|
-
# Store component for updates
|
366
|
-
if not hasattr(self, "_agent_components"):
|
367
|
-
self._agent_components = {}
|
368
|
-
self._agent_components[component_id] = agent_component
|
369
|
-
|
370
|
-
# Only add to hierarchy if this is a root component (no parent)
|
371
|
-
# or if the parent explicitly added it as a child
|
372
|
-
if parent_agent_id:
|
373
|
-
parent_children.append(agent_component)
|
374
|
-
self.agent_children.set(parent_children)
|
375
|
-
else:
|
376
|
-
self.add_component(agent_component)
|
377
|
-
|
378
|
-
return result
|
379
|
-
except Exception as e:
|
380
|
-
error_component = {
|
381
|
-
"code": 500,
|
382
|
-
"type": type(e).__name__,
|
383
|
-
"message": str(e),
|
384
|
-
"details": {},
|
385
|
-
}
|
386
|
-
|
387
|
-
# Get children even in case of error
|
388
|
-
children = self.agent_children.get()
|
389
|
-
|
390
|
-
# Create error component
|
391
|
-
agent_component = self.create_agent_component(
|
392
|
-
component_id=component_id,
|
393
|
-
hash_id=top_level_hash_id,
|
394
|
-
name=name,
|
395
|
-
agent_type=agent_type,
|
396
|
-
version=version,
|
397
|
-
capabilities=capabilities or [],
|
398
|
-
start_time=start_time,
|
399
|
-
memory_used=0,
|
400
|
-
input_data=self.input_data,
|
401
|
-
output_data=None,
|
402
|
-
error=error_component,
|
403
|
-
children=children,
|
404
|
-
parent_id=parent_agent_id, # Add parent ID if exists
|
405
|
-
)
|
406
|
-
|
407
|
-
# Store component for updates
|
408
|
-
if not hasattr(self, "_agent_components"):
|
409
|
-
self._agent_components = {}
|
410
|
-
self._agent_components[component_id] = agent_component
|
411
|
-
|
412
|
-
# Only add to hierarchy if this is a root component (no parent)
|
413
|
-
# or if the parent explicitly added it as a child
|
414
|
-
if parent_agent_id:
|
415
|
-
parent_children.append(agent_component)
|
416
|
-
self.agent_children.set(parent_children)
|
417
|
-
else:
|
418
|
-
# Only add to root components if no parent
|
419
|
-
self.add_component(agent_component, is_error=True)
|
420
|
-
|
421
|
-
raise
|
422
|
-
finally:
|
423
|
-
self.current_agent_id.reset(agent_token)
|
424
|
-
self.current_agent_name.reset(agent_name_token)
|
425
|
-
self.agent_children.reset(children_token)
|
426
|
-
|
427
|
-
async def _trace_agent_execution(
|
428
|
-
self, func, name, agent_type, version, capabilities, hash_id, *args, **kwargs
|
429
|
-
):
|
430
|
-
"""Asynchronous version of agent tracing"""
|
431
|
-
if not self.is_active:
|
432
|
-
return await func(*args, **kwargs)
|
433
|
-
|
434
|
-
if not self.auto_instrument_agent:
|
435
|
-
return await func(*args, **kwargs)
|
436
|
-
|
437
|
-
start_time = datetime.now().astimezone().isoformat()
|
438
|
-
start_memory = psutil.Process().memory_info().rss
|
439
|
-
component_id = str(uuid.uuid4())
|
440
|
-
|
441
|
-
# Extract ground truth if present
|
442
|
-
ground_truth = kwargs.pop("gt", None) if kwargs else None
|
443
|
-
if ground_truth is not None:
|
444
|
-
span = self.span(name)
|
445
|
-
span.add_gt(ground_truth)
|
446
|
-
|
447
|
-
# Get parent agent ID if exists
|
448
|
-
parent_agent_id = self.current_agent_id.get()
|
449
|
-
|
450
|
-
# Set the current agent context
|
451
|
-
agent_token = self.current_agent_id.set(component_id)
|
452
|
-
agent_name_token = self.current_agent_name.set(name)
|
453
|
-
|
454
|
-
# Initialize empty children list for this agent
|
455
|
-
parent_children = self.agent_children.get()
|
456
|
-
children_token = self.agent_children.set([])
|
457
|
-
self.start_component(component_id)
|
458
|
-
|
459
|
-
try:
|
460
|
-
# Execute the agent
|
461
|
-
result = await func(*args, **kwargs)
|
462
|
-
|
463
|
-
# Calculate resource usage
|
464
|
-
end_memory = psutil.Process().memory_info().rss
|
465
|
-
memory_used = max(0, end_memory - start_memory)
|
466
|
-
|
467
|
-
# Get children components collected during execution
|
468
|
-
children = self.agent_children.get()
|
469
|
-
|
470
|
-
self.end_component(component_id)
|
471
|
-
|
472
|
-
# Create agent component with children and parent if exists
|
473
|
-
agent_component = self.create_agent_component(
|
474
|
-
component_id=component_id,
|
475
|
-
hash_id=hash_id,
|
476
|
-
name=name,
|
477
|
-
agent_type=agent_type,
|
478
|
-
version=version,
|
479
|
-
capabilities=capabilities or [],
|
480
|
-
start_time=start_time,
|
481
|
-
memory_used=memory_used,
|
482
|
-
input_data=self._sanitize_input(args, kwargs),
|
483
|
-
output_data=self._sanitize_output(result),
|
484
|
-
children=children,
|
485
|
-
parent_id=parent_agent_id,
|
486
|
-
)
|
487
|
-
|
488
|
-
# Store component for updates
|
489
|
-
if not hasattr(self, "_agent_components"):
|
490
|
-
self._agent_components = {}
|
491
|
-
self._agent_components[component_id] = agent_component
|
492
|
-
|
493
|
-
# Only add to hierarchy if this is a root component (no parent)
|
494
|
-
# or if the parent explicitly added it as a child
|
495
|
-
if parent_agent_id:
|
496
|
-
parent_children.append(agent_component)
|
497
|
-
self.agent_children.set(parent_children)
|
498
|
-
else:
|
499
|
-
self.add_component(agent_component)
|
500
|
-
|
501
|
-
return result
|
502
|
-
except Exception as e:
|
503
|
-
error_component = {
|
504
|
-
"code": 500,
|
505
|
-
"type": type(e).__name__,
|
506
|
-
"message": str(e),
|
507
|
-
"details": {},
|
508
|
-
}
|
509
|
-
|
510
|
-
# Get children even in case of error
|
511
|
-
children = self.agent_children.get()
|
512
|
-
|
513
|
-
# Create error component
|
514
|
-
agent_component = self.create_agent_component(
|
515
|
-
component_id=component_id,
|
516
|
-
hash_id=hash_id,
|
517
|
-
name=name,
|
518
|
-
agent_type=agent_type,
|
519
|
-
version=version,
|
520
|
-
capabilities=capabilities or [],
|
521
|
-
start_time=start_time,
|
522
|
-
memory_used=0,
|
523
|
-
input_data=self._sanitize_input(args, kwargs),
|
524
|
-
output_data=None,
|
525
|
-
error=error_component,
|
526
|
-
children=children,
|
527
|
-
parent_id=parent_agent_id, # Add parent ID if exists
|
528
|
-
)
|
529
|
-
|
530
|
-
# Store component for updates
|
531
|
-
if not hasattr(self, "_agent_components"):
|
532
|
-
self._agent_components = {}
|
533
|
-
self._agent_components[component_id] = agent_component
|
534
|
-
|
535
|
-
# Only add to hierarchy if this is a root component (no parent)
|
536
|
-
# or if the parent explicitly added it as a child
|
537
|
-
if parent_agent_id:
|
538
|
-
parent_children.append(agent_component)
|
539
|
-
self.agent_children.set(parent_children)
|
540
|
-
else:
|
541
|
-
# Only add to root components if no parent
|
542
|
-
self.add_component(agent_component, is_error=True)
|
543
|
-
|
544
|
-
raise
|
545
|
-
finally:
|
546
|
-
# Reset context variables
|
547
|
-
self.current_agent_id.reset(agent_token)
|
548
|
-
self.current_agent_name.reset(agent_name_token)
|
549
|
-
self.agent_children.reset(children_token)
|
550
|
-
|
551
|
-
def create_agent_component(self, **kwargs):
|
552
|
-
"""Create an agent component according to the data structure"""
|
553
|
-
network_calls = []
|
554
|
-
if self.auto_instrument_network:
|
555
|
-
network_calls = self.component_network_calls.get(kwargs["component_id"], [])
|
556
|
-
interactions = []
|
557
|
-
if self.auto_instrument_user_interaction:
|
558
|
-
input_output_interactions = []
|
559
|
-
for interaction in self.component_user_interaction.get(kwargs["component_id"], []):
|
560
|
-
if interaction["interaction_type"] in ["input", "output"]:
|
561
|
-
input_output_interactions.append(interaction)
|
562
|
-
interactions.extend(input_output_interactions)
|
563
|
-
if self.auto_instrument_file_io:
|
564
|
-
file_io_interactions = []
|
565
|
-
for interaction in self.component_user_interaction.get(kwargs["component_id"], []):
|
566
|
-
if interaction["interaction_type"] in ["file_read", "file_write"]:
|
567
|
-
file_io_interactions.append(interaction)
|
568
|
-
interactions.extend(file_io_interactions)
|
569
|
-
|
570
|
-
# Get start time
|
571
|
-
start_time = None
|
572
|
-
if "start_time" in kwargs:
|
573
|
-
start_time = kwargs["start_time"]
|
574
|
-
|
575
|
-
# Get tags, metrics
|
576
|
-
name = kwargs["name"]
|
577
|
-
# tags
|
578
|
-
tags = []
|
579
|
-
if name in self.span_attributes_dict:
|
580
|
-
tags = self.span_attributes_dict[name].tags or []
|
581
|
-
|
582
|
-
# metrics
|
583
|
-
metrics = []
|
584
|
-
if name in self.span_attributes_dict:
|
585
|
-
raw_metrics = self.span_attributes_dict[name].metrics or []
|
586
|
-
for metric in raw_metrics:
|
587
|
-
base_metric_name = metric["name"]
|
588
|
-
counter = sum(1 for x in self.visited_metrics if x.startswith(base_metric_name))
|
589
|
-
metric_name = f'{base_metric_name}_{counter}' if counter > 0 else base_metric_name
|
590
|
-
self.visited_metrics.append(metric_name)
|
591
|
-
metric["name"] = metric_name
|
592
|
-
metrics.append(metric)
|
593
|
-
|
594
|
-
# TODO agent_trace execute metric
|
595
|
-
formatted_metrics = BaseTracer.get_formatted_metric(self.span_attributes_dict, self.project_id, name)
|
596
|
-
if formatted_metrics:
|
597
|
-
metrics.extend(formatted_metrics)
|
598
|
-
|
599
|
-
component = {
|
600
|
-
"id": kwargs["component_id"],
|
601
|
-
"hash_id": kwargs["hash_id"],
|
602
|
-
"source_hash_id": None,
|
603
|
-
"type": "agent",
|
604
|
-
"name": kwargs["name"],
|
605
|
-
"start_time": start_time,
|
606
|
-
"end_time": datetime.now().astimezone().isoformat(),
|
607
|
-
"error": kwargs.get("error"),
|
608
|
-
"parent_id": kwargs.get("parent_id"),
|
609
|
-
"info": {
|
610
|
-
"agent_type": kwargs["agent_type"],
|
611
|
-
"version": kwargs["version"],
|
612
|
-
"capabilities": kwargs["capabilities"],
|
613
|
-
"memory_used": kwargs["memory_used"],
|
614
|
-
"tags": tags,
|
615
|
-
},
|
616
|
-
"data": {
|
617
|
-
"input": kwargs["input_data"],
|
618
|
-
"output": kwargs["output_data"],
|
619
|
-
"children": kwargs.get("children", []),
|
620
|
-
},
|
621
|
-
"metrics": metrics,
|
622
|
-
"network_calls": network_calls,
|
623
|
-
"interactions": interactions,
|
624
|
-
}
|
625
|
-
|
626
|
-
if name in self.span_attributes_dict:
|
627
|
-
span_gt = self.span_attributes_dict[name].gt
|
628
|
-
if span_gt is not None:
|
629
|
-
component["data"]["gt"] = span_gt
|
630
|
-
span_context = self.span_attributes_dict[name].context
|
631
|
-
if span_context:
|
632
|
-
component["data"]["context"] = span_context
|
633
|
-
|
634
|
-
# Reset the SpanAttributes context variable
|
635
|
-
self.span_attributes_dict[kwargs["name"]] = SpanAttributes(kwargs["name"])
|
636
|
-
|
637
|
-
return component
|
638
|
-
|
639
|
-
def start_component(self, component_id):
|
640
|
-
"""Start tracking network calls for a component"""
|
641
|
-
component_network_calls = self.component_network_calls.get()
|
642
|
-
if component_id not in component_network_calls:
|
643
|
-
component_network_calls[component_id] = []
|
644
|
-
self.component_network_calls.set(component_network_calls)
|
645
|
-
|
646
|
-
def end_component(self, component_id):
|
647
|
-
"""End tracking network calls for a component"""
|
648
|
-
component_network_calls = self.component_network_calls.get()
|
649
|
-
if component_id in component_network_calls:
|
650
|
-
component_network_calls[component_id] = []
|
651
|
-
self.component_network_calls.set(component_network_calls)
|
652
|
-
|
653
|
-
def _sanitize_input(self, args: tuple, kwargs: dict) -> dict:
|
654
|
-
"""Sanitize and format input data, including handling of nested lists and dictionaries."""
|
655
|
-
|
656
|
-
def sanitize_value(value):
|
657
|
-
if isinstance(value, (int, float, bool, str)):
|
658
|
-
return value
|
659
|
-
elif isinstance(value, list):
|
660
|
-
return [sanitize_value(item) for item in value]
|
661
|
-
elif isinstance(value, dict):
|
662
|
-
return {key: sanitize_value(val) for key, val in value.items()}
|
663
|
-
else:
|
664
|
-
return str(value) # Convert non-standard types to string
|
665
|
-
|
666
|
-
return {
|
667
|
-
"args": [sanitize_value(arg) for arg in args],
|
668
|
-
"kwargs": {key: sanitize_value(val) for key, val in kwargs.items()},
|
669
|
-
}
|
670
|
-
|
671
|
-
def _sanitize_output(self, output: Any) -> Any:
|
672
|
-
"""Sanitize and format output data"""
|
673
|
-
if isinstance(output, (int, float, bool, str, list, dict)):
|
674
|
-
return output
|
675
|
-
return str(output)
|
676
|
-
|
677
|
-
def instrument_agent_calls(self):
|
678
|
-
self.auto_instrument_agent = True
|
679
|
-
|
680
|
-
def instrument_user_interaction_calls(self):
|
681
|
-
self.auto_instrument_user_interaction = True
|
682
|
-
|
683
|
-
def instrument_network_calls(self):
|
684
|
-
self.auto_instrument_network = True
|
685
|
-
|
686
|
-
def instrument_file_io_calls(self):
|
687
|
-
self.auto_instrument_file_io = True
|