agent: Only show compatible tools in profile selector (#40917)

Bennet Fenner created

In practice this just hides the web search tool when not using the Zed
provider

Release Notes:

- Fixed an issue where the web search tool would show up in the profile
selector even when not using a model via Zed Pro

Change summary

crates/agent/src/thread.rs                                       | 10 
crates/agent/src/tools.rs                                        | 10 
crates/agent/src/tools/web_search_tool.rs                        |  2 
crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs | 19 +
4 files changed, 29 insertions(+), 12 deletions(-)

Detailed changes

crates/agent/src/thread.rs 🔗

@@ -1857,7 +1857,7 @@ impl Thread {
             .tools
             .iter()
             .filter_map(|(tool_name, tool)| {
-                if tool.supported_provider(&model.provider_id())
+                if tool.supports_provider(&model.provider_id())
                     && profile.is_tool_enabled(tool_name)
                 {
                     Some((truncate(tool_name), tool.clone()))
@@ -2133,7 +2133,7 @@ where
 
     /// Some tools rely on a provider for the underlying billing or other reasons.
     /// Allow the tool to check if they are compatible, or should be filtered out.
-    fn supported_provider(&self, _provider: &LanguageModelProviderId) -> bool {
+    fn supports_provider(_provider: &LanguageModelProviderId) -> bool {
         true
     }
 
@@ -2174,7 +2174,7 @@ pub trait AnyAgentTool {
     fn kind(&self) -> acp::ToolKind;
     fn initial_title(&self, input: serde_json::Value, _cx: &mut App) -> SharedString;
     fn input_schema(&self, format: LanguageModelToolSchemaFormat) -> Result<serde_json::Value>;
-    fn supported_provider(&self, _provider: &LanguageModelProviderId) -> bool {
+    fn supports_provider(&self, _provider: &LanguageModelProviderId) -> bool {
         true
     }
     fn run(
@@ -2219,8 +2219,8 @@ where
         Ok(json)
     }
 
-    fn supported_provider(&self, provider: &LanguageModelProviderId) -> bool {
-        self.0.supported_provider(provider)
+    fn supports_provider(&self, provider: &LanguageModelProviderId) -> bool {
+        T::supports_provider(provider)
     }
 
     fn run(

crates/agent/src/tools.rs 🔗

@@ -40,13 +40,19 @@ pub use web_search_tool::*;
 macro_rules! tools {
     ($($tool:ty),* $(,)?) => {
         /// A list of all built-in tool names
-        pub fn built_in_tool_names() -> impl Iterator<Item = String> {
+        pub fn supported_built_in_tool_names(provider: Option<language_model::LanguageModelProviderId>) -> impl Iterator<Item = String> {
             [
                 $(
-                    <$tool>::name().to_string(),
+                    (if let Some(provider) = provider.as_ref() {
+                        <$tool>::supports_provider(provider)
+                    } else {
+                        true
+                    })
+                    .then(|| <$tool>::name().to_string()),
                 )*
             ]
             .into_iter()
+            .flatten()
         }
 
         /// A list of all built-in tools

crates/agent/src/tools/web_search_tool.rs 🔗

@@ -57,7 +57,7 @@ impl AgentTool for WebSearchTool {
     }
 
     /// We currently only support Zed Cloud as a provider.
-    fn supported_provider(&self, provider: &LanguageModelProviderId) -> bool {
+    fn supports_provider(provider: &LanguageModelProviderId) -> bool {
         provider == &ZED_CLOUD_PROVIDER_ID
     }
 

crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs 🔗

@@ -7,6 +7,7 @@ use agent_settings::{AgentProfile, AgentProfileId, AgentSettings, builtin_profil
 use editor::Editor;
 use fs::Fs;
 use gpui::{DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Subscription, prelude::*};
+use language_model::LanguageModel;
 use settings::Settings as _;
 use ui::{
     KeyBinding, ListItem, ListItemSpacing, ListSeparator, Navigable, NavigableEntry, prelude::*,
@@ -96,6 +97,7 @@ pub struct NewProfileMode {
 pub struct ManageProfilesModal {
     fs: Arc<dyn Fs>,
     context_server_registry: Entity<ContextServerRegistry>,
+    active_model: Option<Arc<dyn LanguageModel>>,
     focus_handle: FocusHandle,
     mode: Mode,
 }
@@ -109,9 +111,14 @@ impl ManageProfilesModal {
         workspace.register_action(|workspace, action: &ManageProfiles, window, cx| {
             if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
                 let fs = workspace.app_state().fs.clone();
+                let active_model = panel
+                    .read(cx)
+                    .active_native_agent_thread(cx)
+                    .and_then(|thread| thread.read(cx).model().cloned());
+
                 let context_server_registry = panel.read(cx).context_server_registry().clone();
                 workspace.toggle_modal(window, cx, |window, cx| {
-                    let mut this = Self::new(fs, context_server_registry, window, cx);
+                    let mut this = Self::new(fs, active_model, context_server_registry, window, cx);
 
                     if let Some(profile_id) = action.customize_tools.clone() {
                         this.configure_builtin_tools(profile_id, window, cx);
@@ -125,6 +132,7 @@ impl ManageProfilesModal {
 
     pub fn new(
         fs: Arc<dyn Fs>,
+        active_model: Option<Arc<dyn LanguageModel>>,
         context_server_registry: Entity<ContextServerRegistry>,
         window: &mut Window,
         cx: &mut Context<Self>,
@@ -133,6 +141,7 @@ impl ManageProfilesModal {
 
         Self {
             fs,
+            active_model,
             context_server_registry,
             focus_handle,
             mode: Mode::choose_profile(window, cx),
@@ -228,9 +237,11 @@ impl ManageProfilesModal {
         let tool_picker = cx.new(|cx| {
             let delegate = ToolPickerDelegate::builtin_tools(
                 //todo: This causes the web search tool to show up even it only works when using zed hosted models
-                agent::built_in_tool_names()
-                    .map(|s| s.into())
-                    .collect::<Vec<_>>(),
+                agent::supported_built_in_tool_names(
+                    self.active_model.as_ref().map(|model| model.provider_id()),
+                )
+                .map(|s| s.into())
+                .collect::<Vec<_>>(),
                 self.fs.clone(),
                 profile_id.clone(),
                 profile,