ragaai-catalyst 2.2.1b1__py3-none-any.whl → 2.2.2__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 +119 -82
- ragaai_catalyst/tracers/agentic_tracing/upload/trace_uploader.py +14 -15
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py +132 -67
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_code.py +156 -72
- ragaai_catalyst/tracers/tracer.py +67 -39
- {ragaai_catalyst-2.2.1b1.dist-info → ragaai_catalyst-2.2.2.dist-info}/METADATA +1 -1
- {ragaai_catalyst-2.2.1b1.dist-info → ragaai_catalyst-2.2.2.dist-info}/RECORD +10 -10
- {ragaai_catalyst-2.2.1b1.dist-info → ragaai_catalyst-2.2.2.dist-info}/WHEEL +1 -1
- {ragaai_catalyst-2.2.1b1.dist-info → ragaai_catalyst-2.2.2.dist-info}/licenses/LICENSE +0 -0
- {ragaai_catalyst-2.2.1b1.dist-info → ragaai_catalyst-2.2.2.dist-info}/top_level.txt +0 -0
@@ -1,15 +1,18 @@
|
|
1
|
-
import os
|
2
1
|
import logging
|
3
|
-
import
|
4
|
-
import
|
2
|
+
import os
|
3
|
+
import re
|
5
4
|
import threading
|
5
|
+
import time
|
6
6
|
from typing import Dict, Optional, Union
|
7
|
-
|
7
|
+
|
8
|
+
import requests
|
9
|
+
|
8
10
|
logger = logging.getLogger("RagaAICatalyst")
|
9
11
|
logging_level = (
|
10
12
|
logger.setLevel(logging.DEBUG) if os.getenv("DEBUG") == "1" else logging.INFO
|
11
13
|
)
|
12
14
|
|
15
|
+
|
13
16
|
class RagaAICatalyst:
|
14
17
|
BASE_URL = None
|
15
18
|
TIMEOUT = 10 # Default timeout in seconds
|
@@ -49,15 +52,15 @@ class RagaAICatalyst:
|
|
49
52
|
"RAGAAI_CATALYST_ACCESS_KEY and RAGAAI_CATALYST_SECRET_KEY environment variables must be set"
|
50
53
|
)
|
51
54
|
|
52
|
-
|
53
|
-
access_key, secret_key
|
55
|
+
RagaAICatalyst.access_key, RagaAICatalyst.secret_key = (
|
56
|
+
self._set_access_key_secret_key(access_key, secret_key)
|
54
57
|
)
|
55
58
|
|
56
59
|
# Initialize token management
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
RagaAICatalyst._token_expiry = None
|
61
|
+
RagaAICatalyst._token_refresh_lock = threading.Lock()
|
62
|
+
RagaAICatalyst._refresh_thread = None
|
63
|
+
|
61
64
|
# Set token expiration time (convert hours to seconds)
|
62
65
|
RagaAICatalyst.TOKEN_EXPIRY_TIME = token_expiry_time * 60 * 60
|
63
66
|
|
@@ -72,16 +75,16 @@ class RagaAICatalyst:
|
|
72
75
|
if base_url:
|
73
76
|
RagaAICatalyst.BASE_URL = self._normalize_base_url(base_url)
|
74
77
|
try:
|
75
|
-
#set the os.environ["RAGAAI_CATALYST_BASE_URL"] before getting the token as it is used in the get_token method
|
78
|
+
# set the os.environ["RAGAAI_CATALYST_BASE_URL"] before getting the token as it is used in the get_token method
|
76
79
|
os.environ["RAGAAI_CATALYST_BASE_URL"] = RagaAICatalyst.BASE_URL
|
77
|
-
|
80
|
+
RagaAICatalyst.get_token(force_refresh=True)
|
78
81
|
except requests.exceptions.RequestException:
|
79
82
|
raise ConnectionError(
|
80
83
|
"The provided base_url is not accessible. Please re-check the base_url."
|
81
84
|
)
|
82
85
|
else:
|
83
86
|
# Get the token from the server
|
84
|
-
|
87
|
+
RagaAICatalyst.get_token(force_refresh=True)
|
85
88
|
|
86
89
|
# Set the API keys, if available
|
87
90
|
if self.api_keys:
|
@@ -89,9 +92,11 @@ class RagaAICatalyst:
|
|
89
92
|
|
90
93
|
@staticmethod
|
91
94
|
def _normalize_base_url(url):
|
92
|
-
url = re.sub(
|
93
|
-
|
94
|
-
|
95
|
+
url = re.sub(
|
96
|
+
r"(?<!:)//+", "/", url
|
97
|
+
) # Ignore the `://` part of URLs and remove extra // if any
|
98
|
+
url = url.rstrip("/") # To remove trailing slashes
|
99
|
+
if not url.endswith("/api"): # To ensure it ends with /api
|
95
100
|
url = f"{url}/api"
|
96
101
|
return url
|
97
102
|
|
@@ -141,7 +146,8 @@ class RagaAICatalyst:
|
|
141
146
|
)
|
142
147
|
elapsed_ms = (time.time() - start_time) * 1000
|
143
148
|
logger.debug(
|
144
|
-
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
149
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
150
|
+
)
|
145
151
|
if response.status_code == 200:
|
146
152
|
print("API keys uploaded successfully")
|
147
153
|
else:
|
@@ -158,43 +164,58 @@ class RagaAICatalyst:
|
|
158
164
|
# Token expiration time is now configurable via the token_expiry_time parameter
|
159
165
|
# Default is 6 hours, but can be changed to 23 hours or any other value
|
160
166
|
|
161
|
-
|
167
|
+
@staticmethod
|
168
|
+
def _get_credentials() -> tuple[str, str]:
|
162
169
|
"""Get access key and secret key from instance or environment."""
|
163
|
-
access_key =
|
164
|
-
|
170
|
+
access_key = RagaAICatalyst.access_key or os.getenv(
|
171
|
+
"RAGAAI_CATALYST_ACCESS_KEY"
|
172
|
+
)
|
173
|
+
secret_key = RagaAICatalyst.secret_key or os.getenv(
|
174
|
+
"RAGAAI_CATALYST_SECRET_KEY"
|
175
|
+
)
|
165
176
|
return access_key, secret_key
|
166
177
|
|
167
|
-
|
178
|
+
@staticmethod
|
179
|
+
def _refresh_token_async():
|
168
180
|
"""Refresh token in background thread."""
|
169
181
|
try:
|
170
|
-
|
182
|
+
RagaAICatalyst.get_token(force_refresh=True)
|
171
183
|
except Exception as e:
|
172
184
|
logger.error(f"Background token refresh failed: {str(e)}")
|
173
|
-
|
174
|
-
|
185
|
+
|
186
|
+
@staticmethod
|
187
|
+
def _schedule_token_refresh():
|
175
188
|
"""Schedule a token refresh to happen 20 seconds before expiration."""
|
176
|
-
if not
|
189
|
+
if not RagaAICatalyst._token_expiry:
|
177
190
|
return
|
178
|
-
|
191
|
+
|
179
192
|
# Calculate when to refresh (20 seconds before expiration)
|
180
193
|
current_time = time.time()
|
181
|
-
refresh_buffer = min(
|
182
|
-
|
183
|
-
|
194
|
+
refresh_buffer = min(
|
195
|
+
20, RagaAICatalyst.TOKEN_EXPIRY_TIME * 0.05
|
196
|
+
) # 20 seconds or 5% of expiry time, whichever is smaller
|
197
|
+
time_until_refresh = max(
|
198
|
+
RagaAICatalyst._token_expiry - current_time - refresh_buffer, 1
|
199
|
+
) # At least 1 second
|
200
|
+
|
184
201
|
def delayed_refresh():
|
185
202
|
# Sleep until it's time to refresh
|
186
203
|
time.sleep(time_until_refresh)
|
187
|
-
logger.debug(
|
188
|
-
|
189
|
-
|
204
|
+
logger.debug("Scheduled token refresh triggered")
|
205
|
+
RagaAICatalyst._refresh_token_async()
|
206
|
+
|
190
207
|
# Start a new thread for the delayed refresh
|
191
|
-
if
|
192
|
-
|
193
|
-
|
194
|
-
|
208
|
+
if (
|
209
|
+
not RagaAICatalyst._refresh_thread
|
210
|
+
or not RagaAICatalyst._refresh_thread.is_alive()
|
211
|
+
):
|
212
|
+
RagaAICatalyst._refresh_thread = threading.Thread(target=delayed_refresh)
|
213
|
+
RagaAICatalyst._refresh_thread.daemon = True
|
214
|
+
RagaAICatalyst._refresh_thread.start()
|
195
215
|
logger.debug(f"Token refresh scheduled in {time_until_refresh:.1f} seconds")
|
196
216
|
|
197
|
-
|
217
|
+
@staticmethod
|
218
|
+
def get_token(force_refresh=True) -> Union[str, None]:
|
198
219
|
"""
|
199
220
|
Retrieves or refreshes a token using the provided credentials.
|
200
221
|
|
@@ -205,15 +226,20 @@ class RagaAICatalyst:
|
|
205
226
|
- A string representing the token if successful.
|
206
227
|
- None if credentials are not set or if there is an error.
|
207
228
|
"""
|
208
|
-
with
|
229
|
+
with RagaAICatalyst._token_refresh_lock:
|
209
230
|
current_token = os.getenv("RAGAAI_CATALYST_TOKEN")
|
210
231
|
current_time = time.time()
|
211
232
|
|
212
233
|
# Check if we need to refresh the token
|
213
|
-
if
|
234
|
+
if (
|
235
|
+
not force_refresh
|
236
|
+
and current_token
|
237
|
+
and RagaAICatalyst._token_expiry
|
238
|
+
and current_time < RagaAICatalyst._token_expiry
|
239
|
+
):
|
214
240
|
return current_token
|
215
241
|
|
216
|
-
access_key, secret_key =
|
242
|
+
access_key, secret_key = RagaAICatalyst._get_credentials()
|
217
243
|
if not access_key or not secret_key:
|
218
244
|
logger.error("Access key or secret key is not set")
|
219
245
|
return None
|
@@ -222,16 +248,17 @@ class RagaAICatalyst:
|
|
222
248
|
json_data = {"accessKey": access_key, "secretKey": secret_key}
|
223
249
|
|
224
250
|
start_time = time.time()
|
225
|
-
endpoint = f"{
|
251
|
+
endpoint = f"{RagaAICatalyst.BASE_URL}/token"
|
226
252
|
response = requests.post(
|
227
253
|
endpoint,
|
228
254
|
headers=headers,
|
229
255
|
json=json_data,
|
230
|
-
timeout=
|
256
|
+
timeout=RagaAICatalyst.TIMEOUT,
|
231
257
|
)
|
232
258
|
elapsed_ms = (time.time() - start_time) * 1000
|
233
259
|
logger.debug(
|
234
|
-
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
260
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
261
|
+
)
|
235
262
|
|
236
263
|
# Handle specific status codes before raising an error
|
237
264
|
if response.status_code == 400:
|
@@ -254,12 +281,16 @@ class RagaAICatalyst:
|
|
254
281
|
token = token_response.get("data", {}).get("token")
|
255
282
|
if token:
|
256
283
|
os.environ["RAGAAI_CATALYST_TOKEN"] = token
|
257
|
-
|
258
|
-
|
259
|
-
|
284
|
+
RagaAICatalyst._token_expiry = (
|
285
|
+
time.time() + RagaAICatalyst.TOKEN_EXPIRY_TIME
|
286
|
+
)
|
287
|
+
logger.debug(
|
288
|
+
f"Token refreshed successfully. Next refresh in {RagaAICatalyst.TOKEN_EXPIRY_TIME / 3600:.1f} hours"
|
289
|
+
)
|
290
|
+
|
260
291
|
# Schedule token refresh 20 seconds before expiration
|
261
|
-
|
262
|
-
|
292
|
+
RagaAICatalyst._schedule_token_refresh()
|
293
|
+
|
263
294
|
return token
|
264
295
|
else:
|
265
296
|
logger.error("Token(s) not set")
|
@@ -286,14 +317,16 @@ class RagaAICatalyst:
|
|
286
317
|
if not self._token_expiry or current_time >= self._token_expiry:
|
287
318
|
logger.info("Token expired, refreshing synchronously")
|
288
319
|
return self.get_token(force_refresh=True)
|
289
|
-
|
320
|
+
|
290
321
|
# Case 3: Token valid but approaching expiry (less than 10% of lifetime remaining)
|
291
322
|
# Start background refresh but return current token
|
292
323
|
token_remaining_time = self._token_expiry - current_time
|
293
324
|
if token_remaining_time < (RagaAICatalyst.TOKEN_EXPIRY_TIME * 0.1):
|
294
325
|
if not self._refresh_thread or not self._refresh_thread.is_alive():
|
295
326
|
logger.info("Token approaching expiry, starting background refresh")
|
296
|
-
self._refresh_thread = threading.Thread(
|
327
|
+
self._refresh_thread = threading.Thread(
|
328
|
+
target=self._refresh_token_async
|
329
|
+
)
|
297
330
|
self._refresh_thread.daemon = True
|
298
331
|
self._refresh_thread.start()
|
299
332
|
|
@@ -319,14 +352,11 @@ class RagaAICatalyst:
|
|
319
352
|
headers = self.get_auth_header()
|
320
353
|
start_time = time.time()
|
321
354
|
endpoint = f"{RagaAICatalyst.BASE_URL}/v2/llm/usecase"
|
322
|
-
response = requests.get(
|
323
|
-
endpoint,
|
324
|
-
headers=headers,
|
325
|
-
timeout=self.TIMEOUT
|
326
|
-
)
|
355
|
+
response = requests.get(endpoint, headers=headers, timeout=self.TIMEOUT)
|
327
356
|
elapsed_ms = (time.time() - start_time) * 1000
|
328
357
|
logger.debug(
|
329
|
-
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
358
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
359
|
+
)
|
330
360
|
response.raise_for_status() # Use raise_for_status to handle HTTP errors
|
331
361
|
usecase = response.json()["data"]["usecase"]
|
332
362
|
return usecase
|
@@ -349,16 +379,18 @@ class RagaAICatalyst:
|
|
349
379
|
# Check if the project already exists
|
350
380
|
existing_projects = self.list_projects()
|
351
381
|
if project_name in existing_projects:
|
352
|
-
raise ValueError(
|
382
|
+
raise ValueError(
|
383
|
+
f"Project name '{project_name}' already exists. Please choose a different name."
|
384
|
+
)
|
353
385
|
|
354
386
|
usecase_list = self.project_use_cases()
|
355
387
|
if usecase not in usecase_list:
|
356
388
|
raise ValueError(f"Select a valid usecase from {usecase_list}")
|
357
|
-
|
389
|
+
|
358
390
|
json_data = {"name": project_name, "type": type, "usecase": usecase}
|
359
391
|
headers = {
|
360
392
|
"Content-Type": "application/json",
|
361
|
-
"Authorization": f
|
393
|
+
"Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
|
362
394
|
}
|
363
395
|
try:
|
364
396
|
start_time = time.time()
|
@@ -371,19 +403,20 @@ class RagaAICatalyst:
|
|
371
403
|
)
|
372
404
|
elapsed_ms = (time.time() - start_time) * 1000
|
373
405
|
logger.debug(
|
374
|
-
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
406
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
407
|
+
)
|
375
408
|
response.raise_for_status()
|
376
409
|
print(
|
377
410
|
f"Project Created Successfully with name {response.json()['data']['name']} & usecase {usecase}"
|
378
411
|
)
|
379
|
-
return f
|
412
|
+
return f"Project Created Successfully with name {response.json()['data']['name']} & usecase {usecase}"
|
380
413
|
|
381
414
|
except requests.exceptions.HTTPError as http_err:
|
382
415
|
if response.status_code == 401:
|
383
416
|
logger.warning("Received 401 error. Attempting to refresh token.")
|
384
|
-
|
417
|
+
RagaAICatalyst.get_token(force_refresh=True)
|
385
418
|
headers["Authorization"] = (
|
386
|
-
f
|
419
|
+
f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}"
|
387
420
|
)
|
388
421
|
try:
|
389
422
|
response = requests.post(
|
@@ -397,7 +430,7 @@ class RagaAICatalyst:
|
|
397
430
|
"Project Created Successfully with name %s after token refresh",
|
398
431
|
response.json()["data"]["name"],
|
399
432
|
)
|
400
|
-
return f
|
433
|
+
return f"Project Created Successfully with name {response.json()['data']['name']}"
|
401
434
|
except requests.exceptions.HTTPError as refresh_http_err:
|
402
435
|
logger.error(
|
403
436
|
"Failed to create project after token refresh: %s",
|
@@ -432,7 +465,7 @@ class RagaAICatalyst:
|
|
432
465
|
list: A list of project names retrieved successfully.
|
433
466
|
"""
|
434
467
|
headers = {
|
435
|
-
"Authorization": f
|
468
|
+
"Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
|
436
469
|
}
|
437
470
|
try:
|
438
471
|
start_time = time.time()
|
@@ -444,7 +477,8 @@ class RagaAICatalyst:
|
|
444
477
|
)
|
445
478
|
elapsed_ms = (time.time() - start_time) * 1000
|
446
479
|
logger.debug(
|
447
|
-
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
480
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
481
|
+
)
|
448
482
|
response.raise_for_status()
|
449
483
|
logger.debug("Projects list retrieved successfully")
|
450
484
|
|
@@ -456,9 +490,9 @@ class RagaAICatalyst:
|
|
456
490
|
except requests.exceptions.HTTPError as http_err:
|
457
491
|
if response.status_code == 401:
|
458
492
|
logger.warning("Received 401 error. Attempting to refresh token.")
|
459
|
-
|
493
|
+
RagaAICatalyst.get_token(force_refresh=True)
|
460
494
|
headers["Authorization"] = (
|
461
|
-
f
|
495
|
+
f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}"
|
462
496
|
)
|
463
497
|
try:
|
464
498
|
response = requests.get(
|
@@ -466,17 +500,19 @@ class RagaAICatalyst:
|
|
466
500
|
headers=headers,
|
467
501
|
timeout=self.TIMEOUT,
|
468
502
|
)
|
469
|
-
|
503
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
470
504
|
logger.debug(
|
471
|
-
"
|
505
|
+
f"API Call:[GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
472
506
|
)
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
]
|
478
|
-
|
479
|
-
|
507
|
+
response.raise_for_status()
|
508
|
+
logger.debug("Projects list retrieved successfully")
|
509
|
+
|
510
|
+
project_list = [
|
511
|
+
project["name"]
|
512
|
+
for project in response.json()["data"]["content"]
|
513
|
+
]
|
514
|
+
|
515
|
+
return project_list
|
480
516
|
|
481
517
|
except requests.exceptions.HTTPError as refresh_http_err:
|
482
518
|
logger.error(
|
@@ -505,7 +541,7 @@ class RagaAICatalyst:
|
|
505
541
|
def list_metrics():
|
506
542
|
headers = {
|
507
543
|
"Content-Type": "application/json",
|
508
|
-
"Authorization": f
|
544
|
+
"Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
|
509
545
|
}
|
510
546
|
try:
|
511
547
|
start_time = time.time()
|
@@ -517,7 +553,8 @@ class RagaAICatalyst:
|
|
517
553
|
)
|
518
554
|
elapsed_ms = (time.time() - start_time) * 1000
|
519
555
|
logger.debug(
|
520
|
-
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
556
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
557
|
+
)
|
521
558
|
response.raise_for_status()
|
522
559
|
logger.debug("Metrics list retrieved successfully")
|
523
560
|
|
@@ -529,15 +566,15 @@ class RagaAICatalyst:
|
|
529
566
|
except requests.exceptions.HTTPError as http_err:
|
530
567
|
if response.status_code == 401:
|
531
568
|
logger.warning("Received 401 error. Attempting to refresh token.")
|
532
|
-
|
569
|
+
RagaAICatalyst.get_token(force_refresh=True)
|
533
570
|
headers["Authorization"] = (
|
534
|
-
f
|
571
|
+
f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}"
|
535
572
|
)
|
536
573
|
try:
|
537
574
|
response = requests.get(
|
538
575
|
f"{RagaAICatalyst.BASE_URL}/v1/llm/llm-metrics",
|
539
576
|
headers=headers,
|
540
|
-
timeout=
|
577
|
+
timeout=RagaAICatalyst.TIMEOUT,
|
541
578
|
)
|
542
579
|
response.raise_for_status()
|
543
580
|
logger.debug(
|
@@ -2,23 +2,17 @@
|
|
2
2
|
trace_uploader.py - A dedicated process for handling trace uploads
|
3
3
|
"""
|
4
4
|
|
5
|
-
import
|
6
|
-
import
|
5
|
+
import argparse
|
6
|
+
import atexit
|
7
|
+
import concurrent.futures
|
7
8
|
import json
|
8
|
-
import time
|
9
|
-
import signal
|
10
9
|
import logging
|
11
|
-
import
|
10
|
+
import os
|
12
11
|
import tempfile
|
13
|
-
|
14
|
-
import multiprocessing
|
15
|
-
import queue
|
12
|
+
import time
|
16
13
|
from datetime import datetime
|
17
|
-
import atexit
|
18
|
-
import glob
|
19
14
|
from logging.handlers import RotatingFileHandler
|
20
|
-
import
|
21
|
-
from typing import Dict, Any, Optional
|
15
|
+
from typing import Any, Dict
|
22
16
|
|
23
17
|
# Set up logging
|
24
18
|
log_dir = os.path.join(tempfile.gettempdir(), "ragaai_logs")
|
@@ -43,11 +37,16 @@ logging.basicConfig(
|
|
43
37
|
logger = logging.getLogger("trace_uploader")
|
44
38
|
|
45
39
|
try:
|
46
|
-
from ragaai_catalyst
|
40
|
+
from ragaai_catalyst import RagaAICatalyst
|
41
|
+
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_agentic_traces import (
|
42
|
+
UploadAgenticTraces,
|
43
|
+
)
|
47
44
|
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_code import upload_code
|
45
|
+
|
48
46
|
# from ragaai_catalyst.tracers.agentic_tracing.upload.upload_trace_metric import upload_trace_metric
|
49
|
-
from ragaai_catalyst.tracers.agentic_tracing.utils.create_dataset_schema import
|
50
|
-
|
47
|
+
from ragaai_catalyst.tracers.agentic_tracing.utils.create_dataset_schema import (
|
48
|
+
create_dataset_schema_with_trace,
|
49
|
+
)
|
51
50
|
IMPORTS_AVAILABLE = True
|
52
51
|
except ImportError:
|
53
52
|
logger.warning("RagaAI Catalyst imports not available - running in test mode")
|