From c90a0f8ae6ad5d6e07927cd0dc53b345a77494ae Mon Sep 17 00:00:00 2001 From: batsumaru <> Date: Fri, 11 Sep 2026 15:42:11 +0900 Subject: Added tool calling base --- tools.py | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 tools.py (limited to 'tools.py') diff --git a/tools.py b/tools.py new file mode 100644 index 0000000..64238e7 --- /dev/null +++ b/tools.py @@ -0,0 +1,149 @@ +from abc import ABC, abstractmethod +from dataclasses import dataclass + + +@dataclass +class ToolResult: + content: str + + +class Tool(ABC): + @property + @abstractmethod + def name(self) -> str: ... + + @property + @abstractmethod + def description(self) -> str: ... + + @property + @abstractmethod + def schema(self) -> dict[str, object]: ... + + @abstractmethod + def execute(self, arguments: dict[str, object]) -> ToolResult: ... + + +class ToolRegistry: + def __init__(self) -> None: + self.tools: dict[str, Tool] = {} + + def register(self, tool: Tool) -> None: + self.tools[tool.name] = tool + + def get(self, name: str) -> Tool | None: + return self.tools.get(name) + + def all(self) -> list[Tool]: + return list(self.tools.values()) + + def schemas(self) -> list[dict[str, object]]: + return [ + { + "type": "function", + "function": { + "name": tool.name, + "description": tool.description, + "parameters": tool.schema, + }, + } + for tool in self.tools.values() + ] + + +class HelloTool(Tool): + @property + def name(self) -> str: + return "hello" + + @property + def description(self) -> str: + return "Say hello to someone." + + @property + def schema(self) -> dict[str, object]: + return { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The person to greet.", + }, + }, + "required": ["name"], + } + + def execute(self, arguments: dict[str, object]) -> ToolResult: + name = arguments.get("name", "stranger") + return ToolResult(content=f"Hello, {name}!") + +class CalculatorTool(Tool): + @property + def name(self) -> str: + return "calculator" + + @property + def description(self) -> str: + return "Perform basic arithemtic" + + @property + def schema(self) -> dict[str, object]: + return { + "type": "object", + "properties": { + "a": { + "type": "number", + "description": "The first number.", + }, + "b": { + "type": "number", + "description": "The second number.", + }, + "operation": { + "type": "string", + "enum": ["add", "subtract", "multiply", "divide"], + "description": "The arithemtic operation to perform", + }, + }, + "required": ["a", "b", "operation"], + } + + def execute(self, arguments: dict[str, object]) -> ToolResult: + a = arguments["a"] + b = arguments["b"] + operation = arguments["operation"] + + if not isinstance(a, (int, float)): + raise TypeError("a must be a number") + + if not isinstance(b, (int, float)): + raise TypeError("b must be a number") + + if not isinstance(operation, str): + raise TypeError("operation must be a string") + + if operation == "add": + result = a + b + elif operation == "subtract": + result = a - b + elif operation == "multiply": + result = a * b + elif operation == "divide": + if b == 0: + raise ValueError("cannot divide by zero") + result = a / b + else: + raise ValueError(f"unknown operation: {operation}") + + return ToolResult(content=str(result)) + +if __name__ == "__main__": + registry = ToolRegistry() + + registry.register(HelloTool()) + print(registry.schemas()) + tool = registry.get("hello") + + if tool is not None: + result = tool.execute({"name": "Joseph"}) + print(result.content) -- cgit v1.3