ragaai-catalyst 2.1.3__py3-none-any.whl → 2.1.4__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/tracers/agentic_tracing/data/data_structure.py +37 -11
  2. ragaai_catalyst/tracers/agentic_tracing/tracers/agent_tracer.py +240 -81
  3. ragaai_catalyst/tracers/agentic_tracing/tracers/base.py +632 -114
  4. ragaai_catalyst/tracers/agentic_tracing/tracers/custom_tracer.py +316 -0
  5. ragaai_catalyst/tracers/agentic_tracing/tracers/langgraph_tracer.py +0 -0
  6. ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py +229 -82
  7. ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py +214 -59
  8. ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py +16 -14
  9. ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py +147 -28
  10. ragaai_catalyst/tracers/agentic_tracing/tracers/user_interaction_tracer.py +88 -2
  11. ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py +9 -51
  12. ragaai_catalyst/tracers/agentic_tracing/upload/upload_trace_metric.py +83 -0
  13. ragaai_catalyst/tracers/agentic_tracing/utils/create_dataset_schema.py +26 -0
  14. ragaai_catalyst/tracers/agentic_tracing/utils/get_user_trace_metrics.py +28 -0
  15. ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +45 -15
  16. ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +2520 -2152
  17. ragaai_catalyst/tracers/agentic_tracing/utils/span_attributes.py +59 -0
  18. ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py +23 -0
  19. ragaai_catalyst/tracers/agentic_tracing/utils/zip_list_of_unique_files.py +284 -15
  20. ragaai_catalyst/tracers/llamaindex_callback.py +5 -5
  21. ragaai_catalyst/tracers/tracer.py +83 -10
  22. ragaai_catalyst/tracers/upload_traces.py +1 -1
  23. ragaai_catalyst-2.1.4.dist-info/METADATA +431 -0
  24. {ragaai_catalyst-2.1.3.dist-info → ragaai_catalyst-2.1.4.dist-info}/RECORD +26 -20
  25. ragaai_catalyst-2.1.3.dist-info/METADATA +0 -43
  26. {ragaai_catalyst-2.1.3.dist-info → ragaai_catalyst-2.1.4.dist-info}/WHEEL +0 -0
  27. {ragaai_catalyst-2.1.3.dist-info → ragaai_catalyst-2.1.4.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import os
1
2
  import functools
2
3
  import uuid
3
4
  from datetime import datetime
@@ -7,6 +8,15 @@ from ..utils.unique_decorator import mydecorator, generate_unique_hash_simple
7
8
  import contextvars
8
9
  import asyncio
9
10
  from ..utils.file_name_tracker import TrackName
11
+ from ..utils.span_attributes import SpanAttributes
12
+ import logging
13
+
14
+ logger = logging.getLogger(__name__)
15
+ logging_level = (
16
+ logger.setLevel(logging.DEBUG)
17
+ if os.getenv("DEBUG")
18
+ else logger.setLevel(logging.INFO)
19
+ )
10
20
 
11
21
 
12
22
  class AgentTracerMixin:
@@ -16,42 +26,91 @@ class AgentTracerMixin:
16
26
  self.current_agent_id = contextvars.ContextVar("agent_id", default=None)
17
27
  self.current_agent_name = contextvars.ContextVar("agent_name", default=None)
18
28
  self.agent_children = contextvars.ContextVar("agent_children", default=[])
19
- self.component_network_calls = contextvars.ContextVar("component_network_calls", default={})
20
- self.component_user_interaction = contextvars.ContextVar("component_user_interaction", default={})
21
- self.version = contextvars.ContextVar("version", default="1.0.0")
29
+ self.component_network_calls = contextvars.ContextVar(
30
+ "component_network_calls", default={}
31
+ )
32
+ self.component_user_interaction = contextvars.ContextVar(
33
+ "component_user_interaction", default={}
34
+ )
35
+ self.version = contextvars.ContextVar("version", default=None)
22
36
  self.agent_type = contextvars.ContextVar("agent_type", default="generic")
23
37
  self.capabilities = contextvars.ContextVar("capabilities", default=[])
24
38
  self.start_time = contextvars.ContextVar("start_time", default=None)
25
39
  self.input_data = contextvars.ContextVar("input_data", default=None)
26
40
  self.gt = None
27
41
 
42
+ self.span_attributes_dict = {}
43
+
44
+ # Add auto instrument flags
45
+ self.auto_instrument_agent = False
46
+ self.auto_instrument_user_interaction = False
47
+ self.auto_instrument_network = False
48
+
49
+ def trace_agent(
50
+ self,
51
+ name: str,
52
+ agent_type: str = None,
53
+ version: str = None,
54
+ capabilities: List[str] = None,
55
+ tags: List[str] = [],
56
+ metadata: Dict[str, Any] = {},
57
+ metrics: List[Dict[str, Any]] = [],
58
+ feedback: Optional[Any] = None,
59
+ ):
60
+ if name not in self.span_attributes_dict:
61
+ self.span_attributes_dict[name] = SpanAttributes(name)
62
+ if tags:
63
+ self.span(name).add_tags(tags)
64
+ if metadata:
65
+ self.span(name).add_metadata(metadata)
66
+ if metrics:
67
+ if isinstance(metrics, dict):
68
+ metrics = [metrics]
69
+ try:
70
+ for metric in metrics:
71
+ self.span(name).add_metrics(
72
+ name=metric["name"],
73
+ score=metric["score"],
74
+ reasoning=metric.get("reasoning", ""),
75
+ cost=metric.get("cost", None),
76
+ latency=metric.get("latency", None),
77
+ metadata=metric.get("metadata", {}),
78
+ config=metric.get("config", {}),
79
+ )
80
+ except ValueError as e:
81
+ logger.error(f"Validation Error: {e}")
82
+ except Exception as e:
83
+ logger.error(f"Error adding metric: {e}")
84
+ if feedback:
85
+ self.span(name).add_feedback(feedback)
28
86
 
29
- def trace_agent(self, name: str, agent_type: str = None, version: str = None, capabilities: List[str] = None):
30
87
  def decorator(target):
31
88
  # Check if target is a class
32
89
  is_class = isinstance(target, type)
33
90
  tracer = self # Store reference to tracer instance
34
- top_level_hash_id = generate_unique_hash_simple(target) # Generate hash based on the decorated target code
91
+ top_level_hash_id = generate_unique_hash_simple(
92
+ target
93
+ ) # Generate hash based on the decorated target code
35
94
  self.version.set(version)
36
95
  self.agent_type.set(agent_type)
37
96
  self.capabilities.set(capabilities)
38
-
97
+
39
98
  if is_class:
40
99
  # Store original __init__
41
100
  original_init = target.__init__
42
-
101
+
43
102
  def wrapped_init(self, *args, **kwargs):
44
- self.gt = kwargs.get('gt', None) if kwargs else None
103
+ self.gt = kwargs.get("gt", None) if kwargs else None
45
104
  # Set agent context before initializing
46
105
  component_id = str(uuid.uuid4())
47
106
  hash_id = top_level_hash_id
48
-
107
+
49
108
  # Store the component ID in the instance
50
109
  self._agent_component_id = component_id
51
-
110
+
52
111
  # Get parent agent ID if exists
53
112
  parent_agent_id = tracer.current_agent_id.get()
54
-
113
+
55
114
  # Create agent component
56
115
  agent_component = tracer.create_agent_component(
57
116
  component_id=component_id,
@@ -60,19 +119,19 @@ class AgentTracerMixin:
60
119
  agent_type=agent_type,
61
120
  version=version,
62
121
  capabilities=capabilities or [],
63
- start_time=datetime.now(),
122
+ start_time=datetime.now().astimezone().isoformat(),
64
123
  memory_used=0,
65
124
  input_data=tracer._sanitize_input(args, kwargs),
66
125
  output_data=None,
67
126
  children=[],
68
- parent_id=parent_agent_id
127
+ parent_id=parent_agent_id,
69
128
  )
70
-
129
+
71
130
  # Store component for later updates
72
- if not hasattr(tracer, '_agent_components'):
131
+ if not hasattr(tracer, "_agent_components"):
73
132
  tracer._agent_components = {}
74
133
  tracer._agent_components[component_id] = agent_component
75
-
134
+
76
135
  # If this is a nested agent, add it to parent's children
77
136
  if parent_agent_id:
78
137
  parent_children = tracer.agent_children.get()
@@ -81,61 +140,82 @@ class AgentTracerMixin:
81
140
  else:
82
141
  # Only add to root components if no parent
83
142
  tracer.add_component(agent_component)
84
-
143
+
85
144
  # Call original __init__ with this agent as current
86
145
  token = tracer.current_agent_id.set(component_id)
87
146
  try:
88
147
  original_init(self, *args, **kwargs)
89
148
  finally:
90
149
  tracer.current_agent_id.reset(token)
91
-
150
+
92
151
  # Wrap all public methods to track execution
93
152
  for attr_name in dir(target):
94
- if not attr_name.startswith('_'):
153
+ if not attr_name.startswith("_"):
95
154
  attr_value = getattr(target, attr_name)
96
155
  if callable(attr_value):
156
+
97
157
  def wrap_method(method):
98
158
  @self.file_tracker.trace_decorator
99
159
  @functools.wraps(method)
100
160
  def wrapped_method(self, *args, **kwargs):
101
- self.gt = kwargs.get('gt', None) if kwargs else None
161
+ self.gt = kwargs.get("gt", None) if kwargs else None
102
162
  # Set this agent as current during method execution
103
- token = tracer.current_agent_id.set(self._agent_component_id)
104
-
163
+ token = tracer.current_agent_id.set(
164
+ self._agent_component_id
165
+ )
166
+
105
167
  # Store parent's children before setting new empty list
106
168
  parent_children = tracer.agent_children.get()
107
169
  children_token = tracer.agent_children.set([])
108
-
170
+
109
171
  try:
110
- start_time = datetime.now()
172
+ start_time = datetime.now().astimezone().isoformat()
111
173
  result = method(self, *args, **kwargs)
112
-
174
+
113
175
  # Update agent component with method result
114
- if hasattr(tracer, '_agent_components'):
115
- component = tracer._agent_components.get(self._agent_component_id)
176
+ if hasattr(tracer, "_agent_components"):
177
+ component = tracer._agent_components.get(
178
+ self._agent_component_id
179
+ )
116
180
  if component:
117
- component['data']['output'] = tracer._sanitize_output(result)
118
- component['data']['input'] = tracer._sanitize_input(args, kwargs)
119
- component['start_time'] = start_time.isoformat()
120
-
181
+ component["data"]["output"] = (
182
+ tracer._sanitize_output(result)
183
+ )
184
+ component["data"]["input"] = (
185
+ tracer._sanitize_input(args, kwargs)
186
+ )
187
+ component["start_time"] = (
188
+ start_time
189
+ )
190
+
121
191
  # Get children accumulated during method execution
122
192
  children = tracer.agent_children.get()
123
193
  if children:
124
- if 'children' not in component['data']:
125
- component['data']['children'] = []
126
- component['data']['children'].extend(children)
127
-
194
+ if (
195
+ "children"
196
+ not in component["data"]
197
+ ):
198
+ component["data"][
199
+ "children"
200
+ ] = []
201
+ component["data"][
202
+ "children"
203
+ ].extend(children)
204
+
128
205
  # Add this component as a child to parent's children list
129
206
  parent_children.append(component)
130
- tracer.agent_children.set(parent_children)
207
+ tracer.agent_children.set(
208
+ parent_children
209
+ )
131
210
  return result
132
211
  finally:
133
212
  tracer.current_agent_id.reset(token)
134
213
  tracer.agent_children.reset(children_token)
214
+
135
215
  return wrapped_method
136
-
216
+
137
217
  setattr(target, attr_name, wrap_method(attr_value))
138
-
218
+
139
219
  # Replace __init__ with wrapped version
140
220
  target.__init__ = wrapped_init
141
221
  return target
@@ -143,17 +223,40 @@ class AgentTracerMixin:
143
223
  # For function decorators, use existing sync/async tracing
144
224
  is_async = asyncio.iscoroutinefunction(target)
145
225
  if is_async:
226
+
146
227
  async def wrapper(*args, **kwargs):
147
- return await self._trace_agent_execution(target, name, agent_type, version, capabilities, top_level_hash_id, *args, **kwargs)
228
+ return await self._trace_agent_execution(
229
+ target,
230
+ name,
231
+ agent_type,
232
+ version,
233
+ capabilities,
234
+ top_level_hash_id,
235
+ *args,
236
+ **kwargs,
237
+ )
238
+
148
239
  return wrapper
149
240
  else:
241
+
150
242
  def wrapper(*args, **kwargs):
151
- return self._trace_sync_agent_execution(target, name, agent_type, version, capabilities, *args, **kwargs)
243
+ return self._trace_sync_agent_execution(
244
+ target,
245
+ name,
246
+ agent_type,
247
+ version,
248
+ capabilities,
249
+ *args,
250
+ **kwargs,
251
+ )
252
+
152
253
  return wrapper
153
254
 
154
255
  return decorator
155
256
 
156
- def _trace_sync_agent_execution(self, func, name, agent_type, version, capabilities, *args, **kwargs):
257
+ def _trace_sync_agent_execution(
258
+ self, func, name, agent_type, version, capabilities, *args, **kwargs
259
+ ):
157
260
  # Generate a unique hash_id for this execution context
158
261
  hash_id = str(uuid.uuid4())
159
262
 
@@ -161,18 +264,21 @@ class AgentTracerMixin:
161
264
  if not self.is_active:
162
265
  return func(*args, **kwargs)
163
266
 
164
- start_time = datetime.now()
267
+ if not self.auto_instrument_agent:
268
+ return func(*args, **kwargs)
269
+
270
+ start_time = datetime.now().astimezone().isoformat()
165
271
  self.start_time = start_time
166
272
  self.input_data = self._sanitize_input(args, kwargs)
167
273
  start_memory = psutil.Process().memory_info().rss
168
274
  component_id = str(uuid.uuid4())
169
275
 
170
276
  # Extract ground truth if present
171
- ground_truth = kwargs.pop('gt', None) if kwargs else None
277
+ ground_truth = kwargs.pop("gt", None) if kwargs else None
172
278
 
173
279
  # Get parent agent ID if exists
174
280
  parent_agent_id = self.current_agent_id.get()
175
-
281
+
176
282
  # Set the current agent context
177
283
  agent_token = self.current_agent_id.set(component_id)
178
284
  agent_name_token = self.current_agent_name.set(name)
@@ -180,7 +286,7 @@ class AgentTracerMixin:
180
286
  # Initialize empty children list for this agent
181
287
  parent_children = self.agent_children.get()
182
288
  children_token = self.agent_children.set([])
183
-
289
+
184
290
  # Start tracking network calls for this component
185
291
  self.start_component(component_id)
186
292
 
@@ -211,12 +317,12 @@ class AgentTracerMixin:
211
317
  input_data=self.input_data,
212
318
  output_data=self._sanitize_output(result),
213
319
  children=children,
214
- parent_id=parent_agent_id
320
+ parent_id=parent_agent_id,
215
321
  )
