assistant2: Add button to open the prompt library (#23500)

Marshall Bowers created

This PR adds a button to open the prompt library from the configuration
view in Assistant2.

<img width="1309" alt="Screenshot 2025-01-22 at 5 38 08 PM"
src="https://github.com/user-attachments/assets/d514abca-53bc-4cde-bead-ab68a1994fb5"
/>

Release Notes:

- N/A

Change summary

crates/assistant/src/assistant.rs                |  1 
crates/assistant/src/assistant_panel.rs          |  5 
crates/assistant2/src/assistant_configuration.rs | 16 ++++
crates/assistant2/src/assistant_panel.rs         | 63 ++++++++++++++++-
crates/zed_actions/src/lib.rs                    |  2 
5 files changed, 76 insertions(+), 11 deletions(-)

Detailed changes

crates/assistant/src/assistant.rs 🔗

@@ -33,7 +33,6 @@ actions!(
     [
         InsertActivePrompt,
         DeployHistory,
-        DeployPromptLibrary,
         NewContext,
         CycleNextInlineAssist,
         CyclePreviousInlineAssist

crates/assistant/src/assistant_panel.rs 🔗

@@ -1,7 +1,6 @@
 use crate::assistant_configuration::{ConfigurationView, ConfigurationViewEvent};
 use crate::{
-    terminal_inline_assistant::TerminalInlineAssistant, DeployHistory, DeployPromptLibrary,
-    InlineAssistant, NewContext,
+    terminal_inline_assistant::TerminalInlineAssistant, DeployHistory, InlineAssistant, NewContext,
 };
 use anyhow::{anyhow, Result};
 use assistant_context_editor::{
@@ -38,7 +37,7 @@ use workspace::{
     dock::{DockPosition, Panel, PanelEvent},
     pane, DraggedSelection, Pane, ShowConfiguration, ToggleZoom, Workspace,
 };
-use zed_actions::assistant::{InlineAssist, ToggleFocus};
+use zed_actions::assistant::{DeployPromptLibrary, InlineAssist, ToggleFocus};
 
 pub fn init(cx: &mut AppContext) {
     workspace::FollowableViewRegistry::register::<ContextEditor>(cx);

crates/assistant2/src/assistant_configuration.rs 🔗

@@ -1,9 +1,10 @@
 use std::sync::Arc;
 
 use collections::HashMap;
-use gpui::{AnyView, AppContext, EventEmitter, FocusHandle, FocusableView, Subscription};
+use gpui::{Action, AnyView, AppContext, EventEmitter, FocusHandle, FocusableView, Subscription};
 use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry};
 use ui::{prelude::*, ElevationIndex};
+use zed_actions::assistant::DeployPromptLibrary;
 
 pub struct AssistantConfiguration {
     focus_handle: FocusHandle,
@@ -143,6 +144,19 @@ impl Render for AssistantConfiguration {
             .bg(cx.theme().colors().editor_background)
             .size_full()
             .overflow_y_scroll()
+            .child(
+                h_flex().p(DynamicSpacing::Base16.rems(cx)).child(
+                    Button::new("open-prompt-library", "Open Prompt Library")
+                        .style(ButtonStyle::Filled)
+                        .full_width()
+                        .icon(IconName::Book)
+                        .icon_size(IconSize::Small)
+                        .icon_position(IconPosition::Start)
+                        .on_click(|_event, cx| {
+                            cx.dispatch_action(DeployPromptLibrary.boxed_clone())
+                        }),
+                ),
+            )
             .child(
                 v_flex()
                     .p(DynamicSpacing::Base16.rems(cx))

crates/assistant2/src/assistant_panel.rs 🔗

@@ -4,28 +4,30 @@ use std::sync::Arc;
 use anyhow::{anyhow, Result};
 use assistant_context_editor::{
     make_lsp_adapter_delegate, AssistantPanelDelegate, ContextEditor, ContextHistory,
+    SlashCommandCompletionProvider,
 };
 use assistant_settings::{AssistantDockPosition, AssistantSettings};
 use assistant_slash_command::SlashCommandWorkingSet;
 use assistant_tool::ToolWorkingSet;
 use client::zed_urls;
+use editor::Editor;
 use fs::Fs;
 use gpui::{
     prelude::*, px, svg, Action, AnyElement, AppContext, AsyncWindowContext, Corner, EventEmitter,
-    FocusHandle, FocusableView, FontWeight, Model, Pixels, Subscription, Task, View, ViewContext,
-    WeakView, WindowContext,
+    FocusHandle, FocusableView, FontWeight, Model, Pixels, Subscription, Task, UpdateGlobal, View,
+    ViewContext, WeakView, WindowContext,
 };
 use language::LanguageRegistry;
 use language_model::LanguageModelRegistry;
 use project::Project;
-use prompt_library::PromptBuilder;
+use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};
 use settings::{update_settings_file, Settings};
 use time::UtcOffset;
 use ui::{prelude::*, ContextMenu, KeyBinding, PopoverMenu, PopoverMenuHandle, Tab, Tooltip};
 use util::ResultExt as _;
 use workspace::dock::{DockPosition, Panel, PanelEvent};
 use workspace::Workspace;
-use zed_actions::assistant::ToggleFocus;
+use zed_actions::assistant::{DeployPromptLibrary, ToggleFocus};
 
 use crate::active_thread::ActiveThread;
 use crate::assistant_configuration::{AssistantConfiguration, AssistantConfigurationEvent};
@@ -33,7 +35,10 @@ use crate::message_editor::MessageEditor;
 use crate::thread::{Thread, ThreadError, ThreadId};
 use crate::thread_history::{PastThread, ThreadHistory};
 use crate::thread_store::ThreadStore;
-use crate::{NewPromptEditor, NewThread, OpenConfiguration, OpenHistory, OpenPromptEditorHistory};
+use crate::{
+    InlineAssistant, NewPromptEditor, NewThread, OpenConfiguration, OpenHistory,
+    OpenPromptEditorHistory,
+};
 
 pub fn init(cx: &mut AppContext) {
     cx.observe_new_views(
@@ -280,6 +285,22 @@ impl AssistantPanel {
         }
     }
 
+    fn deploy_prompt_library(&mut self, _: &DeployPromptLibrary, cx: &mut ViewContext<Self>) {
+        open_prompt_library(
+            self.language_registry.clone(),
+            Box::new(PromptLibraryInlineAssist::new(self.workspace.clone())),
+            Arc::new(|| {
+                Box::new(SlashCommandCompletionProvider::new(
+                    Arc::new(SlashCommandWorkingSet::default()),
+                    None,
+                    None,
+                ))
+            }),
+            cx,
+        )
+        .detach_and_log_err(cx);
+    }
+
     fn open_history(&mut self, cx: &mut ViewContext<Self>) {
         self.active_view = ActiveView::History;
         self.history.focus_handle(cx).focus(cx);
@@ -857,6 +878,7 @@ impl Render for AssistantPanel {
             .on_action(cx.listener(|this, _: &OpenHistory, cx| {
                 this.open_history(cx);
             }))
+            .on_action(cx.listener(Self::deploy_prompt_library))
             .child(self.render_toolbar(cx))
             .map(|parent| match self.active_view {
                 ActiveView::Thread => parent
@@ -876,6 +898,37 @@ impl Render for AssistantPanel {
     }
 }
 
+struct PromptLibraryInlineAssist {
+    workspace: WeakView<Workspace>,
+}
+
+impl PromptLibraryInlineAssist {
+    pub fn new(workspace: WeakView<Workspace>) -> Self {
+        Self { workspace }
+    }
+}
+
+impl prompt_library::InlineAssistDelegate for PromptLibraryInlineAssist {
+    fn assist(
+        &self,
+        prompt_editor: &View<Editor>,
+        _initial_prompt: Option<String>,
+        cx: &mut ViewContext<PromptLibrary>,
+    ) {
+        InlineAssistant::update_global(cx, |assistant, cx| {
+            assistant.assist(&prompt_editor, self.workspace.clone(), None, cx)
+        })
+    }
+
+    fn focus_assistant_panel(
+        &self,
+        workspace: &mut Workspace,
+        cx: &mut ViewContext<Workspace>,
+    ) -> bool {
+        workspace.focus_panel::<AssistantPanel>(cx).is_some()
+    }
+}
+
 pub struct ConcreteAssistantPanelDelegate;
 
 impl AssistantPanelDelegate for ConcreteAssistantPanelDelegate {

crates/zed_actions/src/lib.rs 🔗

@@ -82,7 +82,7 @@ pub mod assistant {
     use schemars::JsonSchema;
     use serde::Deserialize;
 
-    actions!(assistant, [ToggleFocus]);
+    actions!(assistant, [ToggleFocus, DeployPromptLibrary]);
 
     #[derive(Clone, Default, Deserialize, PartialEq, JsonSchema)]
     pub struct InlineAssist {