use thiserror::Error;
use uuid::Uuid;
#[derive(Error, Debug)]
pub enum SystemError {
#[error("Database error: {0}")]
Database(String),
#[error("Session {0} not found")]
SessionNotFound(Uuid),
#[error("Workspace {0} not found")]
WorkspaceNotFound(Uuid),
#[error("Checkpoint {0} not found")]
CheckpointNotFound(Uuid),
#[error("Serialization failed: {0}")]
Serialization(String),
#[error("Deserialization failed: {0}")]
Deserialization(String),
#[error("Vector dimension mismatch: expected {expected}, got {actual}")]
VectorDimensionMismatch {
expected: usize,
actual: usize,
},
#[error("HNSW index not built")]
IndexNotBuilt,
#[error("Vector {0} not found")]
VectorNotFound(u32),
#[error("Product Quantization error: {0}")]
ProductQuantization(String),
#[error("Entity extraction failed: {0}")]
EntityExtractionFailed(String),
#[error("Update processing timeout after {0}ms")]
UpdateTimeout(u64),
#[error("Entity graph update failed: {0}")]
GraphUpdateFailed(String),
#[error("Embedding model error: {0}")]
EmbeddingModel(String),
#[error("Vectorization failed: {0}")]
VectorizationFailed(String),
#[error("Storage actor channel closed")]
StorageActorDown,
#[error("Operation timeout after {0}s")]
OperationTimeout(u64),
#[error("Circuit breaker open: {0}")]
CircuitBreakerOpen(String),
#[error("Configuration error: {0}")]
Configuration(String),
#[error("Invalid argument: {0}")]
InvalidArgument(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Task join error: {0}")]
TaskJoin(String),
#[error("Internal error: {0}")]
Internal(String),
}
impl From<bincode::error::EncodeError> for SystemError {
fn from(err: bincode::error::EncodeError) -> Self {
SystemError::Serialization(err.to_string())
}
}
impl From<bincode::error::DecodeError> for SystemError {
fn from(err: bincode::error::DecodeError) -> Self {
SystemError::Deserialization(err.to_string())
}
}
impl From<tokio::task::JoinError> for SystemError {
fn from(err: tokio::task::JoinError) -> Self {
SystemError::TaskJoin(err.to_string())
}
}
impl From<anyhow::Error> for SystemError {
fn from(err: anyhow::Error) -> Self {
SystemError::Internal(err.to_string())
}
}
pub type Result<T> = std::result::Result<T, SystemError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_session_not_found_error() {
let id = Uuid::new_v4();
let err = SystemError::SessionNotFound(id);
assert_eq!(err.to_string(), format!("Session {} not found", id));
}
#[test]
fn test_dimension_mismatch_error() {
let err = SystemError::VectorDimensionMismatch {
expected: 384,
actual: 512,
};
assert_eq!(
err.to_string(),
"Vector dimension mismatch: expected 384, got 512"
);
}
#[test]
fn test_anyhow_conversion() {
let anyhow_err = anyhow::anyhow!("test error");
let system_err: SystemError = anyhow_err.into();
assert!(matches!(system_err, SystemError::Internal(_)));
}
#[test]
fn test_io_error_conversion() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let system_err: SystemError = io_err.into();
assert!(matches!(system_err, SystemError::Io(_)));
}
}