From 4a02367db2c5c7029f939db819708198b3e1f044 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 8 Apr 2026 11:59:33 -0700 Subject: [PATCH] Persist fast mode across new threads (#53356) When toggling fast mode, the setting is now written to `settings.json` under `agent.default_model.speed`, so new threads start with the same speed. This follows the same pattern as `enable_thinking` and `effort`. The `speed` field uses the existing `Speed` enum (`"fast"` / `"standard"`) rather than a boolean, to leave room for future speed tiers. Example settings: ```json { "agent": { "default_model": { "provider": "zed.dev", "model": "claude-sonnet-4", "speed": "fast" } } } ``` cc @benbrandt Release Notes: - N/A --------- Co-authored-by: Ben Brandt --- crates/agent/src/agent.rs | 2 ++ crates/agent/src/native_agent_server.rs | 1 + crates/agent/src/thread.rs | 6 +++++- .../manage_profiles_modal.rs | 1 + crates/agent_ui/src/agent_panel.rs | 1 + .../src/conversation_view/thread_view.rs | 21 ++++++++++++------- crates/agent_ui/src/favorite_models.rs | 1 + crates/language_model_core/src/request.rs | 4 +++- crates/settings_content/src/agent.rs | 2 ++ crates/settings_content/src/merge_from.rs | 1 + 10 files changed, 31 insertions(+), 9 deletions(-) diff --git a/crates/agent/src/agent.rs b/crates/agent/src/agent.rs index b7aa9d1e311016f572928993e049798c2b5e3bb2..fe62d851ef1ba71c787aa6ec516b0b6b67449d67 100644 --- a/crates/agent/src/agent.rs +++ b/crates/agent/src/agent.rs @@ -1355,6 +1355,7 @@ impl acp_thread::AgentModelSelector for NativeAgentModelSelector { let provider = model.provider_id().0.to_string(); let model = model.id().0.to_string(); let enable_thinking = thread.read(cx).thinking_enabled(); + let speed = thread.read(cx).speed(); settings .agent .get_or_insert_default() @@ -1363,6 +1364,7 @@ impl acp_thread::AgentModelSelector for NativeAgentModelSelector { model, enable_thinking, effort, + speed, }); }, ); diff --git a/crates/agent/src/native_agent_server.rs b/crates/agent/src/native_agent_server.rs index 7f19f9005e3ff54e361f57075b7af06508476564..305c4f51952b3bf7e2771a8372a5975cac9e9385 100644 --- a/crates/agent/src/native_agent_server.rs +++ b/crates/agent/src/native_agent_server.rs @@ -97,6 +97,7 @@ fn model_id_to_selection(model_id: &acp::ModelId) -> LanguageModelSelection { model: model.to_owned(), enable_thinking: false, effort: None, + speed: None, } } diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index 220e9e6b30841da2e726cf5f53d0a6ea7d1624bb..e3a075ada62b6108c489779d5261c1c89afec8aa 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -1041,6 +1041,10 @@ impl Thread { .default_model .as_ref() .and_then(|model| model.effort.clone()); + let speed = settings + .default_model + .as_ref() + .and_then(|model| model.speed); let (prompt_capabilities_tx, prompt_capabilities_rx) = watch::channel(Self::prompt_capabilities(model.as_deref())); Self { @@ -1072,7 +1076,7 @@ impl Thread { model, summarization_model: None, thinking_enabled: enable_thinking, - speed: None, + speed, thinking_effort, prompt_capabilities_tx, prompt_capabilities_rx, diff --git a/crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs b/crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs index 9a8b56f43f906f9ad57cb3dec9e7d95af4cb6cc5..9e042b8ad66111213231d99098a8122e85e9ef6a 100644 --- a/crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs +++ b/crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs @@ -267,6 +267,7 @@ impl ManageProfilesModal { effort: model .default_effort_level() .map(|effort| effort.value.to_string()), + speed: None, }); } } diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index f7ab64385874925afb014ba3520a28931a8e8e07..8f51204b14e67248b8857afcc3001750536eb859 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -1861,6 +1861,7 @@ impl AgentPanel { model, enable_thinking, effort, + speed: None, }) }); } diff --git a/crates/agent_ui/src/conversation_view/thread_view.rs b/crates/agent_ui/src/conversation_view/thread_view.rs index 882390f6330a57b0d6b857f4ff78be8079dcf3ee..ae9bf17c76bde99cdacea9d5bb205074a1a4ee39 100644 --- a/crates/agent_ui/src/conversation_view/thread_view.rs +++ b/crates/agent_ui/src/conversation_view/thread_view.rs @@ -8467,13 +8467,20 @@ impl ThreadView { return; }; thread.update(cx, |thread, cx| { - thread.set_speed( - thread - .speed() - .map(|speed| speed.toggle()) - .unwrap_or(Speed::Fast), - cx, - ); + let new_speed = thread + .speed() + .map(|speed| speed.toggle()) + .unwrap_or(Speed::Fast); + thread.set_speed(new_speed, cx); + + let fs = thread.project().read(cx).fs().clone(); + update_settings_file(fs, cx, move |settings, _| { + if let Some(agent) = settings.agent.as_mut() + && let Some(default_model) = agent.default_model.as_mut() + { + default_model.speed = Some(new_speed); + } + }); }); } diff --git a/crates/agent_ui/src/favorite_models.rs b/crates/agent_ui/src/favorite_models.rs index 5e69808f225f525a3e052fdb01e4095ef38cac03..aa48ca8d12459b2860982a6b204a5350e6c4ce4c 100644 --- a/crates/agent_ui/src/favorite_models.rs +++ b/crates/agent_ui/src/favorite_models.rs @@ -11,6 +11,7 @@ fn language_model_to_selection(model: &Arc) -> LanguageModelS model: model.id().0.to_string(), enable_thinking: false, effort: None, + speed: None, } } diff --git a/crates/language_model_core/src/request.rs b/crates/language_model_core/src/request.rs index 48f7f00522bc3dd5c06747d662761efb003886c0..a35f4883389f0ab18ef67fb86851cb59a9294d0e 100644 --- a/crates/language_model_core/src/request.rs +++ b/crates/language_model_core/src/request.rs @@ -333,7 +333,9 @@ pub struct LanguageModelRequest { pub speed: Option, } -#[derive(Clone, Copy, Default, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive( + Clone, Copy, Default, Debug, Serialize, Deserialize, PartialEq, Eq, schemars::JsonSchema, +)] #[serde(rename_all = "snake_case")] pub enum Speed { #[default] diff --git a/crates/settings_content/src/agent.rs b/crates/settings_content/src/agent.rs index 7a9a1ddb16ac91f90f73e17b3972cd31536d7a66..81edf85c8dd97e64567fab522bdcbbebed23997d 100644 --- a/crates/settings_content/src/agent.rs +++ b/crates/settings_content/src/agent.rs @@ -256,6 +256,7 @@ impl AgentSettingsContent { model, enable_thinking: false, effort: None, + speed: None, }); } @@ -397,6 +398,7 @@ pub struct LanguageModelSelection { #[serde(default)] pub enable_thinking: bool, pub effort: Option, + pub speed: Option, } #[with_fallible_options] diff --git a/crates/settings_content/src/merge_from.rs b/crates/settings_content/src/merge_from.rs index c74d5887f11adf13770fe9dc375d960cd3fe68c7..82e3ee9a24e34445cf90b13c446c7b6356586500 100644 --- a/crates/settings_content/src/merge_from.rs +++ b/crates/settings_content/src/merge_from.rs @@ -56,6 +56,7 @@ merge_from_overwrites!( std::sync::Arc, std::path::PathBuf, std::sync::Arc, + language_model_core::Speed, ); impl MergeFrom for Option {