216
322
  # Add ground truth to component data if present
217
323
  if ground_truth is not None:
218
324
  agent_component["data"]["gt"] = ground_truth
219
-
325
+
220
326
  # Add this component as a child to parent's children list
221
327
  parent_children.append(agent_component)
222
328
  self.agent_children.set(parent_children)
@@ -231,19 +337,19 @@ class AgentTracerMixin:
231
337
  "code": 500,
232
338
  "type": type(e).__name__,
233
339
  "message": str(e),
234
- "details": {}
340
+ "details": {},
235
341
  }
236
-
342
+
237
343
  # Get children even in case of error
238
344
  children = self.agent_children.get()
239
-
345
+
240
346
  # Set parent_id for all children
241
347
  for child in children:
242
348
  child["parent_id"] = component_id
243
-
349
+
244
350
  # End tracking network calls for this component
245
351
  self.end_component(component_id)
246
-
352
+
247
353
  agent_component = self.create_agent_component(
248
354
  component_id=component_id,
249
355
  hash_id=hash_id,
@@ -257,39 +363,45 @@ class AgentTracerMixin:
257
363
  output_data=None,
258
364
  error=error_component,
259
365
  children=children,
260
- parent_id=parent_agent_id # Add parent ID if exists
366
+ parent_id=parent_agent_id, # Add parent ID if exists
261
367
  )
