diff --git a/crates/agent/src/active_thread.rs b/crates/agent/src/active_thread.rs index d02839b750bff8acfa6f9e9b14c6c3161767551b..64b9f4cd799599baa33ba0b4a6fd4f5aa4059a37 100644 --- a/crates/agent/src/active_thread.rs +++ b/crates/agent/src/active_thread.rs @@ -55,6 +55,8 @@ pub struct ActiveThread { notifications: Vec>, _subscriptions: Vec, notification_subscriptions: HashMap, Vec>, + showing_feedback_comments: bool, + feedback_comments_editor: Option>, } struct RenderedMessage { @@ -369,6 +371,8 @@ impl ActiveThread { notifications: Vec::new(), _subscriptions: subscriptions, notification_subscriptions: HashMap::default(), + showing_feedback_comments: false, + feedback_comments_editor: None, }; for message in thread.read(cx).messages().cloned().collect::>() { @@ -896,19 +900,100 @@ impl ActiveThread { fn handle_feedback_click( &mut self, feedback: ThreadFeedback, + window: &mut Window, + cx: &mut Context, + ) { + match feedback { + ThreadFeedback::Positive => { + let report = self + .thread + .update(cx, |thread, cx| thread.report_feedback(feedback, cx)); + + let this = cx.entity().downgrade(); + cx.spawn(async move |_, cx| { + report.await?; + this.update(cx, |_this, cx| cx.notify()) + }) + .detach_and_log_err(cx); + } + ThreadFeedback::Negative => { + self.handle_show_feedback_comments(window, cx); + } + } + } + + fn handle_show_feedback_comments(&mut self, window: &mut Window, cx: &mut Context) { + self.showing_feedback_comments = true; + + if self.feedback_comments_editor.is_none() { + let buffer = cx.new(|cx| { + let empty_string = String::new(); + MultiBuffer::singleton(cx.new(|cx| Buffer::local(empty_string, cx)), cx) + }); + + let editor = cx.new(|cx| { + Editor::new( + editor::EditorMode::AutoHeight { max_lines: 4 }, + buffer, + None, + window, + cx, + ) + }); + + self.feedback_comments_editor = Some(editor); + } + + cx.notify(); + } + + fn handle_submit_comments( + &mut self, + _: &ClickEvent, _window: &mut Window, cx: &mut Context, ) { - let report = self - .thread - .update(cx, |thread, cx| thread.report_feedback(feedback, cx)); + if let Some(editor) = self.feedback_comments_editor.clone() { + let comments = editor.read(cx).text(cx); - let this = cx.entity().downgrade(); - cx.spawn(async move |_, cx| { - report.await?; - this.update(cx, |_this, cx| cx.notify()) - }) - .detach_and_log_err(cx); + // Submit negative feedback + let report = self.thread.update(cx, |thread, cx| { + thread.report_feedback(ThreadFeedback::Negative, cx) + }); + + if !comments.is_empty() { + let thread_id = self.thread.read(cx).id().clone(); + let comments_value = String::from(comments.as_str()); + + // Log comments as a separate telemetry event + telemetry::event!( + "Assistant Thread Feedback Comments", + thread_id, + comments = comments_value + ); + } + + self.showing_feedback_comments = false; + self.feedback_comments_editor = None; + + let this = cx.entity().downgrade(); + cx.spawn(async move |_, cx| { + report.await?; + this.update(cx, |_this, cx| cx.notify()) + }) + .detach_and_log_err(cx); + } + } + + fn handle_cancel_comments( + &mut self, + _: &ClickEvent, + _window: &mut Window, + cx: &mut Context, + ) { + self.showing_feedback_comments = false; + self.feedback_comments_editor = None; + cx.notify(); } fn render_message(&self, ix: usize, window: &mut Window, cx: &mut Context) -> AnyElement { @@ -1318,7 +1403,53 @@ impl ActiveThread { .child(styled_message) .when( show_feedback && !self.thread.read(cx).is_generating(), - |parent| parent.child(feedback_items), + |parent| { + parent + .child(feedback_items) + .when(self.showing_feedback_comments, |parent| { + parent.child( + v_flex() + .gap_1() + .px_4() + .child( + Label::new( + "Please share your feedback to help us improve:", + ) + .size(LabelSize::Small), + ) + .child( + div() + .p_2() + .rounded_md() + .border_1() + .border_color(cx.theme().colors().border) + .bg(cx.theme().colors().editor_background) + .child( + self.feedback_comments_editor + .as_ref() + .unwrap() + .clone(), + ), + ) + .child( + h_flex() + .gap_1() + .justify_end() + .pb_2() + .child( + Button::new("cancel-comments", "Cancel").on_click( + cx.listener(Self::handle_cancel_comments), + ), + ) + .child( + Button::new("submit-comments", "Submit").on_click( + cx.listener(Self::handle_submit_comments), + ), + ), + ), + ) + }) + }, ) .into_any() }