ragaai-catalyst 2.1.4.1b0__py3-none-any.whl → 2.1.5b0__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.
@@ -1,6 +1,5 @@
1
1
  from .experiment import Experiment
2
2
  from .ragaai_catalyst import RagaAICatalyst
3
- from .tracers import Tracer
4
3
  from .utils import response_checker
5
4
  from .dataset import Dataset
6
5
  from .prompt_manager import PromptManager
@@ -8,6 +7,24 @@ from .evaluation import Evaluation
8
7
  from .synthetic_data_generation import SyntheticDataGeneration
9
8
  from .guardrails_manager import GuardrailsManager
10
9
  from .guard_executor import GuardExecutor
10
+ from .tracers import Tracer, init_tracing, trace_agent, trace_llm, trace_tool, current_span, trace_custom
11
11
 
12
12
 
13
- __all__ = ["Experiment", "RagaAICatalyst", "Tracer", "PromptManager", "Evaluation","SyntheticDataGeneration", "GuardrailsManager"]
13
+
14
+
15
+ __all__ = [
16
+ "Experiment",
17
+ "RagaAICatalyst",
18
+ "Tracer",
19
+ "PromptManager",
20
+ "Evaluation",
21
+ "SyntheticDataGeneration",
22
+ "GuardrailsManager",
23
+ "GuardExecutor",
24
+ "init_tracing",
25
+ "trace_agent",
26
+ "trace_llm",
27
+ "trace_tool",
28
+ "current_span",
29
+ "trace_custom"
30
+ ]
@@ -1,3 +1,19 @@
1
1
  from .tracer import Tracer
2
+ from .distributed import (
3
+ init_tracing,
4
+ trace_agent,
5
+ trace_llm,
6
+ trace_tool,
7
+ current_span,
8
+ trace_custom,
9
+ )
2
10
 
3
- __all__ = ["Tracer"]
11
+ __all__ = [
12
+ "Tracer",
13
+ "init_tracing",
14
+ "trace_agent",
15
+ "trace_llm",
16
+ "trace_tool",
17
+ "current_span",
18
+ "trace_custom"
19
+ ]
@@ -271,7 +271,7 @@ class ComponentInfo:
271
271
  cost: Optional[Dict[str, float]] = None
272
272
 
273
273
  class Trace:
274
- def __init__(self, id: str, trace_name: str, project_name: str, start_time: str, end_time: str, metadata: Optional[Metadata] = None, data: Optional[List[Dict[str, Any]]] = None, replays: Optional[Dict[str, Any]] = None):
274
+ def __init__(self, id: str, trace_name: str, project_name: str, start_time: str, end_time: str, metadata: Optional[Metadata] = None, data: Optional[List[Dict[str, Any]]] = None, replays: Optional[Dict[str, Any]] = None, metrics: Optional[List[Dict[str, Any]]] = None):
275
275
  self.id = id
276
276
  self.trace_name = trace_name
277
277
  self.project_name = project_name
@@ -280,6 +280,7 @@ class Trace:
280
280
  self.metadata = metadata or Metadata()
281
281
  self.data = data or []
282
282
  self.replays = replays
283
+ self.metrics = metrics or []
283
284
 
284
285
  def to_dict(self):
285
286
  return {
@@ -288,7 +289,8 @@ class Trace:
288
289
  "project_name": self.project_name,
289
290
  "start_time": self.start_time,
290
291
  "end_time": self.end_time,
291
- "metadata": self.metadata.to_dict() if self.metadata else None,
292
+ "metadata": self.metadata,
292
293
  "data": self.data,
293
294
  "replays": self.replays,
295
+ "metrics": self.metrics
294
296
  }
@@ -5,7 +5,7 @@ import psutil
5
5
  import pkg_resources
6
6
  from datetime import datetime
7
7
  from pathlib import Path
8
- from typing import List, Any
8
+ from typing import List, Any, Dict
9
9
  import uuid
10
10
  import sys
11
11
  import tempfile
@@ -81,6 +81,7 @@ class BaseTracer:
81
81
  self.project_id = self.user_details["project_id"] # Access the project_id
82
82
  self.trace_name = self.user_details["trace_name"] # Access the trace_name
83
83
  self.visited_metrics = []
84
+ self.trace_metrics = [] # Store metrics here
84
85
 
85
86
  # Initialize trace data
86
87
  self.trace_id = None
@@ -211,6 +212,10 @@ class BaseTracer:
211
212
  threading.Thread(target=self._track_disk_usage).start()
212
213
  threading.Thread(target=self._track_network_usage).start()
213
214
 
215
+ # Reset metrics
216
+ self.visited_metrics = []
217
+ self.trace_metrics = []
218
+
214
219
  metadata = Metadata(
215
220
  cost={},
216
221
  tokens={},
@@ -241,6 +246,7 @@ class BaseTracer:
241
246
  metadata=metadata,
242
247
  data=self.data_key,
243
248
  replays={"source": None},
249
+ metrics=[] # Initialize empty metrics list
244
250
  )
245
251
 
246
252
  def stop(self):
@@ -300,13 +306,16 @@ class BaseTracer:
300
306
  # replace source code with zip_path
301
307
  self.trace.metadata.system_info.source_code = hash_id
302
308
 
