From 8b8335f4491d154944a0a3d72b9c42b2a7a6afa3 Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Wed, 14 Aug 2024 11:18:40 +0200 Subject: [PATCH] assistant panel: Stop animation & show explicit state if canceled (#16200) This fixes a bug by stopping the animation when a completion is canceled and it also makes the state more explicit, which I think is very valuable. https://github.com/user-attachments/assets/9ede9b25-86ac-4901-8434-7407896bb799 Release Notes: - N/A --- crates/assistant/src/assistant.rs | 7 +++ crates/assistant/src/assistant_panel.rs | 83 ++++++++++++++++--------- crates/assistant/src/context.rs | 13 +++- crates/proto/proto/zed.proto | 3 + 4 files changed, 75 insertions(+), 31 deletions(-) diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs index 3e4bcac69d..3b9941e9ed 100644 --- a/crates/assistant/src/assistant.rs +++ b/crates/assistant/src/assistant.rs @@ -102,6 +102,7 @@ pub enum MessageStatus { Pending, Done, Error(SharedString), + Canceled, } impl MessageStatus { @@ -112,6 +113,7 @@ impl MessageStatus { Some(proto::context_message_status::Variant::Error(error)) => { MessageStatus::Error(error.message.into()) } + Some(proto::context_message_status::Variant::Canceled(_)) => MessageStatus::Canceled, None => MessageStatus::Pending, } } @@ -135,6 +137,11 @@ impl MessageStatus { }, )), }, + MessageStatus::Canceled => proto::ContextMessageStatus { + variant: Some(proto::context_message_status::Variant::Canceled( + proto::context_message_status::Canceled {}, + )), + }, } } } diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 2ab0287a6d..be2ec6d58b 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -1975,7 +1975,7 @@ impl ContextEditor { fn cancel(&mut self, _: &editor::actions::Cancel, cx: &mut ViewContext) { if self .context - .update(cx, |context, _| context.cancel_last_assist()) + .update(cx, |context, cx| context.cancel_last_assist(cx)) { return; } @@ -3042,22 +3042,6 @@ impl ContextEditor { } }); - let trigger = Button::new("show-error", "Error") - .color(Color::Error) - .selected_label_color(Color::Error) - .selected_icon_color(Color::Error) - .icon(IconName::XCircle) - .icon_color(Color::Error) - .icon_size(IconSize::Small) - .icon_position(IconPosition::Start) - .tooltip(move |cx| { - Tooltip::with_meta( - "Error interacting with language model", - None, - "Click for more details", - cx, - ) - }); h_flex() .id(("message_header", message_id.as_u64())) .pl(cx.gutter_dimensions.full_width()) @@ -3066,22 +3050,63 @@ impl ContextEditor { .relative() .gap_1() .child(sender) - .children( - if let MessageStatus::Error(error) = message.status.clone() { + .children(match &message.status { + MessageStatus::Error(error) => { + let error_popover_trigger = + Button::new("show-error", "Error") + .color(Color::Error) + .selected_label_color(Color::Error) + .selected_icon_color(Color::Error) + .icon(IconName::XCircle) + .icon_color(Color::Error) + .icon_size(IconSize::Small) + .icon_position(IconPosition::Start) + .tooltip(move |cx| { + Tooltip::with_meta( + "Error interacting with language model", + None, + "Click for more details", + cx, + ) + }); + Some( PopoverMenu::new("show-error-popover") - .menu(move |cx| { - Some(cx.new_view(|cx| ErrorPopover { - error: error.clone(), - focus_handle: cx.focus_handle(), - })) + .menu({ + let error = error.clone(); + move |cx| { + Some(cx.new_view(|cx| ErrorPopover { + error: error.clone(), + focus_handle: cx.focus_handle(), + })) + } }) - .trigger(trigger), + .trigger(error_popover_trigger) + .into_any_element(), ) - } else { - None - }, - ) + } + MessageStatus::Canceled => Some( + ButtonLike::new("canceled") + .child( + Icon::new(IconName::XCircle).color(Color::Disabled), + ) + .child( + Label::new("Canceled") + .size(LabelSize::Small) + .color(Color::Disabled), + ) + .tooltip(move |cx| { + Tooltip::with_meta( + "Canceled", + None, + "Interaction with the assistant was canceled", + cx, + ) + }) + .into_any_element(), + ), + _ => None, + }) .into_any_element() } }), diff --git a/crates/assistant/src/context.rs b/crates/assistant/src/context.rs index 3aa0629848..ca57bd86dd 100644 --- a/crates/assistant/src/context.rs +++ b/crates/assistant/src/context.rs @@ -401,6 +401,7 @@ impl PartialEq for ImageAnchor { struct PendingCompletion { id: usize, + assistant_message_id: MessageId, _task: Task<()>, } @@ -1806,6 +1807,7 @@ impl Context { self.pending_completions.push(PendingCompletion { id: post_inc(&mut self.completion_count), + assistant_message_id: assistant_message.id, _task: task, }); @@ -1827,8 +1829,15 @@ impl Context { } } - pub fn cancel_last_assist(&mut self) -> bool { - self.pending_completions.pop().is_some() + pub fn cancel_last_assist(&mut self, cx: &mut ModelContext) -> bool { + if let Some(pending_completion) = self.pending_completions.pop() { + self.update_metadata(pending_completion.assistant_message_id, cx, |metadata| { + metadata.status = MessageStatus::Canceled; + }); + true + } else { + false + } } pub fn cycle_message_roles(&mut self, ids: HashSet, cx: &mut ModelContext) { diff --git a/crates/proto/proto/zed.proto b/crates/proto/proto/zed.proto index 299337d6c2..a78f6dca07 100644 --- a/crates/proto/proto/zed.proto +++ b/crates/proto/proto/zed.proto @@ -2310,6 +2310,7 @@ message ContextMessageStatus { Done done = 1; Pending pending = 2; Error error = 3; + Canceled canceled = 4; } message Done {} @@ -2319,6 +2320,8 @@ message ContextMessageStatus { message Error { string message = 1; } + + message Canceled {} } message ContextMessage {