mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
tui: clear stale hook row after turn completion (#27619)
Fixes #27210. ## Why When the app server reports a visible `HookStarted` event for a `PostToolUse` hook but the turn reaches `TurnCompleted` before a matching hook completion event arrives, the TUI can leave the transient `Running PostToolUse hook` row visible after the agent is done. Interrupted and failed turn cleanup already drops transient live hook rows; the normal completion path did not. ## What Changed - Added `ChatWidget::clear_active_hook_cell()` for dropping transient live hook status without writing it to history. - Call that cleanup from normal task completion, while reusing it for the existing start/finalize cleanup paths. - Added `completed_turn_clears_visible_running_hook` snapshot coverage for the reported `PostToolUse` case. ## Tests - `just test -p codex-tui completed_turn_clears_visible_running_hook` - `just test -p codex-tui` (fails on current `main` in unrelated guardian tests: `update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default` and `update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`)
This commit is contained in:
committed by
GitHub
Unverified
parent
92d9036910
commit
44403dd3dd
@@ -6,6 +6,13 @@
|
||||
use super::*;
|
||||
|
||||
impl ChatWidget {
|
||||
/// Drop transient live hook status without flushing it into history.
|
||||
pub(super) fn clear_active_hook_cell(&mut self) {
|
||||
if self.active_hook_cell.take().is_some() {
|
||||
self.bump_active_cell_revision();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn on_hook_started(&mut self, run: codex_app_server_protocol::HookRunSummary) {
|
||||
self.record_visible_turn_activity();
|
||||
self.flush_answer_stream_with_separator();
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tui/src/chatwidget/tests/status_and_layout.rs
|
||||
expression: "format!(\"before completion:\\n{before_completion}after completion:\\n{}\",\nactive_hook_blob(&chat))"
|
||||
---
|
||||
before completion:
|
||||
• Running PostToolUse hook
|
||||
after completion:
|
||||
<empty>
|
||||
@@ -2173,6 +2173,32 @@ async fn interrupted_turn_clears_visible_running_hook() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn completed_turn_clears_visible_running_hook() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
|
||||
handle_hook_started(
|
||||
&mut chat,
|
||||
hook_started_run(
|
||||
"post-tool-use:0:/tmp/hooks.json",
|
||||
codex_app_server_protocol::HookEventName::PostToolUse,
|
||||
/*status_message*/ None,
|
||||
),
|
||||
);
|
||||
reveal_running_hooks(&mut chat);
|
||||
let before_completion = active_hook_blob(&chat);
|
||||
|
||||
handle_turn_completed(&mut chat, "turn-1", /*duration_ms*/ None);
|
||||
|
||||
assert_chatwidget_snapshot!(
|
||||
"completed_turn_clears_visible_running_hook",
|
||||
format!(
|
||||
"before completion:\n{before_completion}after completion:\n{}",
|
||||
active_hook_blob(&chat)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn status_line_fast_mode_renders_on_and_off() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
|
||||
@@ -59,9 +59,7 @@ impl ChatWidget {
|
||||
self.quit_shortcut_key = None;
|
||||
self.update_task_running_state();
|
||||
self.status_state.retry_status_header = None;
|
||||
if self.active_hook_cell.take().is_some() {
|
||||
self.bump_active_cell_revision();
|
||||
}
|
||||
self.clear_active_hook_cell();
|
||||
self.status_state.pending_status_indicator_restore = false;
|
||||
self.bottom_pane
|
||||
.set_interrupt_hint_visible(/*visible*/ true);
|
||||
@@ -162,6 +160,7 @@ impl ChatWidget {
|
||||
// Mark task stopped and request redraw now that all content is in history.
|
||||
self.status_state.pending_status_indicator_restore = false;
|
||||
self.input_queue.user_turn_pending_start = false;
|
||||
self.clear_active_hook_cell();
|
||||
self.turn_lifecycle.finish();
|
||||
self.update_task_running_state();
|
||||
self.running_commands.clear();
|
||||
@@ -302,9 +301,7 @@ impl ChatWidget {
|
||||
// Turn-scoped hook rows are transient live state; once the turn is over,
|
||||
// do not leave an orphaned running row behind if no matching completion
|
||||
// event arrived before cancellation.
|
||||
if self.active_hook_cell.take().is_some() {
|
||||
self.bump_active_cell_revision();
|
||||
}
|
||||
self.clear_active_hook_cell();
|
||||
// Reset running state and clear streaming buffers.
|
||||
self.input_queue.user_turn_pending_start = false;
|
||||
self.turn_lifecycle.finish();
|
||||
|
||||
Reference in New Issue
Block a user