49 lines
1.5 KiB
Python
49 lines
1.5 KiB
Python
"""Meta-tool: dynamically create new tools at runtime."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import textwrap
|
|
from pathlib import Path
|
|
|
|
from . import tool
|
|
|
|
|
|
@tool("build_tool", "Create a new tool from a description. The agent writes Python code with @tool decorator.", category="meta")
|
|
def build_tool(name: str, description: str, code: str, ctx: dict = None) -> str:
|
|
"""Generate a new tool module and hot-load it.
|
|
|
|
Args:
|
|
name: Tool name (snake_case)
|
|
description: What the tool does
|
|
code: Full Python code for the tool function (must use @tool decorator)
|
|
"""
|
|
if not name.isidentifier():
|
|
return f"Invalid tool name: {name}. Must be a valid Python identifier."
|
|
|
|
# Wrap code in a module with the import
|
|
module_code = textwrap.dedent(f'''\
|
|
"""Auto-generated tool: {description}"""
|
|
from __future__ import annotations
|
|
from . import tool
|
|
|
|
{code}
|
|
''')
|
|
|
|
# Write to tools directory
|
|
tools_dir = Path(__file__).parent
|
|
file_path = tools_dir / f"{name}.py"
|
|
if file_path.exists():
|
|
return f"Tool module '{name}' already exists. Choose a different name."
|
|
|
|
file_path.write_text(module_code, encoding="utf-8")
|
|
|
|
# Hot-import the new module
|
|
try:
|
|
importlib.import_module(f".{name}", package=__package__)
|
|
return f"Tool '{name}' created and loaded successfully at {file_path}"
|
|
except Exception as e:
|
|
# Clean up on failure
|
|
file_path.unlink(missing_ok=True)
|
|
return f"Failed to load tool '{name}': {e}"
|