309
+ # Add metrics to trace before saving
310
+ trace_data = self.trace.to_dict()
311
+ trace_data["metrics"] = self.trace_metrics
312
+
303
313
  # Clean up trace_data before saving
304
- trace_data = self.trace.__dict__
305
314
  cleaned_trace_data = self._clean_trace(trace_data)
306
315
 
307
316
  # Format interactions and add to trace
308
317
  interactions = self.format_interactions()
309
- self.trace.workflow = interactions["workflow"]
318
+ trace_data["workflow"] = interactions["workflow"]
310
319
 
311
320
  with open(filepath, "w") as f:
312
321
  json.dump(cleaned_trace_data, f, cls=TracerJSONEncoder, indent=2)
@@ -424,38 +433,44 @@ class BaseTracer:
424
433
  def _extract_cost_tokens(self, trace):
425
434
  cost = {}
426
435
  tokens = {}
427
- for span in trace.data[0]["spans"]:
428
- if span.type == "llm":
429
- info = span.info
430
- if isinstance(info, dict):
431
- cost_info = info.get("cost", {})
432
- for key, value in cost_info.items():
433
- if key not in cost:
434
- cost[key] = 0
435
- cost[key] += value
436
- token_info = info.get("tokens", {})
437
- for key, value in token_info.items():
438
- if key not in tokens:
439
- tokens[key] = 0
440
- tokens[key] += value
441
- if span.type == "agent":
442
- for children in span.data["children"]:
443
- if "type" not in children:
444
- continue
445
- if children["type"] != "llm":
446
- continue
447
- info = children["info"]
448
- if isinstance(info, dict):
449
- cost_info = info.get("cost", {})
450
- for key, value in cost_info.items():
451
- if key not in cost:
452
- cost[key] = 0
453
- cost[key] += value
454
- token_info = info.get("tokens", {})
455
- for key, value in token_info.items():
456
- if key not in tokens:
457
- tokens[key] = 0
458
- tokens[key] += value
436
+
437
+ def process_span_info(info):
438
+ if not isinstance(info, dict):
439
+ return
440
+ cost_info = info.get("cost", {})
441
+ for key, value in cost_info.items():
442
+ if key not in cost:
443
+ cost[key] = 0
444
+ cost[key] += value
445
+ token_info = info.get("tokens", {})
446
+ for key, value in token_info.items():
447
+ if key not in tokens:
448
+ tokens[key] = 0
449
+ tokens[key] += value
450
+
451
+ def process_spans(spans):
452
+ for span in spans:
453
+ # Get span type, handling both span objects and dictionaries
454
+ span_type = span.type if hasattr(span, 'type') else span.get('type')
455
+ span_info = span.info if hasattr(span, 'info') else span.get('info', {})
456
+ span_data = span.data if hasattr(span, 'data') else span.get('data', {})
457
+
458
+ # Process direct LLM spans
459
+ if span_type == "llm":
460
+ process_span_info(span_info)
461
+ # Process agent spans recursively
462
+ elif span_type == "agent":
463
+ # Process LLM children in the current agent span
464
+ children = span_data.get("children", [])
465
+ for child in children:
466
+ child_type = child.get("type")
467
+ if child_type == "llm":
468
+ process_span_info(child.get("info", {}))
469
+ # Recursively process nested agent spans
470
+ elif child_type == "agent":
471
+ process_spans([child])
472
+
473
+ process_spans(trace.data[0]["spans"])
459
474
  trace.metadata.cost = cost
460
475
  trace.metadata.tokens = tokens
461
476
  return trace
@@ -609,9 +624,7 @@ class BaseTracer:
609
624
  "span_id": child.get("id"),
610
625
  "interaction_type": "llm_call_end",
611
626
  "name": child.get("name"),
612
- "content": {
613
- "response": child.get("data", {}).get("output")
614
- },
627
+ "content": {"response": child.get("data", {}).get("output")},
615
628
  "timestamp": child.get("end_time"),
616
629
  "error": child.get("error"),
617
630
  }
@@ -657,7 +670,7 @@ class BaseTracer:
657
670
  {
658
671
  "id": str(interaction_id),
659
672
  "span_id": child.get("id"),
660
- "interaction_type": child_type,
673
+ "interaction_type": f"{child_type}_call_start",
661
674
  "name": child.get("name"),
662
675
  "content": child.get("data", {}),
663
676
  "timestamp": child.get("start_time"),
@@ -665,6 +678,19 @@ class BaseTracer:
665
678
  }
666
679
  )
667
680
  interaction_id += 1
681
+
682
+ interactions.append(
683
+ {
684
+ "id": str(interaction_id),
685
+ "span_id": child.get("id"),
686
+ "interaction_type": f"{child_type}_call_end",
687
+ "name": child.get("name"),
688
+ "content": child.get("data", {}),
689
+ "timestamp": child.get("end_time"),
690
+ "error": child.get("error"),
691
+ }
692
+ )
693
+ interaction_id += 1
668
694
 
669
695
  # Process additional interactions and network calls
670
696
  if "interactions" in child:
@@ -825,7 +851,7 @@ class BaseTracer:
825
851
  {
826
852
  "id": str(interaction_id),
827
853
  "span_id": span.id,
828
- "interaction_type": span.type,
854
+ "interaction_type": f"{span.type}_call_start",
829
855
  "name": span.name,
830
856
  "content": span.data,
831
857
  "timestamp": span.start_time,
@@ -833,6 +859,19 @@ class BaseTracer:
833
859
  }
