ragaai-catalyst 2.0.7.2b0__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.
Files changed (27) 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 +231 -74
  5. ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +32 -42
  6. ragaai_catalyst/tracers/agentic_tracing/base.py +132 -30
  7. ragaai_catalyst/tracers/agentic_tracing/data_structure.py +91 -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 +262 -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 +186 -0
  21. ragaai_catalyst/tracers/exporters/raga_exporter.py +1 -7
  22. ragaai_catalyst/tracers/tracer.py +6 -2
  23. {ragaai_catalyst-2.0.7.2b0.dist-info → ragaai_catalyst-2.1.dist-info}/METADATA +8 -4
  24. {ragaai_catalyst-2.0.7.2b0.dist-info → ragaai_catalyst-2.1.dist-info}/RECORD +26 -20
  25. {ragaai_catalyst-2.0.7.2b0.dist-info → ragaai_catalyst-2.1.dist-info}/WHEEL +1 -1
  26. ragaai_catalyst/tracers/agentic_tracing/Untitled-1.json +0 -660
  27. {ragaai_catalyst-2.0.7.2b0.dist-info → ragaai_catalyst-2.1.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,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
- 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)
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
- self.add_component(agent_component)
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
- # Initialize empty children list for this agent
154
- children_token = self.agent_children.set([])
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
- # Start tracking network calls for this component
161
- self.start_component(component_id)
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
- self.add_component(agent_component)
199
- return result
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
- self.add_component(agent_component)
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": None,
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) -> 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
- }
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(**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
- }]
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(**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
- }]
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()