ragaai-catalyst 2.1.3b0__py3-none-any.whl → 2.1.4b1__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 (24) hide show
  1. ragaai_catalyst/tracers/agentic_tracing/data/data_structure.py +36 -10
  2. ragaai_catalyst/tracers/agentic_tracing/tracers/agent_tracer.py +213 -76
  3. ragaai_catalyst/tracers/agentic_tracing/tracers/base.py +568 -107
  4. ragaai_catalyst/tracers/agentic_tracing/tracers/custom_tracer.py +325 -0
  5. ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py +207 -81
  6. ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py +208 -58
  7. ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py +2 -0
  8. ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py +125 -28
  9. ragaai_catalyst/tracers/agentic_tracing/tracers/user_interaction_tracer.py +86 -0
  10. ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py +9 -51
  11. ragaai_catalyst/tracers/agentic_tracing/upload/upload_trace_metric.py +83 -0
  12. ragaai_catalyst/tracers/agentic_tracing/utils/create_dataset_schema.py +26 -0
  13. ragaai_catalyst/tracers/agentic_tracing/utils/get_user_trace_metrics.py +28 -0
  14. ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +45 -15
  15. ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +2476 -2122
  16. ragaai_catalyst/tracers/agentic_tracing/utils/span_attributes.py +59 -0
  17. ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py +23 -0
  18. ragaai_catalyst/tracers/agentic_tracing/utils/zip_list_of_unique_files.py +284 -15
  19. ragaai_catalyst/tracers/tracer.py +80 -8
  20. ragaai_catalyst-2.1.4b1.dist-info/METADATA +431 -0
  21. {ragaai_catalyst-2.1.3b0.dist-info → ragaai_catalyst-2.1.4b1.dist-info}/RECORD +23 -18
  22. ragaai_catalyst-2.1.3b0.dist-info/METADATA +0 -43
  23. {ragaai_catalyst-2.1.3b0.dist-info → ragaai_catalyst-2.1.4b1.dist-info}/WHEEL +0 -0
  24. {ragaai_catalyst-2.1.3b0.dist-info → ragaai_catalyst-2.1.4b1.dist-info}/top_level.txt +0 -0
@@ -13,46 +13,113 @@ from .tool_tracer import ToolTracerMixin
13
13
  from .agent_tracer import AgentTracerMixin
14
14
  from .network_tracer import NetworkTracer
15
15
  from .user_interaction_tracer import UserInteractionTracer
16
+ from .custom_tracer import CustomTracerMixin
17
+ from ..utils.span_attributes import SpanAttributes
16
18
 
17
19
  from ..data.data_structure import (
18
- Trace, Metadata, SystemInfo, OSInfo, EnvironmentInfo,
19
- Resources, CPUResource, MemoryResource, DiskResource, NetworkResource,
20
- ResourceInfo, MemoryInfo, DiskInfo, NetworkInfo,
21
- Component, LLMComponent, AgentComponent, ToolComponent,
22
- NetworkCall, Interaction, Error
20
+ Trace,
21
+ Metadata,
22
+ SystemInfo,
23
+ OSInfo,
24
+ EnvironmentInfo,
25
+ Resources,
26
+ CPUResource,
27
+ MemoryResource,
28
+ DiskResource,
29
+ NetworkResource,
30
+ ResourceInfo,
31
+ MemoryInfo,
32
+ DiskInfo,
33
+ NetworkInfo,
34
+ Component,
35
+ LLMComponent,
36
+ AgentComponent,
37
+ ToolComponent,
38
+ NetworkCall,
39
+ Interaction,
40
+ Error,
23
41
  )
24
42
 
25
43
  from ....ragaai_catalyst import RagaAICatalyst
26
44
  from ragaai_catalyst.tracers.upload_traces import UploadTraces
27
45
 
