From 81c65414ca36bdf4fd0b9cc2612d7d1180258589 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 2 Feb 2026 20:13:32 -0600 Subject: [PATCH] Make mercury and sweep non experimental (#48227) Closes #ISSUE Release Notes: - N/A *or* Added/Fixed/Improved ... --- crates/agent_ui/src/agent_ui.rs | 2 + .../src/edit_prediction_button.rs | 26 ++-- crates/migrator/src/migrations.rs | 6 + .../src/migrations/m_2026_02_03/settings.rs | 44 +++++++ crates/migrator/src/migrator.rs | 122 ++++++++++++++++++ crates/settings_content/src/language.rs | 32 ++--- .../zed/src/zed/edit_prediction_registry.rs | 40 +++--- 7 files changed, 212 insertions(+), 60 deletions(-) create mode 100644 crates/migrator/src/migrations/m_2026_02_03/settings.rs diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index 19e71e5d8394be5e9566de04ff2592473b4479d7..cd3247f53b4bb4667c5b82be9b49ce6792bd5852 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -401,6 +401,8 @@ fn update_command_palette_filter(cx: &mut App) { } EditPredictionProvider::Zed | EditPredictionProvider::Codestral + | EditPredictionProvider::Sweep + | EditPredictionProvider::Mercury | EditPredictionProvider::Experimental(_) => { filter.show_namespace("edit_prediction"); filter.hide_namespace("copilot"); diff --git a/crates/edit_prediction_ui/src/edit_prediction_button.rs b/crates/edit_prediction_ui/src/edit_prediction_button.rs index 1d66899009b79c892c76e5c7234bf17931d9d42d..08f334862d2717bb626714a0a995f85b5a07c512 100644 --- a/crates/edit_prediction_ui/src/edit_prediction_button.rs +++ b/crates/edit_prediction_ui/src/edit_prediction_button.rs @@ -25,10 +25,7 @@ use language::{ use project::{DisableAiSettings, Project}; use regex::Regex; use settings::{ - EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME, - EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME, - EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME, Settings, SettingsStore, - update_settings_file, + EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME, Settings, SettingsStore, update_settings_file, }; use std::{ sync::{Arc, LazyLock}, @@ -306,7 +303,10 @@ impl Render for EditPredictionButton { .with_handle(self.popover_menu_handle.clone()), ) } - provider @ (EditPredictionProvider::Experimental(_) | EditPredictionProvider::Zed) => { + provider @ (EditPredictionProvider::Experimental(_) + | EditPredictionProvider::Zed + | EditPredictionProvider::Sweep + | EditPredictionProvider::Mercury) => { let enabled = self.editor_enabled.unwrap_or(true); let icons = self .edit_prediction_provider @@ -321,9 +321,7 @@ impl Render for EditPredictionButton { let mut missing_token = false; match provider { - EditPredictionProvider::Experimental( - EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME, - ) => { + EditPredictionProvider::Sweep => { missing_token = edit_prediction::EditPredictionStore::try_global(cx) .is_some_and(|ep_store| !ep_store.read(cx).has_sweep_api_token(cx)); ep_icon = if enabled { icons.base } else { icons.disabled }; @@ -333,9 +331,7 @@ impl Render for EditPredictionButton { "Powered by Sweep" }; } - EditPredictionProvider::Experimental( - EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME, - ) => { + EditPredictionProvider::Mercury => { ep_icon = if enabled { icons.base } else { icons.disabled }; missing_token = edit_prediction::EditPredictionStore::try_global(cx) .is_some_and(|ep_store| !ep_store.read(cx).has_mercury_api_token(cx)); @@ -1327,9 +1323,7 @@ pub fn get_available_providers(cx: &mut App) -> Vec { .read(cx) .has_key() { - providers.push(EditPredictionProvider::Experimental( - EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME, - )); + providers.push(EditPredictionProvider::Sweep); } if cx.has_flag::() @@ -1337,9 +1331,7 @@ pub fn get_available_providers(cx: &mut App) -> Vec { .read(cx) .has_key() { - providers.push(EditPredictionProvider::Experimental( - EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME, - )); + providers.push(EditPredictionProvider::Mercury); } providers diff --git a/crates/migrator/src/migrations.rs b/crates/migrator/src/migrations.rs index de22132176e508a027287a48d868d30aab51a495..6fbb29d155f1fc613d1f33f54787922e3d4cc01a 100644 --- a/crates/migrator/src/migrations.rs +++ b/crates/migrator/src/migrations.rs @@ -171,3 +171,9 @@ pub(crate) mod m_2026_02_02 { pub(crate) use settings::move_edit_prediction_provider_to_edit_predictions; } + +pub(crate) mod m_2026_02_03 { + mod settings; + + pub(crate) use settings::migrate_experimental_sweep_mercury; +} diff --git a/crates/migrator/src/migrations/m_2026_02_03/settings.rs b/crates/migrator/src/migrations/m_2026_02_03/settings.rs new file mode 100644 index 0000000000000000000000000000000000000000..ff0b626730a3b29c5b60fbfc1095c57d2c492359 --- /dev/null +++ b/crates/migrator/src/migrations/m_2026_02_03/settings.rs @@ -0,0 +1,44 @@ +use anyhow::Result; +use serde_json::Value; + +pub fn migrate_experimental_sweep_mercury(value: &mut Value) -> Result<()> { + let Some(obj) = value.as_object_mut() else { + return Ok(()); + }; + + if let Some(edit_predictions) = obj.get_mut("edit_predictions") { + if let Some(edit_predictions_obj) = edit_predictions.as_object_mut() { + migrate_provider_field(edit_predictions_obj, "provider"); + } + } + + if let Some(features) = obj.get_mut("features") { + if let Some(features_obj) = features.as_object_mut() { + migrate_provider_field(features_obj, "edit_prediction_provider"); + } + } + + Ok(()) +} + +fn migrate_provider_field(obj: &mut serde_json::Map, field_name: &str) { + let Some(provider) = obj.get(field_name) else { + return; + }; + + let Some(provider_obj) = provider.as_object() else { + return; + }; + + let Some(experimental_name) = provider_obj.get("experimental") else { + return; + }; + + let Some(name) = experimental_name.as_str() else { + return; + }; + + if name == "sweep" || name == "mercury" { + obj.insert(field_name.to_string(), Value::String(name.to_string())); + } +} diff --git a/crates/migrator/src/migrator.rs b/crates/migrator/src/migrator.rs index cb0560dd40e49e91df32ce194944dc5b5d4df5e0..6219a5caed68ccd14913a3bce83d8c6cb0f19ae9 100644 --- a/crates/migrator/src/migrator.rs +++ b/crates/migrator/src/migrator.rs @@ -235,6 +235,7 @@ pub fn migrate_settings(text: &str) -> Result> { MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, ), + MigrationType::Json(migrations::m_2026_02_03::migrate_experimental_sweep_mercury), ]; run_migrations(text, migrations) } @@ -2470,4 +2471,125 @@ mod tests { None, ); } + + #[test] + fn test_migrate_experimental_sweep_mercury() { + assert_migrate_settings_with_migrations( + &[MigrationType::Json( + migrations::m_2026_02_03::migrate_experimental_sweep_mercury, + )], + &r#"{ }"#.unindent(), + None, + ); + + assert_migrate_settings_with_migrations( + &[MigrationType::Json( + migrations::m_2026_02_03::migrate_experimental_sweep_mercury, + )], + &r#" + { + "edit_predictions": { + "provider": { + "experimental": "sweep" + } + } + } + "# + .unindent(), + Some( + &r#" + { + "edit_predictions": { + "provider": "sweep" + } + } + "# + .unindent(), + ), + ); + + assert_migrate_settings_with_migrations( + &[MigrationType::Json( + migrations::m_2026_02_03::migrate_experimental_sweep_mercury, + )], + &r#" + { + "edit_predictions": { + "provider": { + "experimental": "mercury" + } + } + } + "# + .unindent(), + Some( + &r#" + { + "edit_predictions": { + "provider": "mercury" + } + } + "# + .unindent(), + ), + ); + + assert_migrate_settings_with_migrations( + &[MigrationType::Json( + migrations::m_2026_02_03::migrate_experimental_sweep_mercury, + )], + &r#" + { + "features": { + "edit_prediction_provider": { + "experimental": "sweep" + } + } + } + "# + .unindent(), + Some( + &r#" + { + "features": { + "edit_prediction_provider": "sweep" + } + } + "# + .unindent(), + ), + ); + + assert_migrate_settings_with_migrations( + &[MigrationType::Json( + migrations::m_2026_02_03::migrate_experimental_sweep_mercury, + )], + &r#" + { + "edit_predictions": { + "provider": "zed" + } + } + "# + .unindent(), + None, + ); + + assert_migrate_settings_with_migrations( + &[MigrationType::Json( + migrations::m_2026_02_03::migrate_experimental_sweep_mercury, + )], + &r#" + { + "edit_predictions": { + "provider": { + "experimental": "zeta2" + } + } + } + "# + .unindent(), + None, + ); + } } diff --git a/crates/settings_content/src/language.rs b/crates/settings_content/src/language.rs index c16deacc520eb87a5be6eaee05233de365a183bb..d3a6a726428f1a3c8679142c7940698084f0bcdc 100644 --- a/crates/settings_content/src/language.rs +++ b/crates/settings_content/src/language.rs @@ -84,12 +84,12 @@ pub enum EditPredictionProvider { Supermaven, Zed, Codestral, + Sweep, + Mercury, Experimental(&'static str), } -pub const EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME: &str = "sweep"; pub const EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME: &str = "zeta2"; -pub const EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME: &str = "mercury"; impl<'de> Deserialize<'de> for EditPredictionProvider { fn deserialize(deserializer: D) -> Result @@ -104,6 +104,8 @@ impl<'de> Deserialize<'de> for EditPredictionProvider { Supermaven, Zed, Codestral, + Sweep, + Mercury, Experimental(String), } @@ -113,20 +115,8 @@ impl<'de> Deserialize<'de> for EditPredictionProvider { Content::Supermaven => EditPredictionProvider::Supermaven, Content::Zed => EditPredictionProvider::Zed, Content::Codestral => EditPredictionProvider::Codestral, - Content::Experimental(name) - if name == EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME => - { - EditPredictionProvider::Experimental( - EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME, - ) - } - Content::Experimental(name) - if name == EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME => - { - EditPredictionProvider::Experimental( - EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME, - ) - } + Content::Sweep => EditPredictionProvider::Sweep, + Content::Mercury => EditPredictionProvider::Mercury, Content::Experimental(name) if name == EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME => { @@ -152,6 +142,8 @@ impl EditPredictionProvider { | EditPredictionProvider::Copilot | EditPredictionProvider::Supermaven | EditPredictionProvider::Codestral + | EditPredictionProvider::Sweep + | EditPredictionProvider::Mercury | EditPredictionProvider::Experimental(_) => false, } } @@ -162,12 +154,8 @@ impl EditPredictionProvider { EditPredictionProvider::Copilot => Some("GitHub Copilot"), EditPredictionProvider::Supermaven => Some("Supermaven"), EditPredictionProvider::Codestral => Some("Codestral"), - EditPredictionProvider::Experimental( - EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME, - ) => Some("Sweep"), - EditPredictionProvider::Experimental( - EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME, - ) => Some("Mercury"), + EditPredictionProvider::Sweep => Some("Sweep"), + EditPredictionProvider::Mercury => Some("Mercury"), EditPredictionProvider::Experimental( EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME, ) => Some("Zeta2"), diff --git a/crates/zed/src/zed/edit_prediction_registry.rs b/crates/zed/src/zed/edit_prediction_registry.rs index a59da22be5ff0f557d373b53c90fef5d05b31527..521da62b16946106e4adef54085980f106e988eb 100644 --- a/crates/zed/src/zed/edit_prediction_registry.rs +++ b/crates/zed/src/zed/edit_prediction_registry.rs @@ -10,11 +10,7 @@ use feature_flags::FeatureFlagAppExt; use gpui::{AnyWindowHandle, App, AppContext as _, Context, Entity, WeakEntity}; use language::language_settings::{EditPredictionProvider, all_language_settings}; use language_models::MistralLanguageModelProvider; -use settings::{ - EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME, - EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME, - EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME, SettingsStore, -}; +use settings::{EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME, SettingsStore}; use std::{cell::RefCell, rc::Rc, sync::Arc}; use supermaven::{Supermaven, SupermavenEditPredictionDelegate}; use ui::Window; @@ -195,7 +191,10 @@ fn assign_edit_prediction_provider( let provider = cx.new(|_| CodestralEditPredictionDelegate::new(http_client)); editor.set_edit_prediction_provider(Some(provider), window, cx); } - value @ (EditPredictionProvider::Experimental(_) | EditPredictionProvider::Zed) => { + value @ (EditPredictionProvider::Experimental(_) + | EditPredictionProvider::Zed + | EditPredictionProvider::Sweep + | EditPredictionProvider::Mercury) => { let ep_store = edit_prediction::EditPredictionStore::global(client, &user_store, cx); if let Some(project) = editor.project() @@ -203,28 +202,27 @@ fn assign_edit_prediction_provider( && buffer.read(cx).file().is_some() { let has_model = ep_store.update(cx, |ep_store, cx| { - let model = if let EditPredictionProvider::Experimental(name) = value { - if name == EXPERIMENTAL_SWEEP_EDIT_PREDICTION_PROVIDER_NAME - && cx.has_flag::() - { + let model = match value { + EditPredictionProvider::Sweep if cx.has_flag::() => { edit_prediction::EditPredictionModel::Sweep - } else if name == EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME - && cx.has_flag::() + } + EditPredictionProvider::Mercury if cx.has_flag::() => { + edit_prediction::EditPredictionModel::Mercury + } + EditPredictionProvider::Experimental(name) + if name == EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME + && cx.has_flag::() => { edit_prediction::EditPredictionModel::Zeta2 { version: Default::default(), } - } else if name == EXPERIMENTAL_MERCURY_EDIT_PREDICTION_PROVIDER_NAME - && cx.has_flag::() + } + EditPredictionProvider::Zed + if user_store.read(cx).current_user().is_some() => { - edit_prediction::EditPredictionModel::Mercury - } else { - return false; + edit_prediction::EditPredictionModel::Zeta1 } - } else if user_store.read(cx).current_user().is_some() { - edit_prediction::EditPredictionModel::Zeta1 - } else { - return false; + _ => return false, }; ep_store.set_edit_prediction_model(model);