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.
Files changed (29) hide show
  1. ragaai_catalyst/dataset.py +0 -3
  2. ragaai_catalyst/evaluation.py +1 -2
  3. ragaai_catalyst/tracers/__init__.py +1 -1
  4. ragaai_catalyst/tracers/agentic_tracing/agent_tracer.py +217 -106
  5. ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +27 -41
  6. ragaai_catalyst/tracers/agentic_tracing/base.py +127 -21
  7. ragaai_catalyst/tracers/agentic_tracing/data_structure.py +88 -79
  8. ragaai_catalyst/tracers/agentic_tracing/examples/FinancialAnalysisSystem.ipynb +536 -0
  9. ragaai_catalyst/tracers/agentic_tracing/examples/GameActivityEventPlanner.ipynb +134 -0
  10. ragaai_catalyst/tracers/agentic_tracing/examples/TravelPlanner.ipynb +563 -0
  11. ragaai_catalyst/tracers/agentic_tracing/file_name_tracker.py +46 -0
  12. ragaai_catalyst/tracers/agentic_tracing/llm_tracer.py +258 -356
  13. ragaai_catalyst/tracers/agentic_tracing/tool_tracer.py +31 -19
  14. ragaai_catalyst/tracers/agentic_tracing/unique_decorator.py +61 -117
  15. ragaai_catalyst/tracers/agentic_tracing/upload_agentic_traces.py +187 -0
  16. ragaai_catalyst/tracers/agentic_tracing/upload_code.py +115 -0
  17. ragaai_catalyst/tracers/agentic_tracing/user_interaction_tracer.py +35 -59
  18. ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +0 -4
  19. ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +2201 -324
  20. ragaai_catalyst/tracers/agentic_tracing/zip_list_of_unique_files.py +342 -0
  21. ragaai_catalyst/tracers/exporters/raga_exporter.py +1 -7
  22. ragaai_catalyst/tracers/llamaindex_callback.py +56 -60
  23. ragaai_catalyst/tracers/tracer.py +6 -2
  24. ragaai_catalyst/tracers/upload_traces.py +46 -57
  25. {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1b1.dist-info}/METADATA +6 -2
  26. {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1b1.dist-info}/RECORD +28 -22
  27. ragaai_catalyst/tracers/agentic_tracing/Untitled-1.json +0 -660
  28. {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1b1.dist-info}/WHEEL +0 -0
  29. {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1b1.dist-info}/top_level.txt +0 -0
@@ -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')
@@ -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}/playground/metric-evaluation',
332
+ f'{self.base_url}/v2/llm/metric-evaluation',
334
333
  headers=headers,
335
334
  json=metric_schema_mapping,
336
335
  timeout=self.timeout
@@ -1,3 +1,3 @@
1
1
  from .tracer import Tracer
2
2
 
3
- __all__ = ["Tracer"]
3
+ __all__ = ["Tracer"]
@@ -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._trace_sync_agent_execution = mydecorator(self._trace_sync_agent_execution)
19
- self._trace_agent_execution = mydecorator(self._trace_agent_execution)
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(func):
24
- # Check if the function is async
25
- is_async = asyncio.iscoroutinefunction(func)
26
-
27
- @functools.wraps(func)
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
- return async_wrapper if is_async else sync_wrapper
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
- # Initialize empty children list for this agent
54
- children_token = self.agent_children.set([])
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
- self.add_component(agent_component)
99
- return result
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
- except Exception as e:
102
- error_component = {
103
- "code": 500,
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
- self.add_component(agent_component)
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
- # Initialize empty children list for this agent
154
- children_token = self.agent_children.set([])
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
- # Start tracking network calls for this component
161
- self.start_component(component_id)
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
- self.add_component(agent_component)
199
- return result
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
- self.add_component(agent_component)
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": None,
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) -> Dict:
298
- """Sanitize and format input data"""
299
- return {
300
- "args": [str(arg) if not isinstance(arg, (int, float, bool, str, list, dict)) else arg for arg in args],
301
- "kwargs": {
302
- k: str(v) if not isinstance(v, (int, float, bool, str, list, dict)) else v
303
- for k, v in kwargs.items()
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(**component_data)
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(**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 = AgentComponent(**filtered_data)
177
175
  elif component_data["type"] == "tool":
178
- component = ToolComponent(**component_data)
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