1use hehe_core::error::Error as CoreError;
2use thiserror::Error;
3
4#[derive(Error, Debug)]
5pub enum LlmError {
6 #[error("API error: {provider} - {message}")]
7 Api { provider: String, message: String },
8
9 #[error("Rate limited: {provider}, retry after {retry_after_ms:?}ms")]
10 RateLimited {
11 provider: String,
12 retry_after_ms: Option<u64>,
13 },
14
15 #[error("Context length exceeded: {max_tokens} tokens maximum")]
16 ContextLengthExceeded { max_tokens: u32 },
17
18 #[error("Invalid request: {0}")]
19 InvalidRequest(String),
20
21 #[error("Invalid response: {0}")]
22 InvalidResponse(String),
23
24 #[error("Model not found: {0}")]
25 ModelNotFound(String),
26
27 #[error("Authentication failed: {0}")]
28 AuthenticationFailed(String),
29
30 #[error("Network error: {0}")]
31 Network(String),
32
33 #[error("Timeout after {0}ms")]
34 Timeout(u64),
35
36 #[error("Stream error: {0}")]
37 Stream(String),
38
39 #[error("Provider not available: {0}")]
40 ProviderNotAvailable(String),
41
42 #[error("Tool error: {0}")]
43 Tool(String),
44
45 #[error("Configuration error: {0}")]
46 Config(String),
47
48 #[error(transparent)]
49 Core(#[from] CoreError),
50
51 #[error(transparent)]
52 Reqwest(#[from] reqwest::Error),
53
54 #[error(transparent)]
55 Json(#[from] serde_json::Error),
56}
57
58pub type Result<T> = std::result::Result<T, LlmError>;
59
60impl LlmError {
61 pub fn api(provider: impl Into<String>, message: impl Into<String>) -> Self {
62 Self::Api {
63 provider: provider.into(),
64 message: message.into(),
65 }
66 }
67
68 pub fn rate_limited(provider: impl Into<String>, retry_after_ms: Option<u64>) -> Self {
69 Self::RateLimited {
70 provider: provider.into(),
71 retry_after_ms,
72 }
73 }
74
75 pub fn invalid_request(msg: impl Into<String>) -> Self {
76 Self::InvalidRequest(msg.into())
77 }
78
79 pub fn invalid_response(msg: impl Into<String>) -> Self {
80 Self::InvalidResponse(msg.into())
81 }
82
83 pub fn network(msg: impl Into<String>) -> Self {
84 Self::Network(msg.into())
85 }
86
87 pub fn stream(msg: impl Into<String>) -> Self {
88 Self::Stream(msg.into())
89 }
90
91 pub fn is_retryable(&self) -> bool {
92 matches!(
93 self,
94 LlmError::RateLimited { .. } | LlmError::Timeout(_) | LlmError::Network(_)
95 )
96 }
97}