ragaai-catalyst 2.1.5b15__py3-none-any.whl → 2.1.5b17__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/tracers/agentic_tracing/tracers/llm_tracer.py +4 -2
- ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py +111 -70
- {ragaai_catalyst-2.1.5b15.dist-info → ragaai_catalyst-2.1.5b17.dist-info}/METADATA +1 -1
- {ragaai_catalyst-2.1.5b15.dist-info → ragaai_catalyst-2.1.5b17.dist-info}/RECORD +7 -7
- {ragaai_catalyst-2.1.5b15.dist-info → ragaai_catalyst-2.1.5b17.dist-info}/LICENSE +0 -0
- {ragaai_catalyst-2.1.5b15.dist-info → ragaai_catalyst-2.1.5b17.dist-info}/WHEEL +0 -0
- {ragaai_catalyst-2.1.5b15.dist-info → ragaai_catalyst-2.1.5b17.dist-info}/top_level.txt +0 -0
@@ -45,7 +45,6 @@ class LLMTracerMixin:
|
|
45
45
|
self.model_costs = load_model_costs()
|
46
46
|
except Exception as e:
|
47
47
|
self.model_costs = {
|
48
|
-
# TODO: Default cost handling needs to be improved
|
49
48
|
"default": {"input_cost_per_token": 0.0, "output_cost_per_token": 0.0}
|
50
49
|
}
|
51
50
|
self.MAX_PARAMETERS_TO_DISPLAY = 10
|
@@ -59,7 +58,6 @@ class LLMTracerMixin:
|
|
59
58
|
self.total_cost = 0.0
|
60
59
|
self.llm_data = {}
|
61
60
|
|
62
|
-
# Add auto_instrument options
|
63
61
|
self.auto_instrument_llm = False
|
64
62
|
self.auto_instrument_user_interaction = False
|
65
63
|
self.auto_instrument_file_io = False
|
@@ -258,6 +256,10 @@ class LLMTracerMixin:
|
|
258
256
|
self.wrap_method(chat_class, "acomplete")
|
259
257
|
|
260
258
|
def wrap_openai_client_methods(self, client_class):
|
259
|
+
# Skip if OpenAI is not being used (no API key set)
|
260
|
+
if not os.getenv("OPENAI_API_KEY"):
|
261
|
+
return
|
262
|
+
|
261
263
|
original_init = client_class.__init__
|
262
264
|
|
263
265
|
@functools.wraps(original_init)
|
@@ -5,6 +5,8 @@ from langchain_core.tools import tool
|
|
5
5
|
import psutil
|
6
6
|
import functools
|
7
7
|
from typing import Optional, Any, Dict, List
|
8
|
+
|
9
|
+
from pydantic import tools
|
8
10
|
from ..utils.unique_decorator import generate_unique_hash_simple
|
9
11
|
import contextvars
|
10
12
|
import asyncio
|
@@ -13,6 +15,7 @@ from ..utils.span_attributes import SpanAttributes
|
|
13
15
|
import logging
|
14
16
|
import wrapt
|
15
17
|
import time
|
18
|
+
import inspect
|
16
19
|
|
17
20
|
logger = logging.getLogger(__name__)
|
18
21
|
logging_level = (
|
@@ -38,6 +41,8 @@ class ToolTracerMixin:
|
|
38
41
|
self.auto_instrument_file_io = False
|
39
42
|
self.auto_instrument_network = False
|
40
43
|
self._instrumented_tools = set() # Track which tools we've instrumented
|
44
|
+
self._method_usage = {} # Track which methods are actually used
|
45
|
+
self._active_tool_calls = set() # Track active tool calls to prevent duplicates
|
41
46
|
|
42
47
|
# take care of auto_instrument
|
43
48
|
def instrument_tool_calls(self):
|
@@ -48,71 +53,45 @@ class ToolTracerMixin:
|
|
48
53
|
import sys
|
49
54
|
|
50
55
|
if "langchain_community.tools" in sys.modules:
|
51
|
-
self.
|
56
|
+
self.patch_langchain_tools(sys.modules["langchain_community.tools"])
|
52
57
|
|
53
58
|
if "langchain.tools" in sys.modules:
|
54
|
-
self.
|
59
|
+
self.patch_langchain_tools(sys.modules["langchain.tools"])
|
55
60
|
|
56
61
|
if "langchain_core.tools" in sys.modules:
|
57
62
|
self.patch_langchain_core_tools(sys.modules["langchain_core.tools"])
|
58
63
|
|
59
64
|
# Register hooks for future imports
|
60
65
|
wrapt.register_post_import_hook(
|
61
|
-
self.
|
66
|
+
self.patch_langchain_tools, "langchain_community.tools"
|
62
67
|
)
|
63
68
|
wrapt.register_post_import_hook(
|
64
|
-
self.
|
69
|
+
self.patch_langchain_tools, "langchain.tools"
|
65
70
|
)
|
66
|
-
|
67
71
|
wrapt.register_post_import_hook(
|
68
|
-
self.patch_langchain_core_tools, "langchain_core.tools"
|
72
|
+
self.patch_langchain_core_tools, "langchain_core.tools"
|
69
73
|
)
|
70
74
|
|
71
75
|
def patch_langchain_core_tools(self, module):
|
72
|
-
"""Patch langchain
|
76
|
+
"""Patch langchain tool methods"""
|
73
77
|
from langchain_core.tools import BaseTool, StructuredTool, Tool
|
74
|
-
|
75
|
-
# Patch the tool decorator
|
76
|
-
original_tool = module.tool
|
77
78
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
# Wrap the tool's run/arun methods
|
85
|
-
if hasattr(tool_instance, 'run'):
|
86
|
-
self.wrap_tool_method(tool_instance.__class__, 'run')
|
87
|
-
if hasattr(tool_instance, 'arun'):
|
88
|
-
self.wrap_tool_method(tool_instance.__class__, 'arun')
|
89
|
-
if hasattr(tool_instance, 'invoke'):
|
90
|
-
self.wrap_tool_method(tool_instance.__class__, 'invoke')
|
91
|
-
if hasattr(tool_instance, 'ainvoke'):
|
92
|
-
self.wrap_tool_method(tool_instance.__class__, 'ainvoke')
|
93
|
-
return tool_instance
|
94
|
-
|
95
|
-
return wrapper
|
96
|
-
|
97
|
-
# Replace the original decorator
|
98
|
-
module.tool = wrapped_tool
|
79
|
+
# Process tool classes in order of inheritance (base class first)
|
80
|
+
tool_classes = [BaseTool] # Start with base class
|
81
|
+
# Add derived classes that don't inherit from already processed classes
|
82
|
+
for tool_class in [StructuredTool, Tool]:
|
83
|
+
if not any(issubclass(tool_class, processed) for processed in tool_classes):
|
84
|
+
tool_classes.append(tool_class)
|
99
85
|
|
100
|
-
|
101
|
-
for tool_class in [BaseTool, StructuredTool, Tool]:
|
86
|
+
for tool_class in tool_classes:
|
102
87
|
if tool_class in self._instrumented_tools:
|
103
88
|
continue
|
104
|
-
|
105
|
-
|
106
|
-
if hasattr(tool_class, 'arun'):
|
107
|
-
self.wrap_tool_method(tool_class, f'{tool_class.__name__}.arun')
|
108
|
-
if hasattr(tool_class, 'invoke'):
|
109
|
-
self.wrap_tool_method(tool_class, f'{tool_class.__name__}.invoke')
|
110
|
-
if hasattr(tool_class, 'ainvoke'):
|
111
|
-
self.wrap_tool_method(tool_class, f'{tool_class.__name__}.ainvoke')
|
89
|
+
# Create proxy instead of directly wrapping methods
|
90
|
+
self.ToolMethodProxy(self, tool_class, tool_class.__name__)
|
112
91
|
self._instrumented_tools.add(tool_class)
|
113
|
-
|
114
|
-
def
|
115
|
-
"""Patch langchain
|
92
|
+
|
93
|
+
def patch_langchain_tools(self, module):
|
94
|
+
"""Patch langchain tool methods"""
|
116
95
|
for directory in dir(module):
|
117
96
|
dir_class = getattr(module, directory)
|
118
97
|
tools = getattr(dir_class, "__all__", None)
|
@@ -124,35 +103,97 @@ class ToolTracerMixin:
|
|
124
103
|
if tool_class in self._instrumented_tools:
|
125
104
|
continue
|
126
105
|
|
127
|
-
#
|
128
|
-
|
129
|
-
self.wrap_tool_method(tool_class, f"{tool}.invoke")
|
130
|
-
elif hasattr(tool_class, "run"): # Only wrap run if invoke doesn't exist
|
131
|
-
self.wrap_tool_method(tool_class, f"{tool}.run")
|
132
|
-
|
133
|
-
if hasattr(tool_class, "ainvoke"):
|
134
|
-
self.wrap_tool_method(tool_class, f"{tool}.ainvoke")
|
135
|
-
elif hasattr(tool_class, "arun"): # Only wrap arun if ainvoke doesn't exist
|
136
|
-
self.wrap_tool_method(tool_class, f"{tool}.arun")
|
137
|
-
|
106
|
+
# Create proxy instead of directly wrapping methods
|
107
|
+
self.ToolMethodProxy(self, tool_class, tool)
|
138
108
|
self._instrumented_tools.add(tool_class)
|
139
109
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
110
|
+
class ToolMethodProxy:
|
111
|
+
def __init__(self, tracer, tool_class, tool_name):
|
112
|
+
self.tracer = tracer
|
113
|
+
self.tool_class = tool_class
|
114
|
+
self.tool_name = tool_name
|
115
|
+
self._original_methods = {}
|
116
|
+
self._wrapped = False
|
117
|
+
|
118
|
+
# Store original methods
|
119
|
+
for method in ['run', 'arun', 'invoke', 'ainvoke']:
|
120
|
+
if hasattr(tool_class, method):
|
121
|
+
self._original_methods[method] = getattr(tool_class, method)
|
122
|
+
setattr(tool_class, method, self._create_proxy_method(method))
|
123
|
+
|
124
|
+
def _create_proxy_method(self, method_name):
|
125
|
+
original_method = self._original_methods[method_name]
|
154
126
|
|
155
|
-
|
127
|
+
async def async_proxy_method(*args, **kwargs):
|
128
|
+
if not self._wrapped:
|
129
|
+
self._cleanup_proxy()
|
130
|
+
self.tracer._wrap_specific_method(self.tool_class, method_name, self.tool_name)
|
131
|
+
self._wrapped = True
|
132
|
+
# Get the now-wrapped method
|
133
|
+
wrapped_method = getattr(self.tool_class, method_name)
|
134
|
+
return await wrapped_method(*args, **kwargs)
|
135
|
+
|
136
|
+
def sync_proxy_method(*args, **kwargs):
|
137
|
+
if not self._wrapped:
|
138
|
+
self._cleanup_proxy()
|
139
|
+
self.tracer._wrap_specific_method(self.tool_class, method_name, self.tool_name)
|
140
|
+
self._wrapped = True
|
141
|
+
# Get the now-wrapped method
|
142
|
+
wrapped_method = getattr(self.tool_class, method_name)
|
143
|
+
return wrapped_method(*args, **kwargs)
|
144
|
+
|
145
|
+
# Use appropriate proxy based on whether original method is async
|
146
|
+
proxy_method = async_proxy_method if asyncio.iscoroutinefunction(original_method) else sync_proxy_method
|
147
|
+
proxy_method.__name__ = method_name
|
148
|
+
return proxy_method
|
149
|
+
|
150
|
+
def _cleanup_proxy(self):
|
151
|
+
# Restore all original methods except the one that was called
|
152
|
+
for method, original in self._original_methods.items():
|
153
|
+
if not self._wrapped:
|
154
|
+
setattr(self.tool_class, method, original)
|
155
|
+
|
156
|
+
def _wrap_specific_method(self, tool_class, method_name, tool_name):
|
157
|
+
"""Wrap only the specific method that is being used"""
|
158
|
+
original_method = getattr(tool_class, method_name)
|
159
|
+
|
160
|
+
async def async_wrapper(*args, **kwargs):
|
161
|
+
tool_call_id = kwargs.get('tool_call_id', None)
|
162
|
+
if tool_call_id and tool_call_id in self._active_tool_calls:
|
163
|
+
# Skip tracing if this tool call is already being traced
|
164
|
+
return await original_method(*args, **kwargs)
|
165
|
+
|
166
|
+
if tool_call_id:
|
167
|
+
self._active_tool_calls.add(tool_call_id)
|
168
|
+
try:
|
169
|
+
name = tool_name
|
170
|
+
tool_type = "langchain"
|
171
|
+
version = None
|
172
|
+
return await self._trace_tool_execution(original_method, name, tool_type, version, *args, **kwargs)
|
173
|
+
finally:
|
174
|
+
if tool_call_id:
|
175
|
+
self._active_tool_calls.remove(tool_call_id)
|
176
|
+
|
177
|
+
def sync_wrapper(*args, **kwargs):
|
178
|
+
tool_call_id = kwargs.get('tool_call_id', None)
|
179
|
+
if tool_call_id and tool_call_id in self._active_tool_calls:
|
180
|
+
# Skip tracing if this tool call is already being traced
|
181
|
+
return original_method(*args, **kwargs)
|
182
|
+
|
183
|
+
if tool_call_id:
|
184
|
+
self._active_tool_calls.add(tool_call_id)
|
185
|
+
try:
|
186
|
+
name = tool_name
|
187
|
+
tool_type = "langchain"
|
188
|
+
version = None
|
189
|
+
return self._trace_sync_tool_execution(original_method, name, tool_type, version, *args, **kwargs)
|
190
|
+
finally:
|
191
|
+
if tool_call_id:
|
192
|
+
self._active_tool_calls.remove(tool_call_id)
|
193
|
+
|
194
|
+
wrapper = async_wrapper if asyncio.iscoroutinefunction(original_method) else sync_wrapper
|
195
|
+
wrapper.__name__ = method_name
|
196
|
+
setattr(tool_class, method_name, wrapper)
|
156
197
|
|
157
198
|
def instrument_user_interaction_calls(self):
|
158
199
|
self.auto_instrument_user_interaction = True
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: ragaai_catalyst
|
3
|
-
Version: 2.1.
|
3
|
+
Version: 2.1.5b17
|
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
|
@@ -32,10 +32,10 @@ ragaai_catalyst/tracers/agentic_tracing/tracers/agent_tracer.py,sha256=8d6YovuWi
|
|
32
32
|
ragaai_catalyst/tracers/agentic_tracing/tracers/base.py,sha256=88rX7OkOGEyVNECUrc4bYqODyulXve_-99d9ku5hBeQ,37373
|
33
33
|
ragaai_catalyst/tracers/agentic_tracing/tracers/custom_tracer.py,sha256=OHet_Cphyrsq2CP4WiooTsWSgg3Rc1n8QsOl1s2vqdY,13480
|
34
34
|
ragaai_catalyst/tracers/agentic_tracing/tracers/langgraph_tracer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
|
-
ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py,sha256=
|
35
|
+
ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py,sha256=ySoUbj7NPveV1g-G4E4D8uOH_4Ad93qVu9Z2aAZHH1o,34518
|
36
36
|
ragaai_catalyst/tracers/agentic_tracing/tracers/main_tracer.py,sha256=JEwvFV6KdYcg8zt2qUTKmmPvrkEft0YNAyUYK6FWF7c,18335
|
37
37
|
ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py,sha256=m8CxYkl7iMiFya_lNwN1ykBc3Pmo-2pR_2HmpptwHWQ,10352
|
38
|
-
ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py,sha256=
|
38
|
+
ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py,sha256=nmgkE3jRlTpq_uk6FYw0hTv2VgT8ejxvvBRL7gso39I,21037
|
39
39
|
ragaai_catalyst/tracers/agentic_tracing/tracers/user_interaction_tracer.py,sha256=bhSUhNQCuJXKjgJAXhjKEYjnHMpYN90FSZdR84fNIKU,4614
|
40
40
|
ragaai_catalyst/tracers/agentic_tracing/upload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
41
|
ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py,sha256=1MDKXAAPzOEdxFKWWQrRgrmM3kz--DGXSywGXQmR3lQ,6041
|
@@ -66,8 +66,8 @@ ragaai_catalyst/tracers/utils/__init__.py,sha256=KeMaZtYaTojilpLv65qH08QmpYclfpa
|
|
66
66
|
ragaai_catalyst/tracers/utils/convert_langchain_callbacks_output.py,sha256=ofrNrxf2b1hpjDh_zeaxiYq86azn1MF3kW8-ViYPEg0,1641
|
67
67
|
ragaai_catalyst/tracers/utils/langchain_tracer_extraction_logic.py,sha256=qK67fdUBz5Xr99ajqXbYf1ueKS1V3a3_XR0zCcN4iGI,3061
|
68
68
|
ragaai_catalyst/tracers/utils/utils.py,sha256=ViygfJ7vZ7U0CTSA1lbxVloHp4NSlmfDzBRNCJuMhis,2374
|
69
|
-
ragaai_catalyst-2.1.
|
70
|
-
ragaai_catalyst-2.1.
|
71
|
-
ragaai_catalyst-2.1.
|
72
|
-
ragaai_catalyst-2.1.
|
73
|
-
ragaai_catalyst-2.1.
|
69
|
+
ragaai_catalyst-2.1.5b17.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
70
|
+
ragaai_catalyst-2.1.5b17.dist-info/METADATA,sha256=ZAT6uQwGxjeBf-2Nzdd5qgi0obRJTSad3fOlmbs_iGE,12796
|
71
|
+
ragaai_catalyst-2.1.5b17.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
72
|
+
ragaai_catalyst-2.1.5b17.dist-info/top_level.txt,sha256=HpgsdRgEJMk8nqrU6qdCYk3di7MJkDL0B19lkc7dLfM,16
|
73
|
+
ragaai_catalyst-2.1.5b17.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|