1use thiserror::Error;
4
5pub type ToolResult<T> = Result<T, ToolError>;
7
8#[derive(Error, Debug)]
10pub enum ToolError {
11 #[error("Tool execution failed: {0}")]
12 ExecutionFailed(String),
13
14 #[error("Invalid arguments: {0}")]
15 InvalidArguments(String),
16
17 #[error("Tool execution timed out after {0:?}")]
18 Timeout(std::time::Duration),
19
20 #[error("Tool execution was cancelled")]
21 Cancelled,
22
23 #[error("Network error: {0}")]
24 Network(String),
25
26 #[error("IO error: {0}")]
27 Io(#[from] std::io::Error),
28
29 #[error("Serialization error: {0}")]
30 Serialization(#[from] serde_json::Error),
31
32 #[error("Validation error in field '{field}': {reason}")]
33 ValidationError { field: String, reason: String },
34
35 #[error("Resource limit exceeded: {0}")]
36 ResourceLimitExceeded(String),
37
38 #[error("Permission denied: {0}")]
39 PermissionDenied(String),
40
41 #[error("Tool not found: {0}")]
42 ToolNotFound(String),
43
44 #[error("Custom error: {0}")]
45 Custom(Box<dyn std::error::Error + Send + Sync>),
46}
47
48impl ToolError {
49 pub fn execution_failed(msg: impl Into<String>) -> Self {
50 ToolError::ExecutionFailed(msg.into())
51 }
52
53 pub fn invalid_arguments(msg: impl Into<String>) -> Self {
54 ToolError::InvalidArguments(msg.into())
55 }
56
57 pub fn network(msg: impl Into<String>) -> Self {
58 ToolError::Network(msg.into())
59 }
60
61 pub fn validation(field: impl Into<String>, reason: impl Into<String>) -> Self {
62 ToolError::ValidationError {
63 field: field.into(),
64 reason: reason.into(),
65 }
66 }
67
68 pub fn resource_limit(msg: impl Into<String>) -> Self {
69 ToolError::ResourceLimitExceeded(msg.into())
70 }
71
72 pub fn permission_denied(msg: impl Into<String>) -> Self {
73 ToolError::PermissionDenied(msg.into())
74 }
75
76 pub fn tool_not_found(name: impl Into<String>) -> Self {
77 ToolError::ToolNotFound(name.into())
78 }
79
80 pub fn custom(err: impl std::error::Error + Send + Sync + 'static) -> Self {
81 ToolError::Custom(Box::new(err))
82 }
83
84 pub fn kind(&self) -> ErrorKind {
85 match self {
86 ToolError::ExecutionFailed(_) => ErrorKind::Execution,
87 ToolError::InvalidArguments(_) | ToolError::ValidationError { .. } => {
88 ErrorKind::Validation
89 }
90 ToolError::Timeout(_) => ErrorKind::Timeout,
91 ToolError::Network(_) => ErrorKind::Network,
92 ToolError::PermissionDenied(_) => ErrorKind::Permission,
93 ToolError::ResourceLimitExceeded(_) => ErrorKind::Resource,
94 _ => ErrorKind::Other,
95 }
96 }
97
98 pub fn is_retryable(&self) -> bool {
99 matches!(
100 self.kind(),
101 ErrorKind::Network | ErrorKind::Timeout | ErrorKind::Resource
102 )
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum ErrorKind {
108 Execution,
109 Validation,
110 Network,
111 Timeout,
112 Permission,
113 Resource,
114 Other,
115}