nanobot/nanobot/agent/tools/registry.py
tanyar09 096d76430b Improve agent reliability and error handling
- Add timeout protection (120s) for LLM provider calls
- Skip memory consolidation for CLI mode to avoid blocking
- Add timeout protection for memory consolidation (120s)
- Improve error handling with better logging
- Add parameter type coercion before validation
- Allow None values for optional parameters in validation
- Fix type coercion for memory updates (handle dict responses)
2026-03-03 13:10:53 -05:00

76 lines
2.2 KiB
Python

"""Tool registry for dynamic tool management."""
from typing import Any
from nanobot.agent.tools.base import Tool
class ToolRegistry:
"""
Registry for agent tools.
Allows dynamic registration and execution of tools.
"""
def __init__(self):
self._tools: dict[str, Tool] = {}
def register(self, tool: Tool) -> None:
"""Register a tool."""
self._tools[tool.name] = tool
def unregister(self, name: str) -> None:
"""Unregister a tool by name."""
self._tools.pop(name, None)
def get(self, name: str) -> Tool | None:
"""Get a tool by name."""
return self._tools.get(name)
def has(self, name: str) -> bool:
"""Check if a tool is registered."""
return name in self._tools
def get_definitions(self) -> list[dict[str, Any]]:
"""Get all tool definitions in OpenAI format."""
return [tool.to_schema() for tool in self._tools.values()]
async def execute(self, name: str, params: dict[str, Any]) -> str:
"""
Execute a tool by name with given parameters.
Args:
name: Tool name.
params: Tool parameters.
Returns:
Tool execution result as string.
Raises:
KeyError: If tool not found.
"""
tool = self._tools.get(name)
if not tool:
return f"Error: Tool '{name}' not found"
try:
# Coerce parameter types before validation
coerced_params = tool.coerce_params(params)
errors = tool.validate_params(coerced_params)
if errors:
return f"Error: Invalid parameters for tool '{name}': " + "; ".join(errors)
return await tool.execute(**coerced_params)
except Exception as e:
return f"Error executing {name}: {str(e)}"
@property
def tool_names(self) -> list[str]:
"""Get list of registered tool names."""
return list(self._tools.keys())
def __len__(self) -> int:
return len(self._tools)
def __contains__(self, name: str) -> bool:
return name in self._tools