#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Execution error: {0}")]
ExecutionError(String),
#[error("State error: {0}")]
StateError(String),
#[error("Checkpoint error: {0}")]
CheckpointError(String),
#[error("Channel error: {0}")]
ChannelError(String),
#[error("Graph recursion limit exceeded: {current} > {limit}")]
RecursionLimitError { current: usize, limit: usize },
#[error("Node not found: {0}")]
NodeNotFound(String),
#[error("Invalid graph configuration: {0}")]
InvalidGraph(String),
#[error("Serialization error: {0}")]
SerializationError(#[from] serde_json::Error),
#[error("Interrupt: {0}")]
Interrupt(String),
#[error("Invalid update: {0}")]
InvalidUpdate(String),
#[cfg(any(feature = "sqlite", feature = "postgres"))]
#[error("Database error: {0}")]
DatabaseError(#[from] sqlx::Error),
#[cfg(any(feature = "openai", feature = "anthropic", feature = "ollama"))]
#[error("HTTP error: {0}")]
HttpError(#[from] reqwest::Error),
#[error("{0}")]
Other(String),
}
impl Error {
pub fn execution(msg: impl Into<String>) -> Self {
Error::ExecutionError(msg.into())
}
pub fn state(msg: impl Into<String>) -> Self {
Error::StateError(msg.into())
}
pub fn checkpoint(msg: impl Into<String>) -> Self {
Error::CheckpointError(msg.into())
}
pub fn channel(msg: impl Into<String>) -> Self {
Error::ChannelError(msg.into())
}
pub fn invalid_graph(msg: impl Into<String>) -> Self {
Error::InvalidGraph(msg.into())
}
pub fn node_not_found(name: impl Into<String>) -> Self {
Error::NodeNotFound(name.into())
}
pub fn interrupt(msg: impl Into<String>) -> Self {
Error::Interrupt(msg.into())
}
pub fn invalid_update(msg: impl Into<String>) -> Self {
Error::InvalidUpdate(msg.into())
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_creation() {
let err = Error::execution("test");
assert!(matches!(err, Error::ExecutionError(_)));
assert_eq!(err.to_string(), "Execution error: test");
}
#[test]
fn test_recursion_limit_error() {
let err = Error::RecursionLimitError {
current: 100,
limit: 50,
};
assert!(err.to_string().contains("100"));
assert!(err.to_string().contains("50"));
}
#[test]
fn test_error_from_json() {
let json_err = serde_json::from_str::<i32>("not a number").unwrap_err();
let err: Error = json_err.into();
assert!(matches!(err, Error::SerializationError(_)));
}
}