From 659768831da32c222b5f09503fb346ab5676c398 Mon Sep 17 00:00:00 2001 From: Charles Cunningham Date: Thu, 26 Feb 2026 23:36:23 -0800 Subject: [PATCH] tui: simplify pending nudge submit gating --- codex-rs/tui/src/chatwidget.rs | 22 +++++++++------------- codex-rs/tui/src/chatwidget/tests.rs | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index c9f566ffaa..8bccb294f5 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -3438,24 +3438,20 @@ impl ChatWidget { .bottom_pane .take_recent_submission_mention_bindings(), }; - let Some(user_message) = - self.maybe_defer_user_message_for_realtime(user_message) - else { - return; - }; if user_message.text.is_empty() && user_message.local_images.is_empty() && user_message.remote_image_urls.is_empty() { return; } - let has_images = !user_message.local_images.is_empty() - || !user_message.remote_image_urls.is_empty(); + let Some(user_message) = + self.maybe_defer_user_message_for_realtime(user_message) + else { + return; + }; let should_preview_as_pending_nudge = self.is_session_configured() && self.bottom_pane.is_task_running() - && !self.is_review_mode - && user_message.text.strip_prefix('!').is_none() - && (!has_images || self.current_model_supports_images()); + && !self.is_review_mode; if should_preview_as_pending_nudge { self.submit_user_message_internal(user_message, false); } else if self.is_session_configured() { @@ -4263,9 +4259,9 @@ impl ChatWidget { personality, }; - self.codex_op_tx.send(op).unwrap_or_else(|e| { - tracing::error!("failed to send message: {e}"); - }); + if !self.submit_op(op) { + return; + } // Persist the text to cross-session message history. if !text.is_empty() { diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index cfd09fbdc3..2a3e6f2ef6 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -3579,6 +3579,25 @@ async fn steer_enter_uses_pending_nudges_while_final_answer_stream_is_active() { assert!(lines_to_single_string(&inserted[0]).contains("queued while streaming")); } +#[tokio::test] +async fn failed_pending_nudge_submit_does_not_add_pending_preview() { + let (mut chat, mut rx, op_rx) = make_chatwidget_manual(None).await; + chat.thread_id = Some(ThreadId::new()); + chat.on_task_started(); + drop(op_rx); + + chat.bottom_pane.set_composer_text( + "queued while streaming".to_string(), + Vec::new(), + Vec::new(), + ); + chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); + + assert!(chat.pending_nudges.is_empty()); + assert!(chat.queued_user_messages.is_empty()); + assert!(drain_insert_history(&mut rx).is_empty()); +} + #[tokio::test] async fn raw_response_item_with_canonicalized_user_payload_clears_pending_nudge() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(None).await;