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.
- ragaai_catalyst/tracers/agentic_tracing/data/data_structure.py +36 -10
- ragaai_catalyst/tracers/agentic_tracing/tracers/agent_tracer.py +213 -76
- ragaai_catalyst/tracers/agentic_tracing/tracers/base.py +568 -107
- ragaai_catalyst/tracers/agentic_tracing/tracers/custom_tracer.py +325 -0
- ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py +207 -81
- ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py +208 -58
- ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py +2 -0
- ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py +125 -28
- ragaai_catalyst/tracers/agentic_tracing/tracers/user_interaction_tracer.py +86 -0
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py +9 -51
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_trace_metric.py +83 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/create_dataset_schema.py +26 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/get_user_trace_metrics.py +28 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +45 -15
- ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +2476 -2122
- ragaai_catalyst/tracers/agentic_tracing/utils/span_attributes.py +59 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py +23 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/zip_list_of_unique_files.py +284 -15
- ragaai_catalyst/tracers/tracer.py +80 -8
- ragaai_catalyst-2.1.4b1.dist-info/METADATA +431 -0
- {ragaai_catalyst-2.1.3b0.dist-info → ragaai_catalyst-2.1.4b1.dist-info}/RECORD +23 -18
- ragaai_catalyst-2.1.3b0.dist-info/METADATA +0 -43
- {ragaai_catalyst-2.1.3b0.dist-info → ragaai_catalyst-2.1.4b1.dist-info}/WHEEL +0 -0
- {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,
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
29
|
-
|
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(
|
69
|
+
self.current_component_id = contextvars.ContextVar(
|
70
|
+
"current_component_id", default=None
|
71
|
+
)
|
49
72
|
self.network_tracer = NetworkTracer()
|
50
|
-
|
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] =
|
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] =
|
73
|
-
|
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
|
-
|
88
|
-
|
162
|
+
|
89
163
|
# Activate network tracing
|
90
164
|
self.network_tracer.activate_patches()
|
91
|
-
|
92
|
-
#
|
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 =
|
127
|
-
|
128
|
-
|
129
|
-
|
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(
|
234
|
+
cost_info = info.get("cost", {})
|
133
235
|
if isinstance(cost_info, dict):
|
134
|
-
total_cost += cost_info.get(
|
135
|
-
|
236
|
+
total_cost += cost_info.get("total_cost", 0)
|
237
|
+
|
136
238
|
# Extract tokens
|
137
|
-
token_info = info.get(
|
239
|
+
token_info = info.get("tokens", {})
|
138
240
|
if isinstance(token_info, dict):
|
139
|
-
total_tokens += token_info.get(
|
241
|
+
total_tokens += token_info.get("total_tokens", 0)
|
140
242
|
else:
|
141
|
-
token_info = info.get(
|
243
|
+
token_info = info.get("token_usage", {})
|
142
244
|
if isinstance(token_info, dict):
|
143
|
-
total_tokens += token_info.get(
|
144
|
-
|
245
|
+
total_tokens += token_info.get("total_tokens", 0)
|
246
|
+
|
145
247
|
# Process children if they exist
|
146
|
-
data = comp_dict.get(
|
248
|
+
data = comp_dict.get("data", {})
|
147
249
|
if isinstance(data, dict):
|
148
|
-
children = data.get(
|
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,
|
260
|
+
if hasattr(self, "trace"):
|
159
261
|
if isinstance(self.trace.metadata, dict):
|
160
|
-
self.trace.metadata[
|
161
|
-
self.trace.metadata[
|
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 = {
|
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 =
|
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 = {
|
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,
|