language_model: Add `supports_tools` method to `LanguageModel` (#27867)

Marshall Bowers created

This PR adds a new `supports_tools` method to the `LanguageModel` trait
to indicate whether a given model supports tool use.

Release Notes:

- N/A

Change summary

crates/language_model/src/fake_provider.rs          | 4 ++++
crates/language_model/src/language_model.rs         | 3 +++
crates/language_models/src/provider/anthropic.rs    | 4 ++++
crates/language_models/src/provider/bedrock.rs      | 4 ++++
crates/language_models/src/provider/cloud.rs        | 8 ++++++++
crates/language_models/src/provider/copilot_chat.rs | 9 +++++++++
crates/language_models/src/provider/deepseek.rs     | 4 ++++
crates/language_models/src/provider/google.rs       | 4 ++++
crates/language_models/src/provider/lmstudio.rs     | 4 ++++
crates/language_models/src/provider/mistral.rs      | 4 ++++
crates/language_models/src/provider/ollama.rs       | 4 ++++
crates/language_models/src/provider/open_ai.rs      | 4 ++++
12 files changed, 56 insertions(+)

Detailed changes

crates/language_model/src/fake_provider.rs 🔗

@@ -153,6 +153,10 @@ impl LanguageModel for FakeLanguageModel {
         provider_name()
     }
 
+    fn supports_tools(&self) -> bool {
+        false
+    }
+
     fn telemetry_id(&self) -> String {
         "fake".to_string()
     }

crates/language_model/src/language_model.rs 🔗

@@ -185,6 +185,9 @@ pub trait LanguageModel: Send + Sync {
         LanguageModelAvailability::Public
     }
 
+    /// Whether this model supports tools.
+    fn supports_tools(&self) -> bool;
+
     fn tool_input_format(&self) -> LanguageModelToolSchemaFormat {
         LanguageModelToolSchemaFormat::JsonSchema
     }

crates/language_models/src/provider/anthropic.rs 🔗

@@ -400,6 +400,10 @@ impl LanguageModel for AnthropicModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        true
+    }
+
     fn telemetry_id(&self) -> String {
         format!("anthropic/{}", self.model.id())
     }

crates/language_models/src/provider/bedrock.rs 🔗

@@ -365,6 +365,10 @@ impl LanguageModel for BedrockModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        true
+    }
+
     fn telemetry_id(&self) -> String {
         format!("bedrock/{}", self.model.id())
     }

crates/language_models/src/provider/cloud.rs 🔗

@@ -557,6 +557,14 @@ impl LanguageModel for CloudLanguageModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        match self.model {
+            CloudModel::Anthropic(_) => true,
+            CloudModel::Google(_) => true,
+            CloudModel::OpenAi(_) => false,
+        }
+    }
+
     fn telemetry_id(&self) -> String {
         format!("zed.dev/{}", self.model.id())
     }

crates/language_models/src/provider/copilot_chat.rs 🔗

@@ -180,6 +180,15 @@ impl LanguageModel for CopilotChatLanguageModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        match self.model {
+            CopilotChatModel::Claude3_5Sonnet
+            | CopilotChatModel::Claude3_7Sonnet
+            | CopilotChatModel::Claude3_7SonnetThinking => true,
+            _ => false,
+        }
+    }
+
     fn telemetry_id(&self) -> String {
         format!("copilot_chat/{}", self.model.id())
     }

crates/language_models/src/provider/deepseek.rs 🔗

@@ -279,6 +279,10 @@ impl LanguageModel for DeepSeekLanguageModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        false
+    }
+
     fn telemetry_id(&self) -> String {
         format!("deepseek/{}", self.model.id())
     }

crates/language_models/src/provider/google.rs 🔗

@@ -296,6 +296,10 @@ impl LanguageModel for GoogleLanguageModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        true
+    }
+
     fn tool_input_format(&self) -> LanguageModelToolSchemaFormat {
         LanguageModelToolSchemaFormat::JsonSchemaSubset
     }

crates/language_models/src/provider/lmstudio.rs 🔗

@@ -273,6 +273,10 @@ impl LanguageModel for LmStudioLanguageModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        false
+    }
+
     fn telemetry_id(&self) -> String {
         format!("lmstudio/{}", self.model.id())
     }

crates/language_models/src/provider/mistral.rs 🔗

@@ -291,6 +291,10 @@ impl LanguageModel for MistralLanguageModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        false
+    }
+
     fn telemetry_id(&self) -> String {
         format!("mistral/{}", self.model.id())
     }

crates/language_models/src/provider/ollama.rs 🔗

@@ -300,6 +300,10 @@ impl LanguageModel for OllamaLanguageModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        false
+    }
+
     fn telemetry_id(&self) -> String {
         format!("ollama/{}", self.model.id())
     }

crates/language_models/src/provider/open_ai.rs 🔗

@@ -290,6 +290,10 @@ impl LanguageModel for OpenAiLanguageModel {
         LanguageModelProviderName(PROVIDER_NAME.into())
     }
 
+    fn supports_tools(&self) -> bool {
+        false
+    }
+
     fn telemetry_id(&self) -> String {
         format!("openai/{}", self.model.id())
     }