x_ai: Add support for tools and images with custom models (#38792)

Jowell Young created

After the change, we can add "supports_images", "supports_tools" and
"parallel_tool_calls" properties to set up new models. Our
`settings.json` will be as follows:
```json
  "language_models": {
     "x_ai": {
       "api_url": "https://api.x.ai/v1",
       "available_models": [
         {
           "name": "grok-4-fast-reasoning",
           "display_name": "Grok 4 Fast Reasoning",
           "max_tokens": 2000000,
           "max_output_tokens": 64000,
           "supports_tools": true,
           "parallel_tool_calls": true,
         },
         {
           "name": "grok-4-fast-non-reasoning",
           "display_name": "Grok 4 Fast Non-Reasoning",
           "max_tokens": 2000000,
           "max_output_tokens": 64000,
           "supports_images": true,
         }
       ]
     }
   }

```

Closes https://github.com/zed-industries/zed/issues/38752

Release Notes:

- xAI: Added support for for configuring tool and image support for
custom model configurations

Change summary

crates/language_models/src/provider/x_ai.rs            |  3 +
crates/settings/src/settings_content/language_model.rs |  3 +
crates/x_ai/src/x_ai.rs                                | 20 +++++++++++
3 files changed, 25 insertions(+), 1 deletion(-)

Detailed changes

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

@@ -158,6 +158,9 @@ impl LanguageModelProvider for XAiLanguageModelProvider {
                     max_tokens: model.max_tokens,
                     max_output_tokens: model.max_output_tokens,
                     max_completion_tokens: model.max_completion_tokens,
+                    supports_images: model.supports_images,
+                    supports_tools: model.supports_tools,
+                    parallel_tool_calls: model.parallel_tool_calls,
                 },
             );
         }

crates/settings/src/settings_content/language_model.rs 🔗

@@ -301,6 +301,9 @@ pub struct XaiAvailableModel {
     pub max_tokens: u64,
     pub max_output_tokens: Option<u64>,
     pub max_completion_tokens: Option<u64>,
+    pub supports_images: Option<bool>,
+    pub supports_tools: Option<bool>,
+    pub parallel_tool_calls: Option<bool>,
 }
 
 #[skip_serializing_none]

crates/x_ai/src/x_ai.rs 🔗

@@ -30,6 +30,9 @@ pub enum Model {
         max_tokens: u64,
         max_output_tokens: Option<u64>,
         max_completion_tokens: Option<u64>,
+        supports_images: Option<bool>,
+        supports_tools: Option<bool>,
+        parallel_tool_calls: Option<bool>,
     },
 }
 
@@ -107,6 +110,10 @@ impl Model {
             | Self::Grok3Fast
             | Self::Grok3MiniFast
             | Self::Grok4 => true,
+            Self::Custom {
+                parallel_tool_calls: Some(support),
+                ..
+            } => *support,
             Self::GrokCodeFast1 | Model::Custom { .. } => false,
         }
     }
@@ -124,11 +131,22 @@ impl Model {
             | Self::Grok3MiniFast
             | Self::Grok4
             | Self::GrokCodeFast1 => true,
+            Self::Custom {
+                supports_tools: Some(support),
+                ..
+            } => *support,
             Model::Custom { .. } => false,
         }
     }
 
     pub fn supports_images(&self) -> bool {
-        matches!(self, Self::Grok2Vision)
+        match self {
+            Self::Grok2Vision => true,
+            Self::Custom {
+                supports_images: Some(support),
+                ..
+            } => *support,
+            _ => false,
+        }
     }
 }