ragaai-catalyst 2.0.7.2__py3-none-any.whl → 2.0.7.2b0__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/evaluation.py +107 -153
- ragaai_catalyst/tracers/agentic_tracing/Untitled-1.json +660 -0
- ragaai_catalyst/tracers/agentic_tracing/__init__.py +3 -0
- ragaai_catalyst/tracers/agentic_tracing/agent_tracer.py +311 -0
- ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +212 -0
- ragaai_catalyst/tracers/agentic_tracing/base.py +270 -0
- ragaai_catalyst/tracers/agentic_tracing/data_structure.py +239 -0
- ragaai_catalyst/tracers/agentic_tracing/llm_tracer.py +906 -0
- ragaai_catalyst/tracers/agentic_tracing/network_tracer.py +286 -0
- ragaai_catalyst/tracers/agentic_tracing/sample.py +197 -0
- ragaai_catalyst/tracers/agentic_tracing/tool_tracer.py +235 -0
- ragaai_catalyst/tracers/agentic_tracing/unique_decorator.py +221 -0
- ragaai_catalyst/tracers/agentic_tracing/unique_decorator_test.py +172 -0
- ragaai_catalyst/tracers/agentic_tracing/user_interaction_tracer.py +67 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/__init__.py +3 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/api_utils.py +18 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/data_classes.py +61 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/generic.py +32 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +181 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +5946 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py +74 -0
- ragaai_catalyst/tracers/tracer.py +26 -4
- ragaai_catalyst/tracers/upload_traces.py +127 -0
- ragaai_catalyst-2.0.7.2b0.dist-info/METADATA +39 -0
- ragaai_catalyst-2.0.7.2b0.dist-info/RECORD +50 -0
- ragaai_catalyst-2.0.7.2.dist-info/METADATA +0 -386
- ragaai_catalyst-2.0.7.2.dist-info/RECORD +0 -29
- {ragaai_catalyst-2.0.7.2.dist-info → ragaai_catalyst-2.0.7.2b0.dist-info}/WHEEL +0 -0
- {ragaai_catalyst-2.0.7.2.dist-info → ragaai_catalyst-2.0.7.2b0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,311 @@
|
|
1
|
+
import functools
|
2
|
+
import uuid
|
3
|
+
from datetime import datetime
|
4
|
+
import psutil
|
5
|
+
from typing import Optional, Any, Dict, List
|
6
|
+
from .unique_decorator import mydecorator
|
7
|
+
|
8
|
+
import contextvars
|
9
|
+
import asyncio
|
10
|
+
|
11
|
+
class AgentTracerMixin:
|
12
|
+
def __init__(self, *args, **kwargs):
|
13
|
+
super().__init__(*args, **kwargs)
|
14
|
+
self.current_agent_id = contextvars.ContextVar("agent_id", default=None)
|
15
|
+
self.current_agent_name = contextvars.ContextVar("agent_name", default=None)
|
16
|
+
self.agent_children = contextvars.ContextVar("agent_children", default=[])
|
17
|
+
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)
|
20
|
+
|
21
|
+
|
22
|
+
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
|
+
)
|
38
|
+
|
39
|
+
return async_wrapper if is_async else sync_wrapper
|
40
|
+
|
41
|
+
return decorator
|
42
|
+
|
43
|
+
def _trace_sync_agent_execution(self, func, name, agent_type, version, capabilities, *args, **kwargs):
|
44
|
+
"""Synchronous version of agent tracing"""
|
45
|
+
if not self.is_active:
|
46
|
+
return func(*args, **kwargs)
|
47
|
+
|
48
|
+
start_time = datetime.now()
|
49
|
+
start_memory = psutil.Process().memory_info().rss
|
50
|
+
component_id = str(uuid.uuid4())
|
51
|
+
hash_id = self._trace_sync_agent_execution.hash_id
|
52
|
+
|
53
|
+
# Initialize empty children list for this agent
|
54
|
+
children_token = self.agent_children.set([])
|
55
|
+
|
56
|
+
# Set the current agent context
|
57
|
+
agent_token = self.current_agent_id.set(component_id)
|
58
|
+
agent_name_token = self.current_agent_name.set(name)
|
59
|
+
|
60
|
+
# Start tracking network calls for this component
|
61
|
+
self.start_component(component_id)
|
62
|
+
|
63
|
+
try:
|
64
|
+
# Execute the agent
|
65
|
+
result = func(*args, **kwargs)
|
66
|
+
|
67
|
+
# Calculate resource usage
|
68
|
+
end_time = datetime.now()
|
69
|
+
end_memory = psutil.Process().memory_info().rss
|
70
|
+
memory_used = max(0, end_memory - start_memory)
|
71
|
+
|
72
|
+
# Get children components collected during execution
|
73
|
+
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
|
+
|
79
|
+
# End tracking network calls for this component
|
80
|
+
self.end_component(component_id)
|
81
|
+
|
82
|
+
# Create agent component with children
|
83
|
+
agent_component = self.create_agent_component(
|
84
|
+
component_id=component_id,
|
85
|
+
hash_id=hash_id,
|
86
|
+
name=name,
|
87
|
+
agent_type=agent_type,
|
88
|
+
version=version,
|
89
|
+
capabilities=capabilities or [],
|
90
|
+
start_time=start_time,
|
91
|
+
end_time=end_time,
|
92
|
+
memory_used=memory_used,
|
93
|
+
input_data=self._sanitize_input(args, kwargs),
|
94
|
+
output_data=self._sanitize_output(result),
|
95
|
+
children=children
|
96
|
+
)
|
97
|
+
|
98
|
+
self.add_component(agent_component)
|
99
|
+
return result
|
100
|
+
|
101
|
+
except Exception as e:
|
102
|
+
error_component = {
|
103
|
+
"code": 500,
|
104
|
+
"type": type(e).__name__,
|
105
|
+
"message": str(e),
|
106
|
+
"details": {}
|
107
|
+
}
|
108
|
+
|
109
|
+
# Get children even in case of error
|
110
|
+
children = self.agent_children.get()
|
111
|
+
|
112
|
+
# Set parent_id for all children
|
113
|
+
for child in children:
|
114
|
+
child["parent_id"] = component_id
|
115
|
+
|
116
|
+
# End tracking network calls for this component
|
117
|
+
self.end_component(component_id)
|
118
|
+
|
119
|
+
agent_component = self.create_agent_component(
|
120
|
+
component_id=component_id,
|
121
|
+
hash_id=hash_id,
|
122
|
+
name=name,
|
123
|
+
agent_type=agent_type,
|
124
|
+
version=version,
|
125
|
+
capabilities=capabilities or [],
|
126
|
+
start_time=start_time,
|
127
|
+
end_time=datetime.now(),
|
128
|
+
memory_used=0,
|
129
|
+
input_data=self._sanitize_input(args, kwargs),
|
130
|
+
output_data=None,
|
131
|
+
error=error_component,
|
132
|
+
children=children
|
133
|
+
)
|
134
|
+
|
135
|
+
self.add_component(agent_component)
|
136
|
+
raise
|
137
|
+
finally:
|
138
|
+
# Reset context variables
|
139
|
+
self.current_agent_id.reset(agent_token)
|
140
|
+
self.current_agent_name.reset(agent_name_token)
|
141
|
+
self.agent_children.reset(children_token)
|
142
|
+
|
143
|
+
async def _trace_agent_execution(self, func, name, agent_type, version, capabilities, *args, **kwargs):
|
144
|
+
"""Asynchronous version of agent tracing"""
|
145
|
+
if not self.is_active:
|
146
|
+
return await func(*args, **kwargs)
|
147
|
+
|
148
|
+
start_time = datetime.now()
|
149
|
+
start_memory = psutil.Process().memory_info().rss
|
150
|
+
component_id = str(uuid.uuid4())
|
151
|
+
hash_id = self._trace_agent_execution.hash_id
|
152
|
+
|
153
|
+
# Initialize empty children list for this agent
|
154
|
+
children_token = self.agent_children.set([])
|
155
|
+
|
156
|
+
# Set the current agent context
|
157
|
+
agent_token = self.current_agent_id.set(component_id)
|
158
|
+
agent_name_token = self.current_agent_name.set(name)
|
159
|
+
|
160
|
+
# Start tracking network calls for this component
|
161
|
+
self.start_component(component_id)
|
162
|
+
|
163
|
+
try:
|
164
|
+
# Execute the agent
|
165
|
+
result = await func(*args, **kwargs)
|
166
|
+
|
167
|
+
# Calculate resource usage
|
168
|
+
end_time = datetime.now()
|
169
|
+
end_memory = psutil.Process().memory_info().rss
|
170
|
+
memory_used = max(0, end_memory - start_memory)
|
171
|
+
|
172
|
+
# Get children components collected during execution
|
173
|
+
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
|
+
|
182
|
+
# Create agent component with children
|
183
|
+
agent_component = self.create_agent_component(
|
184
|
+
component_id=component_id,
|
185
|
+
hash_id=hash_id,
|
186
|
+
name=name,
|
187
|
+
agent_type=agent_type,
|
188
|
+
version=version,
|
189
|
+
capabilities=capabilities or [],
|
190
|
+
start_time=start_time,
|
191
|
+
end_time=end_time,
|
192
|
+
memory_used=memory_used,
|
193
|
+
input_data=self._sanitize_input(args, kwargs),
|
194
|
+
output_data=self._sanitize_output(result),
|
195
|
+
children=children
|
196
|
+
)
|
197
|
+
|
198
|
+
self.add_component(agent_component)
|
199
|
+
return result
|
200
|
+
|
201
|
+
except Exception as e:
|
202
|
+
error_component = {
|
203
|
+
"code": 500,
|
204
|
+
"type": type(e).__name__,
|
205
|
+
"message": str(e),
|
206
|
+
"details": {}
|
207
|
+
}
|
208
|
+
|
209
|
+
# Get children even in case of error
|
210
|
+
children = self.agent_children.get()
|
211
|
+
|
212
|
+
# Set parent_id for all children
|
213
|
+
for child in children:
|
214
|
+
child["parent_id"] = component_id
|
215
|
+
|
216
|
+
# End tracking network calls for this component
|
217
|
+
self.end_component(component_id)
|
218
|
+
|
219
|
+
agent_component = self.create_agent_component(
|
220
|
+
component_id=component_id,
|
221
|
+
hash_id=hash_id,
|
222
|
+
name=name,
|
223
|
+
agent_type=agent_type,
|
224
|
+
version=version,
|
225
|
+
capabilities=capabilities or [],
|
226
|
+
start_time=start_time,
|
227
|
+
end_time=datetime.now(),
|
228
|
+
memory_used=0,
|
229
|
+
input_data=self._sanitize_input(args, kwargs),
|
230
|
+
output_data=None,
|
231
|
+
error=error_component,
|
232
|
+
children=children
|
233
|
+
)
|
234
|
+
|
235
|
+
self.add_component(agent_component)
|
236
|
+
raise
|
237
|
+
finally:
|
238
|
+
# Reset context variables
|
239
|
+
self.current_agent_id.reset(agent_token)
|
240
|
+
self.current_agent_name.reset(agent_name_token)
|
241
|
+
self.agent_children.reset(children_token)
|
242
|
+
|
243
|
+
def create_agent_component(self, **kwargs):
|
244
|
+
"""Create an agent component according to the data structure"""
|
245
|
+
start_time = kwargs["start_time"]
|
246
|
+
component = {
|
247
|
+
"id": kwargs["component_id"],
|
248
|
+
"hash_id": kwargs["hash_id"],
|
249
|
+
"source_hash_id": None,
|
250
|
+
"type": "agent",
|
251
|
+
"name": kwargs["name"],
|
252
|
+
"start_time": start_time.isoformat(),
|
253
|
+
"end_time": kwargs["end_time"].isoformat(),
|
254
|
+
"error": kwargs.get("error"),
|
255
|
+
"parent_id": None,
|
256
|
+
"info": {
|
257
|
+
"agent_type": kwargs["agent_type"],
|
258
|
+
"version": kwargs["version"],
|
259
|
+
"capabilities": kwargs["capabilities"],
|
260
|
+
"memory_used": kwargs["memory_used"]
|
261
|
+
},
|
262
|
+
"data": {
|
263
|
+
"input": kwargs["input_data"],
|
264
|
+
"output": kwargs["output_data"],
|
265
|
+
"children": kwargs.get("children", [])
|
266
|
+
},
|
267
|
+
"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
|
+
}]
|
279
|
+
}
|
280
|
+
|
281
|
+
return component
|
282
|
+
|
283
|
+
def start_component(self, component_id):
|
284
|
+
"""Start tracking network calls for a component"""
|
285
|
+
component_network_calls = self.component_network_calls.get()
|
286
|
+
if component_id not in component_network_calls:
|
287
|
+
component_network_calls[component_id] = []
|
288
|
+
self.component_network_calls.set(component_network_calls)
|
289
|
+
|
290
|
+
def end_component(self, component_id):
|
291
|
+
"""End tracking network calls for a component"""
|
292
|
+
component_network_calls = self.component_network_calls.get()
|
293
|
+
if component_id in component_network_calls:
|
294
|
+
component_network_calls[component_id] = []
|
295
|
+
self.component_network_calls.set(component_network_calls)
|
296
|
+
|
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
|
+
}
|
306
|
+
|
307
|
+
def _sanitize_output(self, output: Any) -> Any:
|
308
|
+
"""Sanitize and format output data"""
|
309
|
+
if isinstance(output, (int, float, bool, str, list, dict)):
|
310
|
+
return output
|
311
|
+
return str(output)
|
@@ -0,0 +1,212 @@
|
|
1
|
+
import contextvars
|
2
|
+
from typing import Optional, Dict
|
3
|
+
import json
|
4
|
+
from datetime import datetime
|
5
|
+
import uuid
|
6
|
+
import os
|
7
|
+
from pathlib import Path
|
8
|
+
|
9
|
+
from .base import BaseTracer
|
10
|
+
from .llm_tracer import LLMTracerMixin
|
11
|
+
from .tool_tracer import ToolTracerMixin
|
12
|
+
from .agent_tracer import AgentTracerMixin
|
13
|
+
from .network_tracer import NetworkTracer
|
14
|
+
|
15
|
+
from .data_structure import (
|
16
|
+
Trace, Metadata, SystemInfo, OSInfo, EnvironmentInfo,
|
17
|
+
Resources, CPUResource, MemoryResource, DiskResource, NetworkResource,
|
18
|
+
ResourceInfo, MemoryInfo, DiskInfo, NetworkInfo,
|
19
|
+
Component, LLMComponent, AgentComponent, ToolComponent,
|
20
|
+
NetworkCall, Interaction, Error
|
21
|
+
)
|
22
|
+
|
23
|
+
|
24
|
+
from ...ragaai_catalyst import RagaAICatalyst
|
25
|
+
from ..upload_traces import UploadTraces
|
26
|
+
|
27
|
+
class AgenticTracing(BaseTracer, LLMTracerMixin, ToolTracerMixin, AgentTracerMixin):
|
28
|
+
def __init__(self, user_detail, auto_instrument_llm: bool = True):
|
29
|
+
# Initialize all parent classes
|
30
|
+
LLMTracerMixin.__init__(self)
|
31
|
+
ToolTracerMixin.__init__(self)
|
32
|
+
AgentTracerMixin.__init__(self)
|
33
|
+
|
34
|
+
self.project_name = user_detail["project_name"]
|
35
|
+
self.project_id = user_detail["project_id"]
|
36
|
+
self.dataset_name = user_detail["dataset_name"]
|
37
|
+
self.trace_user_detail = user_detail["trace_user_detail"]
|
38
|
+
self.base_url = f"{RagaAICatalyst.BASE_URL}"
|
39
|
+
self.timeout = 10
|
40
|
+
|
41
|
+
BaseTracer.__init__(self, user_detail)
|
42
|
+
|
43
|
+
self.auto_instrument_llm = auto_instrument_llm
|
44
|
+
self.tools: Dict[str, Tool] = {}
|
45
|
+
self.call_depth = contextvars.ContextVar("call_depth", default=0)
|
46
|
+
self.network_tracer = NetworkTracer()
|
47
|
+
self.is_active = False
|
48
|
+
self.current_agent_id = contextvars.ContextVar("current_agent_id", default=None)
|
49
|
+
self.agent_children = contextvars.ContextVar("agent_children", default=[])
|
50
|
+
self.component_network_calls = {} # Store network calls per component
|
51
|
+
|
52
|
+
# Create output directory if it doesn't exist
|
53
|
+
self.output_dir = Path("./traces") # Using default traces directory
|
54
|
+
self.output_dir.mkdir(exist_ok=True)
|
55
|
+
|
56
|
+
def start_component(self, component_id: str):
|
57
|
+
"""Start tracking network calls for a component"""
|
58
|
+
self.component_network_calls[component_id] = []
|
59
|
+
self.network_tracer.network_calls = [] # Reset network calls
|
60
|
+
|
61
|
+
def end_component(self, component_id: str):
|
62
|
+
"""End tracking network calls for a component"""
|
63
|
+
self.component_network_calls[component_id] = self.network_tracer.network_calls.copy()
|
64
|
+
self.network_tracer.network_calls = [] # Reset for next component
|
65
|
+
|
66
|
+
def start(self):
|
67
|
+
"""Start tracing"""
|
68
|
+
# Start base tracer (includes system info and resource monitoring)
|
69
|
+
super().start()
|
70
|
+
self.is_active = True
|
71
|
+
|
72
|
+
# Activate network tracing
|
73
|
+
self.network_tracer.activate_patches()
|
74
|
+
|
75
|
+
# Instrument calls from mixins
|
76
|
+
if self.auto_instrument_llm:
|
77
|
+
self.instrument_llm_calls()
|
78
|
+
|
79
|
+
def stop(self):
|
80
|
+
"""Stop tracing and save results"""
|
81
|
+
if self.is_active:
|
82
|
+
# Calculate final metrics before stopping
|
83
|
+
self._calculate_final_metrics()
|
84
|
+
|
85
|
+
# Deactivate network tracing
|
86
|
+
self.network_tracer.deactivate_patches()
|
87
|
+
|
88
|
+
# Stop base tracer (includes saving to file)
|
89
|
+
super().stop()
|
90
|
+
|
91
|
+
# Cleanup
|
92
|
+
self.unpatch_llm_calls()
|
93
|
+
self.is_active = False
|
94
|
+
|
95
|
+
|
96
|
+
def _calculate_final_metrics(self):
|
97
|
+
"""Calculate total cost and tokens from all components"""
|
98
|
+
total_cost = 0.0
|
99
|
+
total_tokens = 0
|
100
|
+
|
101
|
+
def process_component(component):
|
102
|
+
nonlocal total_cost, total_tokens
|
103
|
+
# Convert component to dict if it's an object
|
104
|
+
comp_dict = component.__dict__ if hasattr(component, '__dict__') else component
|
105
|
+
|
106
|
+
if comp_dict.get('type') == "llm":
|
107
|
+
info = comp_dict.get('info', {})
|
108
|
+
if isinstance(info, dict):
|
109
|
+
# Extract cost
|
110
|
+
cost_info = info.get('cost', {})
|
111
|
+
if isinstance(cost_info, dict):
|
112
|
+
total_cost += cost_info.get('total_cost', 0)
|
113
|
+
|
114
|
+
# Extract tokens
|
115
|
+
token_info = info.get('tokens', {})
|
116
|
+
if isinstance(token_info, dict):
|
117
|
+
total_tokens += token_info.get('total_tokens', 0)
|
118
|
+
else:
|
119
|
+
token_info = info.get('token_usage', {})
|
120
|
+
if isinstance(token_info, dict):
|
121
|
+
total_tokens += token_info.get('total_tokens', 0)
|
122
|
+
|
123
|
+
# Process children if they exist
|
124
|
+
data = comp_dict.get('data', {})
|
125
|
+
if isinstance(data, dict):
|
126
|
+
children = data.get('children', [])
|
127
|
+
if children:
|
128
|
+
for child in children:
|
129
|
+
process_component(child)
|
130
|
+
|
131
|
+
# Process all root components
|
132
|
+
for component in self.components:
|
133
|
+
process_component(component)
|
134
|
+
|
135
|
+
# Update metadata in trace
|
136
|
+
if hasattr(self, 'trace'):
|
137
|
+
if isinstance(self.trace.metadata, dict):
|
138
|
+
self.trace.metadata['total_cost'] = total_cost
|
139
|
+
self.trace.metadata['total_tokens'] = total_tokens
|
140
|
+
else:
|
141
|
+
self.trace.metadata.total_cost = total_cost
|
142
|
+
self.trace.metadata.total_tokens = total_tokens
|
143
|
+
|
144
|
+
def add_component(self, component_data: dict):
|
145
|
+
"""Add a component to the trace data"""
|
146
|
+
component_id = component_data["id"]
|
147
|
+
|
148
|
+
# Convert dict to appropriate Component type
|
149
|
+
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
|
+
}]
|
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
|
+
}]
|
191
|
+
else:
|
192
|
+
component = Component(**component_data)
|
193
|
+
|
194
|
+
# Check if there's an active agent context
|
195
|
+
current_agent_id = self.current_agent_id.get()
|
196
|
+
if current_agent_id and component_data["type"] in ["llm", "tool"]:
|
197
|
+
# Add this component as a child of the current agent
|
198
|
+
current_children = self.agent_children.get()
|
199
|
+
current_children.append(component_data)
|
200
|
+
self.agent_children.set(current_children)
|
201
|
+
else:
|
202
|
+
# Add component to the main trace
|
203
|
+
super().add_component(component)
|
204
|
+
|
205
|
+
def __enter__(self):
|
206
|
+
"""Context manager entry"""
|
207
|
+
self.start()
|
208
|
+
return self
|
209
|
+
|
210
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
211
|
+
"""Context manager exit"""
|
212
|
+
self.stop()
|