Skip to main content

pulsehive_core/
error.rs

1//! Error types for PulseHive SDK.
2//!
3//! [`PulseHiveError`] is the top-level error returned by all PulseHive public APIs.
4//! It wraps [`pulsedb::PulseDBError`] for seamless substrate error propagation.
5
6use thiserror::Error;
7
8/// Top-level error type for all PulseHive operations.
9#[derive(Debug, Error)]
10pub enum PulseHiveError {
11    /// Error from the PulseDB storage substrate.
12    ///
13    /// Automatically converted from [`pulsedb::PulseDBError`] via the `?` operator.
14    #[error("Substrate error: {0}")]
15    Substrate(#[from] pulsedb::PulseDBError),
16
17    /// Error from an LLM provider (API failure, rate limit, parse error).
18    #[error("LLM error: {0}")]
19    Llm(String),
20
21    /// Error during tool execution.
22    #[error("Tool error: {0}")]
23    Tool(String),
24
25    /// Error in agent lifecycle (deploy, loop, completion).
26    #[error("Agent error: {0}")]
27    Agent(String),
28
29    /// Invalid configuration (missing substrate, no providers, etc.).
30    #[error("Configuration error: {0}")]
31    Config(String),
32
33    /// Input validation failure.
34    #[error("Validation error: {0}")]
35    Validation(String),
36
37    /// Error from an embedding provider.
38    #[error("Embedding error: {0}")]
39    Embedding(String),
40}
41
42impl PulseHiveError {
43    /// Creates an LLM error.
44    pub fn llm(msg: impl Into<String>) -> Self {
45        Self::Llm(msg.into())
46    }
47
48    /// Creates a tool error.
49    pub fn tool(msg: impl Into<String>) -> Self {
50        Self::Tool(msg.into())
51    }
52
53    /// Creates an agent error.
54    pub fn agent(msg: impl Into<String>) -> Self {
55        Self::Agent(msg.into())
56    }
57
58    /// Creates a configuration error.
59    pub fn config(msg: impl Into<String>) -> Self {
60        Self::Config(msg.into())
61    }
62
63    /// Creates a validation error.
64    pub fn validation(msg: impl Into<String>) -> Self {
65        Self::Validation(msg.into())
66    }
67
68    /// Creates an embedding error.
69    pub fn embedding(msg: impl Into<String>) -> Self {
70        Self::Embedding(msg.into())
71    }
72}
73
74/// Result type alias for PulseHive operations.
75pub type Result<T> = std::result::Result<T, PulseHiveError>;
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_pulsedb_error_converts_via_from() {
83        let db_err = pulsedb::PulseDBError::config("test failure");
84        let hive_err: PulseHiveError = db_err.into();
85        assert!(matches!(hive_err, PulseHiveError::Substrate(_)));
86        assert!(hive_err.to_string().contains("test failure"));
87    }
88
89    #[test]
90    fn test_question_mark_propagation() {
91        fn inner() -> Result<()> {
92            // Simulate a PulseDB error propagating with ?
93            Err(pulsedb::PulseDBError::config("missing collective"))?
94        }
95
96        let result = inner();
97        assert!(result.is_err());
98        assert!(matches!(result.unwrap_err(), PulseHiveError::Substrate(_)));
99    }
100
101    #[test]
102    fn test_convenience_constructors() {
103        assert_eq!(
104            PulseHiveError::llm("timeout").to_string(),
105            "LLM error: timeout"
106        );
107        assert_eq!(
108            PulseHiveError::tool("not found").to_string(),
109            "Tool error: not found"
110        );
111        assert_eq!(
112            PulseHiveError::agent("max iterations").to_string(),
113            "Agent error: max iterations"
114        );
115        assert_eq!(
116            PulseHiveError::config("no substrate").to_string(),
117            "Configuration error: no substrate"
118        );
119        assert_eq!(
120            PulseHiveError::validation("empty content").to_string(),
121            "Validation error: empty content"
122        );
123        assert_eq!(
124            PulseHiveError::embedding("dimension mismatch").to_string(),
125            "Embedding error: dimension mismatch"
126        );
127    }
128
129    #[test]
130    fn test_implements_std_error() {
131        let err = PulseHiveError::llm("test");
132        let _: &dyn std::error::Error = &err;
133    }
134}