262
368
  # If this is a nested agent, add it to parent's children
263
369
  if parent_agent_id:
264
370
  parent_component = self._agent_components.get(parent_agent_id)
265
371
  if parent_component:
266
- if 'children' not in parent_component['data']:
267
- parent_component['data']['children'] = []
268
- parent_component['data']['children'].append(agent_component)
372
+ if "children" not in parent_component["data"]:
373
+ parent_component["data"]["children"] = []
374
+ parent_component["data"]["children"].append(agent_component)
269
375
  else:
270
376
  # Only add to root components if no parent
271
377
  self.add_component(agent_component)
378
+
272
379
  raise
273
380
  finally:
274
381
  self.current_agent_id.reset(agent_token)
275
382
  self.current_agent_name.reset(agent_name_token)
276
383
  self.agent_children.reset(children_token)
277
384
 
278
- async def _trace_agent_execution(self, func, name, agent_type, version, capabilities, hash_id, *args, **kwargs):
385
+ async def _trace_agent_execution(
386
+ self, func, name, agent_type, version, capabilities, hash_id, *args, **kwargs
387
+ ):
279
388
  """Asynchronous version of agent tracing"""
280
389
  if not self.is_active:
281
390
  return await func(*args, **kwargs)
282
391
 
283
- start_time = datetime.now()
392
+ if not self.auto_instrument_agent:
393
+ return await func(*args, **kwargs)
394
+
395
+ start_time = datetime.now().astimezone().isoformat()
284
396
  start_memory = psutil.Process().memory_info().rss