28
- class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMixin):
29
- def __init__(self, user_detail, auto_instrument_llm: bool = True):
46
+
47
+ class AgenticTracing(
48
+ BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMixin, CustomTracerMixin
49
+ ):
50
+ def __init__(self, user_detail, auto_instrumentation=None):
30
51
  # Initialize all parent classes
31
52
  self.user_interaction_tracer = UserInteractionTracer()
32
53
  LLMTracerMixin.__init__(self)
33
54
  ToolTracerMixin.__init__(self)
34
55
  AgentTracerMixin.__init__(self)
35
-
56
+ CustomTracerMixin.__init__(self)
57
+
36
58
  self.project_name = user_detail["project_name"]
37
59
  self.project_id = user_detail["project_id"]
38
- self.dataset_name = user_detail["dataset_name"]
60
+ # self.dataset_name = user_detail["dataset_name"]
39
61
  self.trace_user_detail = user_detail["trace_user_detail"]
40
62
  self.base_url = f"{RagaAICatalyst.BASE_URL}"
41
63
  self.timeout = 10
42
64
 
43
65
  BaseTracer.__init__(self, user_detail)
44
-
45
- self.auto_instrument_llm = auto_instrument_llm
66
+
46
67
  self.tools: Dict[str, Tool] = {}
47
68
  self.call_depth = contextvars.ContextVar("call_depth", default=0)
48
- self.current_component_id = contextvars.ContextVar("current_component_id", default=None)
69
+ self.current_component_id = contextvars.ContextVar(
70
+ "current_component_id", default=None
71
+ )
49
72
  self.network_tracer = NetworkTracer()
50
- self.is_active = False
73
+
74
+ # Handle auto_instrumentation
75
+ if auto_instrumentation is None:
76
+ # Default behavior: everything enabled
77
+ self.is_active = True
78
+ self.auto_instrument_llm = True
79
+ self.auto_instrument_tool = True
80
+ self.auto_instrument_agent = True
81
+ self.auto_instrument_user_interaction = True
82
+ self.auto_instrument_file_io = True
83
+ self.auto_instrument_network = True
84
+ self.auto_instrument_custom = True
85
+ else:
86
+ # Set global active state
87
+ self.is_active = (
88
+ any(auto_instrumentation.values())
89
+ if isinstance(auto_instrumentation, dict)
90
+ else bool(auto_instrumentation)
91
+ )
92
+
93
+ # Set individual components
94
+ if isinstance(auto_instrumentation, dict):
95
+ self.auto_instrument_llm = auto_instrumentation.get("llm", False)
96
+ self.auto_instrument_tool = auto_instrumentation.get("tool", False)
97
+ self.auto_instrument_agent = auto_instrumentation.get("agent", False)
98
+ self.auto_instrument_user_interaction = auto_instrumentation.get(
99
+ "user_interaction", False
100
+ )
101
+ self.auto_instrument_file_io = auto_instrumentation.get(
102
+ "file_io", False
103
+ )
104
+ self.auto_instrument_network = auto_instrumentation.get(
105
+ "network", False
106
+ )
107
+ self.auto_instrument_custom = auto_instrumentation.get("custom", False)
108
+ else:
109
+ # If boolean provided, apply to all components
110
+ self.auto_instrument_llm = bool(auto_instrumentation)
111
+ self.auto_instrument_tool = bool(auto_instrumentation)
112
+ self.auto_instrument_agent = bool(auto_instrumentation)
113
+ self.auto_instrument_user_interaction = bool(auto_instrumentation)
114
+ self.auto_instrument_file_io = bool(auto_instrumentation)
115
+ self.auto_instrument_network = bool(auto_instrumentation)
116
+ self.auto_instrument_custom = bool(auto_instrumentation)
117
+
51
118
  self.current_agent_id = contextvars.ContextVar("current_agent_id", default=None)
52
119
  self.agent_children = contextvars.ContextVar("agent_children", default=[])
53
120
  self.component_network_calls = {} # Store network calls per component
