Add support for Grok 4.1 Fast models in xAI provider (#43419)

Martin Bergo created

Release Notes:

- Added support for Grok 4.1 Fast (reasoning and non-reasoning) models
in the xAI provider, with 2M token context windows and full vision
capabilities.
- Extended 2M token context to existing Grok 4 Fast variants (from 128K)
for consistency with xAI updates.
- Enabled image/vision support for all Grok 4 family models.

Doc:
https://docs.x.ai/docs/models/grok-4-1-fast-reasoning
https://docs.x.ai/docs/models/grok-4-1-fast-non-reasoning

Change summary

crates/x_ai/src/x_ai.rs | 38 +++++++++++++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 3 deletions(-)

Detailed changes

crates/x_ai/src/x_ai.rs 🔗

@@ -30,6 +30,17 @@ pub enum Model {
         alias = "grok-4-fast-non-reasoning-latest"
     )]
     Grok4FastNonReasoning,
+    #[serde(
+        rename = "grok-4-1-fast-non-reasoning",
+        alias = "grok-4-1-fast-non-reasoning-latest"
+    )]
+    Grok41FastNonReasoning,
+    #[serde(
+        rename = "grok-4-1-fast-reasoning",
+        alias = "grok-4-1-fast-reasoning-latest",
+        alias = "grok-4-1-fast"
+    )]
+    Grok41FastReasoning,
     #[serde(rename = "grok-code-fast-1", alias = "grok-code-fast-1-0825")]
     GrokCodeFast1,
     #[serde(rename = "custom")]
@@ -56,6 +67,9 @@ impl Model {
             "grok-4" => Ok(Self::Grok4),
             "grok-4-fast-reasoning" => Ok(Self::Grok4FastReasoning),
             "grok-4-fast-non-reasoning" => Ok(Self::Grok4FastNonReasoning),
+            "grok-4-1-fast-non-reasoning" => Ok(Self::Grok41FastNonReasoning),
+            "grok-4-1-fast-reasoning" => Ok(Self::Grok41FastReasoning),
+            "grok-4-1-fast" => Ok(Self::Grok41FastReasoning),
             "grok-2-vision" => Ok(Self::Grok2Vision),
             "grok-3" => Ok(Self::Grok3),
             "grok-3-mini" => Ok(Self::Grok3Mini),
@@ -76,6 +90,8 @@ impl Model {
             Self::Grok4 => "grok-4",
             Self::Grok4FastReasoning => "grok-4-fast-reasoning",
             Self::Grok4FastNonReasoning => "grok-4-fast-non-reasoning",
+            Self::Grok41FastNonReasoning => "grok-4-1-fast-non-reasoning",
+            Self::Grok41FastReasoning => "grok-4-1-fast-reasoning",
             Self::GrokCodeFast1 => "grok-code-fast-1",
             Self::Custom { name, .. } => name,
         }
@@ -91,6 +107,8 @@ impl Model {
             Self::Grok4 => "Grok 4",
             Self::Grok4FastReasoning => "Grok 4 Fast",
             Self::Grok4FastNonReasoning => "Grok 4 Fast (Non-Reasoning)",
+            Self::Grok41FastNonReasoning => "Grok 4.1 Fast (Non-Reasoning)",
+            Self::Grok41FastReasoning => "Grok 4.1 Fast",
             Self::GrokCodeFast1 => "Grok Code Fast 1",
             Self::Custom {
                 name, display_name, ..
@@ -102,7 +120,10 @@ impl Model {
         match self {
             Self::Grok3 | Self::Grok3Mini | Self::Grok3Fast | Self::Grok3MiniFast => 131_072,
             Self::Grok4 | Self::GrokCodeFast1 => 256_000,
-            Self::Grok4FastReasoning | Self::Grok4FastNonReasoning => 128_000,
+            Self::Grok4FastReasoning
+            | Self::Grok4FastNonReasoning
+            | Self::Grok41FastNonReasoning
+            | Self::Grok41FastReasoning => 2_000_000,
             Self::Grok2Vision => 8_192,
             Self::Custom { max_tokens, .. } => *max_tokens,
         }
@@ -114,6 +135,8 @@ impl Model {
             Self::Grok4
             | Self::Grok4FastReasoning
             | Self::Grok4FastNonReasoning
+            | Self::Grok41FastNonReasoning
+            | Self::Grok41FastReasoning
             | Self::GrokCodeFast1 => Some(64_000),
             Self::Grok2Vision => Some(4_096),
             Self::Custom {
@@ -131,7 +154,9 @@ impl Model {
             | Self::Grok3MiniFast
             | Self::Grok4
             | Self::Grok4FastReasoning
-            | Self::Grok4FastNonReasoning => true,
+            | Self::Grok4FastNonReasoning
+            | Self::Grok41FastNonReasoning
+            | Self::Grok41FastReasoning => true,
             Self::Custom {
                 parallel_tool_calls: Some(support),
                 ..
@@ -154,6 +179,8 @@ impl Model {
             | Self::Grok4
             | Self::Grok4FastReasoning
             | Self::Grok4FastNonReasoning
+            | Self::Grok41FastNonReasoning
+            | Self::Grok41FastReasoning
             | Self::GrokCodeFast1 => true,
             Self::Custom {
                 supports_tools: Some(support),
@@ -165,7 +192,12 @@ impl Model {
 
     pub fn supports_images(&self) -> bool {
         match self {
-            Self::Grok2Vision => true,
+            Self::Grok2Vision
+            | Self::Grok4
+            | Self::Grok4FastReasoning
+            | Self::Grok4FastNonReasoning
+            | Self::Grok41FastNonReasoning
+            | Self::Grok41FastReasoning => true,
             Self::Custom {
                 supports_images: Some(support),
                 ..