# PR #1827: Get rid of unnecessary ERROR messages - URL: https://github.com/openai/codex/pull/1827 - Author: easong-openai - Created: 2025-08-04 21:32:49 UTC - Updated: 2025-08-06 05:46:21 UTC - Changes: +17/-7, Files changed: 4, Commits: 3 ## Description When interrupting a model turn with ctr-c or at end of exec, we print an ERROR message, which is jank. Let's not do that. ## Full Diff ```diff diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 568d87c4a8..f2b5101ed2 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -627,8 +627,8 @@ impl AgentTask { self.handle.abort(); let event = Event { id: self.sub_id, - msg: EventMsg::Error(ErrorEvent { - message: "Turn interrupted".to_string(), + msg: EventMsg::BackgroundEvent(BackgroundEventEvent { + message: "Response interrupted.".to_string(), }), }; let tx_event = self.sess.tx_event.clone(); diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index ce4d7f65cc..fe3b058970 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -181,20 +181,22 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option) -> any ) .await; - // Exit the inner loop and return to the main input prompt. The codex - // will emit a `TurnInterrupted` (Error) event which is drained later. break; } res = codex.next_event() => match res { Ok(event) => { + let is_shutdown = matches!(event.msg, EventMsg::ShutdownComplete); debug!("Received event: {event:?}"); if let Err(e) = tx.send(event) { error!("Error sending event: {e:?}"); break; } + if is_shutdown { + break; + } }, Err(e) => { - error!("Error receiving event: {e:?}"); + debug!("Event stream ended: {e:?}"); break; } } diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index cab78bbe3f..c8c88e3a24 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -286,8 +286,8 @@ impl BottomPane<'_> { impl WidgetRef for &BottomPane<'_> { fn render_ref(&self, area: Rect, buf: &mut Buffer) { // Show BottomPaneView if present. - if let Some(ov) = &self.active_view { - ov.render(area, buf); + if let Some(active_view) = &self.active_view { + active_view.render(area, buf); } else { (&self.composer).render_ref(area, buf); } diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index e5ebf58a07..68778f5ec0 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -10,6 +10,7 @@ use codex_core::protocol::AgentMessageEvent; use codex_core::protocol::AgentReasoningDeltaEvent; use codex_core::protocol::AgentReasoningEvent; use codex_core::protocol::ApplyPatchApprovalRequestEvent; +use codex_core::protocol::BackgroundEventEvent; use codex_core::protocol::ErrorEvent; use codex_core::protocol::Event; use codex_core::protocol::EventMsg; @@ -220,6 +221,13 @@ impl ChatWidget<'_> { pub(crate) fn handle_codex_event(&mut self, event: Event) { let Event { id, msg } = event; match msg { + EventMsg::BackgroundEvent(BackgroundEventEvent { message }) => { + self.add_to_history(HistoryCell::new_background_event(message.clone())); + if message.contains("Turn interrupted") { + self.bottom_pane.set_task_running(false); + } + self.request_redraw(); + } EventMsg::SessionConfigured(event) => { self.bottom_pane .set_history_metadata(event.history_log_id, event.history_entry_count); ``` ## Review Comments ### codex-rs/core/src/codex.rs - Created: 2025-08-04 21:52:31 UTC | Link: https://github.com/openai/codex/pull/1827#discussion_r2252649250 ```diff @@ -601,8 +601,8 @@ impl AgentTask { self.handle.abort(); let event = Event { id: self.sub_id, - msg: EventMsg::Error(ErrorEvent { - message: "Turn interrupted".to_string(), + msg: EventMsg::BackgroundEvent(BackgroundEventEvent { ``` > Let's introduce a new variant in `EventMsg` for this and then let the UI decide how it wants to present it. ### codex-rs/exec/src/lib.rs - Created: 2025-08-04 21:56:07 UTC | Link: https://github.com/openai/codex/pull/1827#discussion_r2252653778 ```diff @@ -181,20 +181,22 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option) -> any ) .await; - // Exit the inner loop and return to the main input prompt. The codex - // will emit a `TurnInterrupted` (Error) event which is drained later. break; } res = codex.next_event() => match res { Ok(event) => { + let is_shutdown = matches!(event.msg, EventMsg::ShutdownComplete); debug!("Received event: {event:?}"); if let Err(e) = tx.send(event) { error!("Error sending event: {e:?}"); break; } + if is_shutdown { ``` > I don't think this is a safe way to change the control flow.