#![allow(missing_docs)]
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("HTTP request failed: {0}")]
Http(#[from] reqwest::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("API error (status {status}): {message}")]
Api {
status: u16,
message: String,
},
#[error("Rate limit exceeded — retry after {retry_after}s")]
RateLimit {
retry_after: u64,
},
#[error("Invalid request: {0}")]
InvalidRequest(String),
#[error("Provider configuration error: {0}")]
Configuration(String),
#[error("Stream error: {0}")]
Stream(String),
#[error("Request timed out after {0}s")]
Timeout(u64),
#[error("Max retries ({0}) exceeded")]
RetryExhausted(u32),
#[error("Vector store error: {0}")]
VectorStore(String),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub fn is_rate_limit(&self) -> bool {
matches!(self, Error::RateLimit { .. })
}
pub fn is_retryable(&self) -> bool {
match self {
Error::Http(e) => {
e.is_timeout()
|| e.is_connect()
|| e.status()
.map(|s| s.is_server_error() || s.as_u16() == 429)
.unwrap_or(false)
}
Error::RateLimit { .. } | Error::Timeout(_) => true,
Error::Api { status, .. } => {
matches!(status, 429 | 500 | 502 | 503 | 504)
}
Error::RetryExhausted(_) => false,
_ => false,
}
}
pub fn retry_after(&self) -> Option<u64> {
match self {
Error::RateLimit { retry_after } => Some(*retry_after),
_ => None,
}
}
}