"""
Base class for all tools.
Each tool is self-describing: name, description, and parameters (JSON Schema).
The schema() method builds the LLM-facing function spec automatically.
"""
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from navi.llm.base import ToolSchema
@dataclass
class ToolResult:
success: bool
output: str # always a string — LLM consumes this
error: str | None = None
metadata: dict = field(default_factory=dict)
def to_message_content(self) -> str:
if self.success:
return self.output
return f"Error: {self.error}"
class Tool(ABC):
"""Abstract base for all tools."""
# Override in subclasses:
name: str
description: str
parameters: dict # JSON Schema object
@abstractmethod
async def execute(self, params: dict) -> ToolResult:
"""Execute the tool with given parameters."""
def schema(self) -> ToolSchema:
return ToolSchema(
type="function",
function={
"name": self.name,
"description": self.description,
"parameters": self.parameters,
},
)