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.
- ragaai_catalyst/__init__.py +1 -0
- ragaai_catalyst/dataset.py +1 -4
- ragaai_catalyst/evaluation.py +4 -5
- ragaai_catalyst/guard_executor.py +97 -0
- ragaai_catalyst/guardrails_manager.py +41 -15
- ragaai_catalyst/internal_api_completion.py +1 -1
- ragaai_catalyst/prompt_manager.py +7 -2
- ragaai_catalyst/ragaai_catalyst.py +1 -1
- ragaai_catalyst/synthetic_data_generation.py +7 -0
- ragaai_catalyst/tracers/__init__.py +1 -1
- ragaai_catalyst/tracers/agentic_tracing/__init__.py +3 -0
- ragaai_catalyst/tracers/agentic_tracing/agent_tracer.py +422 -0
- ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +198 -0
- ragaai_catalyst/tracers/agentic_tracing/base.py +376 -0
- ragaai_catalyst/tracers/agentic_tracing/data_structure.py +248 -0
- ragaai_catalyst/tracers/agentic_tracing/examples/FinancialAnalysisSystem.ipynb +536 -0
- ragaai_catalyst/tracers/agentic_tracing/examples/GameActivityEventPlanner.ipynb +134 -0
- ragaai_catalyst/tracers/agentic_tracing/examples/TravelPlanner.ipynb +563 -0
- ragaai_catalyst/tracers/agentic_tracing/file_name_tracker.py +46 -0
- ragaai_catalyst/tracers/agentic_tracing/llm_tracer.py +808 -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 +247 -0
- ragaai_catalyst/tracers/agentic_tracing/unique_decorator.py +165 -0
- ragaai_catalyst/tracers/agentic_tracing/unique_decorator_test.py +172 -0
- ragaai_catalyst/tracers/agentic_tracing/upload_agentic_traces.py +187 -0
- ragaai_catalyst/tracers/agentic_tracing/upload_code.py +115 -0
- ragaai_catalyst/tracers/agentic_tracing/user_interaction_tracer.py +43 -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 +177 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +7823 -0
- ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py +74 -0
- ragaai_catalyst/tracers/agentic_tracing/zip_list_of_unique_files.py +184 -0
- ragaai_catalyst/tracers/exporters/raga_exporter.py +1 -7
- ragaai_catalyst/tracers/tracer.py +30 -4
- ragaai_catalyst/tracers/upload_traces.py +127 -0
- ragaai_catalyst-2.1b2.dist-info/METADATA +43 -0
- ragaai_catalyst-2.1b2.dist-info/RECORD +56 -0
- {ragaai_catalyst-2.1b0.dist-info → ragaai_catalyst-2.1b2.dist-info}/WHEEL +1 -1
- ragaai_catalyst-2.1b0.dist-info/METADATA +0 -295
- ragaai_catalyst-2.1b0.dist-info/RECORD +0 -28
- {ragaai_catalyst-2.1b0.dist-info → ragaai_catalyst-2.1b2.dist-info}/top_level.txt +0 -0
ragaai_catalyst/__init__.py
CHANGED
@@ -7,6 +7,7 @@ from .prompt_manager import PromptManager
|
|
7
7
|
from .evaluation import Evaluation
|
8
8
|
from .synthetic_data_generation import SyntheticDataGeneration
|
9
9
|
from .guardrails_manager import GuardrailsManager
|
10
|
+
from .guard_executor import GuardExecutor
|
10
11
|
|
11
12
|
|
12
13
|
__all__ = ["Experiment", "RagaAICatalyst", "Tracer", "PromptManager", "Evaluation","SyntheticDataGeneration", "GuardrailsManager"]
|
ragaai_catalyst/dataset.py
CHANGED
@@ -5,7 +5,6 @@ from typing import Union
|
|
5
5
|
import logging
|
6
6
|
from .ragaai_catalyst import RagaAICatalyst
|
7
7
|
import pandas as pd
|
8
|
-
import pdb
|
9
8
|
logger = logging.getLogger(__name__)
|
10
9
|
get_token = RagaAICatalyst.get_token
|
11
10
|
|
@@ -16,7 +15,7 @@ class Dataset:
|
|
16
15
|
|
17
16
|
def __init__(self, project_name):
|
18
17
|
self.project_name = project_name
|
19
|
-
self.num_projects =
|
18
|
+
self.num_projects = 99999
|
20
19
|
Dataset.BASE_URL = (
|
21
20
|
os.getenv("RAGAAI_CATALYST_BASE_URL")
|
22
21
|
if os.getenv("RAGAAI_CATALYST_BASE_URL")
|
@@ -202,7 +201,6 @@ class Dataset:
|
|
202
201
|
|
203
202
|
#### put csv to presigned URL
|
204
203
|
def put_csv_to_presignedUrl(url):
|
205
|
-
# pdb.set_trace()
|
206
204
|
headers = {
|
207
205
|
'Content-Type': 'text/csv',
|
208
206
|
'x-ms-blob-type': 'BlockBlob',
|
@@ -224,7 +222,6 @@ class Dataset:
|
|
224
222
|
try:
|
225
223
|
|
226
224
|
put_csv_response = put_csv_to_presignedUrl(url)
|
227
|
-
# pdb.set_trace()
|
228
225
|
print(put_csv_response)
|
229
226
|
if put_csv_response.status_code not in (200, 201):
|
230
227
|
raise ValueError('Unable to put csv to the presignedUrl')
|
ragaai_catalyst/evaluation.py
CHANGED
@@ -4,7 +4,6 @@ import pandas as pd
|
|
4
4
|
import io
|
5
5
|
from .ragaai_catalyst import RagaAICatalyst
|
6
6
|
import logging
|
7
|
-
import pdb
|
8
7
|
|
9
8
|
logger = logging.getLogger(__name__)
|
10
9
|
|
@@ -16,7 +15,7 @@ class Evaluation:
|
|
16
15
|
self.base_url = f"{RagaAICatalyst.BASE_URL}"
|
17
16
|
self.timeout = 10
|
18
17
|
self.jobId = None
|
19
|
-
self.num_projects=
|
18
|
+
self.num_projects=99999
|
20
19
|
|
21
20
|
try:
|
22
21
|
response = requests.get(
|
@@ -242,7 +241,7 @@ class Evaluation:
|
|
242
241
|
|
243
242
|
def _update_base_json(self, metrics):
|
244
243
|
metrics_schema_response = self._get_metrics_schema_response()
|
245
|
-
sub_providers = ["openai","azure","gemini","groq"]
|
244
|
+
sub_providers = ["openai","azure","gemini","groq","anthropic","bedrock"]
|
246
245
|
metricParams = []
|
247
246
|
for metric in metrics:
|
248
247
|
base_json = self._get_metricParams()
|
@@ -252,7 +251,7 @@ class Evaluation:
|
|
252
251
|
for key, value in metric["config"].items():
|
253
252
|
#checking if provider is one of the allowed providers
|
254
253
|
if key.lower()=="provider" and value.lower() not in sub_providers:
|
255
|
-
raise ValueError("Enter a valid provider name. The following Provider names are supported:
|
254
|
+
raise ValueError("Enter a valid provider name. The following Provider names are supported: openai, azure, gemini, groq, anthropic, bedrock")
|
256
255
|
|
257
256
|
if key.lower()=="threshold":
|
258
257
|
if len(value)>1:
|
@@ -330,7 +329,7 @@ class Evaluation:
|
|
330
329
|
metric_schema_mapping = self._update_base_json(metrics)
|
331
330
|
try:
|
332
331
|
response = requests.post(
|
333
|
-
f'{self.base_url}/
|
332
|
+
f'{self.base_url}/v2/llm/metric-evaluation',
|
334
333
|
headers=headers,
|
335
334
|
json=metric_schema_mapping,
|
336
335
|
timeout=self.timeout
|
@@ -0,0 +1,97 @@
|
|
1
|
+
import litellm
|
2
|
+
import json
|
3
|
+
import requests
|
4
|
+
import os
|
5
|
+
import logging
|
6
|
+
logger = logging.getLogger('LiteLLM')
|
7
|
+
logger.setLevel(logging.ERROR)
|
8
|
+
|
9
|
+
class GuardExecutor:
|
10
|
+
|
11
|
+
def __init__(self,id,guard_manager,field_map={}):
|
12
|
+
self.deployment_id = id
|
13
|
+
self.field_map = field_map
|
14
|
+
self.guard_manager = guard_manager
|
15
|
+
self.deployment_details = self.guard_manager.get_deployment(id)
|
16
|
+
if not self.deployment_details:
|
17
|
+
raise ValueError('Error in getting deployment details')
|
18
|
+
self.base_url = guard_manager.base_url
|
19
|
+
for key in field_map.keys():
|
20
|
+
if key not in ['prompt','context','response','instruction']:
|
21
|
+
print('Keys in field map should be in ["prompt","context","response","instruction"]')
|
22
|
+
|
23
|
+
def execute_deployment(self,payload):
|
24
|
+
api = self.base_url + f'/guardrail/deployment/{self.deployment_id}/ingest'
|
25
|
+
|
26
|
+
payload = json.dumps(payload)
|
27
|
+
headers = {
|
28
|
+
'x-project-id': str(self.guard_manager.project_id),
|
29
|
+
'Content-Type': 'application/json',
|
30
|
+
'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}'
|
31
|
+
}
|
32
|
+
try:
|
33
|
+
response = requests.request("POST", api, headers=headers, data=payload,timeout=self.guard_manager.timeout)
|
34
|
+
except Exception as e:
|
35
|
+
print('Failed running guardrail: ',str(e))
|
36
|
+
return None
|
37
|
+
if response.status_code!=200:
|
38
|
+
print('Error in running deployment ',response.json()['message'])
|
39
|
+
if response.json()['success']:
|
40
|
+
return response.json()
|
41
|
+
else:
|
42
|
+
print(response.json()['message'])
|
43
|
+
return None
|
44
|
+
|
45
|
+
def llm_executor(self,messages,model_params,llm_caller):
|
46
|
+
if llm_caller == 'litellm':
|
47
|
+
model_params['messages'] = messages
|
48
|
+
response = litellm.completion(**model_params)
|
49
|
+
return response
|
50
|
+
else:
|
51
|
+
print(f"{llm_caller} not supported currently, use litellm as llm caller")
|
52
|
+
|
53
|
+
|
54
|
+
def __call__(self,messages,prompt_params,model_params,llm_caller='litellm'):
|
55
|
+
for key in self.field_map:
|
56
|
+
if key not in ['prompt','response']:
|
57
|
+
if self.field_map[key] not in prompt_params:
|
58
|
+
raise ValueError(f'{key} added as field map but not passed as prompt parameter')
|
59
|
+
context_var = self.field_map.get('context',None)
|
60
|
+
prompt = None
|
61
|
+
for msg in messages:
|
62
|
+
if 'role' in msg:
|
63
|
+
if msg['role'] == 'user':
|
64
|
+
prompt = msg['content']
|
65
|
+
if not context_var:
|
66
|
+
msg['content'] += '\n' + prompt_params[context_var]
|
67
|
+
doc = dict()
|
68
|
+
doc['prompt'] = prompt
|
69
|
+
doc['context'] = prompt_params[context_var]
|
70
|
+
|
71
|
+
# inactive the guardrails that needs Response variable
|
72
|
+
#deployment_response = self.execute_deployment(doc)
|
73
|
+
|
74
|
+
# activate only guardrails that require response
|
75
|
+
try:
|
76
|
+
llm_response = self.llm_executor(messages,model_params,llm_caller)
|
77
|
+
except Exception as e:
|
78
|
+
print('Error in running llm:',str(e))
|
79
|
+
return None
|
80
|
+
doc['response'] = llm_response['choices'][0].message.content
|
81
|
+
if 'instruction' in self.field_map:
|
82
|
+
instruction = prompt_params[self.field_map['instruction']]
|
83
|
+
doc['instruction'] = instruction
|
84
|
+
response = self.execute_deployment(doc)
|
85
|
+
if response and response['data']['status'] == 'FAIL':
|
86
|
+
print('Guardrail deployment run retured failed status, replacing with alternate response')
|
87
|
+
return response['data']['alternateResponse'],llm_response,response
|
88
|
+
else:
|
89
|
+
return None,llm_response,response
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
@@ -13,7 +13,7 @@ class GuardrailsManager:
|
|
13
13
|
"""
|
14
14
|
self.project_name = project_name
|
15
15
|
self.timeout = 10
|
16
|
-
self.num_projects =
|
16
|
+
self.num_projects = 99999
|
17
17
|
self.deployment_name = "NA"
|
18
18
|
self.deployment_id = "NA"
|
19
19
|
self.base_url = f"{RagaAICatalyst.BASE_URL}"
|
@@ -31,7 +31,7 @@ class GuardrailsManager:
|
|
31
31
|
:return: A tuple containing a list of project names and a list of dictionaries with project IDs and names.
|
32
32
|
"""
|
33
33
|
headers = {'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}'}
|
34
|
-
response = requests.request("GET", f"{self.base_url}/v2/llm/projects?size=
|
34
|
+
response = requests.request("GET", f"{self.base_url}/v2/llm/projects?size={self.num_projects}", headers=headers, timeout=self.timeout)
|
35
35
|
project_content = response.json()["data"]["content"]
|
36
36
|
list_project = [_["name"] for _ in project_content]
|
37
37
|
project_name_with_id = [{"id": _["id"], "name": _["name"]} for _ in project_content]
|
@@ -68,10 +68,11 @@ class GuardrailsManager:
|
|
68
68
|
'X-Project-Id': str(self.project_id)
|
69
69
|
}
|
70
70
|
response = requests.request("GET", f"{self.base_url}/guardrail/deployment/{deployment_id}", headers=headers, data=payload, timeout=self.timeout)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
if response.json()['success']:
|
72
|
+
return response.json()
|
73
|
+
else:
|
74
|
+
print('Error in retrieving deployment details:',response.json()['message'])
|
75
|
+
return None
|
75
76
|
|
76
77
|
|
77
78
|
def list_guardrails(self):
|
@@ -132,11 +133,12 @@ class GuardrailsManager:
|
|
132
133
|
print(response.json()["message"])
|
133
134
|
deployment_ids = self.list_deployment_ids()
|
134
135
|
self.deployment_id = [_["id"] for _ in deployment_ids if _["name"]==self.deployment_name][0]
|
136
|
+
return self.deployment_id
|
135
137
|
else:
|
136
138
|
print(response)
|
137
139
|
|
138
140
|
|
139
|
-
def add_guardrails(self, guardrails, guardrails_config={}):
|
141
|
+
def add_guardrails(self, deployment_id, guardrails, guardrails_config={}):
|
140
142
|
"""
|
141
143
|
Add guardrails to the current deployment.
|
142
144
|
|
@@ -145,16 +147,21 @@ class GuardrailsManager:
|
|
145
147
|
:raises ValueError: If a guardrail name or type is invalid.
|
146
148
|
"""
|
147
149
|
# Checking if guardrails names given already exist or not
|
148
|
-
|
150
|
+
self.deployment_id = deployment_id
|
151
|
+
deployment_details = self.get_deployment(self.deployment_id)
|
152
|
+
if not deployment_details:
|
153
|
+
return None
|
154
|
+
deployment_id_name = deployment_details["data"]["name"]
|
155
|
+
deployment_id_guardrails = deployment_details["data"]["guardrailsResponse"]
|
156
|
+
guardrails_type_name_exists = [{_['metricSpec']["name"]:_['metricSpec']["displayName"]} for _ in deployment_id_guardrails]
|
149
157
|
guardrails_type_name_exists = [list(d.values())[0] for d in guardrails_type_name_exists]
|
150
158
|
user_guardrails_name_list = [_["name"] for _ in guardrails]
|
151
159
|
for g_name in user_guardrails_name_list:
|
152
160
|
if g_name in guardrails_type_name_exists:
|
153
161
|
raise ValueError(f"Guardrail with '{g_name} already exists, choose a unique name'")
|
154
|
-
|
155
162
|
# Checking if guardrails type is correct or not
|
156
163
|
available_guardrails_list = self.list_guardrails()
|
157
|
-
user_guardrails_type_list = [_["
|
164
|
+
user_guardrails_type_list = [_["name"] for _ in guardrails]
|
158
165
|
for g_type in user_guardrails_type_list:
|
159
166
|
if g_type not in available_guardrails_list:
|
160
167
|
raise ValueError(f"Guardrail type '{g_type} does not exists, choose a correct type'")
|
@@ -170,6 +177,8 @@ class GuardrailsManager:
|
|
170
177
|
response = requests.request("POST", f"{self.base_url}/guardrail/deployment/{str(self.deployment_id)}/configure", headers=headers, data=payload)
|
171
178
|
if response.json()["success"]:
|
172
179
|
print(response.json()["message"])
|
180
|
+
else:
|
181
|
+
print('Error updating guardrail ',response.json()['message'])
|
173
182
|
|
174
183
|
def _get_guardrail_config_payload(self, guardrails_config):
|
175
184
|
"""
|
@@ -209,13 +218,30 @@ class GuardrailsManager:
|
|
209
218
|
:param guardrail: A dictionary containing the guardrail's attributes.
|
210
219
|
:return: A dictionary representing the guardrail's data.
|
211
220
|
"""
|
221
|
+
if 'config' in guardrail:
|
222
|
+
if 'mappings' in guardrail.get('config'):
|
223
|
+
for mapping in guardrail.get('config',{}).get('mappings',{}):
|
224
|
+
if mapping['schemaName'] not in ['Text','Prompt','Context','Response']:
|
225
|
+
raise(ValueError('Invalid schemaName in guardrail mapping schema'))
|
226
|
+
if mapping['variableName'] not in ['Instruction','Prompt','Context','Response']:
|
227
|
+
raise(ValueError('Invalid variableName in guardrail mapping schema'))
|
228
|
+
if 'model' in guardrail.get('config'):
|
229
|
+
if guardrail.get('config',{}).get('model','') not in ['gpt-4o-mini','gpt-4o','gpt-4-turbo']:
|
230
|
+
raise(ValueError('Invalid model name in guardrail model schema'))
|
231
|
+
if 'params' not in guardrail.get('config'):
|
232
|
+
guardrail['config']['params'] = {
|
233
|
+
"isActive": {"value": False},
|
234
|
+
"isHighRisk": {"value": False},
|
235
|
+
"threshold": {"lt": 1}
|
236
|
+
}
|
237
|
+
|
238
|
+
|
212
239
|
data = {
|
240
|
+
"displayName": guardrail["displayName"],
|
213
241
|
"name": guardrail["name"],
|
214
|
-
"
|
215
|
-
"isHighRisk": guardrail.get("isHighRisk", False),
|
216
|
-
"isActive": guardrail.get("isActive", False),
|
217
|
-
"threshold": {}
|
242
|
+
"config": guardrail.get("config", {})
|
218
243
|
}
|
244
|
+
'''
|
219
245
|
if "lte" in guardrail["threshold"]:
|
220
246
|
data["threshold"]["lte"] = guardrail["threshold"]["lte"]
|
221
247
|
elif "gte" in guardrail["threshold"]:
|
@@ -223,7 +249,7 @@ class GuardrailsManager:
|
|
223
249
|
elif "eq" in guardrail["threshold"]:
|
224
250
|
data["threshold"]["eq"] = guardrail["threshold"]["eq"]
|
225
251
|
else:
|
226
|
-
data["threshold"]["gte"] = 0.0
|
252
|
+
data["threshold"]["gte"] = 0.0'''
|
227
253
|
return data
|
228
254
|
|
229
255
|
|
@@ -36,7 +36,7 @@ def api_completion(messages, model_config, kwargs):
|
|
36
36
|
raise ValueError(response["error"]["message"])
|
37
37
|
else:
|
38
38
|
result= response["choices"][0]["message"]["content"]
|
39
|
-
response1 = result.replace('\n', '')
|
39
|
+
response1 = result.replace('\n', '').replace('```json','').replace('```', '').strip()
|
40
40
|
try:
|
41
41
|
json_data = json.loads(response1)
|
42
42
|
df = pd.DataFrame(json_data)
|
@@ -23,7 +23,7 @@ class PromptManager:
|
|
23
23
|
self.project_name = project_name
|
24
24
|
self.base_url = f"{RagaAICatalyst.BASE_URL}/playground/prompt"
|
25
25
|
self.timeout = 10
|
26
|
-
self.size =
|
26
|
+
self.size = 99999 #Number of projects to fetch
|
27
27
|
|
28
28
|
try:
|
29
29
|
response = requests.get(
|
@@ -432,7 +432,12 @@ class PromptObject:
|
|
432
432
|
Returns:
|
433
433
|
dict: A dictionary of parameters found in the prompt text.
|
434
434
|
"""
|
435
|
-
parameters = {
|
435
|
+
parameters = {}
|
436
|
+
for param in self.parameters:
|
437
|
+
if "value" in param:
|
438
|
+
parameters[param["name"]] = self._convert_value(param["value"], param["type"])
|
439
|
+
else:
|
440
|
+
parameters[param["name"]] = ""
|
436
441
|
parameters["model"] = self.model
|
437
442
|
return parameters
|
438
443
|
|
@@ -287,7 +287,7 @@ class RagaAICatalyst:
|
|
287
287
|
def get_project_id(self, project_name):
|
288
288
|
pass
|
289
289
|
|
290
|
-
def list_projects(self, num_projects=
|
290
|
+
def list_projects(self, num_projects=99999):
|
291
291
|
"""
|
292
292
|
Retrieves a list of projects with the specified number of projects.
|
293
293
|
|
@@ -141,6 +141,9 @@ class SyntheticDataGeneration:
|
|
141
141
|
|
142
142
|
def _initialize_client(self, provider, api_key, api_base=None, internal_llm_proxy=None):
|
143
143
|
"""Initialize the appropriate client based on provider."""
|
144
|
+
if not provider:
|
145
|
+
raise ValueError("Model configuration must be provided with a valid provider and model.")
|
146
|
+
|
144
147
|
if provider == "groq":
|
145
148
|
if api_key is None and os.getenv("GROQ_API_KEY") is None:
|
146
149
|
raise ValueError("API key must be provided for Groq.")
|
@@ -155,6 +158,9 @@ class SyntheticDataGeneration:
|
|
155
158
|
if api_key is None and os.getenv("OPENAI_API_KEY") is None and internal_llm_proxy is None:
|
156
159
|
raise ValueError("API key must be provided for OpenAI.")
|
157
160
|
openai.api_key = api_key or os.getenv("OPENAI_API_KEY")
|
161
|
+
|
162
|
+
else:
|
163
|
+
raise ValueError(f"Provider is not recognized.")
|
158
164
|
|
159
165
|
def _generate_batch_response(self, text, system_message, provider, model_config, api_key, api_base):
|
160
166
|
"""Generate a batch of responses using the specified provider."""
|
@@ -283,6 +289,7 @@ class SyntheticDataGeneration:
|
|
283
289
|
|
284
290
|
# Extract the content from the response
|
285
291
|
content = response.choices[0].message.content
|
292
|
+
content = content.replace('\n', '').replace('```json','').replace('```', '').strip()
|
286
293
|
|
287
294
|
# Clean the response if needed (remove any prefix before the JSON list)
|
288
295
|
list_start_index = content.find('[')
|