1use thiserror::Error;
4
5#[derive(Debug, Error, Clone)]
7pub enum AgentError {
8 #[error("Model error: {0}")]
9 ModelError(#[from] ModelError),
10
11 #[error("Tool error: {0}")]
12 ToolError(#[from] ToolError),
13
14 #[error("Network error: {0}")]
15 NetworkError(String),
16
17 #[error("Timeout error")]
18 TimeoutError,
19
20 #[error("Configuration error: {0}")]
21 ConfigError(String),
22
23 #[error("Unknown error: {0}")]
24 UnknownError(String),
25}
26
27#[derive(Debug, Error, Clone)]
29pub enum ModelError {
30 #[error("API error: {0}")]
31 APIError(String),
32
33 #[error("Authentication error: {0}")]
34 AuthenticationError(String),
35
36 #[error("Rate limited")]
37 RateLimited,
38
39 #[error("Invalid response: {0}")]
40 InvalidResponse(String),
41
42 #[error("Model not supported: {0}")]
43 ModelNotSupported(String),
44
45 #[error("Quota exceeded")]
46 QuotaExceeded,
47
48 #[error("Network error: {0}")]
49 NetworkError(String),
50}
51
52#[derive(Debug, Error, Clone)]
54pub enum ToolError {
55 #[error("Tool not found: {0}")]
56 ToolNotFound(String),
57
58 #[error("Execution error: {0}")]
59 ExecutionError(String),
60
61 #[error("Invalid parameters: {0}")]
62 InvalidParameters(String),
63
64 #[error("Permission denied: {0}")]
65 PermissionDenied(String),
66
67 #[error("Timeout error")]
68 TimeoutError,
69}
70
71pub struct ErrorHandler {
73 pub max_retries: u32,
74 pub retry_delay_seconds: u64,
75}
76
77impl ErrorHandler {
78 pub fn new(max_retries: u32, retry_delay_seconds: u64) -> Self {
79 Self {
80 max_retries,
81 retry_delay_seconds,
82 }
83 }
84
85 pub async fn handle_with_retry<F, T, Fut>(&self, operation: F) -> Result<T, AgentError>
86 where
87 F: Fn() -> Fut,
88 Fut: std::future::Future<Output = Result<T, AgentError>>,
89 {
90 let mut last_error = None;
91
92 for attempt in 0..=self.max_retries {
93 match operation().await {
94 Ok(result) => return Ok(result),
95 Err(error) => {
96 last_error = Some(error.clone());
97
98 if attempt < self.max_retries && self.should_retry(&error) {
99 tokio::time::sleep(tokio::time::Duration::from_secs(
100 self.retry_delay_seconds * (attempt as u64 + 1)
101 )).await;
102 continue;
103 } else {
104 break;
105 }
106 }
107 }
108 }
109
110 Err(last_error.unwrap_or(AgentError::UnknownError("Unknown error".to_string())))
111 }
112
113 fn should_retry(&self, error: &AgentError) -> bool {
114 match error {
115 AgentError::NetworkError(_) => true,
116 AgentError::TimeoutError => true,
117 AgentError::ModelError(ModelError::RateLimited) => true,
118 _ => false,
119 }
120 }
121}