@@ -609,6 +609,8 @@ impl AcpServerView {
this.handle_load_error(err, window, cx);
} else if let Some(active) = this.active_thread() {
active.update(cx, |active, cx| active.handle_any_thread_error(err, cx));
+ } else {
+ this.handle_load_error(err, window, cx);
}
cx.notify();
})
@@ -3092,6 +3094,38 @@ pub(crate) mod tests {
});
}
+ #[gpui::test]
+ async fn test_connect_failure_transitions_to_load_error(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ let (thread_view, cx) = setup_thread_view(FailingAgentServer, cx).await;
+
+ thread_view.read_with(cx, |view, cx| {
+ let title = view.title(cx);
+ assert_eq!(
+ title.as_ref(),
+ "Error Loading Codex CLI",
+ "Tab title should show the agent name with an error prefix"
+ );
+ match &view.server_state {
+ ServerState::LoadError(LoadError::Other(msg)) => {
+ assert!(
+ msg.contains("Invalid gzip header"),
+ "Error callout should contain the underlying extraction error, got: {msg}"
+ );
+ }
+ other => panic!(
+ "Expected LoadError::Other, got: {}",
+ match other {
+ ServerState::Loading(_) => "Loading (stuck!)",
+ ServerState::LoadError(_) => "LoadError (wrong variant)",
+ ServerState::Connected(_) => "Connected",
+ }
+ ),
+ }
+ });
+ }
+
#[gpui::test]
async fn test_auth_required_on_initial_connect(cx: &mut TestAppContext) {
init_test(cx);
@@ -3602,6 +3636,36 @@ pub(crate) mod tests {
}
}
+ struct FailingAgentServer;
+
+ impl AgentServer for FailingAgentServer {
+ fn logo(&self) -> ui::IconName {
+ ui::IconName::AiOpenAi
+ }
+
+ fn name(&self) -> SharedString {
+ "Codex CLI".into()
+ }
+
+ fn connect(
+ &self,
+ _root_dir: Option<&Path>,
+ _delegate: AgentServerDelegate,
+ _cx: &mut App,
+ ) -> Task<gpui::Result<(Rc<dyn AgentConnection>, Option<task::SpawnInTerminal>)>> {
+ Task::ready(Err(anyhow!(
+ "extracting downloaded asset for \
+ https://github.com/zed-industries/codex-acp/releases/download/v0.9.4/\
+ codex-acp-0.9.4-aarch64-pc-windows-msvc.zip: \
+ failed to iterate over archive: Invalid gzip header"
+ )))
+ }
+
+ fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
+ self
+ }
+ }
+
#[derive(Clone)]
struct StubSessionList {
sessions: Vec<AgentSessionInfo>,