1#![allow(missing_docs)]
3
4use thiserror::Error;
5
6#[derive(Error, Debug)]
8pub enum Error {
9 #[error("HTTP request failed: {0}")]
11 Http(#[from] reqwest::Error),
12
13 #[error("JSON error: {0}")]
15 Json(#[from] serde_json::Error),
16
17 #[error("API error (status {status}): {message}")]
19 Api {
20 status: u16,
22 message: String,
24 },
25
26 #[error("Rate limit exceeded — retry after {retry_after}s")]
28 RateLimit {
29 retry_after: u64,
31 },
32
33 #[error("Invalid request: {0}")]
35 InvalidRequest(String),
36
37 #[error("Provider configuration error: {0}")]
39 Configuration(String),
40
41 #[error("Stream error: {0}")]
43 Stream(String),
44
45 #[error("Request timed out after {0}s")]
47 Timeout(u64),
48
49 #[error("Max retries ({0}) exceeded")]
51 RetryExhausted(u32),
52
53 #[error("Vector store error: {0}")]
55 VectorStore(String),
56}
57
58pub type Result<T> = std::result::Result<T, Error>;
60
61impl Error {
62 pub fn is_rate_limit(&self) -> bool {
64 matches!(self, Error::RateLimit { .. })
65 }
66
67 pub fn is_retryable(&self) -> bool {
69 match self {
70 Error::Http(e) => {
71 e.is_timeout()
72 || e.is_connect()
73 || e.status()
74 .map(|s| s.is_server_error() || s.as_u16() == 429)
75 .unwrap_or(false)
76 }
77 Error::RateLimit { .. } | Error::Timeout(_) => true,
78 Error::Api { status, .. } => {
79 matches!(status, 429 | 500 | 502 | 503 | 504)
80 }
81 Error::RetryExhausted(_) => false,
82 _ => false,
83 }
84 }
85
86 pub fn retry_after(&self) -> Option<u64> {
88 match self {
89 Error::RateLimit { retry_after } => Some(*retry_after),
90 _ => None,
91 }
92 }
93}