ragaai-catalyst 2.0.7.2b1__py3-none-any.whl → 2.1__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/dataset.py +0 -3
- ragaai_catalyst/evaluation.py +1 -2
- ragaai_catalyst/tracers/__init__.py +1 -1
- ragaai_catalyst/tracers/agentic_tracing/agent_tracer.py +231 -74
- ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +32 -42
- ragaai_catalyst/tracers/agentic_tracing/base.py +132 -30
- ragaai_catalyst/tracers/agentic_tracing/data_structure.py +91 -79
- ragaai_catalyst/tracers/agentic_tracing/examples/FinancialAnalysisSystem.ipynb +536 -0
- ragaai_catalyst/tracers/agentic_tracing/examples/GameActivityEventPlanner.ipynb +134 -0
- ragaai_catalyst/tracers/agentic_tracing/examples/TravelPlanner.ipynb +563 -0
- ragaai_catalyst/tracers/agentic_tracing/file_name_tracker.py +46 -0
- ragaai_catalyst/tracers/agentic_tracing/llm_tracer.py +262 -356
- ragaai_catalyst/tracers/agentic_tracing/tool_tracer.py +31 -19
- ragaai_catalyst/tracers/agentic_tracing/unique_decorator.py +61 -117
- ragaai_catalyst/tracers/agentic_tracing/upload_agentic_traces.py +187 -0
- ragaai_catalyst/tracers/agentic_tracing/upload_code.py +115 -0
- ragaai_catalyst/tracers/agentic_tracing/user_interaction_tracer.py +35 -59
- ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +0 -4
- ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +2201 -324
- ragaai_catalyst/tracers/agentic_tracing/zip_list_of_unique_files.py +186 -0
- ragaai_catalyst/tracers/exporters/raga_exporter.py +1 -7
- ragaai_catalyst/tracers/llamaindex_callback.py +56 -60
- ragaai_catalyst/tracers/tracer.py +6 -2
- ragaai_catalyst/tracers/upload_traces.py +46 -57
- {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1.dist-info}/METADATA +8 -4
- {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1.dist-info}/RECORD +28 -22
- {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1.dist-info}/WHEEL +1 -1
- ragaai_catalyst/tracers/agentic_tracing/Untitled-1.json +0 -660
- {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1.dist-info}/top_level.txt +0 -0
ragaai_catalyst/dataset.py
CHANGED
@@ -5,7 +5,6 @@ from typing import Union
|
|
5
5
|
import logging
|
6
6
|
from .ragaai_catalyst import RagaAICatalyst
|
7
7
|
import pandas as pd
|
8
|
-
import pdb
|
9
8
|
logger = logging.getLogger(__name__)
|
10
9
|
get_token = RagaAICatalyst.get_token
|
11
10
|
|
@@ -202,7 +201,6 @@ class Dataset:
|
|
202
201
|
|
203
202
|
#### put csv to presigned URL
|
204
203
|
def put_csv_to_presignedUrl(url):
|
205
|
-
# pdb.set_trace()
|
206
204
|
headers = {
|
207
205
|
'Content-Type': 'text/csv',
|
208
206
|
'x-ms-blob-type': 'BlockBlob',
|
@@ -224,7 +222,6 @@ class Dataset:
|
|
224
222
|
try:
|
225
223
|
|
226
224
|
put_csv_response = put_csv_to_presignedUrl(url)
|
227
|
-
# pdb.set_trace()
|
228
225
|
print(put_csv_response)
|
229
226
|
if put_csv_response.status_code not in (200, 201):
|
230
227
|
raise ValueError('Unable to put csv to the presignedUrl')
|
ragaai_catalyst/evaluation.py
CHANGED
@@ -4,7 +4,6 @@ import pandas as pd
|
|
4
4
|
import io
|
5
5
|
from .ragaai_catalyst import RagaAICatalyst
|
6
6
|
import logging
|
7
|
-
import pdb
|
8
7
|
|
9
8
|
logger = logging.getLogger(__name__)
|
10
9
|
|
@@ -330,7 +329,7 @@ class Evaluation:
|
|
330
329
|
metric_schema_mapping = self._update_base_json(metrics)
|
331
330
|
try:
|
332
331
|
response = requests.post(
|
333
|
-
f'{self.base_url}/
|
332
|
+
f'{self.base_url}/v2/llm/metric-evaluation',
|
334
333
|
headers=headers,
|
335
334
|
json=metric_schema_mapping,
|
336
335
|
timeout=self.timeout
|
@@ -4,43 +4,157 @@ from datetime import datetime
|
|
4
4
|
import psutil
|
5
5
|
from typing import Optional, Any, Dict, List
|
6
6
|
from .unique_decorator import mydecorator
|
7
|
+
from .unique_decorator import generate_unique_hash_simple
|
7
8
|
|
8
9
|
import contextvars
|
9
10
|
import asyncio
|
11
|
+
from .file_name_tracker import TrackName
|
12
|
+
|
10
13
|
|
11
14
|
class AgentTracerMixin:
|
12
15
|
def __init__(self, *args, **kwargs):
|
13
16
|
super().__init__(*args, **kwargs)
|
17
|
+
self.file_tracker = TrackName()
|
14
18
|
self.current_agent_id = contextvars.ContextVar("agent_id", default=None)
|
15
19
|
self.current_agent_name = contextvars.ContextVar("agent_name", default=None)
|
16
20
|
self.agent_children = contextvars.ContextVar("agent_children", default=[])
|
17
21
|
self.component_network_calls = contextvars.ContextVar("component_network_calls", default={})
|
18
|
-
self.
|
19
|
-
self.
|
22
|
+
self.component_user_interaction = contextvars.ContextVar("component_user_interaction", default={})
|
23
|
+
self.gt = None
|
20
24
|
|
21
25
|
|
22
26
|
def trace_agent(self, name: str, agent_type: str = "generic", version: str = "1.0.0", capabilities: List[str] = None):
|
23
|
-
def decorator(
|
24
|
-
# Check if
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
async def async_wrapper(*args, **kwargs):
|
29
|
-
return await self._trace_agent_execution(
|
30
|
-
func, name, agent_type, version, capabilities, *args, **kwargs
|
31
|
-
)
|
32
|
-
|
33
|
-
@functools.wraps(func)
|
34
|
-
def sync_wrapper(*args, **kwargs):
|
35
|
-
return self._trace_sync_agent_execution(
|
36
|
-
func, name, agent_type, version, capabilities, *args, **kwargs
|
37
|
-
)
|
27
|
+
def decorator(target):
|
28
|
+
# Check if target is a class
|
29
|
+
is_class = isinstance(target, type)
|
30
|
+
tracer = self # Store reference to tracer instance
|
31
|
+
top_level_hash_id = generate_unique_hash_simple(target) # Generate hash based on the decorated target code
|
38
32
|
|
39
|
-
|
33
|
+
|
34
|
+
if is_class:
|
35
|
+
# Store original __init__
|
36
|
+
original_init = target.__init__
|
37
|
+
|
38
|
+
def wrapped_init(self, *args, **kwargs):
|
39
|
+
self.gt = kwargs.get('gt', None) if kwargs else None
|
40
|
+
# Set agent context before initializing
|
41
|
+
component_id = str(uuid.uuid4())
|
42
|
+
hash_id = top_level_hash_id
|
43
|
+
|
44
|
+
# Store the component ID in the instance
|
45
|
+
self._agent_component_id = component_id
|
46
|
+
|
47
|
+
# Get parent agent ID if exists
|
48
|
+
parent_agent_id = tracer.current_agent_id.get()
|
49
|
+
|
50
|
+
# Create agent component
|
51
|
+
agent_component = tracer.create_agent_component(
|
52
|
+
component_id=component_id,
|
53
|
+
hash_id=hash_id,
|
54
|
+
name=name,
|
55
|
+
agent_type=agent_type,
|
56
|
+
version=version,
|
57
|
+
capabilities=capabilities or [],
|
58
|
+
start_time=datetime.now(),
|
59
|
+
end_time=datetime.now(),
|
60
|
+
memory_used=0,
|
61
|
+
input_data=tracer._sanitize_input(args, kwargs),
|
62
|
+
output_data=None,
|
63
|
+
children=[],
|
64
|
+
parent_id=parent_agent_id
|
65
|
+
)
|
66
|
+
|
67
|
+
# Store component for later updates
|
68
|
+
if not hasattr(tracer, '_agent_components'):
|
69
|
+
tracer._agent_components = {}
|
70
|
+
tracer._agent_components[component_id] = agent_component
|
71
|
+
|
72
|
+
# If this is a nested agent, add it to parent's children
|
73
|
+
if parent_agent_id:
|
74
|
+
parent_children = tracer.agent_children.get()
|
75
|
+
parent_children.append(agent_component)
|
76
|
+
tracer.agent_children.set(parent_children)
|
77
|
+
else:
|
78
|
+
# Only add to root components if no parent
|
79
|
+
tracer.add_component(agent_component)
|
80
|
+
|
81
|
+
# Call original __init__ with this agent as current
|
82
|
+
token = tracer.current_agent_id.set(component_id)
|
83
|
+
try:
|
84
|
+
original_init(self, *args, **kwargs)
|
85
|
+
finally:
|
86
|
+
tracer.current_agent_id.reset(token)
|
87
|
+
|
88
|
+
# Wrap all public methods to track execution
|
89
|
+
for attr_name in dir(target):
|
90
|
+
if not attr_name.startswith('_'):
|
91
|
+
attr_value = getattr(target, attr_name)
|
92
|
+
if callable(attr_value):
|
93
|
+
def wrap_method(method):
|
94
|
+
@self.file_tracker.trace_decorator
|
95
|
+
@functools.wraps(method)
|
96
|
+
def wrapped_method(self, *args, **kwargs):
|
97
|
+
self.gt = kwargs.get('gt', None) if kwargs else None
|
98
|
+
# Set this agent as current during method execution
|
99
|
+
token = tracer.current_agent_id.set(self._agent_component_id)
|
100
|
+
|
101
|
+
# Store parent's children before setting new empty list
|
102
|
+
parent_children = tracer.agent_children.get()
|
103
|
+
children_token = tracer.agent_children.set([])
|
104
|
+
|
105
|
+
try:
|
106
|
+
start_time = datetime.now()
|
107
|
+
result = method(self, *args, **kwargs)
|
108
|
+
end_time = datetime.now()
|
109
|
+
|
110
|
+
# Update agent component with method result
|
111
|
+
if hasattr(tracer, '_agent_components'):
|
112
|
+
component = tracer._agent_components.get(self._agent_component_id)
|
113
|
+
if component:
|
114
|
+
component['data']['output'] = tracer._sanitize_output(result)
|
115
|
+
component['data']['input'] = tracer._sanitize_input(args, kwargs)
|
116
|
+
component['start_time'] = start_time.isoformat()
|
117
|
+
component['end_time'] = end_time.isoformat()
|
118
|
+
|
119
|
+
# Get children accumulated during method execution
|
120
|
+
children = tracer.agent_children.get()
|
121
|
+
if children:
|
122
|
+
if 'children' not in component['data']:
|
123
|
+
component['data']['children'] = []
|
124
|
+
component['data']['children'].extend(children)
|
125
|
+
|
126
|
+
# Add this component as a child to parent's children list
|
127
|
+
parent_children.append(component)
|
128
|
+
tracer.agent_children.set(parent_children)
|
129
|
+
return result
|
130
|
+
finally:
|
131
|
+
tracer.current_agent_id.reset(token)
|
132
|
+
tracer.agent_children.reset(children_token)
|
133
|
+
return wrapped_method
|
134
|
+
|
135
|
+
setattr(target, attr_name, wrap_method(attr_value))
|
136
|
+
|
137
|
+
# Replace __init__ with wrapped version
|
138
|
+
target.__init__ = wrapped_init
|
139
|
+
return target
|
140
|
+
else:
|
141
|
+
# For function decorators, use existing sync/async tracing
|
142
|
+
is_async = asyncio.iscoroutinefunction(target)
|
143
|
+
if is_async:
|
144
|
+
async def wrapper(*args, **kwargs):
|
145
|
+
return await self._trace_agent_execution(target, name, agent_type, version, capabilities, top_level_hash_id, *args, **kwargs)
|
146
|
+
return wrapper
|
147
|
+
else:
|
148
|
+
def wrapper(*args, **kwargs):
|
149
|
+
return self._trace_sync_agent_execution(target, name, agent_type, version, capabilities, *args, **kwargs)
|
150
|
+
return wrapper
|
40
151
|
|
41
152
|
return decorator
|
42
153
|
|
43
154
|
def _trace_sync_agent_execution(self, func, name, agent_type, version, capabilities, *args, **kwargs):
|
155
|
+
# Generate a unique hash_id for this execution context
|
156
|
+
hash_id = str(uuid.uuid4())
|
157
|
+
|
44
158
|
"""Synchronous version of agent tracing"""
|
45
159
|
if not self.is_active:
|
46
160
|
return func(*args, **kwargs)
|
@@ -48,15 +162,21 @@ class AgentTracerMixin:
|
|
48
162
|
start_time = datetime.now()
|
49
163
|
start_memory = psutil.Process().memory_info().rss
|
50
164
|
component_id = str(uuid.uuid4())
|
51
|
-
hash_id = self._trace_sync_agent_execution.hash_id
|
52
165
|
|
53
|
-
#
|
54
|
-
|
166
|
+
# Extract ground truth if present
|
167
|
+
ground_truth = kwargs.pop('gt', None) if kwargs else None
|
168
|
+
|
169
|
+
# Get parent agent ID if exists
|
170
|
+
parent_agent_id = self.current_agent_id.get()
|
55
171
|
|
56
172
|
# Set the current agent context
|
57
173
|
agent_token = self.current_agent_id.set(component_id)
|
58
174
|
agent_name_token = self.current_agent_name.set(name)
|
59
175
|
|
176
|
+
# Initialize empty children list for this agent
|
177
|
+
parent_children = self.agent_children.get()
|
178
|
+
children_token = self.agent_children.set([])
|
179
|
+
|
60
180
|
# Start tracking network calls for this component
|
61
181
|
self.start_component(component_id)
|
62
182
|
|
@@ -71,15 +191,11 @@ class AgentTracerMixin:
|
|
71
191
|
|
72
192
|
# Get children components collected during execution
|
73
193
|
children = self.agent_children.get()
|
74
|
-
|
75
|
-
# Set parent_id for all children
|
76
|
-
for child in children:
|
77
|
-
child["parent_id"] = component_id
|
78
194
|
|
79
195
|
# End tracking network calls for this component
|
80
196
|
self.end_component(component_id)
|
81
197
|
|
82
|
-
# Create agent component with children
|
198
|
+
# Create agent component with children and parent if exists
|
83
199
|
agent_component = self.create_agent_component(
|
84
200
|
component_id=component_id,
|
85
201
|
hash_id=hash_id,
|
@@ -92,12 +208,23 @@ class AgentTracerMixin:
|
|
92
208
|
memory_used=memory_used,
|
93
209
|
input_data=self._sanitize_input(args, kwargs),
|
94
210
|
output_data=self._sanitize_output(result),
|
95
|
-
children=children
|
211
|
+
children=children,
|
212
|
+
parent_id=parent_agent_id
|
96
213
|
)
|
97
214
|
|
98
|
-
|
99
|
-
|
215
|
+
# Add ground truth to component data if present
|
216
|
+
if ground_truth is not None:
|
217
|
+
agent_component["data"]["gt"] = ground_truth
|
218
|
+
|
219
|
+
# Add this component as a child to parent's children list
|
220
|
+
parent_children.append(agent_component)
|
221
|
+
self.agent_children.set(parent_children)
|
222
|
+
|
223
|
+
# Only add to root components if no parent
|
224
|
+
if not parent_agent_id:
|
225
|
+
self.add_component(agent_component)
|
100
226
|
|
227
|
+
return result
|
101
228
|
except Exception as e:
|
102
229
|
error_component = {
|
103
230
|
"code": 500,
|
@@ -129,18 +256,27 @@ class AgentTracerMixin:
|
|
129
256
|
input_data=self._sanitize_input(args, kwargs),
|
130
257
|
output_data=None,
|
131
258
|
error=error_component,
|
132
|
-
children=children
|
259
|
+
children=children,
|
260
|
+
parent_id=parent_agent_id # Add parent ID if exists
|
133
261
|
)
|
134
|
-
|
135
|
-
|
262
|
+
|
263
|
+
# If this is a nested agent, add it to parent's children
|
264
|
+
if parent_agent_id:
|
265
|
+
parent_component = self._agent_components.get(parent_agent_id)
|
266
|
+
if parent_component:
|
267
|
+
if 'children' not in parent_component['data']:
|
268
|
+
parent_component['data']['children'] = []
|
269
|
+
parent_component['data']['children'].append(agent_component)
|
270
|
+
else:
|
271
|
+
# Only add to root components if no parent
|
272
|
+
self.add_component(agent_component)
|
136
273
|
raise
|
137
274
|
finally:
|
138
|
-
# Reset context variables
|
139
275
|
self.current_agent_id.reset(agent_token)
|
140
276
|
self.current_agent_name.reset(agent_name_token)
|
141
277
|
self.agent_children.reset(children_token)
|
142
278
|
|
143
|
-
async def _trace_agent_execution(self, func, name, agent_type, version, capabilities, *args, **kwargs):
|
279
|
+
async def _trace_agent_execution(self, func, name, agent_type, version, capabilities, hash_id, *args, **kwargs):
|
144
280
|
"""Asynchronous version of agent tracing"""
|
145
281
|
if not self.is_active:
|
146
282
|
return await func(*args, **kwargs)
|
@@ -148,17 +284,20 @@ class AgentTracerMixin:
|
|
148
284
|
start_time = datetime.now()
|
149
285
|
start_memory = psutil.Process().memory_info().rss
|
150
286
|
component_id = str(uuid.uuid4())
|
151
|
-
hash_id = self._trace_agent_execution.hash_id
|
152
287
|
|
153
|
-
#
|
154
|
-
|
288
|
+
# Extract ground truth if present
|
289
|
+
ground_truth = kwargs.pop('gt', None) if kwargs else None
|
290
|
+
|
291
|
+
# Get parent agent ID if exists
|
292
|
+
parent_agent_id = self.current_agent_id.get()
|
155
293
|
|
156
294
|
# Set the current agent context
|
157
295
|
agent_token = self.current_agent_id.set(component_id)
|
158
296
|
agent_name_token = self.current_agent_name.set(name)
|
159
297
|
|
160
|
-
#
|
161
|
-
self.
|
298
|
+
# Initialize empty children list for this agent
|
299
|
+
parent_children = self.agent_children.get()
|
300
|
+
children_token = self.agent_children.set([])
|
162
301
|
|
163
302
|
try:
|
164
303
|
# Execute the agent
|
@@ -171,15 +310,8 @@ class AgentTracerMixin:
|
|
171
310
|
|
172
311
|
# Get children components collected during execution
|
173
312
|
children = self.agent_children.get()
|
174
|
-
|
175
|
-
# Set parent_id for all children
|
176
|
-
for child in children:
|
177
|
-
child["parent_id"] = component_id
|
178
|
-
|
179
|
-
# End tracking network calls for this component
|
180
|
-
self.end_component(component_id)
|
181
313
|
|
182
|
-
# Create agent component with children
|
314
|
+
# Create agent component with children and parent if exists
|
183
315
|
agent_component = self.create_agent_component(
|
184
316
|
component_id=component_id,
|
185
317
|
hash_id=hash_id,
|
@@ -192,12 +324,23 @@ class AgentTracerMixin:
|
|
192
324
|
memory_used=memory_used,
|
193
325
|
input_data=self._sanitize_input(args, kwargs),
|
194
326
|
output_data=self._sanitize_output(result),
|
195
|
-
children=children
|
327
|
+
children=children,
|
328
|
+
parent_id=parent_agent_id
|
196
329
|
)
|
197
330
|
|
198
|
-
|
199
|
-
|
331
|
+
# Add ground truth to component data if present
|
332
|
+
if ground_truth is not None:
|
333
|
+
agent_component["data"]["gt"] = ground_truth
|
200
334
|
|
335
|
+
# Add this component as a child to parent's children list
|
336
|
+
parent_children.append(agent_component)
|
337
|
+
self.agent_children.set(parent_children)
|
338
|
+
|
339
|
+
# Only add to root components if no parent
|
340
|
+
if not parent_agent_id:
|
341
|
+
self.add_component(agent_component)
|
342
|
+
|
343
|
+
return result
|
201
344
|
except Exception as e:
|
202
345
|
error_component = {
|
203
346
|
"code": 500,
|
@@ -229,10 +372,20 @@ class AgentTracerMixin:
|
|
229
372
|
input_data=self._sanitize_input(args, kwargs),
|
230
373
|
output_data=None,
|
231
374
|
error=error_component,
|
232
|
-
children=children
|
375
|
+
children=children,
|
376
|
+
parent_id=parent_agent_id # Add parent ID if exists
|
233
377
|
)
|
234
|
-
|
235
|
-
|
378
|
+
|
379
|
+
# If this is a nested agent, add it to parent's children
|
380
|
+
if parent_agent_id:
|
381
|
+
parent_component = self._agent_components.get(parent_agent_id)
|
382
|
+
if parent_component:
|
383
|
+
if 'children' not in parent_component['data']:
|
384
|
+
parent_component['data']['children'] = []
|
385
|
+
parent_component['data']['children'].append(agent_component)
|
386
|
+
else:
|
387
|
+
# Only add to root components if no parent
|
388
|
+
self.add_component(agent_component)
|
236
389
|
raise
|
237
390
|
finally:
|
238
391
|
# Reset context variables
|
@@ -252,7 +405,7 @@ class AgentTracerMixin:
|
|
252
405
|
"start_time": start_time.isoformat(),
|
253
406
|
"end_time": kwargs["end_time"].isoformat(),
|
254
407
|
"error": kwargs.get("error"),
|
255
|
-
"parent_id":
|
408
|
+
"parent_id": kwargs.get("parent_id"),
|
256
409
|
"info": {
|
257
410
|
"agent_type": kwargs["agent_type"],
|
258
411
|
"version": kwargs["version"],
|
@@ -265,19 +418,12 @@ class AgentTracerMixin:
|
|
265
418
|
"children": kwargs.get("children", [])
|
266
419
|
},
|
267
420
|
"network_calls": self.component_network_calls.get(kwargs["component_id"], []),
|
268
|
-
"interactions": [
|
269
|
-
"id": f"int_{uuid.uuid4()}",
|
270
|
-
"interaction_type": "input",
|
271
|
-
"timestamp": start_time.isoformat(),
|
272
|
-
"content": kwargs["input_data"]
|
273
|
-
}, {
|
274
|
-
"id": f"int_{uuid.uuid4()}",
|
275
|
-
"interaction_type": "output",
|
276
|
-
"timestamp": kwargs["end_time"].isoformat(),
|
277
|
-
"content": kwargs["output_data"]
|
278
|
-
}]
|
421
|
+
"interactions": self.component_user_interaction.get(kwargs["component_id"], [])
|
279
422
|
}
|
280
423
|
|
424
|
+
if self.gt:
|
425
|
+
component["data"]["gt"] = self.gt
|
426
|
+
|
281
427
|
return component
|
282
428
|
|
283
429
|
def start_component(self, component_id):
|
@@ -294,15 +440,26 @@ class AgentTracerMixin:
|
|
294
440
|
component_network_calls[component_id] = []
|
295
441
|
self.component_network_calls.set(component_network_calls)
|
296
442
|
|
297
|
-
def _sanitize_input(self, args: tuple, kwargs: dict) ->
|
298
|
-
"""
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
443
|
+
def _sanitize_input(self, args: tuple, kwargs: dict) -> str:
|
444
|
+
"""Convert input arguments to text format.
|
445
|
+
|
446
|
+
Args:
|
447
|
+
args: Input arguments tuple
|
448
|
+
kwargs: Input keyword arguments dict
|
449
|
+
|
450
|
+
Returns:
|
451
|
+
str: Text representation of the input arguments
|
452
|
+
"""
|
453
|
+
def _sanitize_value(value):
|
454
|
+
if isinstance(value, dict):
|
455
|
+
return str({k: _sanitize_value(v) for k, v in value.items()})
|
456
|
+
elif isinstance(value, (list, tuple)):
|
457
|
+
return str([_sanitize_value(item) for item in value])
|
458
|
+
return str(value)
|
459
|
+
|
460
|
+
sanitized_args = [_sanitize_value(arg) for arg in args]
|
461
|
+
sanitized_kwargs = {k: _sanitize_value(v) for k, v in kwargs.items()}
|
462
|
+
return str({"args": sanitized_args, "kwargs": sanitized_kwargs})
|
306
463
|
|
307
464
|
def _sanitize_output(self, output: Any) -> Any:
|
308
465
|
"""Sanitize and format output data"""
|
@@ -4,6 +4,7 @@ import json
|
|
4
4
|
from datetime import datetime
|
5
5
|
import uuid
|
6
6
|
import os
|
7
|
+
import builtins
|
7
8
|
from pathlib import Path
|
8
9
|
|
9
10
|
from .base import BaseTracer
|
@@ -11,6 +12,7 @@ from .llm_tracer import LLMTracerMixin
|
|
11
12
|
from .tool_tracer import ToolTracerMixin
|
12
13
|
from .agent_tracer import AgentTracerMixin
|
13
14
|
from .network_tracer import NetworkTracer
|
15
|
+
from .user_interaction_tracer import UserInteractionTracer
|
14
16
|
|
15
17
|
from .data_structure import (
|
16
18
|
Trace, Metadata, SystemInfo, OSInfo, EnvironmentInfo,
|
@@ -27,6 +29,7 @@ from ..upload_traces import UploadTraces
|
|
27
29
|
class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMixin):
|
28
30
|
def __init__(self, user_detail, auto_instrument_llm: bool = True):
|
29
31
|
# Initialize all parent classes
|
32
|
+
self.user_interaction_tracer = UserInteractionTracer()
|
30
33
|
LLMTracerMixin.__init__(self)
|
31
34
|
ToolTracerMixin.__init__(self)
|
32
35
|
AgentTracerMixin.__init__(self)
|
@@ -43,11 +46,13 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
|
|
43
46
|
self.auto_instrument_llm = auto_instrument_llm
|
44
47
|
self.tools: Dict[str, Tool] = {}
|
45
48
|
self.call_depth = contextvars.ContextVar("call_depth", default=0)
|
49
|
+
self.current_component_id = contextvars.ContextVar("current_component_id", default=None)
|
46
50
|
self.network_tracer = NetworkTracer()
|
47
51
|
self.is_active = False
|
48
52
|
self.current_agent_id = contextvars.ContextVar("current_agent_id", default=None)
|
49
53
|
self.agent_children = contextvars.ContextVar("agent_children", default=[])
|
50
54
|
self.component_network_calls = {} # Store network calls per component
|
55
|
+
self.component_user_interaction = {}
|
51
56
|
|
52
57
|
# Create output directory if it doesn't exist
|
53
58
|
self.output_dir = Path("./traces") # Using default traces directory
|
@@ -57,14 +62,27 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
|
|
57
62
|
"""Start tracking network calls for a component"""
|
58
63
|
self.component_network_calls[component_id] = []
|
59
64
|
self.network_tracer.network_calls = [] # Reset network calls
|
65
|
+
self.component_user_interaction[component_id] = []
|
66
|
+
self.current_component_id.set(component_id)
|
67
|
+
self.user_interaction_tracer.component_id.set(component_id)
|
60
68
|
|
61
69
|
def end_component(self, component_id: str):
|
62
70
|
"""End tracking network calls for a component"""
|
63
71
|
self.component_network_calls[component_id] = self.network_tracer.network_calls.copy()
|
64
72
|
self.network_tracer.network_calls = [] # Reset for next component
|
73
|
+
self.component_user_interaction[component_id] = self.user_interaction_tracer.interactions.copy()
|
74
|
+
self.user_interaction_tracer.interactions = []
|
65
75
|
|
66
76
|
def start(self):
|
67
77
|
"""Start tracing"""
|
78
|
+
# Setup user interaction tracing
|
79
|
+
self.user_interaction_tracer.project_id.set(self.project_id)
|
80
|
+
self.user_interaction_tracer.trace_id.set(self.trace_id)
|
81
|
+
self.user_interaction_tracer.tracer = self
|
82
|
+
self.user_interaction_tracer.component_id.set(self.current_component_id.get())
|
83
|
+
builtins.print = self.user_interaction_tracer.traced_print
|
84
|
+
builtins.input = self.user_interaction_tracer.traced_input
|
85
|
+
|
68
86
|
# Start base tracer (includes system info and resource monitoring)
|
69
87
|
super().start()
|
70
88
|
self.is_active = True
|
@@ -79,6 +97,10 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
|
|
79
97
|
def stop(self):
|
80
98
|
"""Stop tracing and save results"""
|
81
99
|
if self.is_active:
|
100
|
+
# Restore original print and input functions
|
101
|
+
builtins.print = self.user_interaction_tracer.original_print
|
102
|
+
builtins.input = self.user_interaction_tracer.original_input
|
103
|
+
|
82
104
|
# Calculate final metrics before stopping
|
83
105
|
self._calculate_final_metrics()
|
84
106
|
|
@@ -90,6 +112,7 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
|
|
90
112
|
|
91
113
|
# Cleanup
|
92
114
|
self.unpatch_llm_calls()
|
115
|
+
self.user_interaction_tracer.interactions = [] # Clear interactions list
|
93
116
|
self.is_active = False
|
94
117
|
|
95
118
|
|
@@ -143,53 +166,20 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
|
|
143
166
|
|
144
167
|
def add_component(self, component_data: dict):
|
145
168
|
"""Add a component to the trace data"""
|
146
|
-
component_id = component_data["id"]
|
147
|
-
|
148
169
|
# Convert dict to appropriate Component type
|
170
|
+
filtered_data = {k: v for k, v in component_data.items() if k in ["id", "hash_id", "type", "name", "start_time", "end_time", "parent_id", "info", "data", "network_calls", "interactions", "error"]}
|
171
|
+
|
172
|
+
|
149
173
|
if component_data["type"] == "llm":
|
150
|
-
component = LLMComponent(**
|
151
|
-
|
152
|
-
|
153
|
-
# Add user interaction for LLM calls
|
154
|
-
component_data["interactions"] = [{
|
155
|
-
"id": f"int_{uuid.uuid4()}",
|
156
|
-
"interaction_type": "input",
|
157
|
-
"content": component_data["data"]["input"]
|
158
|
-
}, {
|
159
|
-
"id": f"int_{uuid.uuid4()}",
|
160
|
-
"interaction_type": "output",
|
161
|
-
"content": component_data["data"]["output"]
|
162
|
-
}]
|
163
|
-
elif component_data["type"] == "agent":
|
164
|
-
component = AgentComponent(**component_data)
|
165
|
-
# Add network calls specific to this agent component
|
166
|
-
component_data["network_calls"] = self.component_network_calls.get(component_id, [])
|
167
|
-
# Add user interaction for agent
|
168
|
-
component_data["interactions"] = [{
|
169
|
-
"id": f"int_{uuid.uuid4()}",
|
170
|
-
"interaction_type": "input",
|
171
|
-
"content": component_data["data"]["input"]
|
172
|
-
}, {
|
173
|
-
"id": f"int_{uuid.uuid4()}",
|
174
|
-
"interaction_type": "output",
|
175
|
-
"content": component_data["data"]["output"]
|
176
|
-
}]
|
174
|
+
component = LLMComponent(**filtered_data)
|
175
|
+
elif component_data["type"] == "agent":
|
176
|
+
component = AgentComponent(**filtered_data)
|
177
177
|
elif component_data["type"] == "tool":
|
178
|
-
component = ToolComponent(**
|
179
|
-
# Add network calls specific to this tool component
|
180
|
-
component_data["network_calls"] = self.component_network_calls.get(component_id, [])
|
181
|
-
# Add user interaction for tool
|
182
|
-
component_data["interactions"] = [{
|
183
|
-
"id": f"int_{uuid.uuid4()}",
|
184
|
-
"interaction_type": "input",
|
185
|
-
"content": component_data["data"]["input"]
|
186
|
-
}, {
|
187
|
-
"id": f"int_{uuid.uuid4()}",
|
188
|
-
"interaction_type": "output",
|
189
|
-
"content": component_data["data"]["output"]
|
190
|
-
}]
|
178
|
+
component = ToolComponent(**filtered_data)
|
191
179
|
else:
|
192
180
|
component = Component(**component_data)
|
181
|
+
|
182
|
+
# import pdb; pdb.set_trace()
|
193
183
|
|
194
184
|
# Check if there's an active agent context
|
195
185
|
current_agent_id = self.current_agent_id.get()
|