Ensure functions have docstrings for documentation
async def ainvoke(
1"""Tool that takes in function or coroutine directly."""23from __future__ import annotations45from collections.abc import Awaitable, Callable6from inspect import signature7from typing import (8 TYPE_CHECKING,9 Any,10)1112from typing_extensions import override1314# Cannot move to TYPE_CHECKING as _run/_arun parameter annotations are needed at runtime15from langchain_core.callbacks import (16 AsyncCallbackManagerForToolRun, # noqa: TC00117 CallbackManagerForToolRun, # noqa: TC00118)19from langchain_core.runnables import RunnableConfig, run_in_executor20from langchain_core.tools.base import (21 ArgsSchema,22 BaseTool,23 ToolException,24 _get_runnable_config_param,25)2627if TYPE_CHECKING:28 from langchain_core.messages import ToolCall293031class Tool(BaseTool):32 """Tool that takes in function or coroutine directly."""3334 description: str = ""3536 func: Callable[..., str] | None37 """The function to run when the tool is called."""3839 coroutine: Callable[..., Awaitable[str]] | None = None40 """The asynchronous version of the function."""4142 # --- Runnable ---4344 @override45 async def ainvoke(46 self,47 input: str | dict | ToolCall,48 config: RunnableConfig | None = None,49 **kwargs: Any,50 ) -> Any:51 if not self.coroutine:52 # If the tool does not implement async, fall back to default implementation53 return await run_in_executor(config, self.invoke, input, config, **kwargs)5455 return await super().ainvoke(input, config, **kwargs)5657 # --- Tool ---5859 @property60 def args(self) -> dict:61 """The tool's input arguments.6263 Returns:64 The input arguments for the tool.65 """66 if self.args_schema is not None:67 return super().args68 # For backwards compatibility, if the function signature is ambiguous,69 # assume it takes a single string input.70 return {"tool_input": {"type": "string"}}7172 def _to_args_and_kwargs(73 self, tool_input: str | dict, tool_call_id: str | None74 ) -> tuple[tuple, dict]:75 """Convert tool input to Pydantic model.7677 Args:78 tool_input: The input to the tool.79 tool_call_id: The ID of the tool call.8081 Raises:82 ToolException: If the tool input is invalid.8384 Returns:85 The Pydantic model args and kwargs.86 """87 args, kwargs = super()._to_args_and_kwargs(tool_input, tool_call_id)88 # For backwards compatibility. The tool must be run with a single input89 all_args = list(args) + list(kwargs.values())90 if len(all_args) != 1:91 msg = (92 f"""Too many arguments to single-input tool {self.name}.93 Consider using StructuredTool instead."""94 f" Args: {all_args}"95 )96 raise ToolException(msg)97 return tuple(all_args), {}9899 def _run(100 self,101 *args: Any,102 config: RunnableConfig,103 run_manager: CallbackManagerForToolRun | None = None,104 **kwargs: Any,105 ) -> Any:106 """Use the tool.107108 Args:109 *args: Positional arguments to pass to the tool110 config: Configuration for the run111 run_manager: Optional callback manager to use for the run112 **kwargs: Keyword arguments to pass to the tool113114 Returns:115 The result of the tool execution116 """117 if self.func:118 if run_manager and signature(self.func).parameters.get("callbacks"):119 kwargs["callbacks"] = run_manager.get_child()120 if config_param := _get_runnable_config_param(self.func):121 kwargs[config_param] = config122 return self.func(*args, **kwargs)123 msg = "Tool does not support sync invocation."124 raise NotImplementedError(msg)125126 async def _arun(127 self,128 *args: Any,129 config: RunnableConfig,130 run_manager: AsyncCallbackManagerForToolRun | None = None,131 **kwargs: Any,132 ) -> Any:133 """Use the tool asynchronously.134135 Args:136 *args: Positional arguments to pass to the tool137 config: Configuration for the run138 run_manager: Optional callback manager to use for the run139 **kwargs: Keyword arguments to pass to the tool140141 Returns:142 The result of the tool execution143 """144 if self.coroutine:145 if run_manager and signature(self.coroutine).parameters.get("callbacks"):146 kwargs["callbacks"] = run_manager.get_child()147 if config_param := _get_runnable_config_param(self.coroutine):148 kwargs[config_param] = config149 return await self.coroutine(*args, **kwargs)150151 # NOTE: this code is unreachable since _arun is only called if coroutine is not152 # None.153 return await super()._arun(154 *args, config=config, run_manager=run_manager, **kwargs155 )156157 # TODO: this is for backwards compatibility, remove in future158 def __init__(159 self, name: str, func: Callable | None, description: str, **kwargs: Any160 ) -> None:161 """Initialize tool."""162 super().__init__(name=name, func=func, description=description, **kwargs)163164 @classmethod165 def from_function(166 cls,167 func: Callable | None,168 name: str, # We keep these required to support backwards compatibility169 description: str,170 return_direct: bool = False, # noqa: FBT001,FBT002171 args_schema: ArgsSchema | None = None,172 coroutine: Callable[..., Awaitable[Any]]173 | None = None, # This is last for compatibility, but should be after func174 **kwargs: Any,175 ) -> Tool:176 """Initialize tool from a function.177178 Args:179 func: The function to create the tool from.180 name: The name of the tool.181 description: The description of the tool.182 return_direct: Whether to return the output directly.183 args_schema: The schema of the tool's input arguments.184 coroutine: The asynchronous version of the function.185 **kwargs: Additional arguments to pass to the tool.186187 Returns:188 The tool.189190 Raises:191 ValueError: If the function is not provided.192 """193 if func is None and coroutine is None:194 msg = "Function and/or coroutine must be provided"195 raise ValueError(msg)196 return cls(197 name=name,198 func=func,199 coroutine=coroutine,200 description=description,201 return_direct=return_direct,202 args_schema=args_schema,203 **kwargs,204 )
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.