ragaai-catalyst 2.1.4b0__py3-none-any.whl → 2.1.4b2__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 (23) hide show
  1. ragaai_catalyst/tracers/agentic_tracing/data/data_structure.py +36 -10
  2. ragaai_catalyst/tracers/agentic_tracing/tracers/agent_tracer.py +226 -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 +218 -81
  6. ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py +210 -58
  7. ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py +2 -0
  8. ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py +137 -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 +77 -8
  20. {ragaai_catalyst-2.1.4b0.dist-info → ragaai_catalyst-2.1.4b2.dist-info}/METADATA +2 -1
  21. {ragaai_catalyst-2.1.4b0.dist-info → ragaai_catalyst-2.1.4b2.dist-info}/RECORD +23 -18
  22. {ragaai_catalyst-2.1.4b0.dist-info → ragaai_catalyst-2.1.4b2.dist-info}/WHEEL +0 -0
  23. {ragaai_catalyst-2.1.4b0.dist-info → ragaai_catalyst-2.1.4b2.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,28 @@ 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] = [interaction for interaction in self.user_interaction_tracer.interactions if interaction.get('component_id') == component_id]
141
+ for interaction in self.user_interaction_tracer.interactions:
142
+ interaction_component_id = interaction.get("component_id")
143
+ if interaction_component_id not in self.component_user_interaction:
144
+ self.component_user_interaction[interaction_component_id] = []
145
+ if interaction not in self.component_user_interaction[interaction_component_id]:
146
+ self.component_user_interaction[interaction_component_id].append(interaction)
74
147
 
75
148
  def start(self):
76
149
  """Start tracing"""
150
+ if not self.is_active:
151
+ return
152
+
77
153
  # Setup user interaction tracing
78
154
  self.user_interaction_tracer.project_id.set(self.project_id)
79
155
  self.user_interaction_tracer.trace_id.set(self.trace_id)
@@ -81,84 +157,112 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
81
157
  self.user_interaction_tracer.component_id.set(self.current_component_id.get())
82
158
  builtins.print = self.user_interaction_tracer.traced_print
83
159
  builtins.input = self.user_interaction_tracer.traced_input
84
-
160
+ builtins.open = self.user_interaction_tracer.traced_open
161
+
85
162
  # Start base tracer (includes system info and resource monitoring)
86
163
  super().start()
87
- self.is_active = True
88
-
164
+
89
165
  # Activate network tracing
90
166
  self.network_tracer.activate_patches()
91
-
92
- # Instrument calls from mixins
167
+
168
+ # take care of the auto instrumentation
93
169
  if self.auto_instrument_llm:
94
170
  self.instrument_llm_calls()
95
171
 
172
+ if self.auto_instrument_tool:
173
+ self.instrument_tool_calls()
174
+
175
+ if self.auto_instrument_agent:
176
+ self.instrument_agent_calls()
177
+
178
+ if self.auto_instrument_custom:
179
+ self.instrument_custom_calls()
180
+
181
+ if self.auto_instrument_user_interaction:
182
+
183
+ ToolTracerMixin.instrument_user_interaction_calls(self)
184
+ LLMTracerMixin.instrument_user_interaction_calls(self)
185
+ AgentTracerMixin.instrument_user_interaction_calls(self)
186
+ CustomTracerMixin.instrument_user_interaction_calls(self)
187
+
188
+ if self.auto_instrument_network:
189
+ ToolTracerMixin.instrument_network_calls(self)
190
+ LLMTracerMixin.instrument_network_calls(self)
191
+ AgentTracerMixin.instrument_network_calls(self)
192
+ CustomTracerMixin.instrument_network_calls(self)
193
+
194
+ # These will be implemented later
195
+ # if self.auto_instrument_file_io:
196
+ # self.instrument_file_io_calls()
197
+
96
198
  def stop(self):
97
199
  """Stop tracing and save results"""
98
200
  if self.is_active:
99
201
  # Restore original print and input functions
100
202
  builtins.print = self.user_interaction_tracer.original_print
101
203
  builtins.input = self.user_interaction_tracer.original_input
102
-
204
+ builtins.open = self.user_interaction_tracer.original_open
205
+
103
206
  # Calculate final metrics before stopping
104
207
  self._calculate_final_metrics()
105
-
208
+
106
209
  # Deactivate network tracing
107
210
  self.network_tracer.deactivate_patches()
108
-
211
+
109
212
  # Stop base tracer (includes saving to file)
110
213
  super().stop()
111
-
214
+
112
215
  # Cleanup
113
216
  self.unpatch_llm_calls()
114
217
  self.user_interaction_tracer.interactions = [] # Clear interactions list
115
218
  self.is_active = False
116
219
 
117
-
118
220
  def _calculate_final_metrics(self):
119
221
  """Calculate total cost and tokens from all components"""
120
222
  total_cost = 0.0
121
223
  total_tokens = 0
122
-
224
+
123
225
  def process_component(component):
124
226
  nonlocal total_cost, total_tokens
125
227
  # 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', {})
228
+ comp_dict = (
229
+ component.__dict__ if hasattr(component, "__dict__") else component
230
+ )
231
+
232
+ if comp_dict.get("type") == "llm":
233
+ info = comp_dict.get("info", {})
130
234
  if isinstance(info, dict):
131
235
  # Extract cost
