Only show Worked for after the final assistant message (#7854)

Before:
<img width="1908" height="246" alt="image"
src="https://github.com/user-attachments/assets/f4d5993a-8d37-4982-a6fd-d37f449215b2"
/>
After:
<img width="1102" height="586" alt="image"
src="https://github.com/user-attachments/assets/e833140d-690a-4c33-8bc7-e2b69b9dc92d"
/>
This commit is contained in:
pakrym-oai
2025-12-10 21:13:13 -08:00
committed by GitHub
parent 057250020a
commit 83aac0f985
5 changed files with 24 additions and 13 deletions

View File

@@ -136,6 +136,7 @@ impl BottomPane {
self.request_redraw();
}
#[cfg(test)]
pub fn status_widget(&self) -> Option<&StatusIndicatorWidget> {
self.status.as_ref()
}

View File

@@ -4,6 +4,7 @@ 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;
@@ -333,6 +334,8 @@ pub(crate) struct ChatWidget {
feedback: codex_feedback::CodexFeedback,
// Current session rollout path (if known)
current_rollout_path: Option<PathBuf>,
// Current task start time
task_started_at: Option<Instant>,
}
struct UserMessage {
@@ -518,17 +521,20 @@ 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<String>) {
// 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.
@@ -664,6 +670,7 @@ 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 {
@@ -1007,14 +1014,6 @@ 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)),
));
@@ -1027,6 +1026,16 @@ 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) {
@@ -1330,6 +1339,7 @@ impl ChatWidget {
last_rendered_width: std::cell::Cell::new(None),
feedback,
current_rollout_path: None,
task_started_at: None,
};
widget.prefetch_rate_limits();
@@ -1415,6 +1425,7 @@ impl ChatWidget {
last_rendered_width: std::cell::Cell::new(None),
feedback,
current_rollout_path: None,
task_started_at: None,
};
widget.prefetch_rate_limits();

View File

@@ -1,6 +1,6 @@
---
source: tui/src/chatwidget/tests.rs
expression: visual
expression: term.backend().vt100().screen().contents()
---
• -- Indented code block (4 spaces)
SELECT *
@@ -16,3 +16,4 @@ expression: visual
"path": "C:\\Program Files\\App",
"regex": "^foo.*(bar)?$"
}
─ Worked for 0s ────────────────────────────────────────────────────────────────

View File

@@ -442,6 +442,7 @@ 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)
}

View File

@@ -125,13 +125,10 @@ 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 {