ragaai-catalyst 2.0.7.2b1__py3-none-any.whl → 2.1b1__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 +217 -106
- ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +27 -41
- ragaai_catalyst/tracers/agentic_tracing/base.py +127 -21
- ragaai_catalyst/tracers/agentic_tracing/data_structure.py +88 -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 +258 -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 +342 -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.1b1.dist-info}/METADATA +6 -2
- {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1b1.dist-info}/RECORD +28 -22
- ragaai_catalyst/tracers/agentic_tracing/Untitled-1.json +0 -660
- {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1b1.dist-info}/WHEEL +0 -0
- {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1b1.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,55 +208,29 @@ 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)
|
100
222
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
"type": type(e).__name__,
|
105
|
-
"message": str(e),
|
106
|
-
"details": {}
|
107
|
-
}
|
108
|
-
|
109
|
-
# Get children even in case of error
|
110
|
-
children = self.agent_children.get()
|
111
|
-
|
112
|
-
# Set parent_id for all children
|
113
|
-
for child in children:
|
114
|
-
child["parent_id"] = component_id
|
115
|
-
|
116
|
-
# End tracking network calls for this component
|
117
|
-
self.end_component(component_id)
|
118
|
-
|
119
|
-
agent_component = self.create_agent_component(
|
120
|
-
component_id=component_id,
|
121
|
-
hash_id=hash_id,
|
122
|
-
name=name,
|
123
|
-
agent_type=agent_type,
|
124
|
-
version=version,
|
125
|
-
capabilities=capabilities or [],
|
126
|
-
start_time=start_time,
|
127
|
-
end_time=datetime.now(),
|
128
|
-
memory_used=0,
|
129
|
-
input_data=self._sanitize_input(args, kwargs),
|
130
|
-
output_data=None,
|
131
|
-
error=error_component,
|
132
|
-
children=children
|
133
|
-
)
|
223
|
+
# Only add to root components if no parent
|
224
|
+
if not parent_agent_id:
|
225
|
+
self.add_component(agent_component)
|
134
226
|
|
135
|
-
|
136
|
-
raise
|
227
|
+
return result
|
137
228
|
finally:
|
138
|
-
# Reset context variables
|
139
229
|
self.current_agent_id.reset(agent_token)
|
140
230
|
self.current_agent_name.reset(agent_name_token)
|
141
231
|
self.agent_children.reset(children_token)
|
142
232
|
|
143
|
-
async def _trace_agent_execution(self, func, name, agent_type, version, capabilities, *args, **kwargs):
|
233
|
+
async def _trace_agent_execution(self, func, name, agent_type, version, capabilities, hash_id, *args, **kwargs):
|
144
234
|
"""Asynchronous version of agent tracing"""
|
145
235
|
if not self.is_active:
|
146
236
|
return await func(*args, **kwargs)
|
@@ -148,17 +238,20 @@ class AgentTracerMixin:
|
|
148
238
|
start_time = datetime.now()
|
149
239
|
start_memory = psutil.Process().memory_info().rss
|
150
240
|
component_id = str(uuid.uuid4())
|
151
|
-
hash_id = self._trace_agent_execution.hash_id
|
152
241
|
|
153
|
-
#
|
154
|
-
|
242
|
+
# Extract ground truth if present
|
243
|
+
ground_truth = kwargs.pop('gt', None) if kwargs else None
|
244
|
+
|
245
|
+
# Get parent agent ID if exists
|
246
|
+
parent_agent_id = self.current_agent_id.get()
|
155
247
|
|
156
248
|
# Set the current agent context
|
157
249
|
agent_token = self.current_agent_id.set(component_id)
|
158
250
|
agent_name_token = self.current_agent_name.set(name)
|
159
251
|
|
160
|
-
#
|
161
|
-
self.
|
252
|
+
# Initialize empty children list for this agent
|
253
|
+
parent_children = self.agent_children.get()
|
254
|
+
children_token = self.agent_children.set([])
|
162
255
|
|
163
256
|
try:
|
164
257
|
# Execute the agent
|
@@ -171,15 +264,8 @@ class AgentTracerMixin:
|
|
171
264
|
|
172
265
|
# Get children components collected during execution
|
173
266
|
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
267
|
|
182
|
-
# Create agent component with children
|
268
|
+
# Create agent component with children and parent if exists
|
183
269
|
agent_component = self.create_agent_component(
|
184
270
|
component_id=component_id,
|
185
271
|
hash_id=hash_id,
|
@@ -192,12 +278,23 @@ class AgentTracerMixin:
|
|
192
278
|
memory_used=memory_used,
|
193
279
|
input_data=self._sanitize_input(args, kwargs),
|
194
280
|
output_data=self._sanitize_output(result),
|
195
|
-
children=children
|
281
|
+
children=children,
|
282
|
+
parent_id=parent_agent_id
|
196
283
|
)
|
197
284
|
|
198
|
-
|
199
|
-
|
285
|
+
# Add ground truth to component data if present
|
286
|
+
if ground_truth is not None:
|
287
|
+
agent_component["data"]["gt"] = ground_truth
|
288
|
+
|
289
|
+
# Add this component as a child to parent's children list
|
290
|
+
parent_children.append(agent_component)
|
291
|
+
self.agent_children.set(parent_children)
|
292
|
+
|
293
|
+
# Only add to root components if no parent
|
294
|
+
if not parent_agent_id:
|
295
|
+
self.add_component(agent_component)
|
200
296
|
|
297
|
+
return result
|
201
298
|
except Exception as e:
|
202
299
|
error_component = {
|
203
300
|
"code": 500,
|
@@ -229,10 +326,20 @@ class AgentTracerMixin:
|
|
229
326
|
input_data=self._sanitize_input(args, kwargs),
|
230
327
|
output_data=None,
|
231
328
|
error=error_component,
|
232
|
-
children=children
|
329
|
+
children=children,
|
330
|
+
parent_id=parent_agent_id # Add parent ID if exists
|
233
331
|
)
|
234
|
-
|
235
|
-
|
332
|
+
|
333
|
+
# If this is a nested agent, add it to parent's children
|
334
|
+
if parent_agent_id:
|
335
|
+
parent_component = self._agent_components.get(parent_agent_id)
|
336
|
+
if parent_component:
|
337
|
+
if 'children' not in parent_component['data']:
|
338
|
+
parent_component['data']['children'] = []
|
339
|
+
parent_component['data']['children'].append(agent_component)
|
340
|
+
else:
|
341
|
+
# Only add to root components if no parent
|
342
|
+
self.add_component(agent_component)
|
236
343
|
raise
|
237
344
|
finally:
|
238
345
|
# Reset context variables
|
@@ -252,7 +359,7 @@ class AgentTracerMixin:
|
|
252
359
|
"start_time": start_time.isoformat(),
|
253
360
|
"end_time": kwargs["end_time"].isoformat(),
|
254
361
|
"error": kwargs.get("error"),
|
255
|
-
"parent_id":
|
362
|
+
"parent_id": kwargs.get("parent_id"),
|
256
363
|
"info": {
|
257
364
|
"agent_type": kwargs["agent_type"],
|
258
365
|
"version": kwargs["version"],
|
@@ -265,19 +372,12 @@ class AgentTracerMixin:
|
|
265
372
|
"children": kwargs.get("children", [])
|
266
373
|
},
|
267
374
|
"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
|
-
}]
|
375
|
+
"interactions": self.component_user_interaction.get(kwargs["component_id"], [])
|
279
376
|
}
|
280
377
|
|
378
|
+
if self.gt:
|
379
|
+
component["data"]["gt"] = self.gt
|
380
|
+
|
281
381
|
return component
|
282
382
|
|
283
383
|
def start_component(self, component_id):
|
@@ -294,15 +394,26 @@ class AgentTracerMixin:
|
|
294
394
|
component_network_calls[component_id] = []
|
295
395
|
self.component_network_calls.set(component_network_calls)
|
296
396
|
|
297
|
-
def _sanitize_input(self, args: tuple, kwargs: dict) ->
|
298
|
-
"""
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
397
|
+
def _sanitize_input(self, args: tuple, kwargs: dict) -> str:
|
398
|
+
"""Convert input arguments to text format.
|
399
|
+
|
400
|
+
Args:
|
401
|
+
args: Input arguments tuple
|
402
|
+
kwargs: Input keyword arguments dict
|
403
|
+
|
404
|
+
Returns:
|
405
|
+
str: Text representation of the input arguments
|
406
|
+
"""
|
407
|
+
def _sanitize_value(value):
|
408
|
+
if isinstance(value, dict):
|
409
|
+
return str({k: _sanitize_value(v) for k, v in value.items()})
|
410
|
+
elif isinstance(value, (list, tuple)):
|
411
|
+
return str([_sanitize_value(item) for item in value])
|
412
|
+
return str(value)
|
413
|
+
|
414
|
+
sanitized_args = [_sanitize_value(arg) for arg in args]
|
415
|
+
sanitized_kwargs = {k: _sanitize_value(v) for k, v in kwargs.items()}
|
416
|
+
return str({"args": sanitized_args, "kwargs": sanitized_kwargs})
|
306
417
|
|
307
418
|
def _sanitize_output(self, output: Any) -> Any:
|
308
419
|
"""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
|
|
@@ -143,51 +165,15 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
|
|
143
165
|
|
144
166
|
def add_component(self, component_data: dict):
|
145
167
|
"""Add a component to the trace data"""
|
146
|
-
component_id = component_data["id"]
|
147
|
-
|
148
168
|
# Convert dict to appropriate Component type
|
169
|
+
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"]}
|
170
|
+
|
149
171
|
if component_data["type"] == "llm":
|
150
|
-
component = LLMComponent(**
|
151
|
-
# Add network calls specific to this LLM component
|
152
|
-
component_data["network_calls"] = self.component_network_calls.get(component_id, [])
|
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
|
-
}]
|
172
|
+
component = LLMComponent(**filtered_data)
|
163
173
|
elif component_data["type"] == "agent":
|
164
|
-
component = AgentComponent(**
|
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 = AgentComponent(**filtered_data)
|
177
175
|
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
|
-
}]
|
176
|
+
component = ToolComponent(**filtered_data)
|
191
177
|
else:
|
192
178
|
component = Component(**component_data)
|
193
179
|
|