Skip to main content

steer_core/api/
error.rs

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(Error, Debug, Clone, PartialEq, Eq)]
34pub enum StreamError {
35    #[error("Request cancelled")]
36    Cancelled,
37
38    #[error("SSE parse error: {0}")]
39    SseParse(SseParseError),
40
41    #[error("{provider} error ({error_type}): {message}")]
42    Provider {
43        provider: String,
44        error_type: String,
45        message: String,
46    },
47}
48
49#[derive(Error, Debug)]
50pub enum ApiError {
51    #[error("Network error: {0}")]
52    Network(#[from] reqwest::Error),
53
54    #[error("Authentication failed: {details}")]
55    AuthenticationFailed { provider: String, details: String },
56
57    #[error("Auth error: {0}")]
58    AuthError(String),
59
60    #[error("Rate limited by {provider}: {details}")]
61    RateLimited { provider: String, details: String },
62
63    #[error("Invalid request to {provider}: {details}")]
64    InvalidRequest { provider: String, details: String },
65
66    #[error("{provider} server error (Status: {status_code}): {details}")]
67    ServerError {
68        provider: String,
69        status_code: u16,
70        details: String,
71    },
72
73    #[error("Request timed out for {provider}")]
74    Timeout { provider: String },
75
76    #[error("Request cancelled for {provider}")]
77    Cancelled { provider: String },
78
79    #[error("Failed to parse response from {provider}: {details}")]
80    ResponseParsingError { provider: String, details: String },
81
82    #[error("API returned no choices/candidates for {provider}")]
83    NoChoices { provider: String },
84
85    #[error("Request blocked by {provider}: {details}")]
86    RequestBlocked { provider: String, details: String },
87
88    #[error("Unknown API error from {provider}: {details}")]
89    Unknown { provider: String, details: String },
90
91    #[error("Configuration error: {0}")]
92    Configuration(String),
93
94    #[error("Stream error from {provider}: {details}")]
95    StreamError { provider: String, details: String },
96}
97
98impl From<crate::error::Error> for ApiError {
99    fn from(err: crate::error::Error) -> Self {
100        match err {
101            crate::error::Error::Api(api_err) => api_err,
102            crate::error::Error::Configuration(msg) => ApiError::Configuration(msg),
103            other => ApiError::Unknown {
104                provider: "internal".to_string(),
105                details: format!("Unexpected internal error: {other}"),
106            },
107        }
108    }
109}