in src/smolagents/tools.py [0:0]
def to_dict(self) -> dict:
"""Returns a dictionary representing the tool"""
class_name = self.__class__.__name__
if type(self).__name__ == "SimpleTool":
# Check that imports are self-contained
source_code = get_source(self.forward).replace("@tool", "")
forward_node = ast.parse(source_code)
# If tool was created using '@tool' decorator, it has only a forward pass, so it's simpler to just get its code
method_checker = MethodChecker(set())
method_checker.visit(forward_node)
if len(method_checker.errors) > 0:
errors = [f"- {error}" for error in method_checker.errors]
raise (ValueError(f"SimpleTool validation failed for {self.name}:\n" + "\n".join(errors)))
forward_source_code = get_source(self.forward)
tool_code = textwrap.dedent(
f"""
from smolagents import Tool
from typing import Any, Optional
class {class_name}(Tool):
name = "{self.name}"
description = {json.dumps(textwrap.dedent(self.description).strip())}
inputs = {repr(self.inputs)}
output_type = "{self.output_type}"
"""
).strip()
import re
def add_self_argument(source_code: str) -> str:
"""Add 'self' as first argument to a function definition if not present."""
pattern = r"def forward\(((?!self)[^)]*)\)"
def replacement(match):
args = match.group(1).strip()
if args: # If there are other arguments
return f"def forward(self, {args})"
return "def forward(self)"
return re.sub(pattern, replacement, source_code)
forward_source_code = forward_source_code.replace(self.name, "forward")
forward_source_code = add_self_argument(forward_source_code)
forward_source_code = forward_source_code.replace("@tool", "").strip()
tool_code += "\n\n" + textwrap.indent(forward_source_code, " ")
else: # If the tool was not created by the @tool decorator, it was made by subclassing Tool
if type(self).__name__ in [
"SpaceToolWrapper",
"LangChainToolWrapper",
"GradioToolWrapper",
]:
raise ValueError(
"Cannot save objects created with from_space, from_langchain or from_gradio, as this would create errors."
)
validate_tool_attributes(self.__class__)
tool_code = "from typing import Any, Optional\n" + instance_to_source(self, base_cls=Tool)
requirements = {el for el in get_imports(tool_code) if el not in sys.stdlib_module_names} | {"smolagents"}
return {"name": self.name, "code": tool_code, "requirements": sorted(requirements)}