Returns a dictionary representing the tool
(self)
| 290 | return f"{self.name}: {self.description}\n Takes inputs: {self.inputs}\n Returns an output of type: {self.output_type}" |
| 291 | |
| 292 | def to_dict(self) -> dict: |
| 293 | """Returns a dictionary representing the tool""" |
| 294 | class_name = self.__class__.__name__ |
| 295 | if type(self).__name__ == "SimpleTool": |
| 296 | # Check that imports are self-contained |
| 297 | source_code = get_source(self.forward).replace("@tool", "") |
| 298 | forward_node = ast.parse(source_code) |
| 299 | # If tool was created using '@tool' decorator, it has only a forward pass, so it's simpler to just get its code |
| 300 | method_checker = MethodChecker(set()) |
| 301 | method_checker.visit(forward_node) |
| 302 | |
| 303 | if len(method_checker.errors) > 0: |
| 304 | errors = [f"- {error}" for error in method_checker.errors] |
| 305 | raise (ValueError(f"SimpleTool validation failed for {self.name}:\n" + "\n".join(errors))) |
| 306 | |
| 307 | forward_source_code = get_source(self.forward) |
| 308 | tool_code = textwrap.dedent( |
| 309 | f""" |
| 310 | from smolagents import Tool |
| 311 | from typing import Any, Optional |
| 312 | |
| 313 | class {class_name}(Tool): |
| 314 | name = "{self.name}" |
| 315 | description = {json.dumps(textwrap.dedent(self.description).strip())} |
| 316 | inputs = {repr(self.inputs)} |
| 317 | output_type = "{self.output_type}" |
| 318 | """ |
| 319 | ).strip() |
| 320 | |
| 321 | # Add output_schema if it exists |
| 322 | if hasattr(self, "output_schema") and self.output_schema is not None: |
| 323 | tool_code += f"\n output_schema = {repr(self.output_schema)}" |
| 324 | import re |
| 325 | |
| 326 | def add_self_argument(source_code: str) -> str: |
| 327 | """Add 'self' as first argument to a function definition if not present.""" |
| 328 | pattern = r"def forward\(((?!self)[^)]*)\)" |
| 329 | |
| 330 | def replacement(match): |
| 331 | args = match.group(1).strip() |
| 332 | if args: # If there are other arguments |
| 333 | return f"def forward(self, {args})" |
| 334 | return "def forward(self)" |
| 335 | |
| 336 | return re.sub(pattern, replacement, source_code) |
| 337 | |
| 338 | forward_source_code = forward_source_code.replace(self.name, "forward") |
| 339 | forward_source_code = add_self_argument(forward_source_code) |
| 340 | forward_source_code = forward_source_code.replace("@tool", "").strip() |
| 341 | tool_code += "\n\n" + textwrap.indent(forward_source_code, " ") |
| 342 | |
| 343 | else: # If the tool was not created by the @tool decorator, it was made by subclassing Tool |
| 344 | if type(self).__name__ in [ |
| 345 | "SpaceToolWrapper", |
| 346 | "LangChainToolWrapper", |
| 347 | "GradioToolWrapper", |
| 348 | ]: |
| 349 | raise ValueError( |