285
397
  component_id = str(uuid.uuid4())
286
398
 
287
399
  # Extract ground truth if present
288
- ground_truth = kwargs.pop('gt', None) if kwargs else None
400
+ ground_truth = kwargs.pop("gt", None) if kwargs else None
289
401
 
290
402
  # Get parent agent ID if exists
291
403
  parent_agent_id = self.current_agent_id.get()
292
-
404
+
293
405
  # Set the current agent context
294
406
  agent_token = self.current_agent_id.set(component_id)
295
407
  agent_name_token = self.current_agent_name.set(name)
@@ -297,6 +409,7 @@ class AgentTracerMixin:
297
409
  # Initialize empty children list for this agent
298
410
  parent_children = self.agent_children.get()
299
411
  children_token = self.agent_children.set([])
412
+ self.start_component(component_id)
300
413
 
301
414
  try:
302
415
  # Execute the agent
@@ -309,6 +422,8 @@ class AgentTracerMixin:
309
422
  # Get children components collected during execution
310
423
  children = self.agent_children.get()
311
424
 
425
+ self.end_component(component_id)
426
+
312
427
  # Create agent component with children and parent if exists
313
428
  agent_component = self.create_agent_component(
314
429
  component_id=component_id,
@@ -322,7 +437,7 @@ class AgentTracerMixin:
322
437
  input_data=self._sanitize_input(args, kwargs),
323
438
  output_data=self._sanitize_output(result),
324
439
  children=children,
325
- parent_id=parent_agent_id
440
+ parent_id=parent_agent_id,
326
441
  )