54
121
  self.component_user_interaction = {}
55
-
122
+
56
123
  # Create output directory if it doesn't exist
57
124
  self.output_dir = Path("./traces") # Using default traces directory
58
125
  self.output_dir.mkdir(exist_ok=True)
@@ -61,19 +128,26 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
61
128
  """Start tracking network calls for a component"""
62
129
  self.component_network_calls[component_id] = []
63
130
  self.network_tracer.network_calls = [] # Reset network calls
64
- self.component_user_interaction[component_id] = []
65
131
  self.current_component_id.set(component_id)
66
132
  self.user_interaction_tracer.component_id.set(component_id)
67
133
 
68
134
  def end_component(self, component_id: str):
69
135
  """End tracking network calls for a component"""
70
- self.component_network_calls[component_id] = self.network_tracer.network_calls.copy()
136
+ self.component_network_calls[component_id] = (
137
+ self.network_tracer.network_calls.copy()
138
+ )
71
139
  self.network_tracer.network_calls = [] # Reset for next component
72
- self.component_user_interaction[component_id] = self.user_interaction_tracer.interactions.copy()
73
- self.user_interaction_tracer.interactions = []
140
+ self.component_user_interaction[component_id] = [
141
+ interaction
142
+ for interaction in self.user_interaction_tracer.interactions
143
+ if interaction.get("component_id") == component_id
144
+ ]
74
145
 
75
146
  def start(self):
76
147
  """Start tracing"""
148
+ if not self.is_active:
149
+ return
150
+
77
151
  # Setup user interaction tracing
78
152
  self.user_interaction_tracer.project_id.set(self.project_id)
79
153
  self.user_interaction_tracer.trace_id.set(self.trace_id)
@@ -81,84 +155,112 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
81
155
  self.user_interaction_tracer.component_id.set(self.current_component_id.get())
82
156
  builtins.print = self.user_interaction_tracer.traced_print
83
157
  builtins.input = self.user_interaction_tracer.traced_input
84
-
158
+ builtins.open = self.user_interaction_tracer.traced_open
159
+
85
160
  # Start base tracer (includes system info and resource monitoring)
86
161
  super().start()
87
- self.is_active = True
88
-
162
+
89
163
  # Activate network tracing
90
164
  self.network_tracer.activate_patches()
91
-
92
- # Instrument calls from mixins
165
+
166
+ # take care of the auto instrumentation
93
167
  if self.auto_instrument_llm:
94
168
  self.instrument_llm_calls()
95
169
 
170
+ if self.auto_instrument_tool:
171
+ self.instrument_tool_calls()
172
+
173
+ if self.auto_instrument_agent:
174
+ self.instrument_agent_calls()
175
+
176
+ if self.auto_instrument_custom:
177
+ self.instrument_custom_calls()
178
+
179
+ if self.auto_instrument_user_interaction:
180
+
181
+ ToolTracerMixin.instrument_user_interaction_calls(self)
182
+ LLMTracerMixin.instrument_user_interaction_calls(self)
183
+ AgentTracerMixin.instrument_user_interaction_calls(self)
184
+ CustomTracerMixin.instrument_user_interaction_calls(self)
185
+
186
+ if self.auto_instrument_network:
187
+ ToolTracerMixin.instrument_network_calls(self)
188
+ LLMTracerMixin.instrument_network_calls(self)
189
+ AgentTracerMixin.instrument_network_calls(self)
190
+ CustomTracerMixin.instrument_network_calls(self)
191
+
192
+ # These will be implemented later
193
+ # if self.auto_instrument_file_io:
194
+ # self.instrument_file_io_calls()
195
+
96
196
  def stop(self):
97
197
  """Stop tracing and save results"""
98
198
  if self.is_active:
99
199
  # Restore original print and input functions
100
200
  builtins.print = self.user_interaction_tracer.original_print
101
201
  builtins.input = self.user_interaction_tracer.original_input
