use super::super::*;
use super::MissionControlApp;
impl MissionControlApp {
pub(crate) fn finish_worker_if_ready(
&mut self,
ui_state: &mut state::MissionControlState,
) -> bool {
let Some(worker) = self.worker.take() else {
self.active_run = false;
return false;
};
if worker.handle.is_finished() {
self.reconcile_worker_outcome(ui_state, &worker);
let _ = worker.handle.join();
self.active_run = false;
true
} else {
self.worker = Some(worker);
false
}
}
pub(crate) fn join_completed_worker(
&mut self,
ui_state: &mut state::MissionControlState,
) -> bool {
self.finish_worker_if_ready(ui_state)
}
pub(crate) fn join_worker_with_timeout(
&mut self,
ui_state: &mut state::MissionControlState,
timeout: Duration,
) -> bool {
if self.worker.is_none() {
return true;
}
let deadline = Instant::now() + timeout;
while self
.worker
.as_ref()
.is_some_and(|worker| !worker.handle.is_finished())
&& Instant::now() < deadline
{
thread::sleep(Duration::from_millis(10));
}
if self.finish_worker_if_ready(ui_state) || self.worker.is_none() {
true
} else {
let message = format!(
"provider worker did not shut down within {}ms; exit blocked to avoid background tool/session writes",
timeout.as_millis()
);
ui_state.status = message.clone();
eprintln!("tui warning=worker_join_timeout action=exit_blocked {message}");
false
}
}
pub(crate) fn reconcile_worker_outcome(
&mut self,
ui_state: &mut state::MissionControlState,
worker: &WorkerState,
) {
if !worker.outcome_reconciled
&& !worker.outcome.final_event_sent()
&& let Some(event) = worker.outcome.final_event()
{
apply_worker_final_event(ui_state, event);
}
let pending_steering = worker.steering.pending_count();
if ui_state.set_pending_steering_count(pending_steering) {
self.last_steering_pending_count = pending_steering;
}
ui_state.finish_assistant_streaming();
ui_state.clear_running_prompt();
}
pub(crate) fn cancel_active_worker(
&mut self,
ui_state: &mut state::MissionControlState,
) -> Option<String> {
let Some(worker) = self.worker.take() else {
self.active_run = false;
return None;
};
worker.cancel.store(true, Ordering::SeqCst);
let cleared = worker.steering.clear();
if cleared > 0 || ui_state.pending_steering_count > 0 {
ui_state.set_pending_steering_count(0);
self.last_steering_pending_count = 0;
}
if worker.handle.is_finished() {
self.reconcile_worker_outcome(ui_state, &worker);
let _ = worker.handle.join();
self.active_run = false;
None
} else {
self.worker = Some(worker);
self.active_run = false;
Some("cancellation requested; provider worker is still shutting down its current blocking call".to_string())
}
}
pub(crate) fn cancel_running_prompt(&mut self, ui_state: &mut state::MissionControlState) {
let prompt = ui_state.request_running_prompt_cancel().unwrap_or_default();
let preview = crate::tui::transcript::sanitize_preview(&prompt);
if preview.trim().is_empty() {
ui_state.status = "prompt cancellation requested".to_string();
} else {
ui_state.status = format!("canceling: {preview}");
}
let _ = self.cancel_active_worker(ui_state);
}
}