From bca77e2bd0df392f32ab05eff63ede5ae764fe5c Mon Sep 17 00:00:00 2001 From: Felipe Coury Date: Sat, 30 May 2026 17:39:34 -0300 Subject: [PATCH] fix(tui): sync token loading card in transcript overlay --- codex-rs/tui/src/chatwidget.rs | 18 +++++++++++++----- .../tui/src/chatwidget/tests/slash_commands.rs | 5 +++++ codex-rs/tui/src/chatwidget/tokens.rs | 7 ++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index cabacbe23a..b1e1074261 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -1871,12 +1871,12 @@ impl ChatWidget { self.current_rollout_path.clone() } - /// Returns a cache key describing the current in-flight active cell for the transcript overlay. + /// Returns a cache key describing the current in-flight cells for the transcript overlay. /// /// `Ctrl+T` renders committed transcript cells plus a render-only live tail derived from the - /// current active cell, and the overlay caches that tail; this key is what it uses to decide - /// whether it must recompute. When there is no active cell, this returns `None` so the overlay - /// can drop the tail entirely. + /// current active, hook, and token activity cells, and the overlay caches that tail; this key is + /// what it uses to decide whether it must recompute. When there are no live cells, this returns + /// `None` so the overlay can drop the tail entirely. /// /// If callers mutate the active cell's transcript output without bumping the revision (or /// providing an appropriate animation tick), the overlay will keep showing a stale tail while @@ -1884,7 +1884,8 @@ impl ChatWidget { pub(crate) fn active_cell_transcript_key(&self) -> Option { let cell = self.transcript.active_cell.as_ref(); let hook_cell = self.active_hook_cell.as_ref(); - if cell.is_none() && hook_cell.is_none() { + let token_activity_cell = self.pending_token_activity_output(); + if cell.is_none() && hook_cell.is_none() && token_activity_cell.is_none() { return None; } Some(ActiveCellTranscriptKey { @@ -1922,6 +1923,13 @@ impl ChatWidget { } lines.extend(hook_lines); } + if let Some(token_activity_cell) = self.pending_token_activity_output() { + let token_activity_lines = token_activity_cell.transcript_hyperlink_lines(width); + if !token_activity_lines.is_empty() && !lines.is_empty() { + lines.push(HyperlinkLine::from("")); + } + lines.extend(token_activity_lines); + } (!lines.is_empty()).then_some(lines) } diff --git a/codex-rs/tui/src/chatwidget/tests/slash_commands.rs b/codex-rs/tui/src/chatwidget/tests/slash_commands.rs index 8c5cadf230..22ca2e47fd 100644 --- a/codex-rs/tui/src/chatwidget/tests/slash_commands.rs +++ b/codex-rs/tui/src/chatwidget/tests/slash_commands.rs @@ -1190,6 +1190,11 @@ async fn clearing_pending_token_activity_refreshes_discards_late_result() { .map(|cell| lines_to_single_string(&cell.display_lines(u16::MAX))), Some("/tokens daily\n\n Token activity\n Loading...\n".to_string()), ); + assert_eq!( + chat.active_cell_transcript_lines(u16::MAX) + .map(|lines| lines_to_single_string(&lines)), + Some("/tokens daily\n\n Token activity\n Loading...\n".to_string()), + ); chat.clear_pending_token_activity_refreshes(); diff --git a/codex-rs/tui/src/chatwidget/tokens.rs b/codex-rs/tui/src/chatwidget/tokens.rs index 9099834be2..9a304813dc 100644 --- a/codex-rs/tui/src/chatwidget/tokens.rs +++ b/codex-rs/tui/src/chatwidget/tokens.rs @@ -647,6 +647,7 @@ impl ChatWidget { cell, handle, }); + self.bump_active_cell_revision(); self.request_redraw(); self.app_event_tx .send(AppEvent::RefreshTokenActivity { request_id }); @@ -663,20 +664,20 @@ impl ChatWidget { request_id: u64, result: Result, ) -> Option { - let Some(output) = self.refreshing_token_activity_output.take() else { - return None; - }; + let output = self.refreshing_token_activity_output.take()?; if output.request_id != request_id { self.refreshing_token_activity_output = Some(output); return None; } output.handle.finish(result); + self.bump_active_cell_revision(); self.request_redraw(); Some(output.cell) } pub(crate) fn clear_pending_token_activity_refreshes(&mut self) { if self.refreshing_token_activity_output.take().is_some() { + self.bump_active_cell_revision(); self.request_redraw(); } }