use std::borrow::Cow;
use thiserror::Error;
pub type ToolResult<T> = Result<T, ToolError>;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ToolError {
#[error("Tool '{name}' not found")]
ToolNotFound {
name: Cow<'static, str>,
},
#[error("Invalid parameters for tool '{tool}': {message}")]
InvalidParameters {
tool: Cow<'static, str>,
message: Cow<'static, str>,
},
#[error("Tool '{tool}' execution failed: {message}")]
ExecutionFailed {
tool: Cow<'static, str>,
message: Cow<'static, str>,
},
#[error("Schema validation failed for tool '{tool}': {message}")]
SchemaValidation {
tool: Cow<'static, str>,
message: Cow<'static, str>,
},
#[error("Tool registration failed: {message}")]
RegistrationError {
message: Cow<'static, str>,
},
#[error("Serialization error for tool '{tool}': {source}")]
SerializationError {
tool: Cow<'static, str>,
#[source]
source: serde_json::Error,
},
#[error("Timeout error for tool '{tool}': execution exceeded {timeout:?}")]
TimeoutError {
tool: Cow<'static, str>,
timeout: std::time::Duration,
},
#[error("Tool '{tool}' execution panicked")]
ExecutionPanicked {
tool: Cow<'static, str>,
},
}
impl ToolError {
pub fn is_retryable(&self) -> bool {
matches!(
self,
ToolError::TimeoutError { .. } | ToolError::ExecutionFailed { .. }
)
}
}
pub struct ErrorContext {
tool_name: Option<String>,
}
impl ErrorContext {
pub fn new() -> Self {
Self { tool_name: None }
}
pub fn with_tool(mut self, tool_name: impl Into<String>) -> Self {
self.tool_name = Some(tool_name.into());
self
}
fn get_tool_name(&self) -> String {
self.tool_name
.clone()
.unwrap_or_else(|| "unknown".to_string())
}
pub fn tool_not_found(self) -> ToolError {
ToolError::ToolNotFound {
name: Cow::Owned(self.get_tool_name()),
}
}
pub fn invalid_parameters(self, message: impl Into<String>) -> ToolError {
ToolError::InvalidParameters {
tool: Cow::Owned(self.get_tool_name()),
message: Cow::Owned(message.into()),
}
}
pub fn execution_failed(self, message: impl Into<String>) -> ToolError {
ToolError::ExecutionFailed {
tool: Cow::Owned(self.get_tool_name()),
message: Cow::Owned(message.into()),
}
}
pub fn schema_validation(self, message: impl Into<String>) -> ToolError {
ToolError::SchemaValidation {
tool: Cow::Owned(self.get_tool_name()),
message: Cow::Owned(message.into()),
}
}
pub fn serialization_error(self, source: serde_json::Error) -> ToolError {
ToolError::SerializationError {
tool: Cow::Owned(self.get_tool_name()),
source,
}
}
pub fn timeout_error(self, timeout: std::time::Duration) -> ToolError {
ToolError::TimeoutError {
tool: Cow::Owned(self.get_tool_name()),
timeout,
}
}
}
impl Default for ErrorContext {
fn default() -> Self {
Self::new()
}
}
pub fn error_context() -> ErrorContext {
ErrorContext::new()
}