use riglr_core::{JobResult, ToolError};
use serde_json;
use std::io;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== riglr-core Error Handling Example ===\n");
println!("📋 1. Error Classification Examples\n");
let network_error = io::Error::new(io::ErrorKind::TimedOut, "Connection timed out");
let retriable_error = ToolError::retriable_with_source(
network_error,
"Failed to connect to RPC endpoint, should retry",
);
println!("🔄 Retriable Error:");
println!(" Type: {}", retriable_error);
println!(" Is Retriable: {}", retriable_error.is_retriable());
println!(" Is Rate Limited: {}", retriable_error.is_rate_limited());
println!(
" Serialized: {}",
serde_json::to_string(&retriable_error)?
);
let auth_error = io::Error::new(io::ErrorKind::PermissionDenied, "Invalid API key");
let permanent_error = ToolError::permanent_with_source(
auth_error,
"Authentication failed - check API key configuration",
);
println!("\n🚫 Permanent Error:");
println!(" Type: {}", permanent_error);
println!(" Is Retriable: {}", permanent_error.is_retriable());
println!(" Is Rate Limited: {}", permanent_error.is_rate_limited());
println!(
" Serialized: {}",
serde_json::to_string(&permanent_error)?
);
let rate_error = io::Error::new(io::ErrorKind::Other, "Too many requests");
let rate_limited_error = ToolError::rate_limited_with_source(
rate_error,
"API rate limit exceeded - backoff required",
Some(Duration::from_secs(30)),
);
println!("\n⏱️ Rate Limited Error:");
println!(" Type: {}", rate_limited_error);
println!(" Is Retriable: {}", rate_limited_error.is_retriable());
println!(
" Is Rate Limited: {}",
rate_limited_error.is_rate_limited()
);
println!(" Retry After: {:?}", rate_limited_error.retry_after());
println!(
" Serialized: {}",
serde_json::to_string(&rate_limited_error)?
);
let validation_error = io::Error::new(io::ErrorKind::InvalidInput, "Amount must be positive");
let input_error =
ToolError::invalid_input_with_source(validation_error, "Parameter validation failed");
println!("\n❌ Invalid Input Error:");
println!(" Type: {}", input_error);
println!(" Is Retriable: {}", input_error.is_retriable());
println!(" Is Rate Limited: {}", input_error.is_rate_limited());
println!(" Serialized: {}", serde_json::to_string(&input_error)?);
println!("\n📋 2. String-Based Error Creation\n");
let simple_retriable = ToolError::retriable_string("Network timeout occurred");
let simple_permanent = ToolError::permanent_string("Invalid wallet address format");
let simple_rate_limited = ToolError::rate_limited_string("Rate limit exceeded");
let simple_invalid_input = ToolError::invalid_input_string("Missing required field: amount");
println!("🔄 String Retriable: {}", simple_retriable);
println!("🚫 String Permanent: {}", simple_permanent);
println!("⏱️ String Rate Limited: {}", simple_rate_limited);
println!("❌ String Invalid Input: {}", simple_invalid_input);
println!("\n📋 3. JobResult with Structured Error Data\n");
let _error_data = serde_json::json!({
"endpoint": "https://api.example.com/v1/transfer",
"retry_after_seconds": 60,
"error_code": "RATE_LIMIT_EXCEEDED",
"quota_reset_time": "2024-01-01T12:00:00Z"
});
let job_failure = JobResult::Failure {
error: riglr_core::ToolError::rate_limited_string("API rate limit exceeded"),
};
println!("📊 JobResult with error data:");
println!(" {}", serde_json::to_string_pretty(&job_failure)?);
println!("\n📋 4. Error Conversion Examples\n");
let anyhow_error = anyhow::anyhow!("Something went wrong");
let converted_anyhow =
ToolError::permanent_string(format!("An unknown error occurred: {}", anyhow_error));
println!(
"🔀 From anyhow: {} (retriable: {})",
converted_anyhow,
converted_anyhow.is_retriable()
);
let string_error = "Database connection failed".to_string();
let converted_string = ToolError::retriable_string(string_error); println!(
"🔀 From String: {} (retriable: {})",
converted_string,
converted_string.is_retriable()
);
let str_error = "Configuration file not found";
let converted_str = ToolError::permanent_string(str_error); println!(
"🔀 From &str: {} (retriable: {})",
converted_str,
converted_str.is_retriable()
);
let io_error = io::Error::new(io::ErrorKind::NotFound, "File not found");
let converted_boxed =
ToolError::permanent_with_source(io_error, "A required file was not found");
println!(
"🔀 From Box<Error>: {} (retriable: {})",
converted_boxed,
converted_boxed.is_retriable()
);
println!("\n📋 5. Tool Error Handling Best Practices\n");
let tool_result = simulate_tool_operation("valid_input");
match tool_result {
Ok(result) => println!("✅ Tool succeeded: {:?}", result),
Err(e) => {
println!("❌ Tool failed: {}", e);
if e.is_retriable() {
if e.is_rate_limited() {
if let Some(delay) = e.retry_after() {
println!(" 🔄 Should retry after: {:?}", delay);
} else {
println!(" 🔄 Should retry with exponential backoff");
}
} else {
println!(" 🔄 Should retry immediately with backoff");
}
} else {
println!(" 🚫 Should not retry - permanent failure");
}
}
}
let tool_result_bad = simulate_tool_operation("invalid_input");
match tool_result_bad {
Ok(result) => println!("✅ Tool succeeded: {:?}", result),
Err(e) => {
println!("❌ Tool failed: {}", e);
if e.is_retriable() {
println!(" 🔄 Should retry");
} else {
println!(" 🚫 Should not retry - permanent failure");
}
}
}
println!("\n🎉 Error handling example completed!");
println!("\n🔧 Key takeaways:");
println!(" • Use appropriate error types based on failure category");
println!(" • Preserve error sources with context for debugging");
println!(" • Structured errors enable intelligent retry logic");
println!(" • Error serialization supports distributed processing");
println!(" • Rate limiting errors can include retry timing information");
Ok(())
}
fn simulate_tool_operation(input: &str) -> Result<String, ToolError> {
match input {
"valid_input" => {
Ok("Operation completed successfully".to_string())
}
"network_error" => {
let io_error = io::Error::new(io::ErrorKind::TimedOut, "Connection timed out");
Err(ToolError::retriable_with_source(
io_error,
"Network connection failed",
))
}
"rate_limited" => {
let rate_error = io::Error::new(io::ErrorKind::Other, "Rate limit exceeded");
Err(ToolError::rate_limited_with_source(
rate_error,
"API rate limit hit",
Some(Duration::from_secs(60)),
))
}
"invalid_input" => {
Err(ToolError::invalid_input_string("Input validation failed"))
}
"auth_error" => {
let auth_error = io::Error::new(io::ErrorKind::PermissionDenied, "Access denied");
Err(ToolError::permanent_with_source(
auth_error,
"Authentication failed",
))
}
_ => {
Ok(format!("Processed input: {}", input))
}
}
}