From f2e0bf2d627b998795d81fd27a698de9ed36201c Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Tue, 3 Nov 2026 23:03:45 +0000 Subject: [PATCH] Clarify TUI reconnect status for HTTP 429 stream errors (#59253) ## What changed For live, retryable `ResponseStreamDisconnected` errors with HTTP status `429`, replace `Reconnecting... ` with `Server is busy, reconnecting ` in the TUI status header. ## Testing Update the stream recovery test to assert `Server is busy, reconnecting 2/5` and verify that the previous status is restored when streaming resumes. GitOrigin-RevId: 7fb97f61b856a830565b86ec1bac2ef8608875b8 --- codex-rs/tui/src/chatwidget/protocol.rs | 17 +++++++++++++---- codex-rs/tui/src/chatwidget/tests/app_server.rs | 11 +++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/codex-rs/tui/src/chatwidget/protocol.rs b/codex-rs/tui/src/chatwidget/protocol.rs index 7a08496373..1c9d69844e 100644 --- a/codex-rs/tui/src/chatwidget/protocol.rs +++ b/codex-rs/tui/src/chatwidget/protocol.rs @@ -214,10 +214,19 @@ impl ChatWidget { ServerNotification::Error(notification) => { if notification.will_retry { if !from_replay { - self.on_stream_error( - notification.error.message, - notification.error.additional_details, - ); + let error = notification.error; + let message = + if let Some(AppServerCodexErrorInfo::ResponseStreamDisconnected { + http_status_code: Some(429), + }) = error.codex_error_info + && let Some(attempt) = + error.message.strip_prefix("Reconnecting... ") + { + format!("Server is busy, reconnecting {attempt}") + } else { + error.message + }; + self.on_stream_error(message, error.additional_details); } } else if from_replay || !safety_recourse::defer_error(self, ¬ification) { self.last_non_retry_error = Some(( diff --git a/codex-rs/tui/src/chatwidget/tests/app_server.rs b/codex-rs/tui/src/chatwidget/tests/app_server.rs index 18fae8d94a..b9423af615 100644 --- a/codex-rs/tui/src/chatwidget/tests/app_server.rs +++ b/codex-rs/tui/src/chatwidget/tests/app_server.rs @@ -1889,8 +1889,10 @@ async fn live_app_server_stream_recovery_restores_previous_status_header() { ServerNotification::Error(ErrorNotification { error: AppServerTurnError { misalignment: None, - message: "Reconnecting... 1/5".to_string(), - codex_error_info: Some(CodexErrorInfo::Other), + message: "Reconnecting... 2/5".to_string(), + codex_error_info: Some(CodexErrorInfo::ResponseStreamDisconnected { + http_status_code: Some(429), + }), additional_details: None, }, will_retry: true, @@ -1901,6 +1903,11 @@ async fn live_app_server_stream_recovery_restores_previous_status_header() { ); drain_insert_history(&mut rx); + insta::assert_snapshot!( + chat.bottom_pane.status_widget().unwrap().header(), + @"Server is busy, reconnecting 2/5" + ); + chat.handle_server_notification( ServerNotification::AgentMessageDelta( codex_app_server_protocol::AgentMessageDeltaNotification {