102
-
202
+ builtins.open = self.user_interaction_tracer.original_open
203
+
103
204
  # Calculate final metrics before stopping
104
205
  self._calculate_final_metrics()
105
-
206
+
106
207
  # Deactivate network tracing
107
208
  self.network_tracer.deactivate_patches()
108
-
209
+
109
210
  # Stop base tracer (includes saving to file)
110
211
  super().stop()
111
-
212
+
112
213
  # Cleanup
113
214
  self.unpatch_llm_calls()
114
215
  self.user_interaction_tracer.interactions = [] # Clear interactions list
115
216
  self.is_active = False
116
217
 
117
-
118
218
  def _calculate_final_metrics(self):
119
219
  """Calculate total cost and tokens from all components"""
120
220
  total_cost = 0.0
121
221
  total_tokens = 0
122
-
222
+
123
223
  def process_component(component):
124
224
  nonlocal total_cost, total_tokens
125
225
  # Convert component to dict if it's an object
126
- comp_dict = component.__dict__ if hasattr(component, '__dict__') else component
127
-
128
- if comp_dict.get('type') == "llm":
129
- info = comp_dict.get('info', {})
226
+ comp_dict = (
227
+ component.__dict__ if hasattr(component, "__dict__") else component
228
+ )
229
+
230
+ if comp_dict.get("type") == "llm":
231
+ info = comp_dict.get("info", {})
130
232
  if isinstance(info, dict):
131
233
  # Extract cost
132
- cost_info = info.get('cost', {})
234
+ cost_info = info.get("cost", {})
133
235
  if isinstance(cost_info, dict):
134
- total_cost += cost_info.get('total_cost', 0)
135
-
236
+ total_cost += cost_info.get("total_cost", 0)
237
+
136
238
  # Extract tokens
137
- token_info = info.get('tokens', {})
239
+ token_info = info.get("tokens", {})
138
240
  if isinstance(token_info, dict):
139
- total_tokens += token_info.get('total_tokens', 0)
241
+ total_tokens += token_info.get("total_tokens", 0)
140
242
  else:
141
- token_info = info.get('token_usage', {})
243
+ token_info = info.get("token_usage", {})
142
244
  if isinstance(token_info, dict):
143
- total_tokens += token_info.get('total_tokens', 0)
144
-
245
+ total_tokens += token_info.get("total_tokens", 0)
246
+
145
247
  # Process children if they exist
146
- data = comp_dict.get('data', {})
248
+ data = comp_dict.get("data", {})
147
249
  if isinstance(data, dict):
148
- children = data.get('children', [])
250
+ children = data.get("children", [])
149
251
  if children:
150
252
  for child in children:
151
253
  process_component(child)
152
-
254
+
153
255
  # Process all root components
154
256
  for component in self.components:
155
257
  process_component(component)
156
-
258
+
157
259
  # Update metadata in trace
158
- if hasattr(self, 'trace'):
260
+ if hasattr(self, "trace"):
159
261
  if isinstance(self.trace.metadata, dict):
160
- self.trace.metadata['total_cost'] = total_cost
161
- self.trace.metadata['total_tokens'] = total_tokens
262
+ self.trace.metadata["total_cost"] = total_cost
263
+ self.trace.metadata["total_tokens"] = total_tokens
162
264
  else:
163
265
  self.trace.metadata.total_cost = total_cost
164
266
  self.trace.metadata.total_tokens = total_tokens
@@ -166,11 +268,34 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
166
268
  def add_component(self, component_data: dict, is_error: bool = False):
167
269
  """Add a component to the trace data"""
168
270
  # Convert dict to appropriate Component type
