use crate::interrupt::Interrupt;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, GraphError>;
#[derive(Error, Debug)]
pub enum GraphError {
#[error("Invalid graph structure: {0}")]
InvalidGraph(String),
#[error("Node not found: {0}")]
NodeNotFound(String),
#[error("Edge target not found: {0}")]
EdgeTargetNotFound(String),
#[error("No entry point defined (missing edge from START)")]
NoEntryPoint,
#[error("Recursion limit exceeded: {0} steps")]
RecursionLimitExceeded(usize),
#[error("Execution interrupted: {0:?}")]
Interrupted(Box<InterruptedExecution>),
#[error("Node '{node}' execution failed: {message}")]
NodeExecutionFailed { node: String, message: String },
#[error("State serialization error: {0}")]
SerializationError(String),
#[error("Checkpoint error: {0}")]
CheckpointError(String),
#[error("Router returned unknown target: {0}")]
UnknownRouteTarget(String),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("JSON error: {0}")]
JsonError(#[from] serde_json::Error),
#[cfg(feature = "sqlite")]
#[error("Database error: {0}")]
DatabaseError(#[from] sqlx::Error),
}
#[derive(Debug, Clone)]
pub struct InterruptedExecution {
pub thread_id: String,
pub checkpoint_id: String,
pub interrupt: Interrupt,
pub state: crate::state::State,
pub step: usize,
}
impl InterruptedExecution {
pub fn new(
thread_id: String,
checkpoint_id: String,
interrupt: Interrupt,
state: crate::state::State,
step: usize,
) -> Self {
Self { thread_id, checkpoint_id, interrupt, state, step }
}
}
impl From<GraphError> for adk_core::AdkError {
fn from(err: GraphError) -> Self {
use adk_core::{ErrorCategory, ErrorComponent};
let (category, code) = match &err {
GraphError::InvalidGraph(_) => (ErrorCategory::InvalidInput, "graph.invalid"),
GraphError::NodeNotFound(_) => (ErrorCategory::NotFound, "graph.node_not_found"),
GraphError::EdgeTargetNotFound(_) => {
(ErrorCategory::NotFound, "graph.edge_target_not_found")
}
GraphError::NoEntryPoint => (ErrorCategory::InvalidInput, "graph.no_entry_point"),
GraphError::RecursionLimitExceeded(_) => {
(ErrorCategory::Internal, "graph.recursion_limit")
}
GraphError::Interrupted(_) => (ErrorCategory::Cancelled, "graph.interrupted"),
GraphError::NodeExecutionFailed { .. } => {
(ErrorCategory::Internal, "graph.node_execution_failed")
}
GraphError::SerializationError(_) => (ErrorCategory::Internal, "graph.serialization"),
GraphError::CheckpointError(_) => (ErrorCategory::Internal, "graph.checkpoint"),
GraphError::UnknownRouteTarget(_) => {
(ErrorCategory::NotFound, "graph.unknown_route_target")
}
GraphError::IoError(_) => (ErrorCategory::Internal, "graph.io"),
GraphError::JsonError(_) => (ErrorCategory::Internal, "graph.json"),
#[cfg(feature = "sqlite")]
GraphError::DatabaseError(_) => (ErrorCategory::Internal, "graph.database"),
};
adk_core::AdkError::new(ErrorComponent::Graph, category, code, err.to_string())
.with_source(err)
}
}