@@ -317,6 +317,7 @@ use crate::slash_command::SlashCommand;
317317use crate :: status:: RateLimitSnapshotDisplay ;
318318use crate :: status_indicator_widget:: STATUS_DETAILS_DEFAULT_MAX_LINES ;
319319use crate :: status_indicator_widget:: StatusDetailsCapitalization ;
320+ use crate :: status_indicator_widget:: fmt_elapsed_compact;
320321use crate :: text_formatting:: truncate_text;
321322use crate :: tui:: FrameRequester ;
322323mod background_agents;
@@ -398,6 +399,7 @@ struct UnifiedExecProcessSummary {
398399 key : String ,
399400 call_id : String ,
400401 command_display : String ,
402+ started_at : Instant ,
401403 recent_chunks : Vec < String > ,
402404 output_lines : Vec < String > ,
403405}
@@ -1021,6 +1023,8 @@ pub(crate) struct ChatWidget {
10211023#[ derive( Debug ) ]
10221024struct BackgroundActivity {
10231025 cell : Box < dyn HistoryCell > ,
1026+ started_at : Instant ,
1027+ task : Option < String > ,
10241028}
10251029
10261030impl BackgroundActivity {
@@ -1047,6 +1051,10 @@ fn split_background_task_status(title: String) -> (String, Option<String>) {
10471051 ( title, None )
10481052}
10491053
1054+ fn background_elapsed_text ( started_at : Instant ) -> String {
1055+ fmt_elapsed_compact ( started_at. elapsed ( ) . as_secs ( ) )
1056+ }
1057+
10501058#[ cfg_attr( not( test) , allow( dead_code) ) ]
10511059enum CodexOpTarget {
10521060 Direct ( UnboundedSender < AppCommand > ) ,
@@ -3950,13 +3958,15 @@ impl ChatWidget {
39503958 {
39513959 existing. call_id = call_id. to_string ( ) ;
39523960 existing. command_display = command_display;
3961+ existing. started_at = Instant :: now ( ) ;
39533962 existing. recent_chunks . clear ( ) ;
39543963 existing. output_lines . clear ( ) ;
39553964 } else {
39563965 self . unified_exec_processes . push ( UnifiedExecProcessSummary {
39573966 key,
39583967 call_id : call_id. to_string ( ) ,
39593968 command_display,
3969+ started_at : Instant :: now ( ) ,
39603970 recent_chunks : Vec :: new ( ) ,
39613971 output_lines : Vec :: new ( ) ,
39623972 } ) ;
@@ -6983,8 +6993,11 @@ impl ChatWidget {
69836993 fn finalize_active_cell_as_failed ( & mut self ) {
69846994 if let Some ( cell) = self . active_cell . take ( ) {
69856995 if cell. as_any ( ) . is :: < multi_agents:: CollabAgentActivityCell > ( ) {
6986- self . background_activities
6987- . push_back ( BackgroundActivity { cell } ) ;
6996+ self . background_activities . push_back ( BackgroundActivity {
6997+ cell,
6998+ started_at : Instant :: now ( ) ,
6999+ task : None ,
7000+ } ) ;
69887001 } else {
69897002 self . finalize_boxed_cell_as_failed ( cell) ;
69907003 }
@@ -7092,6 +7105,10 @@ impl ChatWidget {
70927105 user_message_preview_text ( message, self . rejected_steer_history_records . get ( idx) )
70937106 } )
70947107 . collect ( ) ;
7108+ if !queued_messages. is_empty ( ) || !pending_steers. is_empty ( ) || !rejected_steers. is_empty ( )
7109+ {
7110+ self . clear_esc_backtrack_hint ( ) ;
7111+ }
70957112 self . bottom_pane . set_pending_input_preview (
70967113 queued_messages,
70977114 pending_steers,
@@ -10534,8 +10551,11 @@ impl ChatWidget {
1053410551 }
1053510552
1053610553 if let Some ( cell) = self . active_cell . take ( ) {
10537- self . background_activities
10538- . push_back ( BackgroundActivity { cell } ) ;
10554+ self . background_activities . push_back ( BackgroundActivity {
10555+ cell,
10556+ started_at : Instant :: now ( ) ,
10557+ task : None ,
10558+ } ) ;
1053910559 self . bump_active_cell_revision ( ) ;
1054010560 }
1054110561 self . task_backgrounded = true ;
@@ -10580,11 +10600,18 @@ impl ChatWidget {
1058010600 . downcast_ref :: < multi_agents:: CollabAgentActivityCell > ( )
1058110601 {
1058210602 let ( title, status) = split_background_task_status ( title) ;
10603+ let task = activity
10604+ . task
10605+ . as_deref ( )
10606+ . map ( |task| truncate_text ( task, 240 ) ) ;
1058310607 params. subagents . push ( BackgroundTaskItem {
1058410608 kind : BackgroundTaskKind :: Subagent {
1058510609 thread_id : cell. thread_id ( ) ,
1058610610 } ,
1058710611 title,
10612+ role : cell. agent_role ( ) . map ( str:: to_string) ,
10613+ task,
10614+ elapsed : Some ( background_elapsed_text ( activity. started_at ) ) ,
1058810615 detail,
1058910616 status,
1059010617 output_lines : Vec :: new ( ) ,
@@ -10593,6 +10620,9 @@ impl ChatWidget {
1059310620 params. terminals . push ( BackgroundTaskItem {
1059410621 kind : BackgroundTaskKind :: Terminal ,
1059510622 title,
10623+ role : None ,
10624+ task : None ,
10625+ elapsed : Some ( background_elapsed_text ( activity. started_at ) ) ,
1059610626 detail,
1059710627 status : Some ( "running" . to_string ( ) ) ,
1059810628 output_lines : Vec :: new ( ) ,
@@ -10606,6 +10636,9 @@ impl ChatWidget {
1060610636 params. terminals . push ( BackgroundTaskItem {
1060710637 kind : BackgroundTaskKind :: Terminal ,
1060810638 title : process. command_display . clone ( ) ,
10639+ role : None ,
10640+ task : None ,
10641+ elapsed : Some ( background_elapsed_text ( process. started_at ) ) ,
1060910642 detail,
1061010643 status : Some ( "running" . to_string ( ) ) ,
1061110644 output_lines : process. output_lines . clone ( ) ,
@@ -10655,7 +10688,10 @@ impl ChatWidget {
1065510688 }
1065610689
1065710690 fn should_interrupt_before_submitting_pending_input ( & self ) -> bool {
10658- self . is_cancellable_work_active ( ) || self . user_turn_pending_start
10691+ self . agent_turn_running
10692+ || self . mcp_startup_status . is_some ( )
10693+ || self . is_review_mode
10694+ || self . user_turn_pending_start
1065910695 }
1066010696
1066110697 /// Return the markdown body width available to an active stream.
0 commit comments