1use eventsource_stream::EventStreamError;
2use thiserror::Error;
3
4#[derive(Error, Debug, Clone, PartialEq, Eq)]
5pub enum SseParseError {
6 #[error("UTF-8 error: {details}")]
7 Utf8 { details: String },
8 #[error("Parse error: {details}")]
9 Parser { details: String },
10 #[error("Transport error: {details}")]
11 Transport { details: String },
12}
13
14impl<E> From<EventStreamError<E>> for SseParseError
15where
16 E: std::error::Error,
17{
18 fn from(err: EventStreamError<E>) -> Self {
19 match err {
20 EventStreamError::Utf8(err) => Self::Utf8 {
21 details: err.to_string(),
22 },
23 EventStreamError::Parser(err) => Self::Parser {
24 details: err.to_string(),
25 },
26 EventStreamError::Transport(err) => Self::Transport {
27 details: err.to_string(),
28 },
29 }
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub enum ProviderStreamErrorKind {
35 StreamError,
36 StreamRetry,
37 RateLimitExceeded,
38 ResponseFailed,
39 Overloaded,
40 ServiceUnavailable,
41 Timeout,
42 Unknown(String),
43}
44
45impl ProviderStreamErrorKind {
46 pub fn from_provider_error_type(error_type: &str) -> Self {
47 match error_type {
48 "stream_error" | "error" => Self::StreamError,
49 "stream_retry" => Self::StreamRetry,
50 "rate_limit_exceeded" | "rate_limit_error" => Self::RateLimitExceeded,
51 "response_failed" => Self::ResponseFailed,
52 "overloaded_error" => Self::Overloaded,
53 "service_unavailable_error" => Self::ServiceUnavailable,
54 "timeout_error" => Self::Timeout,
55 other => Self::Unknown(other.to_string()),
56 }
57 }
58
59 pub fn is_retryable(&self) -> bool {
60 matches!(
61 self,
62 Self::StreamError
63 | Self::StreamRetry
64 | Self::RateLimitExceeded
65 | Self::ResponseFailed
66 | Self::Overloaded
67 | Self::ServiceUnavailable
68 | Self::Timeout
69 )
70 }
71}
72
73impl std::fmt::Display for ProviderStreamErrorKind {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 match self {
76 Self::StreamError => f.write_str("stream_error"),
77 Self::StreamRetry => f.write_str("stream_retry"),
78 Self::RateLimitExceeded => f.write_str("rate_limit_exceeded"),
79 Self::ResponseFailed => f.write_str("response_failed"),
80 Self::Overloaded => f.write_str("overloaded_error"),
81 Self::ServiceUnavailable => f.write_str("service_unavailable_error"),
82 Self::Timeout => f.write_str("timeout_error"),
83 Self::Unknown(raw) => f.write_str(raw),
84 }
85 }
86}
87
88#[derive(Error, Debug, Clone, PartialEq, Eq)]
89pub enum StreamError {
90 #[error("Request cancelled")]
91 Cancelled,
92
93 #[error("SSE parse error: {0}")]
94 SseParse(SseParseError),
95
96 #[error("{provider} error ({kind}): {message}")]
97 Provider {
98 provider: String,
99 kind: ProviderStreamErrorKind,
100 raw_error_type: Option<String>,
101 message: String,
102 },
103}
104
105#[derive(Error, Debug)]
106pub enum ApiError {
107 #[error("Network error: {0}")]
108 Network(#[from] reqwest::Error),
109
110 #[error("Authentication failed: {details}")]
111 AuthenticationFailed { provider: String, details: String },
112
113 #[error("Auth error: {0}")]
114 AuthError(String),
115
116 #[error("Rate limited by {provider}: {details}")]
117 RateLimited { provider: String, details: String },
118
119 #[error("Invalid request to {provider}: {details}")]
120 InvalidRequest { provider: String, details: String },
121
122 #[error("{provider} server error (Status: {status_code}): {details}")]
123 ServerError {
124 provider: String,
125 status_code: u16,
126 details: String,
127 },
128
129 #[error("Request timed out for {provider}")]
130 Timeout { provider: String },
131
132 #[error("Request cancelled for {provider}")]
133 Cancelled { provider: String },
134
135 #[error("Failed to parse response from {provider}: {details}")]
136 ResponseParsingError { provider: String, details: String },
137
138 #[error("API returned no choices/candidates for {provider}")]
139 NoChoices { provider: String },
140
141 #[error("Request blocked by {provider}: {details}")]
142 RequestBlocked { provider: String, details: String },
143
144 #[error("Unknown API error from {provider}: {details}")]
145 Unknown { provider: String, details: String },
146
147 #[error("Configuration error: {0}")]
148 Configuration(String),
149
150 #[error("{provider} does not support {feature}: {details}")]
151 UnsupportedFeature {
152 provider: String,
153 feature: String,
154 details: String,
155 },
156
157 #[error("Stream error from {provider}: {details}")]
158 StreamError { provider: String, details: String },
159}
160
161impl From<crate::error::Error> for ApiError {
162 fn from(err: crate::error::Error) -> Self {
163 match err {
164 crate::error::Error::Api(api_err) => api_err,
165 crate::error::Error::Configuration(msg) => ApiError::Configuration(msg),
166 other => ApiError::Unknown {
167 provider: "internal".to_string(),
168 details: format!("Unexpected internal error: {other}"),
169 },
170 }
171 }
172}