327
442
 
328
443
  # Add ground truth to component data if present
@@ -343,19 +458,19 @@ class AgentTracerMixin:
343
458
  "code": 500,
344
459
  "type": type(e).__name__,
345
460
  "message": str(e),
346
- "details": {}
461
+ "details": {},
347
462
  }
348
-
463
+
349
464
  # Get children even in case of error
350
465
  children = self.agent_children.get()
351
-
466
+
352
467
  # Set parent_id for all children
353
468
  for child in children:
354
469
  child["parent_id"] = component_id
355
-
470
+
356
471
  # End tracking network calls for this component
357
472
  self.end_component(component_id)
358
-
473
+
359
474
  agent_component = self.create_agent_component(
360
475
  component_id=component_id,
361
476
  hash_id=hash_id,
@@ -369,19 +484,20 @@ class AgentTracerMixin:
369
484
  output_data=None,
370
485
  error=error_component,
371
486
  children=children,
372
- parent_id=parent_agent_id # Add parent ID if exists
487
+ parent_id=parent_agent_id, # Add parent ID if exists
373
488
  )
374
-
489
+
375
490
  # If this is a nested agent, add it to parent's children
376
491
  if parent_agent_id:
377
492
  parent_component = self._agent_components.get(parent_agent_id)
378
493
  if parent_component:
379
- if 'children' not in parent_component['data']:
380
- parent_component['data']['children'] = []
381
- parent_component['data']['children'].append(agent_component)
494
+ if "children" not in parent_component["data"]:
495
+ parent_component["data"]["children"] = []
496
+ parent_component["data"]["children"].append(agent_component)
382
497
  else:
383
498
  # Only add to root components if no parent
384
499
  self.add_component(agent_component)
500
+
385
501
  raise
386
502
  finally:
387
503
  # Reset context variables
@@ -391,14 +507,42 @@ class AgentTracerMixin:
391
507
 
392
508
  def create_agent_component(self, **kwargs):
393
509
  """Create an agent component according to the data structure"""
510
+ network_calls = []
511
+ if self.auto_instrument_network:
512
+ network_calls = self.component_network_calls.get(kwargs["component_id"], [])
513
+ interactions = []
514
+ if self.auto_instrument_user_interaction:
515
+ interactions = self.component_user_interaction.get(
516
+ kwargs["component_id"], []
517
+ )
394
518
  start_time = kwargs["start_time"]
