use crate::app_server_transport::AppServerTransportError;
#[derive(Debug, thiserror::Error)]
pub enum AppServerError {
#[error("{0}")]
InterruptedByUser(String),
#[error("Failed to lock {provider} app-server session map")]
LockPoisoned {
provider: &'static str,
},
#[error("{0}")]
PromptRender(String),
#[error("{0}")]
Provider(String),
#[error(
"{provider} app-server failed, then retry failed after restart: first error: \
{first_error}; retry error: {retry_error}"
)]
RetryExhausted {
provider: &'static str,
first_error: String,
retry_error: String,
},
#[error(transparent)]
Transport(#[from] AppServerTransportError),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lock_poisoned_display_includes_provider_name() {
let error = AppServerError::LockPoisoned { provider: "Codex" };
let display = error.to_string();
assert_eq!(display, "Failed to lock Codex app-server session map");
}
#[test]
fn interrupted_by_user_display_shows_message() {
let error = AppServerError::InterruptedByUser("[Stopped]".to_string());
assert_eq!(error.to_string(), "[Stopped]");
}
#[test]
fn prompt_render_display_shows_message() {
let error = AppServerError::PromptRender("template syntax error".to_string());
assert_eq!(error.to_string(), "template syntax error");
}
#[test]
fn provider_display_shows_message() {
let error = AppServerError::Provider("runtime crashed".to_string());
assert_eq!(error.to_string(), "runtime crashed");
}
#[test]
fn retry_exhausted_display_includes_both_errors() {
let error = AppServerError::RetryExhausted {
provider: "Codex",
first_error: "connection reset".to_string(),
retry_error: "timeout".to_string(),
};
let display = error.to_string();
assert_eq!(
display,
"Codex app-server failed, then retry failed after restart: first error: connection \
reset; retry error: timeout"
);
}
#[test]
fn transport_display_delegates_to_inner_error() {
let error = AppServerError::Transport(AppServerTransportError::ProcessTerminated);
assert_eq!(
error.to_string(),
"App-server terminated before sending expected response"
);
}
#[test]
fn transport_from_conversion_wraps_transport_error() {
let transport_error = AppServerTransportError::Timeout {
response_id: "init-1".to_string(),
timeout_seconds: 300,
};
let error: AppServerError = transport_error.into();
assert!(matches!(error, AppServerError::Transport(_)));
}
}