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(
53 "Both models failed – {primary_model} ({primary_error}) and {fallback_model} ({fallback_error})"
54 )]
55 FallbackFailed {
56 primary_model: String,
58 primary_error: String,
60 fallback_model: String,
62 fallback_error: String,
64 },
65}
66
67impl AgentError {
68 pub fn is_retryable(&self) -> bool {
70 matches!(
71 self,
72 Self::RateLimited { .. } | Self::Stream(_) | Self::RetriesExhausted { .. }
73 )
74 }
75
76 pub fn user_friendly(&self) -> String {
78 match self {
79 Self::Tool { tool_name, message } => {
80 format!("Tool '{}' failed: {}", tool_name, message)
81 }
82 Self::Stream(msg) => format!("Connection error: {}", msg),
83 Self::State(msg) => format!("Internal error: {}", msg),
84 Self::Config(msg) => format!("Configuration error: {}", msg),
85 Self::Model { model_id, message } => {
86 format!("Model '{}' error: {}", model_id, message)
87 }
88 Self::MaxIterations { iterations } => {
89 format!(
90 "Reached the iteration limit ({}). Try simplifying your request.",
91 iterations
92 )
93 }
94 Self::RateLimited { retry_after_secs } => {
95 format!("Rate limited – will retry in {}s", retry_after_secs)
96 }
97 Self::RetriesExhausted {
98 attempts,
99 last_error,
100 } => {
101 format!("Failed after {} attempts: {}", attempts, last_error)
102 }
103 Self::FallbackFailed {
104 primary_model,
105 primary_error,
106 fallback_model,
107 fallback_error: _,
108 } => {
109 format!(
110 "Primary model ({}) failed: {}. Fallback ({}) also failed.",
111 primary_model, primary_error, fallback_model
112 )
113 }
114 }
115 }
116}
117
118impl From<anyhow::Error> for AgentError {
119 fn from(err: anyhow::Error) -> Self {
120 AgentError::Stream(err.to_string())
121 }
122}
123
124pub type Result<T> = std::result::Result<T, AgentError>;