mojentic/
error.rs

1//! Error types and result aliases for the Mojentic library.
2//!
3//! This module defines the core error type [`MojenticError`] and the [`Result`] type alias
4//! used throughout the library. All public APIs that can fail return `Result<T>` for
5//! consistent error handling.
6
7use thiserror::Error;
8
9#[derive(Error, Debug)]
10pub enum MojenticError {
11    #[error("LLM gateway error: {0}")]
12    GatewayError(String),
13
14    #[error("API error: {0}")]
15    ApiError(String),
16
17    #[error("Serialization error: {0}")]
18    SerializationError(#[from] serde_json::Error),
19
20    #[error("HTTP error: {0}")]
21    HttpError(#[from] reqwest::Error),
22
23    #[error("Tool error: {0}")]
24    ToolError(String),
25
26    #[error("Model not supported: {0}")]
27    ModelNotSupported(String),
28
29    #[error("Invalid configuration: {0}")]
30    ConfigError(String),
31
32    #[error("IO error: {0}")]
33    IoError(#[from] std::io::Error),
34
35    #[error("Event processing error: {0}")]
36    EventError(String),
37
38    #[error("Agent error: {0}")]
39    AgentError(String),
40
41    #[error("Dispatcher error: {0}")]
42    DispatcherError(String),
43
44    #[error("Timeout error: {0}")]
45    TimeoutError(String),
46
47    #[error("Invalid argument: {0}")]
48    InvalidArgument(String),
49
50    #[error("Parse error: {0}")]
51    ParseError(String),
52
53    #[error("Tool execution error: {0}")]
54    ToolExecutionError(String),
55
56    #[error("Runtime error: {0}")]
57    RuntimeError(String),
58}
59
60pub type Result<T> = std::result::Result<T, MojenticError>;
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_gateway_error_display() {
68        let err = MojenticError::GatewayError("connection failed".to_string());
69        assert_eq!(err.to_string(), "LLM gateway error: connection failed");
70    }
71
72    #[test]
73    fn test_api_error_display() {
74        let err = MojenticError::ApiError("rate limit exceeded".to_string());
75        assert_eq!(err.to_string(), "API error: rate limit exceeded");
76    }
77
78    #[test]
79    fn test_tool_error_display() {
80        let err = MojenticError::ToolError("invalid parameters".to_string());
81        assert_eq!(err.to_string(), "Tool error: invalid parameters");
82    }
83
84    #[test]
85    fn test_model_not_supported_display() {
86        let err = MojenticError::ModelNotSupported("gpt-5".to_string());
87        assert_eq!(err.to_string(), "Model not supported: gpt-5");
88    }
89
90    #[test]
91    fn test_config_error_display() {
92        let err = MojenticError::ConfigError("missing API key".to_string());
93        assert_eq!(err.to_string(), "Invalid configuration: missing API key");
94    }
95
96    #[test]
97    fn test_serialization_error_conversion() {
98        let json_err = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
99        let err: MojenticError = json_err.into();
100
101        match err {
102            MojenticError::SerializationError(_) => {}
103            _ => panic!("Expected SerializationError"),
104        }
105    }
106
107    #[test]
108    fn test_http_error_conversion() {
109        // Create a reqwest error by building an invalid request
110        let invalid_url = reqwest::Url::parse("http://").unwrap_err();
111        // Test that we can convert a URL parse error into our error type
112        let err = MojenticError::ApiError(invalid_url.to_string());
113        assert!(err.to_string().contains("API error"));
114    }
115
116    #[test]
117    fn test_io_error_conversion() {
118        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
119        let err: MojenticError = io_err.into();
120
121        match err {
122            MojenticError::IoError(_) => {}
123            _ => panic!("Expected IoError"),
124        }
125    }
126
127    #[test]
128    fn test_error_debug() {
129        let err = MojenticError::ToolError("test".to_string());
130        let debug_str = format!("{:?}", err);
131        assert!(debug_str.contains("ToolError"));
132    }
133
134    #[test]
135    fn test_result_type() {
136        let ok_result: Result<i32> = Ok(42);
137        assert!(ok_result.is_ok());
138        if let Ok(value) = ok_result {
139            assert_eq!(value, 42);
140        }
141
142        let err_result: Result<i32> = Err(MojenticError::ToolError("test".to_string()));
143        assert!(err_result.is_err());
144    }
145}