assistant2: Add a way to quickly configure tools for the current profile (#27714)

Marshall Bowers created

This PR adds a new entry to the profile selector to quickly access tool
customization for the current profile:

<img width="228" alt="Screenshot 2025-03-28 at 7 08 51 PM"
src="https://github.com/user-attachments/assets/929ae5e7-5a16-4bf2-8043-6c09b621fc61"
/>

Release Notes:

- N/A

Change summary

Cargo.lock                                                             |  1 
crates/assistant2/Cargo.toml                                           |  1 
crates/assistant2/src/assistant.rs                                     | 21 
crates/assistant2/src/assistant_configuration/manage_profiles_modal.rs | 10 
crates/assistant2/src/profile_selector.rs                              | 16 
5 files changed, 43 insertions(+), 6 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -493,6 +493,7 @@ dependencies = [
  "rand 0.8.5",
  "release_channel",
  "rope",
+ "schemars",
  "serde",
  "serde_json",
  "settings",

crates/assistant2/Cargo.toml 🔗

@@ -65,6 +65,7 @@ prompt_store.workspace = true
 proto.workspace = true
 release_channel.workspace = true
 rope.workspace = true
+schemars.workspace = true
 serde.workspace = true
 serde_json.workspace = true
 settings.workspace = true

crates/assistant2/src/assistant.rs 🔗

@@ -28,8 +28,10 @@ use client::Client;
 use command_palette_hooks::CommandPaletteFilter;
 use feature_flags::{Assistant2FeatureFlag, FeatureFlagAppExt};
 use fs::Fs;
-use gpui::{actions, App};
+use gpui::{actions, impl_actions, App};
 use prompt_store::PromptBuilder;
+use schemars::JsonSchema;
+use serde::Deserialize;
 use settings::Settings as _;
 
 pub use crate::active_thread::ActiveThread;
@@ -50,7 +52,6 @@ actions!(
         RemoveAllContext,
         OpenHistory,
         OpenConfiguration,
-        ManageProfiles,
         AddContextServer,
         RemoveSelectedThread,
         Chat,
@@ -69,6 +70,22 @@ actions!(
     ]
 );
 
+#[derive(PartialEq, Clone, Default, Debug, Deserialize, JsonSchema)]
+pub struct ManageProfiles {
+    #[serde(default)]
+    pub customize_tools: Option<Arc<str>>,
+}
+
+impl ManageProfiles {
+    pub fn customize_tools(profile_id: Arc<str>) -> Self {
+        Self {
+            customize_tools: Some(profile_id),
+        }
+    }
+}
+
+impl_actions!(assistant, [ManageProfiles]);
+
 const NAMESPACE: &str = "assistant2";
 
 /// Initializes the `assistant2` crate.

crates/assistant2/src/assistant_configuration/manage_profiles_modal.rs 🔗

@@ -98,14 +98,20 @@ impl ManageProfilesModal {
         _window: Option<&mut Window>,
         _cx: &mut Context<Workspace>,
     ) {
-        workspace.register_action(|workspace, _: &ManageProfiles, window, cx| {
+        workspace.register_action(|workspace, action: &ManageProfiles, window, cx| {
             if let Some(panel) = workspace.panel::<AssistantPanel>(cx) {
                 let fs = workspace.app_state().fs.clone();
                 let thread_store = panel.read(cx).thread_store();
                 let tools = thread_store.read(cx).tools();
                 let thread_store = thread_store.downgrade();
                 workspace.toggle_modal(window, cx, |window, cx| {
-                    Self::new(fs, tools, thread_store, window, cx)
+                    let mut this = Self::new(fs, tools, thread_store, window, cx);
+
+                    if let Some(profile_id) = action.customize_tools.clone() {
+                        this.configure_tools(profile_id, window, cx);
+                    }
+
+                    this
                 })
             }
         });

crates/assistant2/src/profile_selector.rs 🔗

@@ -94,9 +94,21 @@ impl ProfileSelector {
             }
 
             menu = menu.separator();
-            menu = menu.item(ContextMenuEntry::new("Configure Profiles").handler(
+            menu = menu.header("Customize Current Profile");
+            menu = menu.item(ContextMenuEntry::new("Tools…").handler({
+                let profile_id = settings.default_profile.clone();
                 move |window, cx| {
-                    window.dispatch_action(ManageProfiles.boxed_clone(), cx);
+                    window.dispatch_action(
+                        ManageProfiles::customize_tools(profile_id.clone()).boxed_clone(),
+                        cx,
+                    );
+                }
+            }));
+
+            menu = menu.separator();
+            menu = menu.item(ContextMenuEntry::new("Configure Profiles…").handler(
+                move |window, cx| {
+                    window.dispatch_action(ManageProfiles::default().boxed_clone(), cx);
                 },
             ));