Skip to main content

synwire_core/error/
mod.rs

1//! Error types for the Synwire framework.
2//!
3//! This module provides a structured error hierarchy with [`SynwireError`] as
4//! the top-level type, domain-specific error enums for each subsystem, and
5//! [`SynwireErrorKind`] for discriminant-based retry and fallback matching.
6
7mod embedding;
8mod kind;
9mod model;
10mod parse;
11mod tool;
12mod vectorstore;
13
14pub use embedding::EmbeddingError;
15pub use kind::SynwireErrorKind;
16pub use model::ModelError;
17pub use parse::ParseError;
18pub use tool::ToolError;
19pub use vectorstore::VectorStoreError;
20
21/// Top-level error type for the Synwire framework.
22///
23/// Wraps domain-specific error types via `#[from]` conversions.
24#[derive(Debug, thiserror::Error)]
25#[non_exhaustive]
26pub enum SynwireError {
27    /// Model invocation error.
28    #[error(transparent)]
29    Model(#[from] ModelError),
30    /// Prompt formatting error.
31    #[error("prompt error: {message}")]
32    Prompt {
33        /// Error message.
34        message: String,
35    },
36    /// Output parsing error.
37    #[error(transparent)]
38    Parse(#[from] ParseError),
39    /// Embedding error.
40    #[error(transparent)]
41    Embedding(#[from] EmbeddingError),
42    /// Vector store error.
43    #[error(transparent)]
44    VectorStore(#[from] VectorStoreError),
45    /// Tool invocation error.
46    #[error(transparent)]
47    Tool(#[from] ToolError),
48    /// Serialization error.
49    #[error("serialization error: {0}")]
50    Serialization(#[from] serde_json::Error),
51    /// Graph execution error.
52    #[error("graph error: {0}")]
53    Graph(Box<dyn std::error::Error + Send + Sync>),
54    /// Credential error.
55    #[error("credential error: {message}")]
56    Credential {
57        /// Error message.
58        message: String,
59    },
60    /// I/O error.
61    #[error(transparent)]
62    Io(#[from] std::io::Error),
63    /// Other error.
64    #[error(transparent)]
65    Other(Box<dyn std::error::Error + Send + Sync>),
66}
67
68impl SynwireError {
69    /// Returns the error kind discriminant for this error.
70    pub const fn kind(&self) -> SynwireErrorKind {
71        match self {
72            Self::Model(_) => SynwireErrorKind::Model,
73            Self::Prompt { .. } => SynwireErrorKind::Prompt,
74            Self::Parse(_) => SynwireErrorKind::Parse,
75            Self::Embedding(_) => SynwireErrorKind::Embedding,
76            Self::VectorStore(_) => SynwireErrorKind::VectorStore,
77            Self::Tool(_) => SynwireErrorKind::Tool,
78            Self::Serialization(_) => SynwireErrorKind::Serialization,
79            Self::Graph(_) => SynwireErrorKind::Graph,
80            Self::Credential { .. } => SynwireErrorKind::Credential,
81            Self::Io(_) | Self::Other(_) => SynwireErrorKind::Other,
82        }
83    }
84}
85
86#[cfg(test)]
87#[allow(clippy::unwrap_used)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_error_display_model() {
93        let err = SynwireError::from(ModelError::Timeout);
94        assert!(err.to_string().contains("timed out"));
95    }
96
97    #[test]
98    fn test_error_display_prompt() {
99        let err = SynwireError::Prompt {
100            message: "missing variable 'name'".into(),
101        };
102        assert!(err.to_string().contains("missing variable"));
103    }
104
105    #[test]
106    fn test_error_from_model_error() {
107        let model_err = ModelError::RateLimit { retry_after: None };
108        let err: SynwireError = model_err.into();
109        assert_eq!(err.kind(), SynwireErrorKind::Model);
110    }
111
112    #[test]
113    fn test_error_from_tool_error() {
114        let tool_err = ToolError::NotFound {
115            name: "search".into(),
116        };
117        let err: SynwireError = tool_err.into();
118        assert_eq!(err.kind(), SynwireErrorKind::Tool);
119    }
120
121    #[test]
122    fn test_error_kind_matching() {
123        let err = SynwireError::from(ParseError::ParseFailed {
124            message: "bad json".into(),
125        });
126        assert_eq!(err.kind(), SynwireErrorKind::Parse);
127    }
128}