Preserve MCP activity across thread switches

This commit is contained in:
Charlie Marsh
2026-06-29 09:39:14 -04:00
parent f6e8c636d2
commit 4d13a6c70a
5 changed files with 37 additions and 7 deletions
+13 -4
View File
@@ -379,13 +379,19 @@ impl ChatWidget {
user_turn_pending_start: self.input_queue.user_turn_pending_start,
current_collaboration_mode: self.current_collaboration_mode.clone(),
active_collaboration_mask: self.active_collaboration_mask.clone(),
task_running: self.bottom_pane.is_task_running(),
foreground_task_running: self.bottom_pane.is_foreground_task_running(),
mcp_startup_running: self.bottom_pane.is_mcp_startup_running(),
agent_turn_running: self.turn_lifecycle.agent_turn_running,
})
}
pub(crate) fn restore_thread_input_state(&mut self, input_state: Option<ThreadInputState>) {
let restored_task_running = input_state.as_ref().is_some_and(|state| state.task_running);
let restored_foreground_task_running = input_state
.as_ref()
.is_some_and(|state| state.foreground_task_running);
let restored_mcp_startup_running = input_state
.as_ref()
.is_some_and(|state| state.mcp_startup_running);
if let Some(input_state) = input_state {
self.current_collaboration_mode = input_state.current_collaboration_mode;
self.active_collaboration_mask = input_state.active_collaboration_mask;
@@ -440,10 +446,13 @@ impl ChatWidget {
self.turn_lifecycle
.restore_running(self.turn_lifecycle.agent_turn_running, Instant::now());
self.update_foreground_task_running_state();
if restored_task_running && !self.bottom_pane.is_task_running() {
if restored_foreground_task_running && !self.bottom_pane.is_foreground_task_running() {
self.bottom_pane.set_task_running(/*running*/ true);
self.refresh_status_surfaces();
}
self.bottom_pane
.set_mcp_startup_running(restored_mcp_startup_running);
self.refresh_plan_mode_nudge();
self.refresh_status_surfaces();
self.refresh_pending_input_preview();
self.request_redraw();
}
@@ -1063,7 +1063,8 @@ async fn restore_thread_input_state_syncs_sleep_inhibitor_state() {
user_turn_pending_start: false,
current_collaboration_mode: chat.current_collaboration_mode.clone(),
active_collaboration_mask: chat.active_collaboration_mask.clone(),
task_running: true,
foreground_task_running: true,
mcp_startup_running: false,
agent_turn_running: true,
}));
@@ -107,6 +107,24 @@ async fn mcp_startup_ignores_status_for_other_thread() {
);
}
#[tokio::test]
async fn restored_mcp_only_thread_clears_busy_state_when_startup_finishes() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
chat.set_mcp_startup_expected_servers(["alpha".to_string()]);
notify_mcp_status(&mut chat, "alpha", McpServerStartupState::Starting);
let input_state = chat.capture_thread_input_state();
chat.restore_thread_input_state(/*input_state*/ None);
chat.restore_thread_input_state(input_state);
assert!(!chat.bottom_pane.is_foreground_task_running());
assert!(chat.bottom_pane.is_mcp_startup_running());
notify_mcp_status(&mut chat, "alpha", McpServerStartupState::Ready);
assert!(!chat.bottom_pane.is_task_running());
}
#[tokio::test]
async fn review_command_during_mcp_startup_opens_popup_snapshot() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
@@ -385,7 +385,8 @@ async fn restore_thread_input_state_restores_pending_steers_without_downgrading_
user_turn_pending_start: false,
current_collaboration_mode: chat.current_collaboration_mode.clone(),
active_collaboration_mask: chat.active_collaboration_mask.clone(),
task_running: false,
foreground_task_running: false,
mcp_startup_running: false,
agent_turn_running: false,
}));
+2 -1
View File
@@ -131,7 +131,8 @@ pub(crate) struct ThreadInputState {
pub(super) user_turn_pending_start: bool,
pub(super) current_collaboration_mode: CollaborationMode,
pub(super) active_collaboration_mask: Option<CollaborationModeMask>,
pub(super) task_running: bool,
pub(super) foreground_task_running: bool,
pub(super) mcp_startup_running: bool,
pub(super) agent_turn_running: bool,
}