132
- cost_info = info.get('cost', {})
236
+ cost_info = info.get("cost", {})
133
237
  if isinstance(cost_info, dict):
134
- total_cost += cost_info.get('total_cost', 0)
135
-
238
+ total_cost += cost_info.get("total_cost", 0)
239
+
136
240
  # Extract tokens
137
- token_info = info.get('tokens', {})
241
+ token_info = info.get("tokens", {})
138
242
  if isinstance(token_info, dict):
139
- total_tokens += token_info.get('total_tokens', 0)
243
+ total_tokens += token_info.get("total_tokens", 0)
140
244
  else:
141
- token_info = info.get('token_usage', {})
245
+ token_info = info.get("token_usage", {})
142
246
  if isinstance(token_info, dict):
143
- total_tokens += token_info.get('total_tokens', 0)
144
-
247
+ total_tokens += token_info.get("total_tokens", 0)
248
+
145
249
  # Process children if they exist
146
- data = comp_dict.get('data', {})
250
+ data = comp_dict.get("data", {})
147
251
  if isinstance(data, dict):
148
- children = data.get('children', [])
252
+ children = data.get("children", [])
149
253
  if children:
150
254
  for child in children:
151
255
  process_component(child)
152
-
256
+
153
257
  # Process all root components
154
258
  for component in self.components:
155
259
  process_component(component)
156
-
260
+
157
261
  # Update metadata in trace
158
- if hasattr(self, 'trace'):
262
+ if hasattr(self, "trace"):
159
263
  if isinstance(self.trace.metadata, dict):
160
- self.trace.metadata['total_cost'] = total_cost
161
- self.trace.metadata['total_tokens'] = total_tokens
264
+ self.trace.metadata["total_cost"] = total_cost
265
+ self.trace.metadata["total_tokens"] = total_tokens
162
266
  else:
163
267
  self.trace.metadata.total_cost = total_cost
164
268
  self.trace.metadata.total_tokens = total_tokens
@@ -166,11 +270,34 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
166
270
  def add_component(self, component_data: dict, is_error: bool = False):
167
271
  """Add a component to the trace data"""
168
272
  # 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"]}
273
+ filtered_data = {
274
+ k: v
275
+ for k, v in component_data.items()
276
+ if k
277
+ in [
278
+ "id",
279
+ "hash_id",
280
+ "source_hash_id",
281
+ "type",
282
+ "name",
283
+ "start_time",
284
+ "end_time",
285
+ "parent_id",
286
+ "info",
287
+ "extra_info",
288
+ "data",
289
+ "metadata",
290
+ "metrics",
291
+ "feedback",
292
+ "network_calls",
293
+ "interactions",
294
+ "error",
295
+ ]
296
+ }
170
297
 
171
298
  if component_data["type"] == "llm":
172
299
  component = LLMComponent(**filtered_data)
173
- elif component_data["type"] == "agent":
300
+ elif component_data["type"] == "agent":
174
301
  component = AgentComponent(**filtered_data)
175
302
  elif component_data["type"] == "tool":
176
303
  component = ToolComponent(**filtered_data)
@@ -187,21 +314,27 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
187
314
  else:
188
315
  # Add component to the main trace
189
316
  super().add_component(component)
190
-
317
+
191
318
  # Handle error case
192
319
  if is_error:
193
320
  # Get the parent component if it exists
194
321
  parent_id = component_data.get("parent_id")
195
322
  children = self.agent_children.get()
196
-
323
+
197
324
  # Set parent_id for all children
198
325
  for child in children:
199
326
  child["parent_id"] = parent_id
200
-
327
+
201
328
  agent_tracer_mixin = AgentTracerMixin()
202
329
  agent_tracer_mixin.component_network_calls = self.component_network_calls
203
- agent_tracer_mixin.component_user_interaction = self.component_user_interaction
204
-
330
+ agent_tracer_mixin.component_user_interaction = (
331
+ self.component_user_interaction
332
+ )
333
+
334
+ agent_tracer_mixin.span_attributes_dict[self.current_agent_name.get()] = (
335
+ SpanAttributes(self.current_agent_name.get())
336
+ )
337
+
205
338
  # Create parent component with error info
206
339
  parent_component = agent_tracer_mixin.create_agent_component(
207
340
  component_id=parent_id,
@@ -218,10 +351,29 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
218
351
  input_data=self.input_data,
219
352
  output_data=None,
220
353
  children=children,
221
- parent_id=None # Add parent ID if exists
354
+ parent_id=None, # Add parent ID if exists
222
355
  )
223
356
 
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"]}
357
+ filtered_data = {
358
+ k: v
359
+ for k, v in parent_component.items()
360
+ if k
361
+ in [
362
+ "id",
363
+ "hash_id",
364
+ "source_hash_id",
365
+ "type",
366
+ "name",
367
+ "start_time",
368
+ "end_time",
369
+ "parent_id",
370
+ "info",
371
+ "data",
372
+ "network_calls",
373
+ "interactions",
374
+ "error",
375
+ ]
376
+ }
225
377
  parent_agent_component = AgentComponent(**filtered_data)
226
378
  # Add the parent component to trace and stop tracing
227
379
  super().add_component(parent_agent_component)
@@ -234,4 +386,4 @@ class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMix
234
386
 
235
387
  def __exit__(self, exc_type, exc_value, traceback):
236
388
  """Context manager exit"""
237
- self.stop()
389
+ 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,