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.
@@ -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 in seconds (6 hours by default)
153
- # TODO: Change this to 23 hours
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() + self.TOKEN_EXPIRATION_TIME
230
- logger.info(f"Token refreshed successfully. Next refresh in {self.TOKEN_EXPIRATION_TIME/3600:.1f} hours")
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: Asynchronous refresh in background
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 or about to expire - async refresh
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
- return {k: recursive_mask_values(v, k) for k, v in obj.items()}
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.5b3
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=lMmWPqRMr1IGVCKrCxk6Vfip-z7yfzTh9jqE-rb4I3Q,22248
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=pKHP5PK4au9Gdis-anYmu2PTmqWc4tNDrJvZWWRLQVo,40753
35
- ragaai_catalyst/tracers/upload_traces.py,sha256=yfg1vHP5quz2Vb8xkas_vzXwIrTVqRwrmFNCTrWvFdg,6938
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.5b3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
92
- ragaai_catalyst-2.1.7.5b3.dist-info/METADATA,sha256=gn-nsj810EAkUigEje4FodHJ7AA-vCvslLPRcBAlH94,17607
93
- ragaai_catalyst-2.1.7.5b3.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
94
- ragaai_catalyst-2.1.7.5b3.dist-info/top_level.txt,sha256=HpgsdRgEJMk8nqrU6qdCYk3di7MJkDL0B19lkc7dLfM,16
95
- ragaai_catalyst-2.1.7.5b3.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.4.0)
2
+ Generator: setuptools (80.7.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5