ragaai-catalyst 2.1.7.5b3__py3-none-any.whl → 2.1.7.5b5__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/ragaai_catalyst.py +48 -7
- ragaai_catalyst/tracers/tracer.py +51 -1
- ragaai_catalyst/tracers/upload_traces.py +2 -1
- {ragaai_catalyst-2.1.7.5b3.dist-info → ragaai_catalyst-2.1.7.5b5.dist-info}/METADATA +1 -1
- {ragaai_catalyst-2.1.7.5b3.dist-info → ragaai_catalyst-2.1.7.5b5.dist-info}/RECORD +8 -8
- {ragaai_catalyst-2.1.7.5b3.dist-info → ragaai_catalyst-2.1.7.5b5.dist-info}/WHEEL +1 -1
- {ragaai_catalyst-2.1.7.5b3.dist-info → ragaai_catalyst-2.1.7.5b5.dist-info}/licenses/LICENSE +0 -0
- {ragaai_catalyst-2.1.7.5b3.dist-info → ragaai_catalyst-2.1.7.5b5.dist-info}/top_level.txt +0 -0
@@ -13,6 +13,7 @@ logging_level = (
|
|
13
13
|
class RagaAICatalyst:
|
14
14
|
BASE_URL = None
|
15
15
|
TIMEOUT = 10 # Default timeout in seconds
|
16
|
+
TOKEN_EXPIRY_TIME = 6 # Default token expiration time (6 hours in hours)
|
16
17
|
|
17
18
|
def __init__(
|
18
19
|
self,
|
@@ -20,6 +21,7 @@ class RagaAICatalyst:
|
|
20
21
|
secret_key,
|
21
22
|
api_keys: Optional[Dict[str, str]] = None,
|
22
23
|
base_url: Optional[str] = None,
|
24
|
+
token_expiry_time: Optional[float] = 6,
|
23
25
|
):
|
24
26
|
"""
|
25
27
|
Initializes a new instance of the RagaAICatalyst class.
|
@@ -29,6 +31,7 @@ class RagaAICatalyst:
|
|
29
31
|
secret_key (str): The secret key for the RagaAICatalyst.
|
30
32
|
api_keys (Optional[Dict[str, str]]): A dictionary of API keys for different services. Defaults to None.
|
31
33
|
base_url (Optional[str]): The base URL for the RagaAICatalyst API. Defaults to None.
|
34
|
+
token_expiry_time (Optional[float]): The time in hours before the token expires. Defaults to 0.1 hours.
|
32
35
|
|
33
36
|
Raises:
|
34
37
|
ValueError: If the RAGAAI_CATALYST_ACCESS_KEY and RAGAAI_CATALYST_SECRET_KEY environment variables are not set.
|
@@ -54,6 +57,9 @@ class RagaAICatalyst:
|
|
54
57
|
self._token_expiry = None
|
55
58
|
self._token_refresh_lock = threading.Lock()
|
56
59
|
self._refresh_thread = None
|
60
|
+
|
61
|
+
# Set token expiration time (convert hours to seconds)
|
62
|
+
RagaAICatalyst.TOKEN_EXPIRY_TIME = token_expiry_time * 60 * 60
|
57
63
|
|
58
64
|
RagaAICatalyst.BASE_URL = (
|
59
65
|
os.getenv("RAGAAI_CATALYST_BASE_URL")
|
@@ -149,9 +155,8 @@ class RagaAICatalyst:
|
|
149
155
|
"""Get the API key for a specific service."""
|
150
156
|
return self.api_keys.get(service)
|
151
157
|
|
152
|
-
# Token expiration time
|
153
|
-
#
|
154
|
-
TOKEN_EXPIRATION_TIME = 6 * 60 * 60
|
158
|
+
# Token expiration time is now configurable via the token_expiry_time parameter
|
159
|
+
# Default is 6 hours, but can be changed to 23 hours or any other value
|
155
160
|
|
156
161
|
def _get_credentials(self) -> tuple[str, str]:
|
157
162
|
"""Get access key and secret key from instance or environment."""
|
@@ -165,6 +170,29 @@ class RagaAICatalyst:
|
|
165
170
|
self.get_token(force_refresh=True)
|
166
171
|
except Exception as e:
|
167
172
|
logger.error(f"Background token refresh failed: {str(e)}")
|
173
|
+
|
174
|
+
def _schedule_token_refresh(self):
|
175
|
+
"""Schedule a token refresh to happen 20 seconds before expiration."""
|
176
|
+
if not self._token_expiry:
|
177
|
+
return
|
178
|
+
|
179
|
+
# Calculate when to refresh (20 seconds before expiration)
|
180
|
+
current_time = time.time()
|
181
|
+
refresh_buffer = min(20, RagaAICatalyst.TOKEN_EXPIRY_TIME * 0.05) # 20 seconds or 5% of expiry time, whichever is smaller
|
182
|
+
time_until_refresh = max(self._token_expiry - current_time - refresh_buffer, 1) # At least 1 second
|
183
|
+
|
184
|
+
def delayed_refresh():
|
185
|
+
# Sleep until it's time to refresh
|
186
|
+
time.sleep(time_until_refresh)
|
187
|
+
logger.debug(f"Scheduled token refresh triggered")
|
188
|
+
self._refresh_token_async()
|
189
|
+
|
190
|
+
# Start a new thread for the delayed refresh
|
191
|
+
if not self._refresh_thread or not self._refresh_thread.is_alive():
|
192
|
+
self._refresh_thread = threading.Thread(target=delayed_refresh)
|
193
|
+
self._refresh_thread.daemon = True
|
194
|
+
self._refresh_thread.start()
|
195
|
+
logger.debug(f"Token refresh scheduled in {time_until_refresh:.1f} seconds")
|
168
196
|
|
169
197
|
def get_token(self, force_refresh=False) -> Union[str, None]:
|
170
198
|
"""
|
@@ -226,8 +254,12 @@ class RagaAICatalyst:
|
|
226
254
|
token = token_response.get("data", {}).get("token")
|
227
255
|
if token:
|
228
256
|
os.environ["RAGAAI_CATALYST_TOKEN"] = token
|
229
|
-
self._token_expiry = time.time() +
|
230
|
-
logger.
|
257
|
+
self._token_expiry = time.time() + RagaAICatalyst.TOKEN_EXPIRY_TIME
|
258
|
+
logger.debug(f"Token refreshed successfully. Next refresh in {RagaAICatalyst.TOKEN_EXPIRY_TIME/3600:.1f} hours")
|
259
|
+
|
260
|
+
# Schedule token refresh 20 seconds before expiration
|
261
|
+
self._schedule_token_refresh()
|
262
|
+
|
231
263
|
return token
|
232
264
|
else:
|
233
265
|
logger.error("Token(s) not set")
|
@@ -237,7 +269,7 @@ class RagaAICatalyst:
|
|
237
269
|
"""
|
238
270
|
Ensures a valid token is available, with different handling for missing token vs expired token:
|
239
271
|
- Missing token: Synchronous retrieval (fail fast)
|
240
|
-
- Expired token:
|
272
|
+
- Expired token: Synchronous refresh (since token is needed immediately)
|
241
273
|
|
242
274
|
Returns:
|
243
275
|
- A string representing the valid token if successful.
|
@@ -250,13 +282,22 @@ class RagaAICatalyst:
|
|
250
282
|
if not current_token:
|
251
283
|
return self.get_token(force_refresh=True)
|
252
284
|
|
253
|
-
# Case 2: Token expired
|
285
|
+
# Case 2: Token expired - synchronous refresh (since we need a valid token now)
|
254
286
|
if not self._token_expiry or current_time >= self._token_expiry:
|
287
|
+
logger.info("Token expired, refreshing synchronously")
|
288
|
+
return self.get_token(force_refresh=True)
|
289
|
+
|
290
|
+
# Case 3: Token valid but approaching expiry (less than 10% of lifetime remaining)
|
291
|
+
# Start background refresh but return current token
|
292
|
+
token_remaining_time = self._token_expiry - current_time
|
293
|
+
if token_remaining_time < (RagaAICatalyst.TOKEN_EXPIRY_TIME * 0.1):
|
255
294
|
if not self._refresh_thread or not self._refresh_thread.is_alive():
|
295
|
+
logger.info("Token approaching expiry, starting background refresh")
|
256
296
|
self._refresh_thread = threading.Thread(target=self._refresh_token_async)
|
257
297
|
self._refresh_thread.daemon = True
|
258
298
|
self._refresh_thread.start()
|
259
299
|
|
300
|
+
# Return current token (which is valid)
|
260
301
|
return current_token
|
261
302
|
|
262
303
|
def get_auth_header(self) -> Dict[str, str]:
|
@@ -402,7 +402,50 @@ class Tracer(AgenticTracing):
|
|
402
402
|
def recursive_mask_values(obj, parent_key=None):
|
403
403
|
"""Apply masking to all values in nested structure."""
|
404
404
|
if isinstance(obj, dict):
|
405
|
-
|
405
|
+
if self.tracer_type == "langchain":
|
406
|
+
# Special handling for LangChain data
|
407
|
+
if isinstance(obj, dict):
|
408
|
+
if obj.get("name", "") == "retrieve_documents.langchain.workflow":
|
409
|
+
prompt_structured_data = {
|
410
|
+
"traceloop.entity.input": json.dumps({
|
411
|
+
"kwargs": {
|
412
|
+
"input": masking_func(json.loads(obj.get("attributes", {}).get("traceloop.entity.input", "")).get("kwargs", {}).get("input", "")),
|
413
|
+
}
|
414
|
+
})
|
415
|
+
}
|
416
|
+
prompt_data = {
|
417
|
+
"name": "retrieve_documents.langchain.workflow",
|
418
|
+
"attributes": prompt_structured_data,
|
419
|
+
}
|
420
|
+
return prompt_data
|
421
|
+
elif obj.get("name", "") == "PromptTemplate.langchain.task":
|
422
|
+
context_structured_data = {
|
423
|
+
"traceloop.entity.input": json.dumps({
|
424
|
+
"kwargs": {
|
425
|
+
"context": masking_func(json.loads(obj.get("attributes", {}).get("traceloop.entity.input", "")).get("kwargs", {}).get("context", "")),
|
426
|
+
}
|
427
|
+
}),
|
428
|
+
"traceloop.entity.output": json.dumps({
|
429
|
+
"kwargs": {
|
430
|
+
"text": masking_func(json.loads(obj.get("attributes", {}).get("traceloop.entity.output", "")).get("kwargs", {}).get("text", "")),
|
431
|
+
}
|
432
|
+
})
|
433
|
+
}
|
434
|
+
context_data = {
|
435
|
+
"name": "PromptTemplate.langchain.task",
|
436
|
+
"attributes": context_structured_data,
|
437
|
+
}
|
438
|
+
return context_data
|
439
|
+
elif obj.get("name", "") == "ChatOpenAI.langchain.task":
|
440
|
+
response_structured_data = {"gen_ai.completion.0.content": masking_func(obj.get("attributes", {}).get("gen_ai.completion.0.content", "")),
|
441
|
+
"gen_ai.prompt.0.content": masking_func(obj.get("attributes", {}).get("gen_ai.prompt.0.content", ""))}
|
442
|
+
response_data = {
|
443
|
+
"name": "ChatOpenAI.langchain.task",
|
444
|
+
"attributes" : response_structured_data
|
445
|
+
}
|
446
|
+
return response_data
|
447
|
+
else:
|
448
|
+
return {k: recursive_mask_values(v, k) for k, v in obj.items()}
|
406
449
|
elif isinstance(obj, list):
|
407
450
|
return [recursive_mask_values(item, parent_key) for item in obj]
|
408
451
|
elif isinstance(obj, str):
|
@@ -492,11 +535,18 @@ class Tracer(AgenticTracing):
|
|
492
535
|
'max_upload_workers': self.max_upload_workers
|
493
536
|
}
|
494
537
|
|
538
|
+
# Save the model_custom_cost before reinitialization
|
539
|
+
saved_model_custom_cost = self.model_custom_cost.copy()
|
540
|
+
|
495
541
|
# Reinitialize self with new external_id and stored parameters
|
496
542
|
self.__init__(
|
497
543
|
external_id=external_id,
|
498
544
|
**current_params
|
499
545
|
)
|
546
|
+
|
547
|
+
# Restore the model_custom_cost after reinitialization
|
548
|
+
self.model_custom_cost = saved_model_custom_cost
|
549
|
+
self.dynamic_exporter.custom_model_cost = self.model_custom_cost
|
500
550
|
|
501
551
|
|
502
552
|
|
@@ -37,7 +37,8 @@ class UploadTraces:
|
|
37
37
|
"model_name": {"columnType": "metadata"},
|
38
38
|
"total_cost": {"columnType": "metadata", "dataType": "numerical"},
|
39
39
|
"total_latency": {"columnType": "metadata", "dataType": "numerical"},
|
40
|
-
"error": {"columnType": "metadata"}
|
40
|
+
"error": {"columnType": "metadata"},
|
41
|
+
"externalId": {"columnType": "externalId"}
|
41
42
|
}
|
42
43
|
|
43
44
|
if additional_metadata_keys:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ragaai_catalyst
|
3
|
-
Version: 2.1.7.
|
3
|
+
Version: 2.1.7.5b5
|
4
4
|
Summary: RAGA AI CATALYST
|
5
5
|
Author-email: Kiran Scaria <kiran.scaria@raga.ai>, Kedar Gaikwad <kedar.gaikwad@raga.ai>, Dushyant Mahajan <dushyant.mahajan@raga.ai>, Siddhartha Kosti <siddhartha.kosti@raga.ai>, Ritika Goel <ritika.goel@raga.ai>, Vijay Chaurasia <vijay.chaurasia@raga.ai>, Tushar Kumar <tushar.kumar@raga.ai>
|
6
6
|
Requires-Python: <=3.13.2,>=3.10
|
@@ -8,7 +8,7 @@ ragaai_catalyst/guardrails_manager.py,sha256=_VrARJ1udmCF8TklNKy7XTQUaM8ATDhTOAG
|
|
8
8
|
ragaai_catalyst/internal_api_completion.py,sha256=DdICI5yfEudiOAIC8L4oxH0Qz7kX-BZCdo9IWsi2gNo,2965
|
9
9
|
ragaai_catalyst/prompt_manager.py,sha256=W8ypramzOprrJ7-22d5vkBXIuIQ8v9XAzKDGxKsTK28,16550
|
10
10
|
ragaai_catalyst/proxy_call.py,sha256=CHxldeceZUaLU-to_hs_Kf1z_b2vHMssLS_cOBedu78,5499
|
11
|
-
ragaai_catalyst/ragaai_catalyst.py,sha256=
|
11
|
+
ragaai_catalyst/ragaai_catalyst.py,sha256=W_heG_ab650rzQkAhSOoxaNy3JKHAIXNvivxtOPpyeg,24590
|
12
12
|
ragaai_catalyst/redteaming_old.py,sha256=W2d89Ok8W-C8g7TBM3fDIFLof3q9FuYSr0jcryH2XQo,7097
|
13
13
|
ragaai_catalyst/synthetic_data_generation.py,sha256=7lIWa3nwgW2-FlJrDaGxTN6OE4-dbbhLtKNOBQufhho,37952
|
14
14
|
ragaai_catalyst/utils.py,sha256=TlhEFwLyRU690HvANbyoRycR3nQ67lxVUQoUOfTPYQ0,3772
|
@@ -31,8 +31,8 @@ ragaai_catalyst/tracers/distributed.py,sha256=MwlBwIxCAng-OI-7Ove_rkE1mTLeuW4Jw-
|
|
31
31
|
ragaai_catalyst/tracers/langchain_callback.py,sha256=CB75zzG3-DkYTELj0vI1MOHQTY0MuQJfoHIXz9Cl8S8,34568
|
32
32
|
ragaai_catalyst/tracers/llamaindex_callback.py,sha256=ZY0BJrrlz-P9Mg2dX-ZkVKG3gSvzwqBtk7JL_05MiYA,14028
|
33
33
|
ragaai_catalyst/tracers/llamaindex_instrumentation.py,sha256=Ys_jLkvVqo12bKgXDmkp4TxJu9HkBATrFE8cIcTYxWw,14329
|
34
|
-
ragaai_catalyst/tracers/tracer.py,sha256=
|
35
|
-
ragaai_catalyst/tracers/upload_traces.py,sha256=
|
34
|
+
ragaai_catalyst/tracers/tracer.py,sha256=w9Poa2dsN3WNMPEH_v4M7SqFF_MQp_iSam4A-qcoAXM,43921
|
35
|
+
ragaai_catalyst/tracers/upload_traces.py,sha256=w1clGGfdOMpStUJX40NAlxe6dcFdN4pwcezyII0bGYA,6994
|
36
36
|
ragaai_catalyst/tracers/agentic_tracing/README.md,sha256=X4QwLb7-Jg7GQMIXj-SerZIgDETfw-7VgYlczOR8ZeQ,4508
|
37
37
|
ragaai_catalyst/tracers/agentic_tracing/__init__.py,sha256=yf6SKvOPSpH-9LiKaoLKXwqj5sez8F_5wkOb91yp0oE,260
|
38
38
|
ragaai_catalyst/tracers/agentic_tracing/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -88,8 +88,8 @@ ragaai_catalyst/tracers/utils/model_prices_and_context_window_backup.json,sha256
|
|
88
88
|
ragaai_catalyst/tracers/utils/rag_trace_json_converter.py,sha256=adCKk7Nj8307XYYg2sB-QT-66OShOs2iTGwNVwqbHig,19373
|
89
89
|
ragaai_catalyst/tracers/utils/trace_json_converter.py,sha256=E0_QfciQMMpCtQYrNB4l8HJhlaFalr5bkMqkVRgQahY,14073
|
90
90
|
ragaai_catalyst/tracers/utils/utils.py,sha256=ViygfJ7vZ7U0CTSA1lbxVloHp4NSlmfDzBRNCJuMhis,2374
|
91
|
-
ragaai_catalyst-2.1.7.
|
92
|
-
ragaai_catalyst-2.1.7.
|
93
|
-
ragaai_catalyst-2.1.7.
|
94
|
-
ragaai_catalyst-2.1.7.
|
95
|
-
ragaai_catalyst-2.1.7.
|
91
|
+
ragaai_catalyst-2.1.7.5b5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
92
|
+
ragaai_catalyst-2.1.7.5b5.dist-info/METADATA,sha256=qTUNGuVyjtbjoOnA2Zq_HARkI0TgkYnYj8qDU7W33aE,17607
|
93
|
+
ragaai_catalyst-2.1.7.5b5.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
94
|
+
ragaai_catalyst-2.1.7.5b5.dist-info/top_level.txt,sha256=HpgsdRgEJMk8nqrU6qdCYk3di7MJkDL0B19lkc7dLfM,16
|
95
|
+
ragaai_catalyst-2.1.7.5b5.dist-info/RECORD,,
|
{ragaai_catalyst-2.1.7.5b3.dist-info → ragaai_catalyst-2.1.7.5b5.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|