834
860
  )
835
861
  interaction_id += 1
862
+
863
+ interactions.append(
864
+ {
865
+ "id": str(interaction_id),
866
+ "span_id": span.id,
867
+ "interaction_type": f"{span.type}_call_end",
868
+ "name": span.name,
869
+ "content": span.data,
870
+ "timestamp": span.end_time,
871
+ "error": span.error,
872
+ }
873
+ )
874
+ interaction_id += 1
836
875
 
837
876
  # Process interactions from span.data if they exist
838
877
  if span.interactions:
@@ -882,8 +921,90 @@ class BaseTracer:
882
921
 
883
922
  return {"workflow": sorted_interactions}
884
923
 
924
+ def add_metrics(
925
+ self,
926
+ name: str | List[Dict[str, Any]] | Dict[str, Any] = None,
927
+ score: float | int = None,
928
+ reasoning: str = "",
929
+ cost: float = None,
930
+ latency: float = None,
931
+ metadata: Dict[str, Any] = None,
932
+ config: Dict[str, Any] = None,
933
+ ):
934
+ """Add metrics at the trace level.
935
+
936
+ Can be called in two ways:
937
+ 1. With individual parameters:
938
+ tracer.add_metrics(name="metric_name", score=0.9, reasoning="Good performance")
939
+
940
+ 2. With a dictionary or list of dictionaries:
941
+ tracer.add_metrics({"name": "metric_name", "score": 0.9})
942
+ tracer.add_metrics([{"name": "metric1", "score": 0.9}, {"name": "metric2", "score": 0.8}])
943
+
944
+ Args:
945
+ name: Either the metric name (str) or a metric dictionary/list of dictionaries
946
+ score: Score value (float or int) when using individual parameters
947
+ reasoning: Optional explanation for the score
948
+ cost: Optional cost associated with the metric
949
+ latency: Optional latency measurement
950
+ metadata: Optional additional metadata as key-value pairs
951
+ config: Optional configuration parameters
952
+ """
953
+ if not hasattr(self, 'trace'):
954
+ logger.warning("Cannot add metrics before trace is initialized. Call start() first.")
955
+ return
956
+
957
+ # Convert individual parameters to metric dict if needed
958
+ if isinstance(name, str):
959
+ metrics = [{
960
+ "name": name,
961
+ "score": score,
962
+ "reasoning": reasoning,
963
+ "cost": cost,
964
+ "latency": latency,
965
+ "metadata": metadata or {},
966
+ "config": config or {}
967
+ }]
968
+ else:
969
+ # Handle dict or list input
970
+ metrics = name if isinstance(name, list) else [name] if isinstance(name, dict) else []
971
+
972
+ try:
973
+ for metric in metrics:
974
+ if not isinstance(metric, dict):
975
+ raise ValueError(f"Expected dict, got {type(metric)}")
976
+
977
+ if "name" not in metric or "score" not in metric:
978
+ raise ValueError("Metric must contain 'name' and 'score' fields")
979
+
980
+ # Handle duplicate metric names
981
+ metric_name = metric["name"]
982
+ if metric_name in self.visited_metrics:
983
+ count = sum(1 for m in self.visited_metrics if m.startswith(metric_name))
984
+ metric_name = f"{metric_name}_{count + 1}"
985
+ self.visited_metrics.append(metric_name)
986
+
987
+ formatted_metric = {
988
+ "name": metric_name,
989
+ "score": metric["score"],
990
+ "reason": metric.get("reasoning", ""),
991
+ "source": "user",
992
+ "cost": metric.get("cost"),
993
+ "latency": metric.get("latency"),
994
+ "metadata": metric.get("metadata", {}),
995
+ "mappings": [],
996
+ "config": metric.get("config", {})
997
+ }
998
+
999
+ self.trace_metrics.append(formatted_metric)
1000
+ logger.debug(f"Added trace-level metric: {formatted_metric}")
1001
+
1002
+ except ValueError as e:
1003
+ logger.error(f"Validation Error: {e}")
1004
+ except Exception as e:
1005
+ logger.error(f"Error adding metric: {e}")
1006
+
885
1007
  def span(self, span_name):
886
1008
  if span_name not in self.span_attributes_dict:
887
1009
  self.span_attributes_dict[span_name] = SpanAttributes(span_name)
888
- return self.span_attributes_dict[span_name]
889
-
1010
+ return self.span_attributes_dict[span_name]
@@ -475,7 +475,7 @@ class LLMTracerMixin:
475
475
  parameters=parameters,
476
476
  )
477
477
 
478
- # self.add_component(llm_component)
478
+ self.add_component(llm_component)
479
479
  self.llm_data = llm_component
480
480
 
481
481
  return result
@@ -137,13 +137,28 @@ class AgenticTracing(
137
137
  self.network_tracer.network_calls.copy()
138
138
  )
139
139
  self.network_tracer.network_calls = [] # Reset for next component
140
- # self.component_user_interaction[component_id] = [interaction for interaction in self.user_interaction_tracer.interactions if interaction.get('component_id') == component_id]
140
+
141
+ # Store user interactions for the component
141
142
  for interaction in self.user_interaction_tracer.interactions:
142
143
  interaction_component_id = interaction.get("component_id")
