test/moxie/tools/base.py
2026-03-24 04:04:58 +00:00

101 lines
2.7 KiB
Python
Executable File

"""
Base Tool Class
All tools inherit from this class.
"""
from abc import ABC, abstractmethod
from typing import Dict, Any, Optional
from pydantic import BaseModel
from loguru import logger
class ToolResult:
"""Result from a tool execution."""
def __init__(
self,
success: bool,
data: Any = None,
error: Optional[str] = None
):
self.success = success
self.data = data
self.error = error
def to_string(self) -> str:
"""Convert result to string for LLM consumption."""
if self.success:
if isinstance(self.data, str):
return self.data
elif isinstance(self.data, dict):
return str(self.data)
else:
return str(self.data)
else:
return f"Error: {self.error}"
class BaseTool(ABC):
"""
Abstract base class for all tools.
Each tool must implement:
- name: The tool's identifier
- description: What the tool does
- parameters: JSON schema for parameters
- execute: The actual tool logic
"""
def __init__(self, config: Optional[Dict] = None):
self.config = config or {}
self._validate_config()
@property
@abstractmethod
def name(self) -> str:
"""Tool name used in function calls."""
pass
@property
@abstractmethod
def description(self) -> str:
"""Tool description shown to the LLM."""
pass
@property
@abstractmethod
def parameters(self) -> Dict[str, Any]:
"""JSON schema for tool parameters."""
pass
def get_definition(self) -> Dict[str, Any]:
"""Get the OpenAI-style tool definition."""
return {
"type": "function",
"function": {
"name": self.name,
"description": self.description,
"parameters": self.parameters,
}
}
@abstractmethod
async def execute(self, **kwargs) -> ToolResult:
"""Execute the tool with given parameters."""
pass
def _validate_config(self) -> None:
"""Validate tool configuration. Override in subclasses."""
pass
def _log_execution(self, kwargs: Dict) -> None:
"""Log tool execution."""
logger.info(f"Executing tool: {self.name} with args: {kwargs}")
def _log_success(self, result: Any) -> None:
"""Log successful execution."""
logger.debug(f"Tool {self.name} completed successfully")
def _log_error(self, error: str) -> None:
"""Log execution error."""
logger.error(f"Tool {self.name} failed: {error}")