519
+
520
+ # Get tags, metrics
521
+ name = kwargs["name"]
522
+ # tags
523
+ tags = []
524
+ if name in self.span_attributes_dict:
525
+ tags = self.span_attributes_dict[name].tags or []
526
+
527
+ # metrics
528
+ metrics = []
529
+ if name in self.span_attributes_dict:
530
+ raw_metrics = self.span_attributes_dict[name].metrics or []
531
+ for metric in raw_metrics:
532
+ base_metric_name = metric["name"]
533
+ counter = sum(1 for x in self.visited_metrics if x.startswith(base_metric_name))
534
+ metric_name = f'{base_metric_name}_{counter}' if counter > 0 else base_metric_name
535
+ self.visited_metrics.append(metric_name)
536
+ metric["name"] = metric_name
537
+ metrics.append(metric)
538
+
395
539
  component = {
396
540
  "id": kwargs["component_id"],
397
541
  "hash_id": kwargs["hash_id"],
398
542
  "source_hash_id": None,
399
543
  "type": "agent",
400
544
  "name": kwargs["name"],
401
- "start_time": start_time.isoformat(),
545
+ "start_time": start_time,
402
546
  "end_time": datetime.now().astimezone().isoformat(),
403
547
  "error": kwargs.get("error"),
404
548
  "parent_id": kwargs.get("parent_id"),
@@ -406,20 +550,25 @@ class AgentTracerMixin:
406
550
  "agent_type": kwargs["agent_type"],
407
551
  "version": kwargs["version"],
408
552
  "capabilities": kwargs["capabilities"],
409
- "memory_used": kwargs["memory_used"]
553
+ "memory_used": kwargs["memory_used"],
554
+ "tags": tags,
410
555
  },
411
556
  "data": {
412
557
  "input": kwargs["input_data"],
413
558
  "output": kwargs["output_data"],
414
- "children": kwargs.get("children", [])
559
+ "children": kwargs.get("children", []),
415
560
  },
416
- "network_calls": self.component_network_calls.get(kwargs["component_id"], []),
417
- "interactions": self.component_user_interaction.get(kwargs["component_id"], [])
561
+ "metrics": metrics,
562
+ "network_calls": network_calls,
563
+ "interactions": interactions,
418
564
  }
419
565
 
420
- if self.gt:
566
+ if self.gt:
421
567
  component["data"]["gt"] = self.gt
422
568
 
569
+ # Reset the SpanAttributes context variable
570
+ self.span_attributes_dict[kwargs["name"]] = SpanAttributes(kwargs["name"])
571
+
423
572
  return component
424
573
 
425
574
  def start_component(self, component_id):
@@ -438,21 +587,22 @@ class AgentTracerMixin:
438
587
 
439
588
  def _sanitize_input(self, args: tuple, kwargs: dict) -> str:
440
589
  """Convert input arguments to text format.
441
-
590
+
442
591
  Args:
443
592
  args: Input arguments tuple
444
593
  kwargs: Input keyword arguments dict
445
-
594
+
446
595
  Returns:
447
596
  str: Text representation of the input arguments
448
597
  """
598
+
449
599
  def _sanitize_value(value):
450
600
  if isinstance(value, dict):
451
601
  return str({k: _sanitize_value(v) for k, v in value.items()})
452
602
  elif isinstance(value, (list, tuple)):
453
603
  return str([_sanitize_value(item) for item in value])
454
604
  return str(value)
455
-
605
+
456
606
  sanitized_args = [_sanitize_value(arg) for arg in args]
457
607
  sanitized_kwargs = {k: _sanitize_value(v) for k, v in kwargs.items()}
458
608
  return str({"args": sanitized_args, "kwargs": sanitized_kwargs})
@@ -461,4 +611,13 @@ class AgentTracerMixin:
461
611
  """Sanitize and format output data"""
462
612
  if isinstance(output, (int, float, bool, str, list, dict)):
463
613
  return output
464
- return str(output)
614
+ return str(output)
615
+
616
+ def instrument_agent_calls(self):
617
+ self.auto_instrument_agent = True
618
+
619
+ def instrument_user_interaction_calls(self):
620
+ self.auto_instrument_user_interaction = True
621
+
622
+ def instrument_network_calls(self):
623
+ self.auto_instrument_network = True