Praval Tool System Specification๏
Overview๏
The Praval Tool System provides a comprehensive framework for creating, registering, and managing tools that can be used by agents. This system extends Pravalโs decorator-based architecture to support modular, reusable tools that can be shared across multiple agents.
Key Features๏
1. Declarative Tool Definition๏
Tools are defined using the @tool decorator, similar to how agents are defined with @agent:
@tool(
tool_name="mathematical_add",
owned_by="calculator",
description="Add two numbers together",
category="arithmetic"
)
def add_numbers(x: float, y: float) -> float:
"""Add two numbers and return the result."""
return x + y
2. Tool Registry๏
A centralized registry manages all tools and their relationships to agents:
from praval import get_tool_registry
registry = get_tool_registry()
tools = registry.get_tools_for_agent("calculator")
all_tools = registry.list_all_tools()
3. Agent-Tool Association๏
Tools can be associated with agents in multiple ways:
Direct Ownership:
owned_by="agent_name"Shared Tools:
shared=True(available to all agents)Category-based:
category="math"(agents can request tools by category)Runtime Assignment: Tools can be dynamically assigned to agents
4. Type Safety and Validation๏
All tools must include proper type hints and validation:
@tool("validator", owned_by="data_processor")
def validate_email(email: str) -> bool:
"""Validate email address format."""
import re
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
Architecture๏
Core Components๏
ToolRegistry: Central registry for all tools
Tool: Individual tool wrapper with metadata
ToolCollection: Group of related tools
@tool Decorator: Function decorator for tool registration
Agent Integration: Seamless integration with existing agent system
Tool Metadata Structure๏
@dataclass
class ToolMetadata:
tool_name: str
owned_by: Optional[str] = None
description: str = ""
category: str = "general"
shared: bool = False
version: str = "1.0.0"
author: str = ""
tags: List[str] = field(default_factory=list)
parameters: Dict[str, Any] = field(default_factory=dict)
return_type: str = "Any"
Tool Registry Interface๏
class ToolRegistry:
def register_tool(self, tool: Tool) -> None
def get_tool(self, tool_name: str) -> Optional[Tool]
def get_tools_for_agent(self, agent_name: str) -> List[Tool]
def get_tools_by_category(self, category: str) -> List[Tool]
def get_shared_tools(self) -> List[Tool]
def list_all_tools(self) -> List[Tool]
def assign_tool_to_agent(self, tool_name: str, agent_name: str) -> bool
def remove_tool_from_agent(self, tool_name: str, agent_name: str) -> bool
def clear_registry(self) -> None
Usage Patterns๏
Pattern 1: Agent-Specific Tools๏
from praval import agent, tool
@tool("calculator_add", owned_by="calculator")
def add(x: float, y: float) -> float:
return x + y
@tool("calculator_multiply", owned_by="calculator")
def multiply(x: float, y: float) -> float:
return x * y
@agent("calculator")
def calculator_agent(spore):
# Tools are automatically available to this agent
query = spore.knowledge.get("query", "")
return {"result": "calculation complete"}
Pattern 3: Category-Based Tools๏
@tool("sin", category="trigonometry", owned_by="math_agent")
def sine(angle: float) -> float:
import math
return math.sin(math.radians(angle))
@tool("cos", category="trigonometry", owned_by="math_agent")
def cosine(angle: float) -> float:
import math
return math.cos(math.radians(angle))
# Agent can request all trigonometry tools
@agent("scientific_calculator")
def sci_calc_agent(spore):
# Automatically gets access to trigonometry category tools
pass
Pattern 4: Dynamic Tool Assignment๏
from praval import get_tool_registry
# Runtime tool assignment
registry = get_tool_registry()
registry.assign_tool_to_agent("advanced_math", "calculator")
registry.assign_tool_to_agent("data_export", "calculator")
Integration with Existing Agent System๏
Enhanced @agent Decorator๏
The existing @agent decorator will be enhanced to support tool integration:
@agent(
"calculator",
tools=["math_add", "math_multiply"], # Specific tools
tool_categories=["arithmetic", "geometry"], # Tool categories
auto_discover_tools=True # Automatically find owned tools
)
def calculator_agent(spore):
pass
Tool Method Exposure๏
The @agent decorator will expose tool-related methods:
@agent("processor")
def data_processor(spore):
pass
# Enhanced tool access
data_processor.add_tool("csv_parser")
data_processor.remove_tool("xml_parser")
data_processor.list_tools()
data_processor.tool_exists("json_parser")
Error Handling and Validation๏
Tool Validation๏
class ToolValidationError(Exception):
pass
# Automatic validation on registration
@tool("invalid_tool", owned_by="agent1")
def bad_tool(x, y): # Missing type hints
return x + y # Will raise ToolValidationError
Runtime Error Handling๏
@tool("safe_divide", owned_by="calculator")
def divide(x: float, y: float) -> float:
if y == 0:
raise ValueError("Division by zero")
return x / y
# Agent automatically handles tool errors
@agent("calculator")
def calc_agent(spore):
try:
# Tool execution is automatically wrapped in error handling
pass
except ValueError as e:
return {"error": str(e)}
Tool Discovery and Introspection๏
Tool Discovery๏
from praval import discover_tools
# Discover tools in a module
tools = discover_tools("my_project.math_tools")
# Discover tools with pattern
tools = discover_tools(pattern="*_tool.py")
# Discover tools by category
math_tools = discover_tools(category="mathematics")
Tool Introspection๏
tool_info = registry.get_tool("calculator_add")
print(f"Name: {tool_info.metadata.tool_name}")
print(f"Owner: {tool_info.metadata.owned_by}")
print(f"Category: {tool_info.metadata.category}")
print(f"Parameters: {tool_info.metadata.parameters}")
Backward Compatibility๏
The new tool system maintains full backward compatibility with existing code:
Existing
agent.tooldecorator continues to workTools registered with old system are automatically migrated
Agent behavior remains unchanged for existing implementations
Testing Requirements๏
Unit Tests๏
Tool registration and retrieval
Agent-tool association
Tool validation and error handling
Registry operations (add, remove, list, search)
Integration Tests๏
Tool execution within agent context
Cross-agent tool sharing
Category-based tool assignment
Runtime tool management
Performance Tests๏
Tool lookup performance with large registries
Memory usage with many tools
Tool execution overhead
Implementation Phases๏
Phase 1: Core Infrastructure๏
ToolRegistry implementation
Tool metadata classes
Basic @tool decorator
Agent integration points
Phase 2: Advanced Features๏
Category-based tool management
Shared tools system
Tool discovery mechanisms
Enhanced error handling
Phase 3: Developer Experience๏
CLI tools for tool management
Tool documentation generation
IDE integration helpers
Performance monitoring
Migration Guide๏
For Existing Code๏
# Before (current approach)
@agent("calculator")
def calc_agent(spore):
pass
@calc_agent._praval_agent.tool
def add(x: float, y: float) -> float:
return x + y
# After (new approach)
@tool("add", owned_by="calculator")
def add(x: float, y: float) -> float:
return x + y
@agent("calculator")
def calc_agent(spore):
pass
Benefits of Migration๏
Cleaner, more modular code
Better tool reusability
Enhanced type safety
Improved debugging and introspection
Better testing capabilities
This specification provides the foundation for a robust, scalable tool system that enhances Pravalโs capabilities while maintaining its simple, decorator-based philosophy.