Tools¶
Tools extend the capabilities of agents, allowing them to interact with the system and external resources.
Available Tools¶
File Operations¶
file_read¶
Read the contents of a file.
Parameters:
- path (str, required): Path to the file
- offset (int, optional): Line offset to start from (0-indexed)
- limit (int, optional): Maximum lines to read
Example:
file_write¶
Write content to a file.
Parameters:
- path (str, required): Path to the file
- content (str, required): Content to write
- append (bool, optional): Append instead of overwrite
Example:
{
"name": "file_write",
"arguments": {
"path": "output.txt",
"content": "Hello, World!",
"append": false
}
}
file_edit¶
Edit a file using search and replace.
Parameters:
- path (str, required): Path to the file
- old_string (str, required): Text to find
- new_string (str, required): Text to replace with
Example:
{
"name": "file_edit",
"arguments": {
"path": "config.py",
"old_string": "DEBUG = True",
"new_string": "DEBUG = False"
}
}
System Operations¶
bash¶
Execute bash commands.
Parameters:
- command (str, required): Command to execute
- cwd (str, optional): Working directory
- timeout (int, optional): Timeout in seconds
Example:
Security: - Dangerous commands are blocked - Cannot access files outside working directory - Timeout prevents hanging commands
Web Operations¶
web_search¶
Search the web using DuckDuckGo.
Parameters:
- query (str, required): Search query
- max_results (int, optional): Maximum results (default: 5)
- region (str, optional): Region code (default: "wt-wt")
- safesearch (str, optional): Safe search level
Example:
{
"name": "web_search",
"arguments": {
"query": "Python asyncio best practices",
"max_results": 3
}
}
Using Tools¶
In Chat¶
Agents automatically use tools when needed:
You: Read the README.md file and tell me what this project does.
Agent: [Uses file_read tool]
This project is a CLI framework for autonomous AI agents...
Disable Tools¶
Or in interactive mode:
Creating Custom Tools¶
Basic Tool Structure¶
from legionhercules.tools.base import Tool, ToolResult
from typing import Any
class MyTool(Tool):
def __init__(self):
super().__init__(
name="my_tool",
description="Description of what my tool does"
)
async def execute(self, param1: str, param2: int = 0) -> ToolResult:
"""Execute the tool.
Args:
param1: Description of param1
param2: Description of param2
"""
try:
# Your tool logic here
result = f"Processed {param1} with {param2}"
return ToolResult(
success=True,
output=result,
metadata={"param1": param1}
)
except Exception as e:
return ToolResult(success=False, error=str(e))
def get_schema(self) -> dict[str, Any]:
"""Define the JSON schema for tool parameters."""
return {
"type": "object",
"properties": {
"param1": {
"type": "string",
"description": "Description of param1"
},
"param2": {
"type": "integer",
"description": "Description of param2",
"default": 0
}
},
"required": ["param1"]
}
Registering Custom Tools¶
from legionhercules.tools.base import ToolRegistry
# Create registry
registry = ToolRegistry()
# Register tool
registry.register(MyTool())
# Use in agent
from legionhercules.core.agent import Agent, AgentConfig
config = AgentConfig(
name="custom_agent",
tools=["my_tool", "file_read"]
)
Tool Best Practices¶
1. Clear Descriptions¶
Write clear, specific descriptions:
2. Validate Inputs¶
Always validate inputs and return helpful errors:
async def execute(self, number: int) -> ToolResult:
if number < 0:
return ToolResult(
success=False,
error="Number must be non-negative"
)
# ...
3. Security First¶
- Validate file paths
- Sanitize command inputs
- Set reasonable timeouts
- Limit resource usage
4. Meaningful Results¶
Return structured data when possible:
return ToolResult(
success=True,
output={"count": 42, "items": [...]},
metadata={"query_time": 0.5}
)
Tool Registry¶
The ToolRegistry manages available tools:
from legionhercules.tools.base import ToolRegistry
# Create with default tools
registry = ToolRegistry.create_default_registry()
# List tools
tools = registry.list_tools()
# Get tool
tool = registry.get_tool("file_read")
# Check if tool exists
if registry.has_tool("bash"):
print("Bash tool available")
# Get all tool schemas (for LLM)
schemas = registry.get_tool_schemas()
Error Handling¶
Tools should handle errors gracefully:
async def execute(self, path: str) -> ToolResult:
try:
# Attempt operation
content = Path(path).read_text()
return ToolResult(success=True, output=content)
except FileNotFoundError:
return ToolResult(
success=False,
error=f"File not found: {path}"
)
except PermissionError:
return ToolResult(
success=False,
error=f"Permission denied: {path}"
)
except Exception as e:
return ToolResult(
success=False,
error=f"Unexpected error: {str(e)}"
)