1use std::{error::Error as StdError, fmt, time::Duration};
2
3use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum WesichainError {
7 #[error("LLM provider failed: {0}")]
8 LlmProvider(String),
9 #[error("Tool call failed for '{tool_name}': {reason}")]
10 ToolCallFailed { tool_name: String, reason: String },
11 #[error("Parsing failed on output '{output}': {reason}")]
12 ParseFailed { output: String, reason: String },
13 #[error("Operation timed out after {0:?}")]
14 Timeout(Duration),
15 #[error("Max retries ({max}) exceeded")]
16 MaxRetriesExceeded { max: usize },
17 #[error("Checkpoint failed: {0}")]
18 CheckpointFailed(String),
19 #[error("Operation was cancelled")]
20 Cancelled,
21 #[error("Invalid configuration: {0}")]
22 InvalidConfig(String),
23 #[error("Serialization/deserialization error: {0}")]
24 Serde(#[from] serde_json::Error),
25 #[error("{0}")]
26 Custom(String),
27 #[error("authentication failed for '{provider}': {message}")]
28 AuthenticationFailed { provider: String, message: String },
29 #[error("rate limit exceeded (retry after {retry_after:?})")]
30 RateLimitExceeded { retry_after: Option<Duration> },
31 #[error("context window exceeded: limit {limit} tokens, got {actual}")]
32 ContextWindowExceeded { limit: usize, actual: usize },
33 #[error("content policy violation: {reason}")]
34 ContentPolicyViolation { reason: String },
35}
36
37impl From<EmbeddingError> for WesichainError {
38 fn from(err: EmbeddingError) -> Self {
39 WesichainError::Custom(err.to_string())
40 }
41}
42
43impl From<StoreError> for WesichainError {
44 fn from(err: StoreError) -> Self {
45 WesichainError::Custom(err.to_string())
46 }
47}
48
49#[derive(Debug)]
50pub enum EmbeddingError {
51 InvalidResponse(String),
52 RateLimited { retry_after: Option<Duration> },
53 Timeout(Duration),
54 Provider(String),
55 Other(Box<dyn StdError + Send + Sync>),
56}
57
58impl fmt::Display for EmbeddingError {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 EmbeddingError::InvalidResponse(message) => {
62 write!(f, "Embedding invalid response: {message}")
63 }
64 EmbeddingError::RateLimited { retry_after } => match retry_after {
65 Some(duration) => write!(f, "Embedding rate limited (retry_after={duration:?})"),
66 None => write!(f, "Embedding rate limited (retry_after=unknown)"),
67 },
68 EmbeddingError::Timeout(duration) => write!(f, "Embedding timeout after {duration:?}"),
69 EmbeddingError::Provider(message) => write!(f, "Embedding provider error: {message}"),
70 EmbeddingError::Other(error) => write!(f, "Embedding error: {error}"),
71 }
72 }
73}
74
75impl StdError for EmbeddingError {
76 fn source(&self) -> Option<&(dyn StdError + 'static)> {
77 match self {
78 EmbeddingError::Other(error) => Some(error.as_ref()),
79 _ => None,
80 }
81 }
82}
83
84#[derive(Debug, Error)]
85pub enum StoreError {
86 #[error("dimension mismatch: expected {expected}, got {got}")]
87 DimensionMismatch { expected: usize, got: usize },
88 #[error("invalid document id: {0}")]
89 InvalidId(String),
90 #[error("Store error: {0}")]
91 Internal(#[source] Box<dyn StdError + Send + Sync>),
92}