Fix agent cancellation and monitor UI
This commit is contained in:
@@ -3839,7 +3839,7 @@ impl TerminalView {
|
||||
});
|
||||
ctx.emit(Event::SummarizationCancelDialogToggled { is_open: *is_open });
|
||||
}
|
||||
BlocklistAIStatusBarEvent::Stop => me.ctrl_c(ctx),
|
||||
BlocklistAIStatusBarEvent::Stop => me.cancel_active_conversation_via_status_bar(ctx),
|
||||
});
|
||||
if let Some(ambient_agent_view_model) = ambient_agent_view_model.as_ref() {
|
||||
ctx.subscribe_to_model(ambient_agent_view_model, |me, _, event, ctx| {
|
||||
@@ -8679,6 +8679,10 @@ impl TerminalView {
|
||||
.ai_controller
|
||||
.as_ref(ctx)
|
||||
.has_active_stream_for_conversation(conversation_id, ctx);
|
||||
let had_active_provider_run = self
|
||||
.ai_controller
|
||||
.as_ref(ctx)
|
||||
.has_active_provider_run(conversation_id);
|
||||
|
||||
self.ai_controller.update(ctx, |controller, ctx| {
|
||||
controller.cancel_conversation_progress(
|
||||
@@ -8688,6 +8692,12 @@ impl TerminalView {
|
||||
);
|
||||
});
|
||||
|
||||
if !had_active_stream && !had_active_provider_run {
|
||||
log::debug!(
|
||||
"Stop agent requested for {conversation_id:?}, but no provider run or response stream was visible"
|
||||
);
|
||||
}
|
||||
|
||||
let visible_conversation_id = self
|
||||
.agent_view_controller
|
||||
.as_ref(ctx)
|
||||
@@ -8767,8 +8777,13 @@ impl TerminalView {
|
||||
active_block.is_active_and_long_running()
|
||||
&& active_block.ai_conversation_id() == Some(conversation_id)
|
||||
};
|
||||
let provider_run_is_active = self
|
||||
.ai_controller
|
||||
.as_ref(ctx)
|
||||
.has_active_provider_run(conversation_id);
|
||||
|
||||
(conversation_has_progress || command_is_monitored).then_some(conversation_id)
|
||||
(conversation_has_progress || command_is_monitored || provider_run_is_active)
|
||||
.then_some(conversation_id)
|
||||
}
|
||||
|
||||
fn user_write_ctrl_c_to_pty(&mut self, ctx: &mut ViewContext<Self>) {
|
||||
@@ -9081,13 +9096,19 @@ impl TerminalView {
|
||||
.active_conversation(self.view_id)
|
||||
.map(|conversation| conversation.id())
|
||||
});
|
||||
let status_bar = self.input.as_ref(ctx).agent_status_bar().clone();
|
||||
status_bar.update(ctx, |status_bar, ctx| {
|
||||
if let Some(conversation_id) = conversation_id {
|
||||
status_bar.handle_ctrl_c_for_conversation(conversation_id, ctx);
|
||||
} else {
|
||||
status_bar.handle_ctrl_c(ctx);
|
||||
}
|
||||
let Some(conversation_id) = conversation_id else {
|
||||
log::debug!("Stop agent requested, but AgentView has no active conversation identity");
|
||||
return;
|
||||
};
|
||||
// The status bar model can be stale or absent after the latest exchange completes. Clear
|
||||
// its activity UI immediately, then cancel through the controller's authoritative identity.
|
||||
self.input.update(ctx, |input, ctx| {
|
||||
input.agent_status_bar().update(ctx, |status_bar, ctx| {
|
||||
status_bar.cancel_conversation_for_terminal(conversation_id, ctx);
|
||||
});
|
||||
// The cancellation synchronously updates conversation status in the history model;
|
||||
// refresh the placeholder after that transition so it cannot remain on "Steer...".
|
||||
input.set_zero_state_hint_text(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ use crate::ai::blocklist::agent_view::{
|
||||
ExitAgentViewError,
|
||||
};
|
||||
use crate::ai::blocklist::block::cli_controller::UserTakeOverReason;
|
||||
use crate::ai::blocklist::block::status_bar::BlocklistAIStatusBarAction;
|
||||
use crate::ai::blocklist::{
|
||||
BlocklistAIHistoryEvent, BlocklistAIHistoryModel, InputConfig, InputType, ResponseStream,
|
||||
ResponseStreamId,
|
||||
@@ -5646,6 +5647,58 @@ fn ctrl_c_after_stop_takeover_cancels_conversation() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn status_bar_stop_cancels_conversation_after_exchange_finishes() {
|
||||
App::test((), |mut app| async move {
|
||||
initialize_app_for_terminal_view(&mut app);
|
||||
FeatureFlag::AgentView.set_enabled(true);
|
||||
let terminal = add_window_with_terminal(&mut app, None);
|
||||
|
||||
let conversation_id = terminal.update(&mut app, |view, ctx| {
|
||||
let conversation_id =
|
||||
BlocklistAIHistoryModel::handle(ctx).update(ctx, |history, ctx| {
|
||||
history.start_new_conversation(view.view_id, false, false, false, ctx)
|
||||
});
|
||||
let stream_id = ResponseStreamId::new_for_test();
|
||||
BlocklistAIHistoryModel::handle(ctx).update(ctx, |history, ctx| {
|
||||
history
|
||||
.conversation_mut(&conversation_id)
|
||||
.expect("conversation should exist")
|
||||
.append_reassigned_exchange(
|
||||
&stream_id,
|
||||
exchange_with_inputs(vec![]),
|
||||
view.view_id,
|
||||
ctx,
|
||||
)
|
||||
.expect("exchange should append");
|
||||
});
|
||||
let stream = ctx.add_model(|_| ResponseStream::new_for_test(stream_id.clone()));
|
||||
view.ai_controller.update(ctx, |controller, ctx| {
|
||||
controller.register_mock_stream_for_test(stream_id, conversation_id, stream, ctx);
|
||||
});
|
||||
conversation_id
|
||||
});
|
||||
|
||||
terminal.update(&mut app, |view, ctx| {
|
||||
view.input.update(ctx, |input, ctx| {
|
||||
input.agent_status_bar().update(ctx, |status_bar, ctx| {
|
||||
status_bar.handle_action(&BlocklistAIStatusBarAction::Stop, ctx);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
terminal.read(&app, |_, ctx| {
|
||||
assert_eq!(
|
||||
BlocklistAIHistoryModel::as_ref(ctx)
|
||||
.conversation(&conversation_id)
|
||||
.expect("conversation should exist")
|
||||
.status(),
|
||||
&ConversationStatus::Cancelled
|
||||
);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ctrl_c_after_transfer_takeover_does_not_cancel_conversation() {
|
||||
App::test((), |mut app| async move {
|
||||
|
||||
Reference in New Issue
Block a user