pub trait Tool: Send + Sync {
// Required methods
fn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
params: Value,
context: &'life1 ApplicationContext,
) -> Pin<Box<dyn Future<Output = Result<JobResult, ToolError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn name(&self) -> &str;
fn description(&self) -> &str;
// Provided method
fn schema(&self) -> Value { ... }
}Expand description
A trait defining the execution interface for tools.
This is compatible with rig::Tool and provides the foundation
for executing tools within the riglr ecosystem. Tools represent
individual operations that can be executed by the ToolWorker.
§Design Principles
- Stateless: Tools should not maintain internal state between executions
- Idempotent: When possible, tools should be safe to retry
- Error-aware: Tools should classify errors as retriable or permanent
- Resource-conscious: Tools should handle rate limits and timeouts gracefully
§Error Handling
Tools should carefully distinguish between different types of errors:
- Retriable errors: Network timeouts, rate limits, temporary service unavailability
- Permanent errors: Invalid parameters, insufficient funds, authorization failures
- System errors: Internal configuration issues, unexpected state
§Examples
§Basic Tool Implementation
use riglr_core::{Tool, JobResult};
use async_trait::async_trait;
use serde_json::Value;
struct HttpFetcher;
#[async_trait]
impl Tool for HttpFetcher {
async fn execute(&self, params: Value, _context: &ApplicationContext) -> Result<JobResult, ToolError> {
let url = params["url"].as_str()
.ok_or("Missing required parameter: url")?;
// Mock HTTP client behavior for this example
if url.starts_with("https://") {
let body = r#"{"data": "success"}"#;
Ok(JobResult::success(&serde_json::json!({"body": body}))?)
} else if url.contains("error") {
// Simulate client error
Ok(JobResult::Failure {
error: ToolError::permanent_string("Client error: Invalid URL")
})
} else if url.contains("timeout") {
// Simulate timeout
Ok(JobResult::Failure {
error: ToolError::retriable_string("Request timeout: Connection timed out")
})
} else {
// Simulate server error
Ok(JobResult::Failure {
error: ToolError::retriable_string("Server error: HTTP 503")
})
}
}
fn name(&self) -> &str {
"http_fetcher"
}
}§Tool with Resource-Aware Naming
use riglr_core::{Tool, JobResult};
use async_trait::async_trait;
use serde_json::Value;
// The name starts with "solana_" which will use the solana_rpc resource limit
struct SolanaBalanceChecker;
#[async_trait]
impl Tool for SolanaBalanceChecker {
async fn execute(&self, params: Value, _context: &ApplicationContext) -> Result<JobResult, ToolError> {
let address = params["address"].as_str()
.ok_or("Missing required parameter: address")?;
// This tool will be rate-limited by the "solana_rpc" resource limit
// because its name starts with "solana_"
// Implementation would use Solana RPC client here...
let balance = 1.5; // Mock balance
Ok(JobResult::success(&serde_json::json!({
"address": address,
"balance": balance,
"unit": "SOL"
}))?)
}
fn name(&self) -> &str {
"solana_balance_check" // Name prefix determines resource pool
}
}§Tool Using Signer Context
use riglr_core::{Tool, JobResult, SignerContext};
use async_trait::async_trait;
use serde_json::Value;
struct TransferTool;
#[async_trait]
impl Tool for TransferTool {
async fn execute(&self, params: Value, _context: &ApplicationContext) -> Result<JobResult, ToolError> {
// Check if we have a signer context
if !SignerContext::is_available().await {
return Ok(JobResult::Failure {
error: ToolError::permanent_string("Transfer operations require a signer context")
});
}
let signer = SignerContext::current().await
.map_err(|_| "Failed to get signer context")?;
let recipient = params["recipient"].as_str()
.ok_or("Missing required parameter: recipient")?;
let amount = params["amount"].as_f64()
.ok_or("Missing required parameter: amount")?;
// Use the signer to perform the transfer...
// This is just a mock implementation
Ok(JobResult::success_with_tx(
&serde_json::json!({
"recipient": recipient,
"amount": amount,
"status": "completed"
}),
"mock_tx_hash_12345"
)?)
}
fn name(&self) -> &str {
"transfer"
}
}Required Methods§
Sourcefn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
params: Value,
context: &'life1 ApplicationContext,
) -> Pin<Box<dyn Future<Output = Result<JobResult, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
params: Value,
context: &'life1 ApplicationContext,
) -> Pin<Box<dyn Future<Output = Result<JobResult, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Execute the tool with the given parameters.
This method performs the core work of the tool. It receives parameters
as a JSON value and should return a JobResult indicating success or failure.
§Parameters
params- JSON parameters passed to the tool. Tools should validate and extract required parameters, returning appropriate errors for missing or invalid data.
§Returns
Ok(JobResult::Success)- Tool executed successfully with result dataOk(JobResult::Failure { retriable: true })- Tool failed but can be retriedOk(JobResult::Failure { retriable: false })- Tool failed permanentlyErr(Box<dyn Error>)- Unexpected system error occurred
§Error Classification Guidelines
Return retriable failures (JobResult::Failure { error: ToolError::retriable_string(...) }) for:
- Network timeouts or connection errors
- Rate limiting (HTTP 429, RPC rate limits) - use
ToolError::rate_limited_stringfor these - Temporary service unavailability (HTTP 503)
- Blockchain congestion or temporary RPC failures
Return permanent failures (JobResult::Failure { error: ToolError::permanent_string(...) }) for:
- Invalid parameters or malformed requests - use
ToolError::invalid_input_stringfor these - Authentication/authorization failures
- Insufficient funds or balance
- Invalid blockchain addresses or transaction data
§Examples
use riglr_core::{Tool, JobResult};
use async_trait::async_trait;
use serde_json::Value;
struct WeatherTool;
#[async_trait]
impl Tool for WeatherTool {
async fn execute(&self, params: Value, _context: &ApplicationContext) -> Result<JobResult, ToolError> {
// Validate parameters
let city = params["city"].as_str()
.ok_or("Missing required parameter: city")?;
if city.is_empty() {
return Ok(JobResult::Failure {
error: ToolError::invalid_input_string("City name cannot be empty")
});
}
// Simulate API call with mock weather service
let weather_data = if city == "InvalidCity" {
return Ok(JobResult::Failure {
error: ToolError::permanent_string(format!("City not found: {}", city))
});
} else if city == "TimeoutCity" {
return Ok(JobResult::Failure {
error: ToolError::retriable_string("Network timeout")
});
} else {
serde_json::json!({
"city": city,
"temperature": 22,
"condition": "sunny"
})
};
Ok(JobResult::success(&weather_data)?)
}
fn name(&self) -> &str {
"weather"
}
}Sourcefn name(&self) -> &str
fn name(&self) -> &str
Get the name of this tool.
The tool name is used for:
- Tool registration and lookup in the worker
- Job identification and logging
- Resource limit mapping (based on name prefixes)
- Metrics and monitoring
§Naming Conventions
Tool names should follow these patterns for automatic resource management:
solana_*- Uses “solana_rpc” resource pool (e.g., “solana_balance”, “solana_transfer”)evm_*- Uses “evm_rpc” resource pool (e.g., “evm_balance”, “evm_swap”)web_*- Uses “http_api” resource pool (e.g., “web_fetch”, “web_scrape”)- Others - Use default resource pool
§Returns
A string identifier for this tool that must be unique within a worker.
§Examples
use riglr_core::Tool;
struct BitcoinPriceChecker;
fn name(&self) -> &str {
"web_bitcoin_price" // Will use "http_api" resource pool
}Sourcefn description(&self) -> &str
fn description(&self) -> &str
A concise, AI-friendly description of this tool’s purpose.
This should be a short, human-readable sentence that explains what the tool does and when to use it. It’s intended for AI models and end-user UIs, and is separate from developer-facing rustdoc.
When using the #[tool] macro from riglr-macros, this value is:
- Taken from the explicit
#[tool(description = "...")]attribute when provided - Otherwise derived from the item’s doc comments
- Falls back to an empty string if neither is present
Provided Methods§
Sourcefn schema(&self) -> Value
fn schema(&self) -> Value
Returns the JSON schema for this tool’s parameters.
This schema is used by AI models to understand what parameters the tool accepts and their types. It should be a valid JSON Schema object describing the parameters structure.
The default implementation returns a generic object schema that accepts any properties, which may not work well with all AI providers. Tools should override this to provide their actual parameter schema.