ag_agent/app_server/
error.rs1use std::error::Error;
2
3use crate::app_server_transport::AppServerTransportError;
4
5#[derive(Debug, thiserror::Error)]
11pub enum AppServerError {
12 #[error("{0}")]
14 InterruptedByUser(String),
15
16 #[error("Failed to lock {provider} app-server session map")]
18 LockPoisoned {
19 provider: &'static str,
21 },
22
23 #[error("{0}")]
25 PromptRender(String),
26
27 #[error("{0}")]
29 Provider(String),
30
31 #[error(
33 "{provider} app-server failed, then retry failed after restart: first error: \
34 {first_error}; retry error: {retry_error}"
35 )]
36 RetryExhausted {
37 provider: &'static str,
39 first_error: String,
41 retry_error: String,
43 },
44
45 #[error(transparent)]
47 Transport(Box<dyn Error + Send + Sync>),
48}
49
50impl From<AppServerTransportError> for AppServerError {
51 fn from(error: AppServerTransportError) -> Self {
52 Self::Transport(Box::new(error))
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn lock_poisoned_display_includes_provider_name() {
62 let error = AppServerError::LockPoisoned { provider: "Codex" };
64
65 let display = error.to_string();
67
68 assert_eq!(display, "Failed to lock Codex app-server session map");
70 }
71
72 #[test]
73 fn interrupted_by_user_display_shows_message() {
74 let error = AppServerError::InterruptedByUser("[Stopped]".to_string());
76
77 assert_eq!(error.to_string(), "[Stopped]");
79 }
80
81 #[test]
82 fn prompt_render_display_shows_message() {
83 let error = AppServerError::PromptRender("template syntax error".to_string());
85
86 assert_eq!(error.to_string(), "template syntax error");
88 }
89
90 #[test]
91 fn provider_display_shows_message() {
92 let error = AppServerError::Provider("runtime crashed".to_string());
94
95 assert_eq!(error.to_string(), "runtime crashed");
97 }
98
99 #[test]
100 fn retry_exhausted_display_includes_both_errors() {
101 let error = AppServerError::RetryExhausted {
103 provider: "Codex",
104 first_error: "connection reset".to_string(),
105 retry_error: "timeout".to_string(),
106 };
107
108 let display = error.to_string();
110
111 assert_eq!(
113 display,
114 "Codex app-server failed, then retry failed after restart: first error: connection \
115 reset; retry error: timeout"
116 );
117 }
118
119 #[test]
120 fn transport_display_delegates_to_inner_error() {
121 let error = AppServerError::from(AppServerTransportError::ProcessTerminated);
123
124 assert_eq!(
126 error.to_string(),
127 "App-server terminated before sending expected response"
128 );
129 }
130
131 #[test]
132 fn transport_from_conversion_wraps_transport_error() {
133 let transport_error = AppServerTransportError::Timeout {
135 response_id: "init-1".to_string(),
136 timeout_seconds: 300,
137 };
138
139 let error: AppServerError = transport_error.into();
141
142 assert!(matches!(error, AppServerError::Transport(_)));
144 }
145}