1#[derive(Debug, thiserror::Error)]
5pub enum AgentError {
6 #[error("Tool '{tool_name}' failed: {message}")]
8 Tool {
9 tool_name: String,
11 message: String,
13 },
14 #[error("Stream error: {0}")]
16 Stream(String),
17 #[error("State error: {0}")]
19 State(String),
20 #[error("Config error: {0}")]
22 Config(String),
23 #[error("Model '{model_id}' error: {message}")]
25 Model {
26 model_id: String,
28 message: String,
30 },
31 #[error("Maximum iterations reached ({iterations})")]
33 MaxIterations {
34 iterations: usize,
36 },
37 #[error("Rate limited – retry after {retry_after_secs}s")]
39 RateLimited {
40 retry_after_secs: u64,
42 },
43 #[error("Failed after {attempts} retries: {last_error}")]
45 RetriesExhausted {
46 attempts: usize,
48 last_error: String,
50 },
51 #[error("Both models failed – {primary_model} ({primary_error}) and {fallback_model} ({fallback_error})")]
53 FallbackFailed {
54 primary_model: String,
56 primary_error: String,
58 fallback_model: String,
60 fallback_error: String,
62 },
63}
64
65impl AgentError {
66 pub fn is_retryable(&self) -> bool {
68 matches!(
69 self,
70 Self::RateLimited { .. } | Self::Stream(_) | Self::RetriesExhausted { .. }
71 )
72 }
73
74 pub fn user_friendly(&self) -> String {
76 match self {
77 Self::Tool { tool_name, message } => {
78 format!("Tool '{}' failed: {}", tool_name, message)
79 }
80 Self::Stream(msg) => format!("Connection error: {}", msg),
81 Self::State(msg) => format!("Internal error: {}", msg),
82 Self::Config(msg) => format!("Configuration error: {}", msg),
83 Self::Model { model_id, message } => {
84 format!("Model '{}' error: {}", model_id, message)
85 }
86 Self::MaxIterations { iterations } => {
87 format!(
88 "Reached the iteration limit ({}). Try simplifying your request.",
89 iterations
90 )
91 }
92 Self::RateLimited { retry_after_secs } => {
93 format!("Rate limited – will retry in {}s", retry_after_secs)
94 }
95 Self::RetriesExhausted {
96 attempts,
97 last_error,
98 } => {
99 format!("Failed after {} attempts: {}", attempts, last_error)
100 }
101 Self::FallbackFailed {
102 primary_model,
103 primary_error,
104 fallback_model,
105 fallback_error: _,
106 } => {
107 format!(
108 "Primary model ({}) failed: {}. Fallback ({}) also failed.",
109 primary_model, primary_error, fallback_model
110 )
111 }
112 }
113 }
114}
115
116impl From<anyhow::Error> for AgentError {
117 fn from(err: anyhow::Error) -> Self {
118 AgentError::Stream(err.to_string())
119 }
120}
121
122pub type Result<T> = std::result::Result<T, AgentError>;