1use std::fmt;
2use std::time::Duration;
3use zenwave::{BodyError, Error as ZenwaveError, sse::ParseError as SseParseError};
4
5#[derive(Debug)]
7pub enum OpenAIError {
8 Http(ZenwaveError),
10 Body(BodyError),
12 Stream(SseParseError),
14 Json(serde_json::Error),
16 Decode(base64::DecodeError),
18 Api(String),
20 RateLimit {
22 message: String,
24 retry_after: Option<Duration>,
26 },
27 ServerError {
29 status: u16,
31 message: String,
33 },
34 Timeout,
36}
37
38impl fmt::Display for OpenAIError {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 Self::Http(err) => write!(f, "HTTP error: {err}"),
42 Self::Body(err) => write!(f, "Body error: {err}"),
43 Self::Stream(err) => write!(f, "SSE error: {err}"),
44 Self::Json(err) => write!(f, "JSON error: {err}"),
45 Self::Decode(err) => write!(f, "Base64 decode error: {err}"),
46 Self::Api(message) => write!(f, "{message}"),
47 Self::RateLimit {
48 message,
49 retry_after,
50 } => {
51 write!(f, "Rate limit exceeded: {message}")?;
52 if let Some(delay) = retry_after {
53 write!(f, " (retry after {}s)", delay.as_secs())?;
54 }
55 Ok(())
56 }
57 Self::ServerError { status, message } => {
58 write!(f, "Server error {status}: {message}")
59 }
60 Self::Timeout => write!(f, "Request timed out"),
61 }
62 }
63}
64
65impl std::error::Error for OpenAIError {}
66
67impl OpenAIError {
68 pub(crate) fn from_http(err: zenwave::Error) -> Self {
70 if let zenwave::Error::Http { status, .. } = &err {
72 if status.as_u16() == 429 {
73 return Self::RateLimit {
74 message: "Rate limit exceeded".to_string(),
75 retry_after: None,
76 };
77 }
78 if status.as_u16() >= 500 {
79 return Self::ServerError {
80 status: status.as_u16(),
81 message: err.to_string(),
82 };
83 }
84 }
85 if err.is_timeout() {
86 return Self::Timeout;
87 }
88 Self::Http(err)
89 }
90}
91
92impl From<BodyError> for OpenAIError {
93 fn from(value: BodyError) -> Self {
94 Self::Body(value)
95 }
96}
97
98impl From<SseParseError> for OpenAIError {
99 fn from(value: SseParseError) -> Self {
100 Self::Stream(value)
101 }
102}
103
104impl From<serde_json::Error> for OpenAIError {
105 fn from(value: serde_json::Error) -> Self {
106 Self::Json(value)
107 }
108}
109
110impl From<base64::DecodeError> for OpenAIError {
111 fn from(value: base64::DecodeError) -> Self {
112 Self::Decode(value)
113 }
114}
115
116impl From<std::io::Error> for OpenAIError {
117 fn from(value: std::io::Error) -> Self {
118 Self::Api(format!("IO error: {value}"))
119 }
120}