Overview
Tools are the agent’s interface to the outside world. The tool system provides:
- Trait-based extensibility for custom tools
- Built-in tools (shell, HTTP, file operations, memory)
- WASM-based sandboxed tool execution
- MCP (Model Context Protocol) integration
- Rate limiting and approval requirements
- Cost estimation and timeout configuration
All tools implement the Tool trait for uniform execution.
#[async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn parameters_schema(&self) -> serde_json::Value;
async fn execute(
&self,
params: serde_json::Value,
ctx: &JobContext,
) -> Result<ToolOutput, ToolError>;
fn estimated_cost(&self, params: &serde_json::Value) -> Option<Decimal>;
fn estimated_duration(&self, params: &serde_json::Value) -> Option<Duration>;
fn requires_sanitization(&self) -> bool;
fn requires_approval(&self, params: &serde_json::Value) -> ApprovalRequirement;
fn execution_timeout(&self) -> Duration;
fn domain(&self) -> ToolDomain;
fn rate_limit_config(&self) -> Option<ToolRateLimitConfig>;
fn schema(&self) -> ToolSchema;
}
Required Methods
Unique identifier for the tool
Human-readable description of what the tool does
parameters_schema
serde_json::Value
required
JSON Schema defining the tool’s input parameters
Execute the tool with the given parameters and context
Optional Methods
Estimated cost of running this tool (for budget tracking)
Whether output needs sanitization (true for external services)
requires_approval
ApprovalRequirement
default:"Never"
Whether this tool requires user approval before execution
Maximum execution time before timeout
domain
ToolDomain
default:"Orchestrator"
Where the tool executes: Orchestrator (main process) or Container (sandboxed)
rate_limit_config
Option<ToolRateLimitConfig>
Per-user rate limiting configuration
Registry for managing available tools.
Constructor
Creates a new empty registry.
register
pub async fn register(&self, tool: Arc<dyn Tool>)
Registers a tool. Rejects dynamic tools that try to shadow built-in names.
get
pub async fn get(&self, name: &str) -> Option<Arc<dyn Tool>>
Get a tool by name.
list
pub async fn list(&self) -> Vec<String>
List all registered tool names.
pub async fn tool_definitions(&self) -> Vec<ToolDefinition>
Get tool definitions for LLM function calling.
Bulk Registration Methods
pub fn register_builtin_tools(&self)
pub fn register_orchestrator_tools(&self)
pub fn register_container_tools(&self)
pub fn register_memory_tools(&self, workspace: Arc<Workspace>)
pub fn register_job_tools(&self, /* ... */)
pub fn register_extension_tools(&self, manager: Arc<ExtensionManager>)
pub fn register_skill_tools(&self, registry: Arc<RwLock<SkillRegistry>>, catalog: Arc<SkillCatalog>)
pub fn register_routine_tools(&self, store: Arc<dyn Database>, engine: Arc<RoutineEngine>)
Result from a tool execution.
pub struct ToolOutput {
pub result: serde_json::Value,
pub cost: Option<Decimal>,
pub duration: Duration,
pub raw: Option<String>,
}
result
serde_json::Value
required
The output data (JSON value)
Cost incurred by this execution
Raw output before sanitization (for debugging)
Error types for tool execution.
pub enum ToolError {
InvalidParameters(String),
ExecutionFailed(String),
Timeout(Duration),
NotAuthorized(String),
RateLimited(Option<Duration>),
ExternalService(String),
Sandbox(String),
}
ApprovalRequirement
Defines when a tool requires user approval.
pub enum ApprovalRequirement {
/// No approval needed
Never,
/// Needs approval, but session auto-approve can bypass
UnlessAutoApproved,
/// Always needs explicit approval
Always,
}
ToolDomain
Defines where a tool executes.
pub enum ToolDomain {
/// Safe to run in orchestrator (pure functions, memory, job management)
Orchestrator,
/// Must run inside sandboxed container (filesystem, shell, code)
Container,
}
Per-tool rate limiting configuration.
pub struct ToolRateLimitConfig {
pub requests_per_minute: u32,
pub requests_per_hour: u32,
}
use ironclaw::tools::{Tool, ToolOutput, ToolError};
use async_trait::async_trait;
use std::time::Duration;
#[derive(Debug)]
pub struct MyTool;
#[async_trait]
impl Tool for MyTool {
fn name(&self) -> &str {
"my_tool"
}
fn description(&self) -> &str {
"Does something useful"
}
fn parameters_schema(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "Input data"
}
},
"required": ["input"]
})
}
async fn execute(
&self,
params: serde_json::Value,
ctx: &JobContext,
) -> Result<ToolOutput, ToolError> {
let input = params.get("input")
.and_then(|v| v.as_str())
.ok_or_else(|| ToolError::InvalidParameters("missing input".into()))?;
// Do work here
let result = format!("Processed: {}", input);
Ok(ToolOutput::text(result, Duration::from_millis(10)))
}
}
// Register the tool
let registry = ToolRegistry::new();
registry.register(Arc::new(MyTool)).await;