use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;
#[derive(Debug, Error, Serialize, Deserialize, JsonSchema)]
pub struct ToolError {
pub code: ErrorCode,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub details: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub enum ErrorCode {
BadRequest,
InvalidArgument,
NotFound,
PermissionDenied,
Internal,
Timeout,
Conflict,
NetworkError,
ExternalServiceError,
ExecutionFailed,
SerializationError,
IoError,
}
impl std::fmt::Display for ToolError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{:?}] {}", self.code, self.message)
}
}
impl ToolError {
pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
details: None,
}
}
pub fn with_details(mut self, details: HashMap<String, serde_json::Value>) -> Self {
self.details = Some(details);
self
}
pub fn with_detail(mut self, key: &str, value: impl Into<serde_json::Value>) -> Self {
let mut details = self.details.unwrap_or_default();
details.insert(key.to_string(), value.into());
self.details = Some(details);
self
}
pub fn internal(message: impl Into<String>) -> Self {
Self::new(ErrorCode::Internal, message)
}
pub fn not_found(message: impl Into<String>) -> Self {
Self::new(ErrorCode::NotFound, message)
}
pub fn invalid_input(message: impl Into<String>) -> Self {
Self::new(ErrorCode::InvalidArgument, message)
}
pub fn conflict(message: impl Into<String>) -> Self {
Self::new(ErrorCode::Conflict, message)
}
}
impl From<std::io::Error> for ToolError {
fn from(err: std::io::Error) -> Self {
Self::new(ErrorCode::ExecutionFailed, err.to_string())
}
}
impl From<serde_json::Error> for ToolError {
fn from(err: serde_json::Error) -> Self {
Self::new(ErrorCode::InvalidArgument, err.to_string())
}
}
impl From<String> for ToolError {
fn from(err: String) -> Self {
Self::new(ErrorCode::ExecutionFailed, err)
}
}
impl From<&str> for ToolError {
fn from(err: &str) -> Self {
Self::new(ErrorCode::ExecutionFailed, err)
}
}