Remove deprecated GPT-4o, GPT-4.1, GPT-4.1-mini, and o4-mini (#49082)

Richard Feldman created

Remove GPT-4o, GPT-4.1, GPT-4.1-mini, and o4-mini from BYOK model
options in Zed before OpenAI retires these models.

These models are being retired by OpenAI (ChatGPT workspace support ends
April 3, 2026), so they have been removed from the available models list
in Zed's BYOK provider.

Closes AI-4

Release Notes:

- Removed deprecated GPT-4o, GPT-4.1, GPT-4.1-mini, and o4-mini models
from OpenAI BYOK provider

Change summary

crates/agent/src/edit_agent/evals.rs                              | 13 
crates/agent_ui/src/acp/model_selector.rs                         | 29 
crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs |  2 
crates/agent_ui/src/language_model_selector.rs                    | 48 
crates/eval/src/examples/grep_params_escapement.rs                |  2 
crates/language_models/src/provider/open_ai.rs                    | 14 
crates/open_ai/src/open_ai.rs                                     | 42 
7 files changed, 39 insertions(+), 111 deletions(-)

Detailed changes

crates/agent/src/edit_agent/evals.rs 🔗

@@ -88,7 +88,6 @@ fn eval_extract_handle_command_output() {
     // claude-sonnet-4             |  0.97 (2025-06-14)
     // gemini-2.5-pro-06-05        |  0.98 (2025-06-16)
     // gemini-2.5-flash            |  0.11 (2025-05-22)
-    // gpt-4.1                     |  1.00 (2025-05-22)
 
     let input_file_path = "root/blame.rs";
     let input_file_content = include_str!("evals/fixtures/extract_handle_command_output/before.rs");
@@ -164,7 +163,6 @@ fn eval_delete_run_git_blame() {
     // claude-sonnet-4             | 0.96 (2025-06-14)
     // gemini-2.5-pro-06-05        | 1.0  (2025-06-16)
     // gemini-2.5-flash            |
-    // gpt-4.1                     |
 
     let input_file_path = "root/blame.rs";
     let input_file_content = include_str!("evals/fixtures/delete_run_git_blame/before.rs");
@@ -230,7 +228,6 @@ fn eval_translate_doc_comments() {
     //  claude-sonnet-4                |  1.0  (2025-06-14)
     //  gemini-2.5-pro-preview-03-25   |  1.0  (2025-05-22)
     //  gemini-2.5-flash-preview-04-17 |
-    //  gpt-4.1                        |
 
     let input_file_path = "root/canvas.rs";
     let input_file_content = include_str!("evals/fixtures/translate_doc_comments/before.rs");
@@ -295,7 +292,6 @@ fn eval_use_wasi_sdk_in_compile_parser_to_wasm() {
     //  claude-sonnet-4                |  0.11 (2025-06-14)
     //  gemini-2.5-pro-preview-latest  |  0.99 (2025-06-16)
     //  gemini-2.5-flash-preview-04-17 |
-    //  gpt-4.1                        |
 
     let input_file_path = "root/lib.rs";
     let input_file_content =
@@ -419,7 +415,6 @@ fn eval_disable_cursor_blinking() {
     //  claude-sonnet-4                |  0.81 (2025-07-14)
     //  gemini-2.5-pro                 |  0.95 (2025-07-14)
     //  gemini-2.5-flash-preview-04-17 |  0.78 (2025-07-14)
-    //  gpt-4.1                        |  0.00 (2025-07-14) (follows edit_description too literally)
 
     let input_file_path = "root/editor.rs";
     let input_file_content = include_str!("evals/fixtures/disable_cursor_blinking/before.rs");
@@ -509,7 +504,6 @@ fn eval_from_pixels_constructor() {
     //  claude-4.0-sonnet              | 2025-06-14  | 0.99
     //  claude-3.7-sonnet              | 2025-06-14  | 0.88
     //  gemini-2.5-pro-preview-06-05   | 2025-06-16  | 0.98
-    //  gpt-4.1                        |
 
     let input_file_path = "root/canvas.rs";
     let input_file_content = include_str!("evals/fixtures/from_pixels_constructor/before.rs");
@@ -718,7 +712,6 @@ fn eval_zode() {
     //  claude-sonnet-4                |  1.0 (2025-06-14)
     //  gemini-2.5-pro-preview-03-25   |  1.0 (2025-05-22)
     //  gemini-2.5-flash-preview-04-17 |  1.0 (2025-05-22)
-    //  gpt-4.1                        |  1.0 (2025-05-22)
 
     let input_file_path = "root/zode.py";
     let input_content = None;
@@ -823,7 +816,6 @@ fn eval_add_overwrite_test() {
     //  claude-sonnet-4                |  0.07 (2025-06-14)
     //  gemini-2.5-pro-preview-03-25   |  0.35 (2025-05-22)
     //  gemini-2.5-flash-preview-04-17 |
-    //  gpt-4.1                        |
 
     let input_file_path = "root/action_log.rs";
     let input_file_content = include_str!("evals/fixtures/add_overwrite_test/before.rs");
@@ -1057,11 +1049,6 @@ fn eval_create_empty_file() {
     //  claude-sonnet-4                |  1.00 (2025-06-14)
     //  gemini-2.5-pro-preview-03-25   |  1.00 (2025-05-21)
     //  gemini-2.5-flash-preview-04-17 |  1.00 (2025-05-21)
-    //  gpt-4.1                        |  1.00 (2025-05-21)
-    //
-    //
-    // TODO: gpt-4.1-mini errored 38 times:
-    // "data did not match any variant of untagged enum ResponseStreamResult"
 
     let input_file_content = None;
     let expected_output_content = String::new();

crates/agent_ui/src/acp/model_selector.rs 🔗

@@ -632,36 +632,27 @@ mod tests {
                 vec![
                     "Claude 3.7 Sonnet",
                     "Claude 3.7 Sonnet Thinking",
-                    "gpt-4.1",
-                    "gpt-4.1-nano",
+                    "gpt-5",
+                    "gpt-5-mini",
                 ],
             ),
-            ("openai", vec!["gpt-3.5-turbo", "gpt-4.1", "gpt-4.1-nano"]),
+            ("openai", vec!["gpt-3.5-turbo", "gpt-5", "gpt-5-mini"]),
             ("ollama", vec!["mistral", "deepseek"]),
         ]);
 
         // Results should preserve models order whenever possible.
-        // In the case below, `zed/gpt-4.1` and `openai/gpt-4.1` have identical
-        // similarity scores, but `zed/gpt-4.1` was higher in the models list,
+        // In the case below, `zed/gpt-5-mini` and `openai/gpt-5-mini` have identical
+        // similarity scores, but `zed/gpt-5-mini` was higher in the models list,
         // so it should appear first in the results.
-        let results = fuzzy_search(models.clone(), "41".into(), cx.executor()).await;
+        let results = fuzzy_search(models.clone(), "mini".into(), cx.executor()).await;
         assert_models_eq(
             results,
-            vec![
-                ("zed", vec!["gpt-4.1", "gpt-4.1-nano"]),
-                ("openai", vec!["gpt-4.1", "gpt-4.1-nano"]),
-            ],
+            vec![("zed", vec!["gpt-5-mini"]), ("openai", vec!["gpt-5-mini"])],
         );
 
-        // Fuzzy search
-        let results = fuzzy_search(models.clone(), "4n".into(), cx.executor()).await;
-        assert_models_eq(
-            results,
-            vec![
-                ("zed", vec!["gpt-4.1-nano"]),
-                ("openai", vec!["gpt-4.1-nano"]),
-            ],
-        );
+        // Fuzzy search - test with specific model name
+        let results = fuzzy_search(models.clone(), "mistral".into(), cx.executor()).await;
+        assert_models_eq(results, vec![("ollama", vec!["mistral"])]);
     }
 
     #[gpui::test]

crates/agent_ui/src/language_model_selector.rs 🔗

@@ -752,11 +752,11 @@ mod tests {
         let models = create_models(vec![
             ("zed", "Claude 3.7 Sonnet"),
             ("zed", "Claude 3.7 Sonnet Thinking"),
-            ("zed", "gpt-4.1"),
-            ("zed", "gpt-4.1-nano"),
+            ("zed", "gpt-5"),
+            ("zed", "gpt-5-mini"),
             ("openai", "gpt-3.5-turbo"),
-            ("openai", "gpt-4.1"),
-            ("openai", "gpt-4.1-nano"),
+            ("openai", "gpt-5"),
+            ("openai", "gpt-5-mini"),
             ("ollama", "mistral"),
             ("ollama", "deepseek"),
         ]);
@@ -767,14 +767,14 @@ mod tests {
         );
 
         // The order of models should be maintained, case doesn't matter
-        let results = matcher.exact_search("GPT-4.1");
+        let results = matcher.exact_search("GPT-5");
         assert_models_eq(
             results,
             vec![
-                "zed/gpt-4.1",
-                "zed/gpt-4.1-nano",
-                "openai/gpt-4.1",
-                "openai/gpt-4.1-nano",
+                "zed/gpt-5",
+                "zed/gpt-5-mini",
+                "openai/gpt-5",
+                "openai/gpt-5-mini",
             ],
         );
     }
@@ -784,11 +784,11 @@ mod tests {
         let models = create_models(vec![
             ("zed", "Claude 3.7 Sonnet"),
             ("zed", "Claude 3.7 Sonnet Thinking"),
-            ("zed", "gpt-4.1"),
-            ("zed", "gpt-4.1-nano"),
+            ("zed", "gpt-5"),
+            ("zed", "gpt-5-mini"),
             ("openai", "gpt-3.5-turbo"),
-            ("openai", "gpt-4.1"),
-            ("openai", "gpt-4.1-nano"),
+            ("openai", "gpt-5"),
+            ("openai", "gpt-5-mini"),
             ("ollama", "mistral"),
             ("ollama", "deepseek"),
         ]);
@@ -799,27 +799,19 @@ mod tests {
         );
 
         // Results should preserve models order whenever possible.
-        // In the case below, `zed/gpt-4.1` and `openai/gpt-4.1` have identical
-        // similarity scores, but `zed/gpt-4.1` was higher in the models list,
+        // In the case below, `zed/gpt-5-mini` and `openai/gpt-5-mini` have identical
+        // similarity scores, but `zed/gpt-5-mini` was higher in the models list,
         // so it should appear first in the results.
-        let results = matcher.fuzzy_search("41");
-        assert_models_eq(
-            results,
-            vec![
-                "zed/gpt-4.1",
-                "openai/gpt-4.1",
-                "zed/gpt-4.1-nano",
-                "openai/gpt-4.1-nano",
-            ],
-        );
+        let results = matcher.fuzzy_search("mini");
+        assert_models_eq(results, vec!["zed/gpt-5-mini", "openai/gpt-5-mini"]);
 
         // Model provider should be searchable as well
         let results = matcher.fuzzy_search("ol"); // meaning "ollama"
         assert_models_eq(results, vec!["ollama/mistral", "ollama/deepseek"]);
 
-        // Fuzzy search
-        let results = matcher.fuzzy_search("z4n");
-        assert_models_eq(results, vec!["zed/gpt-4.1-nano"]);
+        // Fuzzy search - search for Claude to get the Thinking variant
+        let results = matcher.fuzzy_search("thinking");
+        assert_models_eq(results, vec!["zed/Claude 3.7 Sonnet Thinking"]);
     }
 
     #[gpui::test]

crates/eval/src/examples/grep_params_escapement.rs 🔗

@@ -15,7 +15,7 @@ This eval checks that the model doesn't use HTML escapement for characters like
                       original     +system_prompt change    +tool description
   claude-opus-4        89%          92%                     97%+
   claude-sonnet-4      100%
-  gpt-4.1-mini         100%
+  gpt-5-mini           100%
   gemini-2.5-pro                    98%
 
 */

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

@@ -300,10 +300,7 @@ impl LanguageModel for OpenAiLanguageModel {
     fn supports_images(&self) -> bool {
         use open_ai::Model;
         match &self.model {
-            Model::FourOmni
-            | Model::FourOmniMini
-            | Model::FourPointOne
-            | Model::FourPointOneMini
+            Model::FourOmniMini
             | Model::FourPointOneNano
             | Model::Five
             | Model::FiveCodex
@@ -313,8 +310,7 @@ impl LanguageModel for OpenAiLanguageModel {
             | Model::FivePointTwo
             | Model::FivePointTwoCodex
             | Model::O1
-            | Model::O3
-            | Model::O4Mini => true,
+            | Model::O3 => true,
             Model::ThreePointFiveTurbo
             | Model::Four
             | Model::FourTurbo
@@ -1155,7 +1151,7 @@ pub fn count_open_ai_tokens(
         match model {
             Model::Custom { max_tokens, .. } => {
                 let model = if max_tokens >= 100_000 {
-                    // If the max tokens is 100k or more, it is likely the o200k_base tokenizer from gpt4o
+                    // If the max tokens is 100k or more, it likely uses the o200k_base tokenizer
                     "gpt-4o"
                 } else {
                     // Otherwise fallback to gpt-4, since only cl100k_base and o200k_base are
@@ -1171,15 +1167,11 @@ pub fn count_open_ai_tokens(
             Model::ThreePointFiveTurbo
             | Model::Four
             | Model::FourTurbo
-            | Model::FourOmni
             | Model::FourOmniMini
-            | Model::FourPointOne
-            | Model::FourPointOneMini
             | Model::FourPointOneNano
             | Model::O1
             | Model::O3
             | Model::O3Mini
-            | Model::O4Mini
             | Model::Five
             | Model::FiveCodex
             | Model::FiveMini

crates/open_ai/src/open_ai.rs 🔗

@@ -63,15 +63,8 @@ pub enum Model {
     Four,
     #[serde(rename = "gpt-4-turbo")]
     FourTurbo,
-    #[serde(rename = "gpt-4o")]
-    #[default]
-    FourOmni,
     #[serde(rename = "gpt-4o-mini")]
     FourOmniMini,
-    #[serde(rename = "gpt-4.1")]
-    FourPointOne,
-    #[serde(rename = "gpt-4.1-mini")]
-    FourPointOneMini,
     #[serde(rename = "gpt-4.1-nano")]
     FourPointOneNano,
     #[serde(rename = "o1")]
@@ -80,13 +73,12 @@ pub enum Model {
     O3Mini,
     #[serde(rename = "o3")]
     O3,
-    #[serde(rename = "o4-mini")]
-    O4Mini,
     #[serde(rename = "gpt-5")]
     Five,
     #[serde(rename = "gpt-5-codex")]
     FiveCodex,
     #[serde(rename = "gpt-5-mini")]
+    #[default]
     FiveMini,
     #[serde(rename = "gpt-5-nano")]
     FiveNano,
@@ -116,8 +108,7 @@ const fn default_supports_chat_completions() -> bool {
 
 impl Model {
     pub fn default_fast() -> Self {
-        // TODO: Replace with FiveMini since all other models are deprecated
-        Self::FourPointOneMini
+        Self::FiveMini
     }
 
     pub fn from_id(id: &str) -> Result<Self> {
@@ -125,15 +116,11 @@ impl Model {
             "gpt-3.5-turbo" => Ok(Self::ThreePointFiveTurbo),
             "gpt-4" => Ok(Self::Four),
             "gpt-4-turbo-preview" => Ok(Self::FourTurbo),
-            "gpt-4o" => Ok(Self::FourOmni),
             "gpt-4o-mini" => Ok(Self::FourOmniMini),
-            "gpt-4.1" => Ok(Self::FourPointOne),
-            "gpt-4.1-mini" => Ok(Self::FourPointOneMini),
             "gpt-4.1-nano" => Ok(Self::FourPointOneNano),
             "o1" => Ok(Self::O1),
             "o3-mini" => Ok(Self::O3Mini),
             "o3" => Ok(Self::O3),
-            "o4-mini" => Ok(Self::O4Mini),
             "gpt-5" => Ok(Self::Five),
             "gpt-5-codex" => Ok(Self::FiveCodex),
             "gpt-5-mini" => Ok(Self::FiveMini),
@@ -150,15 +137,11 @@ impl Model {
             Self::ThreePointFiveTurbo => "gpt-3.5-turbo",
             Self::Four => "gpt-4",
             Self::FourTurbo => "gpt-4-turbo",
-            Self::FourOmni => "gpt-4o",
             Self::FourOmniMini => "gpt-4o-mini",
-            Self::FourPointOne => "gpt-4.1",
-            Self::FourPointOneMini => "gpt-4.1-mini",
             Self::FourPointOneNano => "gpt-4.1-nano",
             Self::O1 => "o1",
             Self::O3Mini => "o3-mini",
             Self::O3 => "o3",
-            Self::O4Mini => "o4-mini",
             Self::Five => "gpt-5",
             Self::FiveCodex => "gpt-5-codex",
             Self::FiveMini => "gpt-5-mini",
@@ -175,15 +158,11 @@ impl Model {
             Self::ThreePointFiveTurbo => "gpt-3.5-turbo",
             Self::Four => "gpt-4",
             Self::FourTurbo => "gpt-4-turbo",
-            Self::FourOmni => "gpt-4o",
             Self::FourOmniMini => "gpt-4o-mini",
-            Self::FourPointOne => "gpt-4.1",
-            Self::FourPointOneMini => "gpt-4.1-mini",
             Self::FourPointOneNano => "gpt-4.1-nano",
             Self::O1 => "o1",
             Self::O3Mini => "o3-mini",
             Self::O3 => "o3",
-            Self::O4Mini => "o4-mini",
             Self::Five => "gpt-5",
             Self::FiveCodex => "gpt-5-codex",
             Self::FiveMini => "gpt-5-mini",
@@ -191,9 +170,7 @@ impl Model {
             Self::FivePointOne => "gpt-5.1",
             Self::FivePointTwo => "gpt-5.2",
             Self::FivePointTwoCodex => "gpt-5.2-codex",
-            Self::Custom {
-                name, display_name, ..
-            } => display_name.as_ref().unwrap_or(name),
+            Self::Custom { display_name, .. } => display_name.as_deref().unwrap_or(&self.id()),
         }
     }
 
@@ -202,15 +179,11 @@ impl Model {
             Self::ThreePointFiveTurbo => 16_385,
             Self::Four => 8_192,
             Self::FourTurbo => 128_000,
-            Self::FourOmni => 128_000,
             Self::FourOmniMini => 128_000,
-            Self::FourPointOne => 1_047_576,
-            Self::FourPointOneMini => 1_047_576,
             Self::FourPointOneNano => 1_047_576,
             Self::O1 => 200_000,
             Self::O3Mini => 200_000,
             Self::O3 => 200_000,
-            Self::O4Mini => 200_000,
             Self::Five => 272_000,
             Self::FiveCodex => 272_000,
             Self::FiveMini => 272_000,
@@ -230,15 +203,11 @@ impl Model {
             Self::ThreePointFiveTurbo => Some(4_096),
             Self::Four => Some(8_192),
             Self::FourTurbo => Some(4_096),
-            Self::FourOmni => Some(16_384),
             Self::FourOmniMini => Some(16_384),
-            Self::FourPointOne => Some(32_768),
-            Self::FourPointOneMini => Some(32_768),
             Self::FourPointOneNano => Some(32_768),
             Self::O1 => Some(100_000),
             Self::O3Mini => Some(100_000),
             Self::O3 => Some(100_000),
-            Self::O4Mini => Some(100_000),
             Self::Five => Some(128_000),
             Self::FiveCodex => Some(128_000),
             Self::FiveMini => Some(128_000),
@@ -277,10 +246,7 @@ impl Model {
             Self::ThreePointFiveTurbo
             | Self::Four
             | Self::FourTurbo
-            | Self::FourOmni
             | Self::FourOmniMini
-            | Self::FourPointOne
-            | Self::FourPointOneMini
             | Self::FourPointOneNano
             | Self::Five
             | Self::FiveCodex
@@ -289,7 +255,7 @@ impl Model {
             | Self::FivePointTwo
             | Self::FivePointTwoCodex
             | Self::FiveNano => true,
-            Self::O1 | Self::O3 | Self::O3Mini | Self::O4Mini | Model::Custom { .. } => false,
+            Self::O1 | Self::O3 | Self::O3Mini | Model::Custom { .. } => false,
         }
     }