1use crate::transport::TransportError;
2use thiserror::Error;
3
4#[derive(Error, Debug)]
5pub enum AiLibError {
6 #[error("Provider error: {0}")]
7 ProviderError(String),
8
9 #[error("Transport error: {0}")]
10 TransportError(#[from] TransportError),
11
12 #[error("Invalid request: {0}")]
13 InvalidRequest(String),
14
15 #[error("Rate limit exceeded: {0}")]
16 RateLimitExceeded(String),
17
18 #[error("Authentication failed: {0}")]
19 AuthenticationError(String),
20
21 #[error("Configuration error: {0}")]
22 ConfigurationError(String),
23
24 #[error("Network error: {0}")]
25 NetworkError(String),
26
27 #[error("Timeout error: {0}")]
28 TimeoutError(String),
29
30 #[error("Retry exhausted: {0}")]
31 RetryExhausted(String),
32
33 #[error("Serialization error: {0}")]
34 SerializationError(String),
35
36 #[error("Deserialization error: {0}")]
37 DeserializationError(String),
38
39 #[error("File operation error: {0}")]
40 FileError(String),
41
42 #[error("Unsupported feature: {0}")]
43 UnsupportedFeature(String),
44
45 #[error("Model not found: {0}")]
46 ModelNotFound(String),
47
48 #[error("Invalid model response: {0}")]
49 InvalidModelResponse(String),
50
51 #[error("Context length exceeded: {0}")]
52 ContextLengthExceeded(String),
53}
54
55impl AiLibError {
56 pub fn is_retryable(&self) -> bool {
58 match self {
59 AiLibError::NetworkError(_) => true,
60 AiLibError::TimeoutError(_) => true,
61 AiLibError::RateLimitExceeded(_) => true,
62 AiLibError::TransportError(transport_err) => {
63 transport_err.to_string().contains("timeout")
65 || transport_err.to_string().contains("connection")
66 || transport_err.to_string().contains("temporary")
67 }
68 _ => false,
69 }
70 }
71
72 pub fn retry_delay_ms(&self) -> u64 {
74 match self {
75 AiLibError::RateLimitExceeded(_) => 60000, AiLibError::NetworkError(_) => 1000, AiLibError::TimeoutError(_) => 2000, _ => 1000,
79 }
80 }
81
82 pub fn context(&self) -> &str {
84 match self {
85 AiLibError::ProviderError(_) => "Provider API call failed",
86 AiLibError::TransportError(_) => "Network transport layer error",
87 AiLibError::InvalidRequest(_) => "Invalid request parameters",
88 AiLibError::RateLimitExceeded(_) => "API rate limit exceeded",
89 AiLibError::AuthenticationError(_) => "Authentication failed",
90 AiLibError::ConfigurationError(_) => "Configuration validation failed",
91 AiLibError::NetworkError(_) => "Network connectivity issue",
92 AiLibError::TimeoutError(_) => "Request timed out",
93 AiLibError::RetryExhausted(_) => "All retry attempts failed",
94 AiLibError::SerializationError(_) => "Request serialization failed",
95 AiLibError::DeserializationError(_) => "Response deserialization failed",
96 AiLibError::FileError(_) => "File operation failed",
97 AiLibError::UnsupportedFeature(_) => "Feature not supported by provider",
98 AiLibError::ModelNotFound(_) => "Specified model not found",
99 AiLibError::InvalidModelResponse(_) => "Invalid response from model",
100 AiLibError::ContextLengthExceeded(_) => "Context length limit exceeded",
101 }
102 }
103
104 pub fn is_auth_error(&self) -> bool {
106 match self {
107 AiLibError::AuthenticationError(_) => true,
108 AiLibError::TransportError(TransportError::AuthenticationError(_)) => true,
109 AiLibError::TransportError(TransportError::ClientError { status, .. }) => {
110 *status == 401 || *status == 403
111 }
112 _ => false,
113 }
114 }
115
116 pub fn is_config_error(&self) -> bool {
118 matches!(self, AiLibError::ConfigurationError(_))
119 }
120
121 pub fn is_request_error(&self) -> bool {
123 matches!(
124 self,
125 AiLibError::InvalidRequest(_)
126 | AiLibError::ContextLengthExceeded(_)
127 | AiLibError::UnsupportedFeature(_)
128 )
129 }
130}