summaryrefslogtreecommitdiff
path: root/tools.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools.py')
-rw-r--r--tools.py149
1 files changed, 149 insertions, 0 deletions
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)