diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index 6f804c44ff..71075f3d06 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -17,7 +17,6 @@ use std::collections::VecDeque; use std::path::PathBuf; use crate::app::app_server_requests::ResolvedAppServerRequest; -use crate::app_command::AppCommand; use crate::app_event::AppEvent; use crate::app_event::ConnectorsSnapshot; use crate::app_event_sender::AppEventSender; @@ -209,6 +208,7 @@ pub(crate) struct BottomPane { app_event_tx: AppEventSender, frame_requester: FrameRequester, + thread_id: Option, has_input_focus: bool, enhanced_keys_supported: bool, @@ -274,6 +274,7 @@ impl BottomPane { last_composer_activity_at: None, app_event_tx, frame_requester, + thread_id: None, has_input_focus, enhanced_keys_supported, disable_paste_burst, @@ -780,8 +781,14 @@ impl BottomPane { pub(crate) fn clear_composer_for_ctrl_c(&mut self) { if let Some(text) = self.composer.clear_for_ctrl_c() { - self.app_event_tx - .send(AppEvent::CodexOp(AppCommand::add_to_history(text))); + if let Some(thread_id) = self.thread_id { + self.app_event_tx + .send(AppEvent::AppendMessageHistoryEntry { thread_id, text }); + } else { + tracing::warn!( + "failed to append Ctrl+C-cleared draft to history: no active thread id" + ); + } } self.request_redraw(); } @@ -1438,6 +1445,7 @@ impl BottomPane { log_id: u64, entry_count: usize, ) { + self.thread_id = Some(thread_id); self.composer .set_history_metadata(thread_id, log_id, entry_count); } diff --git a/codex-rs/tui/src/chatwidget/tests/slash_commands.rs b/codex-rs/tui/src/chatwidget/tests/slash_commands.rs index 1bb4684c94..87ad226b51 100644 --- a/codex-rs/tui/src/chatwidget/tests/slash_commands.rs +++ b/codex-rs/tui/src/chatwidget/tests/slash_commands.rs @@ -1584,7 +1584,13 @@ async fn slash_clear_requests_ui_clear_when_idle() { #[tokio::test] async fn slash_clear_after_ctrl_c_keeps_stashed_draft_recallable() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + let thread_id = ThreadId::new(); + chat.thread_id = Some(thread_id); + chat.bottom_pane + .set_history_metadata(thread_id, /*log_id*/ 1, /*entry_count*/ 0); + submit_composer_text(&mut chat, "ok"); + assert_eq!(next_add_to_history_event(&mut rx), "ok"); let stashed_draft = "explain why history recall lost this draft"; @@ -1592,10 +1598,7 @@ async fn slash_clear_after_ctrl_c_keeps_stashed_draft_recallable() { .set_composer_text(stashed_draft.to_string(), Vec::new(), Vec::new()); chat.handle_key_event(KeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL)); assert_eq!(chat.bottom_pane.composer_text(), ""); - assert_matches!( - rx.try_recv(), - Ok(AppEvent::CodexOp(Op::AddToHistory { text })) if text == stashed_draft - ); + assert_eq!(next_add_to_history_event(&mut rx), stashed_draft); chat.bottom_pane .set_composer_text("/clear".to_string(), Vec::new(), Vec::new());