104 lines
3.4 KiB
Rust
104 lines
3.4 KiB
Rust
|
|
use reqwest::StatusCode;
|
|||
|
|
use serde_json;
|
|||
|
|
use std::io;
|
|||
|
|
use thiserror::Error;
|
|||
|
|
use tokio::task::JoinError;
|
|||
|
|
|
|||
|
|
pub type Result<T> = std::result::Result<T, CodexErr>;
|
|||
|
|
|
|||
|
|
#[derive(Error, Debug)]
|
|||
|
|
pub enum SandboxErr {
|
|||
|
|
/// Error from sandbox execution
|
|||
|
|
#[error("sandbox denied exec error, exit code: {0}, stdout: {1}, stderr: {2}")]
|
|||
|
|
Denied(i32, String, String),
|
|||
|
|
|
|||
|
|
/// Error from linux seccomp filter setup
|
|||
|
|
#[cfg(target_os = "linux")]
|
|||
|
|
#[error("seccomp setup error")]
|
|||
|
|
SeccompInstall(#[from] seccompiler::Error),
|
|||
|
|
|
|||
|
|
/// Error from linux seccomp backend
|
|||
|
|
#[cfg(target_os = "linux")]
|
|||
|
|
#[error("seccomp backend error")]
|
|||
|
|
SeccompBackend(#[from] seccompiler::BackendError),
|
|||
|
|
|
|||
|
|
/// Error from linux landlock
|
|||
|
|
#[error("Landlock was not able to fully enforce all sandbox rules")]
|
|||
|
|
LandlockRestrict,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#[derive(Error, Debug)]
|
|||
|
|
pub enum CodexErr {
|
|||
|
|
/// Returned by ResponsesClient when the SSE stream disconnects or errors out **after** the HTTP
|
|||
|
|
/// handshake has succeeded but **before** it finished emitting `response.completed`.
|
|||
|
|
///
|
|||
|
|
/// The Session loop treats this as a transient error and will automatically retry the turn.
|
|||
|
|
#[error("stream disconnected before completion: {0}")]
|
|||
|
|
Stream(String),
|
|||
|
|
|
|||
|
|
/// Returned by run_command_stream when the spawned child process timed out (10s).
|
|||
|
|
#[error("timeout waiting for child process to exit")]
|
|||
|
|
Timeout,
|
|||
|
|
|
|||
|
|
/// Returned by run_command_stream when the child could not be spawned (its stdout/stderr pipes
|
|||
|
|
/// could not be captured). Analogous to the previous `CodexError::Spawn` variant.
|
|||
|
|
#[error("spawn failed: child stdout/stderr not captured")]
|
|||
|
|
Spawn,
|
|||
|
|
|
|||
|
|
/// Returned by run_command_stream when the user pressed Ctrl‑C (SIGINT). Session uses this to
|
|||
|
|
/// surface a polite FunctionCallOutput back to the model instead of crashing the CLI.
|
|||
|
|
#[error("interrupted (Ctrl‑C)")]
|
|||
|
|
Interrupted,
|
|||
|
|
|
|||
|
|
/// Unexpected HTTP status code.
|
|||
|
|
#[error("unexpected status {0}: {1}")]
|
|||
|
|
UnexpectedStatus(StatusCode, String),
|
|||
|
|
|
|||
|
|
/// Retry limit exceeded.
|
|||
|
|
#[error("exceeded retry limit, last status: {0}")]
|
|||
|
|
RetryLimit(StatusCode),
|
|||
|
|
|
|||
|
|
/// Agent loop died unexpectedly
|
|||
|
|
#[error("internal error; agent loop died unexpectedly")]
|
|||
|
|
InternalAgentDied,
|
|||
|
|
|
|||
|
|
/// Sandbox error
|
|||
|
|
#[error("sandbox error: {0}")]
|
|||
|
|
Sandbox(#[from] SandboxErr),
|
|||
|
|
|
|||
|
|
// -----------------------------------------------------------------
|
|||
|
|
// Automatic conversions for common external error types
|
|||
|
|
// -----------------------------------------------------------------
|
|||
|
|
#[error(transparent)]
|
|||
|
|
Io(#[from] io::Error),
|
|||
|
|
|
|||
|
|
#[error(transparent)]
|
|||
|
|
Reqwest(#[from] reqwest::Error),
|
|||
|
|
|
|||
|
|
#[error(transparent)]
|
|||
|
|
Json(#[from] serde_json::Error),
|
|||
|
|
|
|||
|
|
#[cfg(target_os = "linux")]
|
|||
|
|
#[error(transparent)]
|
|||
|
|
LandlockRuleset(#[from] landlock::RulesetError),
|
|||
|
|
|
|||
|
|
#[cfg(target_os = "linux")]
|
|||
|
|
#[error(transparent)]
|
|||
|
|
LandlockPathFd(#[from] landlock::PathFdError),
|
|||
|
|
|
|||
|
|
#[error(transparent)]
|
|||
|
|
TokioJoin(#[from] JoinError),
|
|||
|
|
|
|||
|
|
#[error("missing environment variable {0}")]
|
|||
|
|
EnvVar(&'static str),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl CodexErr {
|
|||
|
|
/// Minimal shim so that existing `e.downcast_ref::<CodexErr>()` checks continue to compile
|
|||
|
|
/// after replacing `anyhow::Error` in the return signature. This mirrors the behavior of
|
|||
|
|
/// `anyhow::Error::downcast_ref` but works directly on our concrete enum.
|
|||
|
|
pub fn downcast_ref<T: std::any::Any>(&self) -> Option<&T> {
|
|||
|
|
(self as &dyn std::any::Any).downcast_ref::<T>()
|
|||
|
|
}
|
|||
|
|
}
|