use std::time::Duration;
use thiserror::Error;
#[derive(Debug, Clone, Error)]
pub enum SandboxError {
#[error("execution timed out after {timeout:?}")]
Timeout {
timeout: Duration,
},
#[error("memory limit exceeded: {limit_mb} MB")]
MemoryExceeded {
limit_mb: u32,
},
#[error("execution failed: {0}")]
ExecutionFailed(String),
#[error("invalid request: {0}")]
InvalidRequest(String),
#[error("backend unavailable: {0}")]
BackendUnavailable(String),
#[error("enforcer '{enforcer}' failed: {message}")]
EnforcerFailed {
enforcer: String,
message: String,
},
#[error("enforcer '{enforcer}' unavailable: {message}")]
EnforcerUnavailable {
enforcer: String,
message: String,
},
#[error("policy violation: {0}")]
PolicyViolation(String),
#[cfg(feature = "workspace")]
#[error("provisioning failed for '{resource}': {reason}. {suggestion}")]
ProvisionFailed {
resource: String,
reason: String,
suggestion: String,
},
#[cfg(feature = "workspace")]
#[error("session '{handle}' not found. It may have been stopped or expired.")]
SessionNotFound {
handle: String,
},
#[cfg(feature = "workspace")]
#[error("snapshot '{id}' not found. It may have been deleted or expired.")]
SnapshotNotFound {
id: String,
},
#[cfg(feature = "workspace")]
#[error("path traversal rejected: '{path}' escapes workspace root. Use relative paths only.")]
PathTraversal {
path: String,
},
#[cfg(feature = "workspace")]
#[error("Docker unavailable: {reason}. Ensure Docker daemon is running and accessible.")]
DockerUnavailable {
reason: String,
},
#[cfg(feature = "workspace")]
#[error(
"session timed out after {timeout:?}. Consider increasing session_timeout in SandboxConfig."
)]
SessionTimeout {
timeout: Duration,
},
}
impl From<std::io::Error> for SandboxError {
fn from(err: std::io::Error) -> Self {
SandboxError::ExecutionFailed(format!("I/O error: {err}"))
}
}
impl From<SandboxError> for adk_core::AdkError {
fn from(err: SandboxError) -> Self {
use adk_core::{ErrorCategory, ErrorComponent};
let (category, code) = match &err {
SandboxError::Timeout { .. } => (ErrorCategory::Timeout, "code.sandbox_timeout"),
SandboxError::MemoryExceeded { .. } => (ErrorCategory::Internal, "code.sandbox_memory"),
SandboxError::ExecutionFailed(_) => (ErrorCategory::Internal, "code.sandbox_execution"),
SandboxError::InvalidRequest(_) => {
(ErrorCategory::InvalidInput, "code.sandbox_invalid_request")
}
SandboxError::BackendUnavailable(_) => {
(ErrorCategory::Unavailable, "code.sandbox_unavailable")
}
SandboxError::EnforcerFailed { .. } => {
(ErrorCategory::Internal, "code.sandbox_enforcer_failed")
}
SandboxError::EnforcerUnavailable { .. } => {
(ErrorCategory::Unavailable, "code.sandbox_enforcer_unavailable")
}
SandboxError::PolicyViolation(_) => {
(ErrorCategory::InvalidInput, "code.sandbox_policy_violation")
}
#[cfg(feature = "workspace")]
SandboxError::ProvisionFailed { .. } => {
(ErrorCategory::Internal, "code.sandbox_provision_failed")
}
#[cfg(feature = "workspace")]
SandboxError::SessionNotFound { .. } => {
(ErrorCategory::NotFound, "code.sandbox_session_not_found")
}
#[cfg(feature = "workspace")]
SandboxError::SnapshotNotFound { .. } => {
(ErrorCategory::NotFound, "code.sandbox_snapshot_not_found")
}
#[cfg(feature = "workspace")]
SandboxError::PathTraversal { .. } => {
(ErrorCategory::InvalidInput, "code.sandbox_path_traversal")
}
#[cfg(feature = "workspace")]
SandboxError::DockerUnavailable { .. } => {
(ErrorCategory::Unavailable, "code.sandbox_docker_unavailable")
}
#[cfg(feature = "workspace")]
SandboxError::SessionTimeout { .. } => {
(ErrorCategory::Timeout, "code.sandbox_session_timeout")
}
};
adk_core::AdkError::new(ErrorComponent::Code, category, code, err.to_string())
.with_source(err)
}
}