1use thiserror::Error;
7
8pub type Result<T> = std::result::Result<T, Error>;
10
11#[derive(Error, Debug)]
15pub enum Error {
16 #[error("HTTP request failed: {0}")]
18 Http(#[from] reqwest::Error),
19
20 #[error("JSON error: {0}")]
22 Json(#[from] serde_json::Error),
23
24 #[error("Invalid configuration: {0}")]
26 Config(String),
27
28 #[error("API error{}: {message}", .status.map(|code| format!(" {code}")).unwrap_or_default())]
33 Api {
34 status: Option<u16>,
37
38 message: String,
40 },
41
42 #[error("Streaming error: {0}")]
44 Stream(String),
45
46 #[error("Tool execution error: {0}")]
48 Tool(String),
49
50 #[error("Invalid input: {0}")]
52 InvalidInput(String),
53
54 #[error("Request timeout")]
56 Timeout,
57
58 #[error("Error: {0}")]
60 Other(String),
61}
62
63impl Error {
64 pub fn config(msg: impl Into<String>) -> Self {
66 Error::Config(msg.into())
67 }
68
69 pub fn api(msg: impl Into<String>) -> Self {
74 Error::Api {
75 status: None,
76 message: msg.into(),
77 }
78 }
79
80 pub fn api_status(status: u16, msg: impl Into<String>) -> Self {
101 Error::Api {
102 status: Some(status),
103 message: msg.into(),
104 }
105 }
106
107 pub fn status_code(&self) -> Option<u16> {
111 match self {
112 Error::Api { status, .. } => *status,
113 _ => None,
114 }
115 }
116
117 pub fn stream(msg: impl Into<String>) -> Self {
119 Error::Stream(msg.into())
120 }
121
122 pub fn tool(msg: impl Into<String>) -> Self {
124 Error::Tool(msg.into())
125 }
126
127 pub fn invalid_input(msg: impl Into<String>) -> Self {
129 Error::InvalidInput(msg.into())
130 }
131
132 pub fn other(msg: impl Into<String>) -> Self {
134 Error::Other(msg.into())
135 }
136
137 pub fn timeout() -> Self {
139 Error::Timeout
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_error_config() {
149 let err = Error::config("Invalid model");
150 assert!(matches!(err, Error::Config(_)));
151 assert_eq!(err.to_string(), "Invalid configuration: Invalid model");
152 }
153
154 #[test]
155 fn test_error_api() {
156 let err = Error::api("Internal Server Error");
157 assert!(matches!(err, Error::Api { status: None, .. }));
158 assert_eq!(err.to_string(), "API error: Internal Server Error");
159
160 let err = Error::api_status(500, "Internal Server Error");
162 assert!(matches!(
163 err,
164 Error::Api {
165 status: Some(500),
166 ..
167 }
168 ));
169 assert_eq!(err.to_string(), "API error 500: Internal Server Error");
170 assert_eq!(err.status_code(), Some(500));
171 }
172
173 #[test]
174 fn test_error_stream() {
175 let err = Error::stream("Connection lost");
176 assert!(matches!(err, Error::Stream(_)));
177 assert_eq!(err.to_string(), "Streaming error: Connection lost");
178 }
179
180 #[test]
181 fn test_error_tool() {
182 let err = Error::tool("Tool not found");
183 assert!(matches!(err, Error::Tool(_)));
184 assert_eq!(err.to_string(), "Tool execution error: Tool not found");
185 }
186
187 #[test]
188 fn test_error_invalid_input() {
189 let err = Error::invalid_input("Missing parameter");
190 assert!(matches!(err, Error::InvalidInput(_)));
191 assert_eq!(err.to_string(), "Invalid input: Missing parameter");
192 }
193
194 #[test]
195 fn test_error_timeout() {
196 let err = Error::timeout();
197 assert!(matches!(err, Error::Timeout));
198 assert_eq!(err.to_string(), "Request timeout");
199 }
200
201 #[test]
202 fn test_error_other() {
203 let err = Error::other("Something went wrong");
204 assert!(matches!(err, Error::Other(_)));
205 assert_eq!(err.to_string(), "Error: Something went wrong");
206 }
207
208 #[test]
209 fn test_error_from_serde_json() {
210 let json_err = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
212 let err: Error = json_err.into();
213 assert!(matches!(err, Error::Json(_)));
214 }
215}