diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index c0d600732..851668728 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -136,7 +136,6 @@ impl BottomPane { self.request_redraw(); } - #[cfg(test)] pub fn status_widget(&self) -> Option<&StatusIndicatorWidget> { self.status.as_ref() } diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index d7a451e82..82f00f9ca 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -4,7 +4,6 @@ use std::collections::VecDeque; use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; -use std::time::Instant; use codex_app_server_protocol::AuthMode; use codex_backend_client::Client as BackendClient; @@ -334,8 +333,6 @@ pub(crate) struct ChatWidget { feedback: codex_feedback::CodexFeedback, // Current session rollout path (if known) current_rollout_path: Option, - // Current task start time - task_started_at: Option, } struct UserMessage { @@ -521,20 +518,17 @@ impl ChatWidget { self.set_status_header(String::from("Working")); self.full_reasoning_buffer.clear(); self.reasoning_buffer.clear(); - self.task_started_at = Some(Instant::now()); self.request_redraw(); } fn on_task_complete(&mut self, last_agent_message: Option) { // If a stream is currently active, finalize it. self.flush_answer_stream_with_separator(); - self.add_final_message_separator(); // Mark task stopped and request redraw now that all content is in history. self.bottom_pane.set_task_running(false); self.running_commands.clear(); self.suppressed_exec_calls.clear(); self.last_unified_wait = None; - self.task_started_at = None; self.request_redraw(); // If there is a queued user message, send exactly one now to begin the next turn. @@ -670,7 +664,6 @@ impl ChatWidget { self.suppressed_exec_calls.clear(); self.last_unified_wait = None; self.stream_controller = None; - self.task_started_at = None; self.maybe_show_pending_rate_limit_prompt(); } pub(crate) fn get_model_family(&self) -> ModelFamily { @@ -1014,6 +1007,14 @@ impl ChatWidget { self.flush_active_cell(); if self.stream_controller.is_none() { + if self.needs_final_message_separator { + let elapsed_seconds = self + .bottom_pane + .status_widget() + .map(super::status_indicator_widget::StatusIndicatorWidget::elapsed_seconds); + self.add_to_history(history_cell::FinalMessageSeparator::new(elapsed_seconds)); + self.needs_final_message_separator = false; + } self.stream_controller = Some(StreamController::new( self.last_rendered_width.get().map(|w| w.saturating_sub(2)), )); @@ -1026,16 +1027,6 @@ impl ChatWidget { self.request_redraw(); } - fn add_final_message_separator(&mut self) { - if self.needs_final_message_separator { - let elapsed_seconds = self - .task_started_at - .map(|start_time| start_time.elapsed().as_secs()); - self.add_to_history(history_cell::FinalMessageSeparator::new(elapsed_seconds)); - self.needs_final_message_separator = false; - } - } - pub(crate) fn handle_exec_end_now(&mut self, ev: ExecCommandEndEvent) { let running = self.running_commands.remove(&ev.call_id); if self.suppressed_exec_calls.remove(&ev.call_id) { @@ -1339,7 +1330,6 @@ impl ChatWidget { last_rendered_width: std::cell::Cell::new(None), feedback, current_rollout_path: None, - task_started_at: None, }; widget.prefetch_rate_limits(); @@ -1425,7 +1415,6 @@ impl ChatWidget { last_rendered_width: std::cell::Cell::new(None), feedback, current_rollout_path: None, - task_started_at: None, }; widget.prefetch_rate_limits(); diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_markdown_code_blocks_vt100_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_markdown_code_blocks_vt100_snapshot.snap index 8f9b55927..1ed73b5fa 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_markdown_code_blocks_vt100_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_markdown_code_blocks_vt100_snapshot.snap @@ -1,6 +1,6 @@ --- source: tui/src/chatwidget/tests.rs -expression: term.backend().vt100().screen().contents() +expression: visual --- • -- Indented code block (4 spaces) SELECT * @@ -16,4 +16,3 @@ expression: term.backend().vt100().screen().contents() "path": "C:\\Program Files\\App", "regex": "^foo.*(bar)?$" } -─ Worked for 0s ──────────────────────────────────────────────────────────────── diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index f03346ee5..bd85a9edc 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -442,7 +442,6 @@ fn make_chatwidget_manual( last_rendered_width: std::cell::Cell::new(None), feedback: codex_feedback::CodexFeedback::new(), current_rollout_path: None, - task_started_at: None, }; (widget, rx, op_rx) } diff --git a/codex-rs/tui/src/status_indicator_widget.rs b/codex-rs/tui/src/status_indicator_widget.rs index e850c32fe..642b9ca2b 100644 --- a/codex-rs/tui/src/status_indicator_widget.rs +++ b/codex-rs/tui/src/status_indicator_widget.rs @@ -125,10 +125,13 @@ impl StatusIndicatorWidget { elapsed } - #[cfg(test)] fn elapsed_seconds_at(&self, now: Instant) -> u64 { self.elapsed_duration_at(now).as_secs() } + + pub fn elapsed_seconds(&self) -> u64 { + self.elapsed_seconds_at(Instant::now()) + } } impl Renderable for StatusIndicatorWidget {