|
4 | 4 | Python module-based tools, as well as utilities for validating tool uses and normalizing tool schemas. |
5 | 5 | """ |
6 | 6 |
|
7 | | -import inspect |
8 | 7 | import logging |
9 | 8 | import re |
10 | | -from typing import Any, Callable, Dict, Optional, cast |
11 | | - |
12 | | -from typing_extensions import Unpack |
| 9 | +from typing import Any, Callable, Dict |
13 | 10 |
|
14 | 11 | from ..types.tools import AgentTool, ToolResult, ToolSpec, ToolUse |
15 | 12 |
|
@@ -144,132 +141,6 @@ def normalize_tool_spec(tool_spec: ToolSpec) -> ToolSpec: |
144 | 141 | return normalized |
145 | 142 |
|
146 | 143 |
|
147 | | -class FunctionTool(AgentTool): |
148 | | - """Tool implementation for function-based tools created with @tool. |
149 | | -
|
150 | | - This class adapts Python functions decorated with @tool to the AgentTool interface. |
151 | | - """ |
152 | | - |
153 | | - def __new__(cls, *args: Any, **kwargs: Any) -> Any: |
154 | | - """Compatability shim to allow callers to continue working after the introduction of DecoratedFunctionTool.""" |
155 | | - if isinstance(args[0], AgentTool): |
156 | | - return args[0] |
157 | | - |
158 | | - return super().__new__(cls) |
159 | | - |
160 | | - def __init__(self, func: Callable[[ToolUse, Unpack[Any]], ToolResult], tool_name: Optional[str] = None) -> None: |
161 | | - """Initialize a function-based tool. |
162 | | -
|
163 | | - Args: |
164 | | - func: The decorated function. |
165 | | - tool_name: Optional tool name (defaults to function name). |
166 | | -
|
167 | | - Raises: |
168 | | - ValueError: If func is not decorated with @tool. |
169 | | - """ |
170 | | - super().__init__() |
171 | | - |
172 | | - self._func = func |
173 | | - |
174 | | - # Get TOOL_SPEC from the decorated function |
175 | | - if hasattr(func, "TOOL_SPEC") and isinstance(func.TOOL_SPEC, dict): |
176 | | - self._tool_spec = cast(ToolSpec, func.TOOL_SPEC) |
177 | | - # Use name from tool spec if available, otherwise use function name or passed tool_name |
178 | | - name = self._tool_spec.get("name", tool_name or func.__name__) |
179 | | - if isinstance(name, str): |
180 | | - self._name = name |
181 | | - else: |
182 | | - raise ValueError(f"Tool name must be a string, got {type(name)}") |
183 | | - else: |
184 | | - raise ValueError(f"Function {func.__name__} is not decorated with @tool") |
185 | | - |
186 | | - @property |
187 | | - def tool_name(self) -> str: |
188 | | - """Get the name of the tool. |
189 | | -
|
190 | | - Returns: |
191 | | - The name of the tool. |
192 | | - """ |
193 | | - return self._name |
194 | | - |
195 | | - @property |
196 | | - def tool_spec(self) -> ToolSpec: |
197 | | - """Get the tool specification for this function-based tool. |
198 | | -
|
199 | | - Returns: |
200 | | - The tool specification. |
201 | | - """ |
202 | | - return self._tool_spec |
203 | | - |
204 | | - @property |
205 | | - def tool_type(self) -> str: |
206 | | - """Get the type of the tool. |
207 | | -
|
208 | | - Returns: |
209 | | - The string "function" indicating this is a function-based tool. |
210 | | - """ |
211 | | - return "function" |
212 | | - |
213 | | - @property |
214 | | - def supports_hot_reload(self) -> bool: |
215 | | - """Check if this tool supports automatic reloading when modified. |
216 | | -
|
217 | | - Returns: |
218 | | - Always true for function-based tools. |
219 | | - """ |
220 | | - return True |
221 | | - |
222 | | - def invoke(self, tool: ToolUse, *args: Any, **kwargs: Any) -> ToolResult: |
223 | | - """Execute the function with the given tool use request. |
224 | | -
|
225 | | - Args: |
226 | | - tool: The tool use request containing the tool name, ID, and input parameters. |
227 | | - *args: Additional positional arguments to pass to the function. |
228 | | - **kwargs: Additional keyword arguments to pass to the function. |
229 | | -
|
230 | | - Returns: |
231 | | - A ToolResult containing the status and content from the function execution. |
232 | | - """ |
233 | | - # Make sure to pass through all kwargs, including 'agent' if provided |
234 | | - try: |
235 | | - # Check if the function accepts agent as a keyword argument |
236 | | - sig = inspect.signature(self._func) |
237 | | - if "agent" in sig.parameters: |
238 | | - # Pass agent if function accepts it |
239 | | - return self._func(tool, **kwargs) |
240 | | - else: |
241 | | - # Skip passing agent if function doesn't accept it |
242 | | - filtered_kwargs = {k: v for k, v in kwargs.items() if k != "agent"} |
243 | | - return self._func(tool, **filtered_kwargs) |
244 | | - except Exception as e: |
245 | | - return { |
246 | | - "toolUseId": tool.get("toolUseId", "unknown"), |
247 | | - "status": "error", |
248 | | - "content": [{"text": f"Error executing function: {str(e)}"}], |
249 | | - } |
250 | | - |
251 | | - @property |
252 | | - def original_function(self) -> Callable: |
253 | | - """Get the original function (without wrapper). |
254 | | -
|
255 | | - Returns: |
256 | | - Undecorated function. |
257 | | - """ |
258 | | - if hasattr(self._func, "original_function"): |
259 | | - return cast(Callable, self._func.original_function) |
260 | | - return self._func |
261 | | - |
262 | | - def get_display_properties(self) -> dict[str, str]: |
263 | | - """Get properties to display in UI representations. |
264 | | -
|
265 | | - Returns: |
266 | | - Function properties (e.g., function name). |
267 | | - """ |
268 | | - properties = super().get_display_properties() |
269 | | - properties["Function"] = self.original_function.__name__ |
270 | | - return properties |
271 | | - |
272 | | - |
273 | 144 | class PythonAgentTool(AgentTool): |
274 | 145 | """Tool implementation for Python-based tools. |
275 | 146 |
|
|
0 commit comments