ragaai-catalyst 2.1b0__py3-none-any.whl → 2.1b2__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 (45) hide show
  1. ragaai_catalyst/__init__.py +1 -0
  2. ragaai_catalyst/dataset.py +1 -4
  3. ragaai_catalyst/evaluation.py +4 -5
  4. ragaai_catalyst/guard_executor.py +97 -0
  5. ragaai_catalyst/guardrails_manager.py +41 -15
  6. ragaai_catalyst/internal_api_completion.py +1 -1
  7. ragaai_catalyst/prompt_manager.py +7 -2
  8. ragaai_catalyst/ragaai_catalyst.py +1 -1
  9. ragaai_catalyst/synthetic_data_generation.py +7 -0
  10. ragaai_catalyst/tracers/__init__.py +1 -1
  11. ragaai_catalyst/tracers/agentic_tracing/__init__.py +3 -0
  12. ragaai_catalyst/tracers/agentic_tracing/agent_tracer.py +422 -0
  13. ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +198 -0
  14. ragaai_catalyst/tracers/agentic_tracing/base.py +376 -0
  15. ragaai_catalyst/tracers/agentic_tracing/data_structure.py +248 -0
  16. ragaai_catalyst/tracers/agentic_tracing/examples/FinancialAnalysisSystem.ipynb +536 -0
  17. ragaai_catalyst/tracers/agentic_tracing/examples/GameActivityEventPlanner.ipynb +134 -0
  18. ragaai_catalyst/tracers/agentic_tracing/examples/TravelPlanner.ipynb +563 -0
  19. ragaai_catalyst/tracers/agentic_tracing/file_name_tracker.py +46 -0
  20. ragaai_catalyst/tracers/agentic_tracing/llm_tracer.py +808 -0
  21. ragaai_catalyst/tracers/agentic_tracing/network_tracer.py +286 -0
  22. ragaai_catalyst/tracers/agentic_tracing/sample.py +197 -0
  23. ragaai_catalyst/tracers/agentic_tracing/tool_tracer.py +247 -0
  24. ragaai_catalyst/tracers/agentic_tracing/unique_decorator.py +165 -0
  25. ragaai_catalyst/tracers/agentic_tracing/unique_decorator_test.py +172 -0
  26. ragaai_catalyst/tracers/agentic_tracing/upload_agentic_traces.py +187 -0
  27. ragaai_catalyst/tracers/agentic_tracing/upload_code.py +115 -0
  28. ragaai_catalyst/tracers/agentic_tracing/user_interaction_tracer.py +43 -0
  29. ragaai_catalyst/tracers/agentic_tracing/utils/__init__.py +3 -0
  30. ragaai_catalyst/tracers/agentic_tracing/utils/api_utils.py +18 -0
  31. ragaai_catalyst/tracers/agentic_tracing/utils/data_classes.py +61 -0
  32. ragaai_catalyst/tracers/agentic_tracing/utils/generic.py +32 -0
  33. ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +177 -0
  34. ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +7823 -0
  35. ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py +74 -0
  36. ragaai_catalyst/tracers/agentic_tracing/zip_list_of_unique_files.py +184 -0
  37. ragaai_catalyst/tracers/exporters/raga_exporter.py +1 -7
  38. ragaai_catalyst/tracers/tracer.py +30 -4
  39. ragaai_catalyst/tracers/upload_traces.py +127 -0
  40. ragaai_catalyst-2.1b2.dist-info/METADATA +43 -0
  41. ragaai_catalyst-2.1b2.dist-info/RECORD +56 -0
  42. {ragaai_catalyst-2.1b0.dist-info → ragaai_catalyst-2.1b2.dist-info}/WHEEL +1 -1
  43. ragaai_catalyst-2.1b0.dist-info/METADATA +0 -295
  44. ragaai_catalyst-2.1b0.dist-info/RECORD +0 -28
  45. {ragaai_catalyst-2.1b0.dist-info → ragaai_catalyst-2.1b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,286 @@
1
+ from datetime import datetime
2
+ import socket
3
+ from http.client import HTTPConnection, HTTPSConnection
4
+ import aiohttp
5
+ import requests
6
+ import urllib
7
+ import uuid
8
+
9
+
10
+ class NetworkTracer:
11
+ def __init__(self):
12
+ self.network_calls = []
13
+ self.patches_applied = False # Track whether patches are active
14
+ # Store original functions for restoration
15
+ self._original_urlopen = None
16
+ self._original_requests_request = None
17
+ self._original_http_request = None
18
+ self._original_https_request = None
19
+ self._original_socket_create_connection = None
20
+
21
+ def record_call(
22
+ self,
23
+ method,
24
+ url,
25
+ status_code=None,
26
+ error=None,
27
+ start_time=None,
28
+ end_time=None,
29
+ request_headers=None,
30
+ response_headers=None,
31
+ request_body=None,
32
+ response_body=None,
33
+ ):
34
+ duration = (
35
+ (end_time - start_time).total_seconds() if start_time and end_time else None
36
+ )
37
+
38
+ # Calculate bytes sent/received from headers and body
39
+ bytes_sent = len(str(request_headers or "")) + len(str(request_body or ""))
40
+ bytes_received = len(str(response_headers or "")) + len(str(response_body or ""))
41
+
42
+ # Extract protocol from URL
43
+ protocol = "https" if url.startswith("https") else "http"
44
+
45
+ self.network_calls.append(
46
+ {
47
+ "url": url,
48
+ "method": method,
49
+ "status_code": status_code,
50
+ "response_time": duration,
51
+ "bytes_sent": bytes_sent,
52
+ "bytes_received": bytes_received,
53
+ "protocol": protocol,
54
+ "connection_id": str(uuid.uuid4()), # Generate unique connection ID
55
+ "parent_id": None, # Will be set by the component
56
+ "request": {
57
+ "headers": request_headers,
58
+ "body": request_body[:1000] if request_body else None, # Limit to 1000 chars
59
+ },
60
+ "response": {
61
+ "headers": response_headers,
62
+ "body": response_body[:1000] if response_body else None, # Limit to 1000 chars
63
+ },
64
+ "error": str(error) if error else None,
65
+ }
66
+ )
67
+
68
+ def activate_patches(self):
69
+ if not self.patches_applied:
70
+ # Apply monkey patches and store originals
71
+ self._original_urlopen = monkey_patch_urllib(self)
72
+ self._original_requests_request = monkey_patch_requests(self)
73
+ self._original_http_request, self._original_https_request = (
74
+ monkey_patch_http_client(self)
75
+ )
76
+ self._original_socket_create_connection = monkey_patch_socket(self)
77
+ self.patches_applied = True
78
+
79
+ def deactivate_patches(self):
80
+ if self.patches_applied:
81
+ # Restore original functions
82
+ restore_urllib(self._original_urlopen)
83
+ restore_requests(self._original_requests_request)
84
+ restore_http_client(
85
+ self._original_http_request, self._original_https_request
86
+ )
87
+ restore_socket(self._original_socket_create_connection)
88
+ self.network_calls = []
89
+ self.patches_applied = False
90
+
91
+
92
+ # Define the monkey patch and restore functions
93
+ def monkey_patch_urllib(network_tracer):
94
+ from urllib.request import urlopen
95
+
96
+ original_urlopen = urlopen
97
+
98
+ def patched_urlopen(url, data=None, timeout=None, *args, **kwargs):
99
+ if isinstance(url, str):
100
+ method = "GET" if data is None else "POST"
101
+ url_str = url
102
+ else:
103
+ method = url.get_method()
104
+ url_str = url.full_url
105
+
106
+ start_time = datetime.now()
107
+ try:
108
+ response = original_urlopen(url, data, timeout, *args, **kwargs)
109
+ end_time = datetime.now()
110
+ network_tracer.record_call(
111
+ method=method,
112
+ url=url_str,
113
+ status_code=response.status,
114
+ start_time=start_time,
115
+ end_time=end_time,
116
+ request_headers=dict(response.request.headers),
117
+ response_headers=dict(response.headers),
118
+ request_body=data,
119
+ response_body=response.read().decode("utf-8", errors="ignore"),
120
+ )
121
+ return response
122
+ except Exception as e:
123
+ end_time = datetime.now()
124
+ network_tracer.record_call(
125
+ method=method,
126
+ url=url_str,
127
+ error=e,
128
+ start_time=start_time,
129
+ end_time=end_time,
130
+ )
131
+ raise
132
+
133
+ urllib.request.urlopen = patched_urlopen
134
+ return original_urlopen # Return the original function
135
+
136
+
137
+ def restore_urllib(original_urlopen):
138
+ urllib.request.urlopen = original_urlopen
139
+
140
+
141
+ def monkey_patch_requests(network_tracer):
142
+ original_request = requests.Session.request
143
+
144
+ def patched_request(self, method, url, *args, **kwargs):
145
+ start_time = datetime.now()
146
+ try:
147
+ response = original_request(self, method, url, *args, **kwargs)
148
+ end_time = datetime.now()
149
+ network_tracer.record_call(
150
+ method=method,
151
+ url=url,
152
+ status_code=response.status_code,
153
+ start_time=start_time,
154
+ end_time=end_time,
155
+ request_headers=dict(response.request.headers),
156
+ response_headers=dict(response.headers),
157
+ request_body=kwargs.get("data") or kwargs.get("json"),
158
+ response_body=response.text,
159
+ )
160
+ return response
161
+ except Exception as e:
162
+ end_time = datetime.now()
163
+ network_tracer.record_call(
164
+ method=method,
165
+ url=url,
166
+ error=e,
167
+ start_time=start_time,
168
+ end_time=end_time,
169
+ )
170
+ raise
171
+
172
+ requests.Session.request = patched_request
173
+ return original_request
174
+
175
+
176
+ def restore_requests(original_request):
177
+ requests.Session.request = original_request
178
+
179
+
180
+ def monkey_patch_http_client(network_tracer):
181
+ original_http_request = HTTPConnection.request
182
+ original_https_request = HTTPSConnection.request
183
+
184
+ def patched_request(self, method, url, body=None, headers=None, *args, **kwargs):
185
+ start_time = datetime.now()
186
+ try:
187
+ result = (
188
+ original_http_request(self, method, url, body, headers, *args, **kwargs)
189
+ if isinstance(self, HTTPConnection)
190
+ else original_https_request(
191
+ self, method, url, body, headers, *args, **kwargs
192
+ )
193
+ )
194
+ response = self.getresponse()
195
+ end_time = datetime.now()
196
+ network_tracer.record_call(
197
+ method=method,
198
+ url=f"{self._http_vsn_str} {self.host}:{self.port}{url}",
199
+ status_code=response.status,
200
+ start_time=start_time,
201
+ end_time=end_time,
202
+ request_headers=headers,
203
+ response_headers=dict(response.headers),
204
+ request_body=body,
205
+ response_body=response.read().decode("utf-8", errors="ignore"),
206
+ )
207
+ return result
208
+ except Exception as e:
209
+ end_time = datetime.now()
210
+ network_tracer.record_call(
211
+ method=method,
212
+ url=f"{self._http_vsn_str} {self.host}:{self.port}{url}",
213
+ error=e,
214
+ start_time=start_time,
215
+ end_time=end_time,
216
+ )
217
+ raise
218
+
219
+ HTTPConnection.request = patched_request
220
+ HTTPSConnection.request = patched_request
221
+ return original_http_request, original_https_request
222
+
223
+
224
+ def restore_http_client(original_http_request, original_https_request):
225
+ HTTPConnection.request = original_http_request
226
+ HTTPSConnection.request = original_https_request
227
+
228
+
229
+ def monkey_patch_socket(network_tracer):
230
+ original_create_connection = socket.create_connection
231
+
232
+ def patched_create_connection(address, *args, **kwargs):
233
+ host, port = address
234
+ start_time = datetime.now()
235
+ try:
236
+ result = original_create_connection(address, *args, **kwargs)
237
+ end_time = datetime.now()
238
+ network_tracer.record_call(
239
+ method="CONNECT",
240
+ url=f"{host}:{port}",
241
+ start_time=start_time,
242
+ end_time=end_time,
243
+ )
244
+ return result
245
+ except Exception as e:
246
+ end_time = datetime.now()
247
+ network_tracer.record_call(
248
+ method="CONNECT",
249
+ url=f"{host}:{port}",
250
+ error=e,
251
+ start_time=start_time,
252
+ end_time=end_time,
253
+ )
254
+ raise
255
+
256
+ socket.create_connection = patched_create_connection
257
+ return original_create_connection
258
+
259
+
260
+ def restore_socket(original_create_connection):
261
+ socket.create_connection = original_create_connection
262
+
263
+
264
+ async def patch_aiohttp_trace_config(network_tracer):
265
+ async def on_request_start(session, trace_config_ctx, params):
266
+ trace_config_ctx.start = datetime.now()
267
+
268
+ async def on_request_end(session, trace_config_ctx, params):
269
+ end_time = datetime.now()
270
+ response = params.response
271
+ network_tracer.record_call(
272
+ method=params.method,
273
+ url=str(params.url),
274
+ status_code=response.status,
275
+ start_time=trace_config_ctx.start,
276
+ end_time=end_time,
277
+ request_headers=dict(params.headers),
278
+ response_headers=dict(response.headers),
279
+ request_body=await params.response.text(),
280
+ response_body=await response.text(),
281
+ )
282
+
283
+ trace_config = aiohttp.TraceConfig()
284
+ trace_config.on_request_start.append(on_request_start)
285
+ trace_config.on_request_end.append(on_request_end)
286
+ return trace_config
@@ -0,0 +1,197 @@
1
+ import os
2
+ import json
3
+ from openai import OpenAI
4
+ import requests
5
+ from datetime import datetime
6
+ from dotenv import load_dotenv
7
+ import sys
8
+
9
+ # Load environment variables
10
+ load_dotenv()
11
+
12
+ # Initialize OpenAI client
13
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
14
+
15
+ # Initialize tracer
16
+ from tracer import Tracer
17
+ tracer = Tracer(
18
+ project_name="travel_agent_demo",
19
+ output_dir="./traces"
20
+ )
21
+
22
+ # Start tracing
23
+ tracer.start()
24
+
25
+ @tracer.trace_tool(
26
+ name="llm_call",
27
+ tool_type="llm",
28
+ version="1.0.0"
29
+ )
30
+ def llm_call(prompt, max_tokens=512, model="gpt-3.5-turbo"):
31
+ response = client.chat.completions.create(
32
+ model=model,
33
+ messages=[{"role": "user", "content": prompt}],
34
+ max_tokens=max_tokens,
35
+ temperature=0.7,
36
+ )
37
+ return response.choices[0].message.content.strip()
38
+
39
+ @tracer.trace_tool(
40
+ name="weather_tool",
41
+ tool_type="api",
42
+ version="1.0.0"
43
+ )
44
+ def weather_tool(destination):
45
+ api_key = os.environ.get("OPENWEATHERMAP_API_KEY")
46
+ base_url = "http://api.openweathermap.org/data/2.5/weather"
47
+ params = {"q": destination, "appid": api_key, "units": "metric"}
48
+
49
+ try:
50
+ response = requests.get(base_url, params=params)
51
+ response.raise_for_status()
52
+ data = response.json()
53
+ weather_description = data["weather"][0]["description"]
54
+ temperature = data["main"]["temp"]
55
+ return f"{weather_description.capitalize()}, {temperature:.1f}°C"
56
+ except requests.RequestException:
57
+ return "Weather data not available."
58
+
59
+ @tracer.trace_tool(
60
+ name="currency_converter_tool",
61
+ tool_type="api",
62
+ version="1.0.0"
63
+ )
64
+ def currency_converter_tool(amount, from_currency, to_currency):
65
+ api_key = os.environ.get("EXCHANGERATE_API_KEY")
66
+ base_url = f"https://v6.exchangerate-api.com/v6/{api_key}/pair/{from_currency}/{to_currency}"
67
+
68
+ try:
69
+ response = requests.get(base_url)
70
+ response.raise_for_status()
71
+ data = response.json()
72
+ if data["result"] == "success":
73
+ rate = data["conversion_rate"]
74
+ return amount * rate
75
+ return None
76
+ except requests.RequestException:
77
+ return None
78
+
79
+ @tracer.trace_tool(
80
+ name="flight_price_estimator_tool",
81
+ tool_type="mock",
82
+ version="1.0.0"
83
+ )
84
+ def flight_price_estimator_tool(origin, destination):
85
+ return f"Estimated price from {origin} to {destination}: $500-$1000"
86
+
87
+ @tracer.trace_agent(
88
+ name="itinerary_agent",
89
+ agent_type="planner",
90
+ capabilities=["itinerary_planning", "llm_interaction"]
91
+ )
92
+ class ItineraryAgent:
93
+ def __init__(self, persona="Itinerary Agent"):
94
+ self.persona = persona
95
+
96
+ def plan_itinerary(self, user_preferences, duration=3):
97
+ itinerary_prompt = f"""
98
+ You are a travel expert named {self.persona}.
99
+ Based on the following user preferences, create a {duration}-day travel itinerary.
100
+
101
+ User Preferences:
102
+ {user_preferences}
103
+
104
+ Itinerary:
105
+ """
106
+ return llm_call(itinerary_prompt, max_tokens=512)
107
+
108
+ @tracer.trace_agent(
109
+ name="travel_agent",
110
+ agent_type="orchestrator",
111
+ capabilities=["preference_extraction", "travel_planning", "information_gathering"]
112
+ )
113
+ def travel_agent():
114
+ print("Welcome to the Personalized Travel Planner!\n")
115
+
116
+ # Get user input
117
+ user_input = "karela, 10 days, $100, nature"
118
+
119
+ # Extract preferences
120
+ preferences_prompt = f"""
121
+ Extract key travel preferences from the following user input:
122
+ "{user_input}"
123
+
124
+ Please provide the extracted information in this format:
125
+ Destination:
126
+ Activities:
127
+ Budget:
128
+ Duration (in days):
129
+ """
130
+ extracted_preferences = llm_call(preferences_prompt)
131
+ print("\nExtracted Preferences:")
132
+ print(extracted_preferences)
133
+
134
+ # Parse extracted preferences
135
+ preferences = {}
136
+ for line in extracted_preferences.split("\n"):
137
+ if ":" in line:
138
+ key, value = line.split(":", 1)
139
+ preferences[key.strip()] = value.strip()
140
+
141
+ # Validate extracted preferences
142
+ required_keys = ["Destination", "Activities", "Budget", "Duration (in days)"]
143
+ if not all(key in preferences for key in required_keys):
144
+ print("\nCould not extract all required preferences. Please try again.")
145
+ return
146
+
147
+ # Fetch additional information
148
+ weather = weather_tool(preferences["Destination"])
149
+ print(f"\nWeather in {preferences['Destination']}: {weather}")
150
+
151
+ origin = "delhi"
152
+ flight_price = flight_price_estimator_tool(origin, preferences["Destination"])
153
+ print(flight_price)
154
+
155
+ # Plan itinerary
156
+ itinerary_agent = ItineraryAgent()
157
+ itinerary = itinerary_agent.plan_itinerary(
158
+ extracted_preferences, int(preferences["Duration (in days)"])
159
+ )
160
+ print("\nPlanned Itinerary:")
161
+ print(itinerary)
162
+
163
+ # Currency conversion
164
+ budget_amount = float(preferences["Budget"].replace("$", "").replace(",", ""))
165
+ converted_budget = currency_converter_tool(budget_amount, "USD", "INR")
166
+ if converted_budget:
167
+ print(f"\nBudget in INR: {converted_budget:.2f} INR")
168
+ else:
169
+ print("\nCurrency conversion not available.")
170
+
171
+ # Generate travel summary
172
+ summary_prompt = f"""
173
+ Summarize the following travel plan:
174
+
175
+ Destination: {preferences['Destination']}
176
+ Activities: {preferences['Activities']}
177
+ Budget: {preferences['Budget']}
178
+ Duration: {preferences['Duration (in days)']} days
179
+ Itinerary: {itinerary}
180
+ Weather: {weather}
181
+ Flight Price: {flight_price}
182
+
183
+ Travel Summary:
184
+ """
185
+ travel_summary = llm_call(summary_prompt, max_tokens=2048)
186
+ print("\nTravel Summary:")
187
+ print(travel_summary)
188
+
189
+ def main():
190
+ try:
191
+ travel_agent()
192
+ finally:
193
+ # Stop tracing and save results
194
+ tracer.stop()
195
+
196
+ if __name__ == "__main__":
197
+ main()