llm_observatory_sdk/
error.rs1pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Debug, thiserror::Error)]
11pub enum Error {
12 #[error("Configuration error: {0}")]
14 Config(String),
15
16 #[error("OpenTelemetry error: {0}")]
18 OpenTelemetry(String),
19
20 #[error("HTTP error: {0}")]
22 Http(#[from] reqwest::Error),
23
24 #[error("API error: {status} - {message}")]
26 Api {
27 status: u16,
29 message: String,
31 },
32
33 #[error("Rate limit exceeded: {0}")]
35 RateLimit(String),
36
37 #[error("Authentication error: {0}")]
39 Auth(String),
40
41 #[error("Invalid API key")]
43 InvalidApiKey,
44
45 #[error("Serialization error: {0}")]
47 Serialization(#[from] serde_json::Error),
48
49 #[error("Invalid input: {0}")]
51 InvalidInput(String),
52
53 #[error("Streaming error: {0}")]
55 Stream(String),
56
57 #[error("Cost calculation error: {0}")]
59 CostCalculation(String),
60
61 #[error("Model not found: {0}")]
63 ModelNotFound(String),
64
65 #[error("Request timeout")]
67 Timeout,
68
69 #[error("Internal error: {0}")]
71 Internal(String),
72
73 #[error("Core error: {0}")]
75 Core(#[from] llm_observatory_core::Error),
76}
77
78impl Error {
79 pub fn config(msg: impl Into<String>) -> Self {
81 Self::Config(msg.into())
82 }
83
84 pub fn api(status: u16, message: impl Into<String>) -> Self {
86 Self::Api {
87 status,
88 message: message.into(),
89 }
90 }
91
92 pub fn rate_limit(msg: impl Into<String>) -> Self {
94 Self::RateLimit(msg.into())
95 }
96
97 pub fn auth(msg: impl Into<String>) -> Self {
99 Self::Auth(msg.into())
100 }
101
102 pub fn invalid_input(msg: impl Into<String>) -> Self {
104 Self::InvalidInput(msg.into())
105 }
106
107 pub fn stream(msg: impl Into<String>) -> Self {
109 Self::Stream(msg.into())
110 }
111
112 pub fn cost_calculation(msg: impl Into<String>) -> Self {
114 Self::CostCalculation(msg.into())
115 }
116
117 pub fn internal(msg: impl Into<String>) -> Self {
119 Self::Internal(msg.into())
120 }
121
122 pub fn is_retryable(&self) -> bool {
124 matches!(
125 self,
126 Error::RateLimit(_) | Error::Timeout | Error::Api { status: 429, .. }
127 )
128 }
129
130 pub fn is_auth_error(&self) -> bool {
132 matches!(
133 self,
134 Error::Auth(_) | Error::InvalidApiKey | Error::Api { status: 401, .. }
135 )
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn test_error_creation() {
145 let err = Error::config("test config error");
146 assert!(matches!(err, Error::Config(_)));
147 }
148
149 #[test]
150 fn test_is_retryable() {
151 let rate_limit = Error::rate_limit("too many requests");
152 assert!(rate_limit.is_retryable());
153
154 let timeout = Error::Timeout;
155 assert!(timeout.is_retryable());
156
157 let config = Error::config("bad config");
158 assert!(!config.is_retryable());
159 }
160
161 #[test]
162 fn test_is_auth_error() {
163 let invalid_key = Error::InvalidApiKey;
164 assert!(invalid_key.is_auth_error());
165
166 let auth_err = Error::auth("invalid token");
167 assert!(auth_err.is_auth_error());
168
169 let api_401 = Error::api(401, "unauthorized");
170 assert!(api_401.is_auth_error());
171
172 let api_500 = Error::api(500, "server error");
173 assert!(!api_500.is_auth_error());
174 }
175}