serdes_ai_embeddings/
error.rs1use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum EmbeddingError {
8 #[error("HTTP error {status}: {body}")]
10 Http {
11 status: u16,
13 body: String,
15 },
16
17 #[error("API error: {0}")]
19 Api(String),
20
21 #[error("Rate limited: retry after {retry_after:?}")]
23 RateLimited {
24 retry_after: Option<std::time::Duration>,
26 },
27
28 #[error("Input too long: {length} tokens (max: {max})")]
30 InputTooLong {
31 length: usize,
33 max: usize,
35 },
36
37 #[error("Not supported: {0}")]
39 NotSupported(String),
40
41 #[error("Configuration error: {0}")]
43 Config(String),
44
45 #[error("JSON error: {0}")]
47 Json(#[from] serde_json::Error),
48
49 #[error("IO error: {0}")]
51 Io(#[from] std::io::Error),
52
53 #[error("{0}")]
55 Other(#[from] anyhow::Error),
56}
57
58impl EmbeddingError {
59 pub fn api(msg: impl Into<String>) -> Self {
61 Self::Api(msg.into())
62 }
63
64 pub fn config(msg: impl Into<String>) -> Self {
66 Self::Config(msg.into())
67 }
68
69 pub fn is_retryable(&self) -> bool {
71 matches!(
72 self,
73 Self::RateLimited { .. }
74 | Self::Http {
75 status: 429 | 500..=599,
76 ..
77 }
78 )
79 }
80
81 pub fn retry_after(&self) -> Option<std::time::Duration> {
83 match self {
84 Self::RateLimited { retry_after } => *retry_after,
85 _ => None,
86 }
87 }
88}
89
90pub type EmbeddingResult<T> = Result<T, EmbeddingError>;
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_error_display() {
99 let err = EmbeddingError::api("invalid key");
100 assert!(err.to_string().contains("invalid key"));
101 }
102
103 #[test]
104 fn test_retryable() {
105 assert!(EmbeddingError::RateLimited { retry_after: None }.is_retryable());
106 assert!(EmbeddingError::Http {
107 status: 500,
108 body: String::new()
109 }
110 .is_retryable());
111 assert!(!EmbeddingError::Api("bad".into()).is_retryable());
112 }
113}