169
- filtered_data = {k: v for k, v in component_data.items() if k in ["id", "hash_id", "source_hash_id", "type", "name", "start_time", "end_time", "parent_id", "info", "extra_info", "data", "network_calls", "interactions", "error"]}
271
+ filtered_data = {
272
+ k: v
273
+ for k, v in component_data.items()
274
+ if k
275
+ in [
276
+ "id",
277
+ "hash_id",
278
+ "source_hash_id",
279
+ "type",
280
+ "name",
281
+ "start_time",
282
+ "end_time",
283
+ "parent_id",
284
+ "info",
285
+ "extra_info",
286
+ "data",
287
+ "metadata",
288
+ "metrics",
289
+ "feedback",
290
+ "network_calls",
291
+ "interactions",
292
+ "error",
293
+ ]
294
+ }
170
295
 
171
296
  if component_data["type"] == "llm":
172
297
  component = LLMComponent(**filtered_data)
173
- elif component_data["type"] == "agent":
298
+ elif component_data["type"] == "agent":
174
299
  component = AgentComponent(**filtered_data)
175
300
  elif component_data["type"] == "tool":
176
301
  component = ToolComponent(**filtered_data)
@@ -187,21 +312,27 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
187
312
  else:
188
313
  # Add component to the main trace
189
314
  super().add_component(component)
190
-
315
+
191
316
  # Handle error case
192
317
  if is_error:
193
318
  # Get the parent component if it exists
194
319
  parent_id = component_data.get("parent_id")
195
320
  children = self.agent_children.get()
196
-
321
+
197
322
  # Set parent_id for all children
198
323
  for child in children:
199
324
  child["parent_id"] = parent_id
200
-
325
+
201
326
  agent_tracer_mixin = AgentTracerMixin()
202
327
  agent_tracer_mixin.component_network_calls = self.component_network_calls
203
- agent_tracer_mixin.component_user_interaction = self.component_user_interaction
204
-
328
+ agent_tracer_mixin.component_user_interaction = (
329
+ self.component_user_interaction
330
+ )
331
+
332
+ agent_tracer_mixin.span_attributes_dict[self.current_agent_name.get()] = (
333
+ SpanAttributes(self.current_agent_name.get())
334
+ )
335
+
205
336
  # Create parent component with error info
206
337
  parent_component = agent_tracer_mixin.create_agent_component(
207
338
  component_id=parent_id,
@@ -218,10 +349,29 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
218
349
  input_data=self.input_data,
219
350
  output_data=None,
220
351
  children=children,
221
- parent_id=None # Add parent ID if exists
352
+ parent_id=None, # Add parent ID if exists
222
353
  )
223
354
 
224
- filtered_data = {k: v for k, v in parent_component.items() if k in ["id", "hash_id", "source_hash_id", "type", "name", "start_time", "end_time", "parent_id", "info", "data", "network_calls", "interactions", "error"]}
355
+ filtered_data = {
356
+ k: v
357
+ for k, v in parent_component.items()
358
+ if k
359
+ in [
360
+ "id",
361
+ "hash_id",
362
+ "source_hash_id",
363
+ "type",
364
+ "name",
365
+ "start_time",
366
+ "end_time",
367
+ "parent_id",
368
+ "info",
369
+ "data",
370
+ "network_calls",
371
+ "interactions",
372
+ "error",
373
+ ]
374
+ }
225
375
  parent_agent_component = AgentComponent(**filtered_data)
226
376
  # Add the parent component to trace and stop tracing
227
377
  super().add_component(parent_agent_component)
@@ -234,4 +384,4 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
234
384
 
235
385
  def __exit__(self, exc_type, exc_value, traceback):
236
386
  """Context manager exit"""
237
- self.stop()
387
+ self.stop()
@@ -47,6 +47,8 @@ class NetworkTracer:
47
47
  "url": url,
48
48
  "method": method,
49
49
  "status_code": status_code,
50
+ "start_time": start_time.isoformat() if start_time else None,
51
+ "end_time": end_time.isoformat() if end_time else None,
50
52
  "response_time": duration,
51
53
  "bytes_sent": bytes_sent,
52
54
  "bytes_received": bytes_received,