143
144
  if interaction_component_id not in self.component_user_interaction:
144
145
  self.component_user_interaction[interaction_component_id] = []
145
146
  if interaction not in self.component_user_interaction[interaction_component_id]:
146
147
  self.component_user_interaction[interaction_component_id].append(interaction)
148
+
149
+ # Only reset component_id if it matches the current one
150
+ # This ensures we don't reset a parent's component_id when a child component ends
151
+ if self.current_component_id.get() == component_id:
152
+ # Get the parent agent's component_id if it exists
153
+ parent_agent_id = self.current_agent_id.get()
154
+ # If there's a parent agent, set the component_id back to the parent's
155
+ if parent_agent_id:
156
+ self.current_component_id.set(parent_agent_id)
157
+ self.user_interaction_tracer.component_id.set(parent_agent_id)
158
+ else:
159
+ # Only reset to None if there's no parent
160
+ self.current_component_id.set(None)
161
+ self.user_interaction_tracer.component_id.set(None)
147
162
 
148
163
  def start(self):
149
164
  """Start tracing"""
@@ -41,7 +41,7 @@ class NetworkTracer:
41
41
 
42
42
  # Extract protocol from URL
43
43
  protocol = "https" if url.startswith("https") else "http"
44
-
44
+
45
45
  self.network_calls.append(
46
46
  {
47
47
  "url": url,
@@ -57,11 +57,11 @@ class NetworkTracer:
57
57
  "parent_id": None, # Will be set by the component
58
58
  "request": {
59
59
  "headers": request_headers,
60
- "body": request_body[:1000] if request_body else None, # Limit to 1000 chars
60
+ "body": request_body if request_body else None,
61
61
  },
62
62
  "response": {
63
63
  "headers": response_headers,
64
- "body": response_body[:1000] if response_body else None, # Limit to 1000 chars
64
+ "body": response_body if response_body else None,
65
65
  },
66
66
  "error": str(error) if error else None,
67
67
  }
@@ -59,6 +59,13 @@ def _get_children_metrics_of_agent(children_traces):
59
59
 
60
60
  def get_trace_metrics_from_trace(traces):
61
61
  metrics = []
62
+
63
+ # get trace level metrics
64
+ if "metrics" in traces.keys():
65
+ if len(traces["metrics"]) > 0:
66
+ metrics.extend(traces["metrics"])
67
+
68
+ # get span level metrics
62
69
  for span in traces["data"][0]["spans"]:
63
70
  if span["type"] == "agent":
64
71
  children_metric = _get_children_metrics_of_agent(span["data"]["children"])
@@ -5,7 +5,6 @@ import re
5
5
  import ast
6
6
  import importlib.util
7
7
  import json
8
- import astor
9
8
  import ipynbname
10
9
  import sys
11
10
 
@@ -74,12 +73,14 @@ class PackageUsageRemover(ast.NodeTransformer):
74
73
  def remove_package_code(source_code: str, package_name: str) -> str:
75
74
  try:
76
75
  tree = ast.parse(source_code)
77
- transformer = PackageUsageRemover(package_name)
78
- modified_tree = transformer.visit(tree)
79
- modified_code = astor.to_source(modified_tree)
76
+ remover = PackageUsageRemover(package_name)
77
+ modified_tree = remover.visit(tree)
78
+ modified_code = ast.unparse(modified_tree)
79
+
80
80
  return modified_code
81
81
  except Exception as e:
82
- raise Exception(f"Error processing source code: {str(e)}")
82
+ logger.error(f"Error in remove_package_code: {e}")
83
+ return source_code
83
84
 
84
85
  class JupyterNotebookHandler:
85
86
  @staticmethod
@@ -452,4 +453,3 @@ if __name__ == "__main__":
452
453
  hash_id, zip_path = zip_list_of_unique_files(filepaths)
453
454
  print(f"Created zip file: {zip_path}")
454
455
  print(f"Hash ID: {hash_id}")
455
-
@@ -0,0 +1,286 @@
1
+ """
2
+ Distributed tracing functionality for RagaAI Catalyst.
3
+ Provides simplified initialization and decorator-based tracing.
4
+ """
5
+
6
+ import os
7
+ import threading
8
+ from typing import Optional, Dict, Any, List
9
+ from functools import wraps
10
+ from contextlib import contextmanager
11
+ import uuid
12
+ from datetime import datetime
13
+ import asyncio
14
+
15
+ from .tracer import Tracer
16
+ from ..ragaai_catalyst import RagaAICatalyst
17
+
18
+ # Global state
19
+ _global_tracer: Optional[Tracer] = None
20
+ _global_catalyst: Optional[RagaAICatalyst] = None
21
+ _tracer_lock = threading.Lock()
22
+ _active_spans = threading.local()
23
+
24
+ def get_current_tracer() -> Optional[Tracer]:
25
+ """Get the current global tracer instance."""
26
+ return _global_tracer
27
+
28
+ def get_current_catalyst() -> Optional[RagaAICatalyst]:
29
+ """Get the current global catalyst instance."""
30
+ return _global_catalyst
31
+
32
+ def init_tracing(
33
+ project_name: str = None,
34
+ dataset_name: str = None,
35
+ access_key: str = None,
36
+ secret_key: str = None,
37
+ base_url: str = None,
38
+ tracer: Tracer = None,
39
+ catalyst: RagaAICatalyst = None,
40
+ **kwargs
41
+ ) -> None:
42
+ """Initialize distributed tracing.
43
+
44
+ Args:
45
+ project_name: Project name for new tracer
46
+ dataset_name: Dataset name for new tracer
47
+ access_key: RagaAI Catalyst access key
48
+ secret_key: RagaAI Catalyst secret key
49
+ base_url: RagaAI Catalyst API base URL
50
+ tracer: Existing Tracer instance
51
+ catalyst: Existing RagaAICatalyst instance
52
+ **kwargs: Additional tracer configuration
53
+ """
54
+ global _global_tracer, _global_catalyst
55
+
56
+ with _tracer_lock:
57
+ if tracer and catalyst:
58
+ _global_tracer = tracer
59
+ _global_catalyst = catalyst
60
+ else:
61
+ # Use env vars as fallback
62
+ access_key = access_key or os.getenv("RAGAAI_CATALYST_ACCESS_KEY")
63
+ secret_key = secret_key or os.getenv("RAGAAI_CATALYST_SECRET_KEY")
64
+ base_url = base_url or os.getenv("RAGAAI_CATALYST_BASE_URL")
65
+
66
+ if not all([access_key, secret_key]):
67
+ raise ValueError(
68
+ "Missing required credentials. Either provide access_key and secret_key "
69
+ "or set RAGAAI_CATALYST_ACCESS_KEY and RAGAAI_CATALYST_SECRET_KEY environment variables."
70
+ )
71
+
72
+ _global_catalyst = RagaAICatalyst(
73
+ access_key=access_key,
74
+ secret_key=secret_key,
75
+ base_url=base_url
76
+ )
77
+
78
+ _global_tracer = Tracer(
79
+ project_name=project_name,
80
+ dataset_name=dataset_name,
81
+ **kwargs
82
+ )
83
+
84
+ def trace_agent(name: str = None, agent_type: str = "generic", version: str = "1.0.0", **kwargs):
85
+ """Decorator for tracing agent functions."""
86
+ def decorator(func):
87
+ is_async = asyncio.iscoroutinefunction(func)
88
+ span_name = name or func.__name__
89
+
90
+ @wraps(func)
91
+ async def async_wrapper(*args, **kwargs):
92
+ tracer = get_current_tracer()
93
+ if not tracer:
94
+ return await func(*args, **kwargs)
95
+
96
+ # Set current agent name and store the token
97
+ name_token = tracer.current_agent_name.set(span_name)
98
+
99
+ try:
100
+ # Use async agent tracing
101
+ return await tracer._trace_agent_execution(
102
+ func,
103
+ span_name,
104
+ agent_type,
105
+ version,
106
+ None, # capabilities
107
+ str(uuid.uuid4()), # hash_id
108
+ *args,
109
+ **kwargs
110
+ )
111
+ finally:
112
+ # Reset using the stored token
113
+ if name_token:
114
+ tracer.current_agent_name.reset(name_token)
115
+
116
+ @wraps(func)
117
+ def sync_wrapper(*args, **kwargs):
118
+ tracer = get_current_tracer()
119
+ if not tracer:
120
+ return func(*args, **kwargs)
121
+
122
+ # Set current agent name and store the token
123
+ name_token = tracer.current_agent_name.set(span_name)
124
+
125
+ try:
126
+ # Use synchronous agent tracing
127
+ return tracer._trace_sync_agent_execution(
128
+ func,
129
+ span_name,
130
+ agent_type,
131
+ version,
132
+ None, # capabilities
133
+ *args,
134
+ **kwargs
135
+ )
136
+ finally:
137
+ # Reset using the stored token
138
+ if name_token:
139
+ tracer.current_agent_name.reset(name_token)
140
+
141
+ return async_wrapper if is_async else sync_wrapper
142
+ return decorator
143
+
144
+ def trace_llm(name: str = None, model: str = None, **kwargs):
145
+ """Decorator for tracing LLM calls."""
146
+ def decorator(func):
147
+ is_async = asyncio.iscoroutinefunction(func)
148
+ span_name = name or func.__name__
149
+
150
+ @wraps(func)
151
+ async def async_wrapper(*args, **kwargs):
152
+ tracer = get_current_tracer()
153
+ if not tracer:
154
+ return await func(*args, **kwargs)
155
+
156
+ # Set current LLM name and store the token
157
+ name_token = tracer.current_llm_call_name.set(span_name)
158
+
159
+ try:
160
+ # Just execute the function within the current span
161
+ result = await func(*args, **kwargs)
162
+ return result
163
+ finally:
164
+ # Reset using the stored token
165
+ if name_token:
166
+ tracer.current_llm_call_name.reset(name_token)
167
+
168
+ @wraps(func)
169
+ def sync_wrapper(*args, **kwargs):
170
+ tracer = get_current_tracer()
171
+ if not tracer:
172
+ return func(*args, **kwargs)
173
+
174
+ # Set current LLM name and store the token
175
+ name_token = tracer.current_llm_call_name.set(span_name)
176
+
177
+ try:
178
+ # Just execute the function within the current span
179
+ result = func(*args, **kwargs)
180
+ return result
181
+ finally:
182
+ # Reset using the stored token
183
+ if name_token:
184
+ tracer.current_llm_call_name.reset(name_token)
185
+
186
+ return async_wrapper if is_async else sync_wrapper
187
+ return decorator
188
+
189
+
190
+ def trace_tool(name: str = None, tool_type: str = "generic", version: str = "1.0.0", **kwargs):
191
+ """Decorator for tracing tool functions."""
192
+ def decorator(func):
193
+ is_async = asyncio.iscoroutinefunction(func)
194
+
195
+ @wraps(func)
196
+ async def async_wrapper(*args, **kwargs):
197
+ tracer = get_current_tracer()
198
+ if not tracer:
199
+ return await func(*args, **kwargs)
200
+
201
+ # Use async tool tracing
202
+ return await tracer._trace_tool_execution(
203
+ func,
204
+ name or func.__name__,
205
+ tool_type,
206
+ version,
207
+ *args,
208
+ **kwargs
209
+ )
210
+
211
+ @wraps(func)
212
+ def sync_wrapper(*args, **kwargs):
213
+ tracer = get_current_tracer()
214
+ if not tracer:
215
+ return func(*args, **kwargs)
216
+
217
+ # Use synchronous tool tracing
218
+ return tracer._trace_sync_tool_execution(
219
+ func,
220
+ name or func.__name__,
221
+ tool_type,
222
+ version,
223
+ *args,
224
+ **kwargs
225
+ )
226
+
227
+ return async_wrapper if is_async else sync_wrapper
228
+ return decorator
229
+
230
+
231
+
232
+ def trace_custom(name: str = None, custom_type: str = "generic", version: str = "1.0.0", trace_variables: bool = False, **kwargs):
233
+ """Decorator for tracing custom functions."""
234
+ def decorator(func):
235
+ is_async = asyncio.iscoroutinefunction(func)
236
+
237
+ @wraps(func)
238
+ async def async_wrapper(*args, **kwargs):
239
+ tracer = get_current_tracer()
240
+ if not tracer:
241
+ return await func(*args, **kwargs)
242
+
243
+ # Use async tool tracing
244
+ return await tracer._trace_custom_execution(
245
+ func,
246
+ name or func.__name__,
247
+ custom_type,
248
+ version,
249
+ trace_variables,
250
+ *args,
251
+ **kwargs
252
+ )
253
+
254
+ @wraps(func)
255
+ def sync_wrapper(*args, **kwargs):
256
+ tracer = get_current_tracer()
257
+ if not tracer:
258
+ return func(*args, **kwargs)
259
+
260
+ # Use synchronous tool tracing
261
+ return tracer._trace_sync_custom_execution(
262
+ func,
263
+ name or func.__name__,
264
+ custom_type,
265
+ version,
266
+ trace_variables,
267
+ *args,
268
+ **kwargs
269
+ )
270
+
271
+ return async_wrapper if is_async else sync_wrapper
272
+ return decorator
273
+
274
+
275
+ def current_span():
276
+ """Get the current active span for adding metrics."""
277
+ tracer = get_current_tracer()
278
+ if not tracer:
279
+ return None
280
+
281
+ # Get the current agent name from context
282
+ agent_name = tracer.current_agent_name.get()
283
+ if not agent_name:
284
+ raise ValueError("No active span found. Make sure you're calling this within a traced function.")
285
+
286
+ return tracer.span(agent_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ragaai_catalyst
3
- Version: 2.1.4.1b0
3
+ Version: 2.1.5b0
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>
6
6
  Requires-Python: <3.13,>=3.9
@@ -34,7 +34,6 @@ Requires-Dist: psutil~=6.0.0
34
34
  Requires-Dist: py-cpuinfo~=9.0.0
35
35
  Requires-Dist: requests~=2.32.3
36
36
  Requires-Dist: GPUtil~=1.4.0
37
- Requires-Dist: astor>=0.8.1
38
37
  Requires-Dist: ipynbname
39
38
  Provides-Extra: dev
40
39
  Requires-Dist: pytest; extra == "dev"
@@ -1,4 +1,4 @@
1
- ragaai_catalyst/__init__.py,sha256=BdIJ_UUre0uEnRTsLw_hE0C0muWk6XWNZqdVOel22R4,537
1
+ ragaai_catalyst/__init__.py,sha256=tvESV8UuVtth14E89wQxgf0WvQZSApWfDeLiIdmMhkE,791
2
2
  ragaai_catalyst/_version.py,sha256=JKt9KaVNOMVeGs8ojO6LvIZr7ZkMzNN-gCcvryy4x8E,460
3
3
  ragaai_catalyst/dataset.py,sha256=aTRvZicAXmrC0KdmmsoJH_rtEJrxbqYmf1P806c1Wg0,10521
4
4
  ragaai_catalyst/evaluation.py,sha256=34H2bYZNSrcu0jMQgDZw1OLVbQU80PaVLo2avju8POM,20311
@@ -11,14 +11,15 @@ ragaai_catalyst/proxy_call.py,sha256=CHxldeceZUaLU-to_hs_Kf1z_b2vHMssLS_cOBedu78
11
11
  ragaai_catalyst/ragaai_catalyst.py,sha256=FdqMzwuQLqS2-3JJDsTQ8uh2itllOxfPrRUjb8Kwmn0,17428
12
12
  ragaai_catalyst/synthetic_data_generation.py,sha256=uDV9tNwto2xSkWg5XHXUvjErW-4P34CTrxaJpRfezyA,19250
13
13
  ragaai_catalyst/utils.py,sha256=TlhEFwLyRU690HvANbyoRycR3nQ67lxVUQoUOfTPYQ0,3772
14
- ragaai_catalyst/tracers/__init__.py,sha256=yxepo7iVjTNI_wFdk3Z6Ghu64SazVyszCPEHYrX5WQk,50
14
+ ragaai_catalyst/tracers/__init__.py,sha256=LfgTes-nHpazssbGKnn8kyLZNr49kIPrlkrqqoTFTfc,301
15
+ ragaai_catalyst/tracers/distributed.py,sha256=_KO7swUDoPErbfahxNSRpxQk22rstQItfPGP8e4l7E4,9334
15
16
  ragaai_catalyst/tracers/llamaindex_callback.py,sha256=ZY0BJrrlz-P9Mg2dX-ZkVKG3gSvzwqBtk7JL_05MiYA,14028
16
17
  ragaai_catalyst/tracers/tracer.py,sha256=UX-01NYWcH2y4UW1W287Cn-jy760rgaFqu8llJbeMdg,15654
17
18
  ragaai_catalyst/tracers/upload_traces.py,sha256=mT5rverNUL5Rcal9VR5_c75wHBAUrm2pvYetTZqP3ok,4796
18
19
  ragaai_catalyst/tracers/agentic_tracing/README.md,sha256=X4QwLb7-Jg7GQMIXj-SerZIgDETfw-7VgYlczOR8ZeQ,4508
19
20
  ragaai_catalyst/tracers/agentic_tracing/__init__.py,sha256=yf6SKvOPSpH-9LiKaoLKXwqj5sez8F_5wkOb91yp0oE,260
20
21
  ragaai_catalyst/tracers/agentic_tracing/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- ragaai_catalyst/tracers/agentic_tracing/data/data_structure.py,sha256=nFnwqL1-Uznwndi2ugDnhziUbIASlcBYnM6Dyq7pPt8,9243
22
+ ragaai_catalyst/tracers/agentic_tracing/data/data_structure.py,sha256=icAtNzKN_I0YtfuJ3RF8BdZJK3ohqxkVZIdvM5_YugY,9327
22
23
  ragaai_catalyst/tracers/agentic_tracing/tests/FinancialAnalysisSystem.ipynb,sha256=0qZxjWqYCTAVvdo3Tsp544D8Am48wfeMQ9RKpKgAL8g,34291
23
24
  ragaai_catalyst/tracers/agentic_tracing/tests/GameActivityEventPlanner.ipynb,sha256=QCMFJYbGX0fd9eMW4PqyQLZjyWuTXo7n1nqO_hMLf0s,4225
24
25
  ragaai_catalyst/tracers/agentic_tracing/tests/TravelPlanner.ipynb,sha256=fU3inXoemJbdTkGAQl_N1UwVEZ10LrKv4gCEpbQ4ISg,43481
@@ -27,18 +28,18 @@ ragaai_catalyst/tracers/agentic_tracing/tests/ai_travel_agent.py,sha256=S4rCcKzU
27
28
  ragaai_catalyst/tracers/agentic_tracing/tests/unique_decorator_test.py,sha256=Xk1cLzs-2A3dgyBwRRnCWs7Eubki40FVonwd433hPN8,4805
28
29
  ragaai_catalyst/tracers/agentic_tracing/tracers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
30
  ragaai_catalyst/tracers/agentic_tracing/tracers/agent_tracer.py,sha256=aLiq5nPie5TT61QYtvAtvErsxjPFYiUxjayn5aCX1_k,25543
30
- ragaai_catalyst/tracers/agentic_tracing/tracers/base.py,sha256=u2DX_BsMGsuJkWqN6ucxboMO8GnvOcArKJe5L08y-YI,35014
31
+ ragaai_catalyst/tracers/agentic_tracing/tracers/base.py,sha256=XZH5qi8eMIHG_qjedRHa3lGYp0NiAtCUxN9P_uW_NMo,39981
31
32
  ragaai_catalyst/tracers/agentic_tracing/tracers/custom_tracer.py,sha256=uay8lU7T-CKsVu8KvWX31qfMqufK9S3Ive7XKo2Ksmk,12252
32
33
  ragaai_catalyst/tracers/agentic_tracing/tracers/langgraph_tracer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py,sha256=fn5qxb365GmQkJy_yZAY5TiiWRMFKPNJdYk8KFr8uWA,29343
34
- ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py,sha256=nxUOQSyWBTnbsZfxmr1lje2OggqNf9fwtGUb-sBo6mI,15215
35
- ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py,sha256=CviGiAg0W0krJxORMBDTosQytIoJDQ5RwU6xt_U_mOg,10408
34
+ ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py,sha256=hU97LWEdqFL-tnIb_Qlk6VJdS6yVPH0QVzVzg1yuCB0,29341
35
+ ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py,sha256=9K1swf0IOEEzgpkO2A_k_Yxk6ybLRXDcVoQAzm-_fWs,15889
36
+ ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py,sha256=m8CxYkl7iMiFya_lNwN1ykBc3Pmo-2pR_2HmpptwHWQ,10352
36
37
  ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py,sha256=4h6epgRHPVRfTrCznwc6KPK6xevwBaZwE-q0Zj-4Kkk,12160
37
38
  ragaai_catalyst/tracers/agentic_tracing/tracers/user_interaction_tracer.py,sha256=bhSUhNQCuJXKjgJAXhjKEYjnHMpYN90FSZdR84fNIKU,4614
38
39
  ragaai_catalyst/tracers/agentic_tracing/upload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
40
  ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py,sha256=1MDKXAAPzOEdxFKWWQrRgrmM3kz--DGXSywGXQmR3lQ,6041
40
41
  ragaai_catalyst/tracers/agentic_tracing/upload/upload_code.py,sha256=HgpMgI-JTWZrizcM7GGUIaAgaZF4aRT3D0dJXVEkblY,4271
41
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_trace_metric.py,sha256=iFagpPltlg6aKvdyAFvXsuxyjUUjcHAMmvXlevL-uYM,3312
42
+ ragaai_catalyst/tracers/agentic_tracing/upload/upload_trace_metric.py,sha256=id66gfx-XYj_zsAmicBKojBOqJQ__FJLSoZ0db56aes,3493
42
43
  ragaai_catalyst/tracers/agentic_tracing/utils/__init__.py,sha256=XdB3X_ufe4RVvGorxSqAiB9dYv4UD7Hvvuw3bsDUppY,60
43
44
  ragaai_catalyst/tracers/agentic_tracing/utils/api_utils.py,sha256=JyNCbfpW-w4O9CjtemTqmor2Rh1WGpQwhRaDSRmBxw8,689
44
45
  ragaai_catalyst/tracers/agentic_tracing/utils/create_dataset_schema.py,sha256=lgvJL0cakJrX8WGsnU05YGvotequSj6HgSohyR4OJNE,804
@@ -50,7 +51,7 @@ ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json,sha256=weznWpRd6N
50
51
  ragaai_catalyst/tracers/agentic_tracing/utils/span_attributes.py,sha256=MqeRNGxzeuh9qTK0NbYMftl9V9Z0V7gMgBoHkrXP56k,1592
51
52
  ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py,sha256=RciiDdo2riibEoM8X0FKHaXi78y3bWwNkV8U0leqigk,3508
52
53
  ragaai_catalyst/tracers/agentic_tracing/utils/unique_decorator.py,sha256=DQHjcEuqEKsNSWaNs7SoOaq50yK4Jsl966S7mBnV-zA,5723
53
- ragaai_catalyst/tracers/agentic_tracing/utils/zip_list_of_unique_files.py,sha256=fvL7SQSO1-FPQ3zT1ErAcj8cLCKn4rUSG0Ug-nL-By0,18824
54
+ ragaai_catalyst/tracers/agentic_tracing/utils/zip_list_of_unique_files.py,sha256=8SAN4pjA3XKBWlUZiDGXGh26ve1qRH_fv0VwewsfCFc,18818
54
55
  ragaai_catalyst/tracers/exporters/__init__.py,sha256=kVA8zp05h3phu4e-iHSlnznp_PzMRczB7LphSsZgUjg,138
55
56
  ragaai_catalyst/tracers/exporters/file_span_exporter.py,sha256=RgGteu-NVGprXKkynvyIO5yOjpbtA41R3W_NzCjnkwE,6445
56
57
  ragaai_catalyst/tracers/exporters/raga_exporter.py,sha256=6xvjWXyh8XPkHKSLLmAZUQSvwuyY17ov8pv2VdfI0qA,17875
@@ -60,8 +61,8 @@ ragaai_catalyst/tracers/instrumentators/llamaindex.py,sha256=SMrRlR4xM7k9HK43hak
60
61
  ragaai_catalyst/tracers/instrumentators/openai.py,sha256=14R4KW9wQCR1xysLfsP_nxS7cqXrTPoD8En4MBAaZUU,379
61
62
  ragaai_catalyst/tracers/utils/__init__.py,sha256=KeMaZtYaTojilpLv65qH08QmpYclfpacDA0U3wg6Ybw,64
62
63
  ragaai_catalyst/tracers/utils/utils.py,sha256=ViygfJ7vZ7U0CTSA1lbxVloHp4NSlmfDzBRNCJuMhis,2374
63
- ragaai_catalyst-2.1.4.1b0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
64
- ragaai_catalyst-2.1.4.1b0.dist-info/METADATA,sha256=V5fmS2GcC5Ykd7yakB0_gDvqRPKHxzTtkp7TCt6T3O4,12794
65
- ragaai_catalyst-2.1.4.1b0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
66
- ragaai_catalyst-2.1.4.1b0.dist-info/top_level.txt,sha256=HpgsdRgEJMk8nqrU6qdCYk3di7MJkDL0B19lkc7dLfM,16
67
- ragaai_catalyst-2.1.4.1b0.dist-info/RECORD,,
64
+ ragaai_catalyst-2.1.5b0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
65
+ ragaai_catalyst-2.1.5b0.dist-info/METADATA,sha256=R0r0eV49WTeIO0O1NlkFk99eIbAPnvqf0urcA-GpF48,12764
66
+ ragaai_catalyst-2.1.5b0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
67
+ ragaai_catalyst-2.1.5b0.dist-info/top_level.txt,sha256=HpgsdRgEJMk8nqrU6qdCYk3di7MJkDL0B19lkc7dLfM,16
68
+ ragaai_catalyst-2.1.5b0.dist-info/RECORD,,