agent: Add `agent.default_model.enable_thinking` setting (#48536)

Marshall Bowers created

This PR adds a new `enable_thinking` setting for the default model,
which controls whether the model uses thinking or not.

Release Notes:

- N/A

Change summary

assets/settings/default.json                                     |  2 
crates/agent/src/agent.rs                                        | 13 
crates/agent/src/native_agent_server.rs                          |  1 
crates/agent/src/thread.rs                                       | 29 +
crates/agent_settings/src/agent_settings.rs                      | 21 -
crates/agent_ui/src/acp/thread_view/active_thread.rs             | 13 
crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs |  1 
crates/agent_ui/src/agent_panel.rs                               |  1 
crates/agent_ui/src/favorite_models.rs                           |  1 
crates/agent_ui/src/text_thread_editor.rs                        |  2 
crates/settings_content/src/agent.rs                             |  3 
11 files changed, 57 insertions(+), 30 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -929,6 +929,8 @@
       "provider": "zed.dev",
       // The model to use.
       "model": "claude-sonnet-4",
+      // Whether thinking is enabled.
+      "enable_thinking": false,
     },
     // Additional parameters for language model requests. When making a request to a model, parameters will be taken
     // from the last entry in this list that matches the model's provider and name. In each entry, both provider

crates/agent/src/agent.rs 🔗

@@ -1158,15 +1158,26 @@ impl acp_thread::AgentModelSelector for NativeAgentModelSelector {
         update_settings_file(
             self.connection.0.read(cx).fs.clone(),
             cx,
-            move |settings, _cx| {
+            move |settings, cx| {
                 let provider = model.provider_id().0.to_string();
                 let model = model.id().0.to_string();
+                let enable_thinking = settings
+                    .agent
+                    .as_ref()
+                    .and_then(|agent| {
+                        agent
+                            .default_model
+                            .as_ref()
+                            .map(|default_model| default_model.enable_thinking)
+                    })
+                    .unwrap_or_else(|| thread.read(cx).thinking_enabled());
                 settings
                     .agent
                     .get_or_insert_default()
                     .set_model(LanguageModelSelection {
                         provider: provider.into(),
                         model,
+                        enable_thinking,
                     });
             },
         );

crates/agent/src/native_agent_server.rs 🔗

@@ -107,6 +107,7 @@ fn model_id_to_selection(model_id: &acp::ModelId) -> LanguageModelSelection {
     LanguageModelSelection {
         provider: provider.to_owned().into(),
         model: model.to_owned(),
+        enable_thinking: false,
     }
 }
 

crates/agent/src/thread.rs 🔗

@@ -827,7 +827,12 @@ impl Thread {
         model: Option<Arc<dyn LanguageModel>>,
         cx: &mut Context<Self>,
     ) -> Self {
-        let profile_id = AgentSettings::get_global(cx).default_profile.clone();
+        let settings = AgentSettings::get_global(cx);
+        let profile_id = settings.default_profile.clone();
+        let enable_thinking = settings
+            .default_model
+            .as_ref()
+            .is_some_and(|model| model.enable_thinking);
         let action_log = cx.new(|_cx| ActionLog::new(project.clone()));
         let (prompt_capabilities_tx, prompt_capabilities_rx) =
             watch::channel(Self::prompt_capabilities(model.as_deref()));
@@ -859,7 +864,7 @@ impl Thread {
             templates,
             model,
             summarization_model: None,
-            thinking_enabled: true,
+            thinking_enabled: enable_thinking,
             prompt_capabilities_tx,
             prompt_capabilities_rx,
             project,
@@ -881,7 +886,12 @@ impl Thread {
         parent_tools: BTreeMap<SharedString, Arc<dyn AnyAgentTool>>,
         cx: &mut Context<Self>,
     ) -> Self {
-        let profile_id = AgentSettings::get_global(cx).default_profile.clone();
+        let settings = AgentSettings::get_global(cx);
+        let profile_id = settings.default_profile.clone();
+        let enable_thinking = settings
+            .default_model
+            .as_ref()
+            .is_some_and(|model| model.enable_thinking);
         let action_log = cx.new(|_cx| ActionLog::new(project.clone()));
         let (prompt_capabilities_tx, prompt_capabilities_rx) =
             watch::channel(Self::prompt_capabilities(Some(model.as_ref())));
@@ -921,7 +931,7 @@ impl Thread {
             templates,
             model: Some(model),
             summarization_model: None,
-            thinking_enabled: true,
+            thinking_enabled: enable_thinking,
             prompt_capabilities_tx,
             prompt_capabilities_rx,
             project,
@@ -1061,9 +1071,14 @@ impl Thread {
         templates: Arc<Templates>,
         cx: &mut Context<Self>,
     ) -> Self {
+        let settings = AgentSettings::get_global(cx);
         let profile_id = db_thread
             .profile
-            .unwrap_or_else(|| AgentSettings::get_global(cx).default_profile.clone());
+            .unwrap_or_else(|| settings.default_profile.clone());
+        let enable_thinking = settings
+            .default_model
+            .as_ref()
+            .is_some_and(|model| model.enable_thinking);
 
         let mut model = LanguageModelRegistry::global(cx).update(cx, |registry, cx| {
             db_thread
@@ -1119,8 +1134,8 @@ impl Thread {
             templates,
             model,
             summarization_model: None,
-            // TODO: Persist this on the `DbThread`.
-            thinking_enabled: true,
+            // TODO: Should we persist this on the `DbThread`?
+            thinking_enabled: enable_thinking,
             project,
             action_log,
             updated_at: db_thread.updated_at,

crates/agent_settings/src/agent_settings.rs 🔗

@@ -76,27 +76,6 @@ impl AgentSettings {
         return None;
     }
 
-    pub fn set_inline_assistant_model(&mut self, provider: String, model: String) {
-        self.inline_assistant_model = Some(LanguageModelSelection {
-            provider: provider.into(),
-            model,
-        });
-    }
-
-    pub fn set_commit_message_model(&mut self, provider: String, model: String) {
-        self.commit_message_model = Some(LanguageModelSelection {
-            provider: provider.into(),
-            model,
-        });
-    }
-
-    pub fn set_thread_summary_model(&mut self, provider: String, model: String) {
-        self.thread_summary_model = Some(LanguageModelSelection {
-            provider: provider.into(),
-            model,
-        });
-    }
-
     pub fn set_message_editor_max_lines(&self) -> usize {
         self.message_editor_min_lines * 2
     }

crates/agent_ui/src/acp/thread_view/active_thread.rs 🔗

@@ -1,4 +1,5 @@
 use gpui::List;
+use settings::update_settings_file;
 
 use super::*;
 
@@ -2725,7 +2726,17 @@ impl AcpThreadView {
                 .on_click(cx.listener(move |this, _, _window, cx| {
                     if let Some(thread) = this.as_native_thread(cx) {
                         thread.update(cx, |thread, cx| {
-                            thread.set_thinking_enabled(!thread.thinking_enabled(), cx);
+                            let enable_thinking = !thread.thinking_enabled();
+                            thread.set_thinking_enabled(enable_thinking, 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.enable_thinking = enable_thinking;
+                                }
+                            });
                         });
                     }
                 })),

crates/agent_ui/src/agent_panel.rs 🔗

@@ -1400,6 +1400,7 @@ impl AgentPanel {
                             .set_model(LanguageModelSelection {
                                 provider: LanguageModelProviderSetting(provider),
                                 model,
+                                enable_thinking: false,
                             })
                     });
                 }

crates/agent_ui/src/favorite_models.rs 🔗

@@ -9,6 +9,7 @@ fn language_model_to_selection(model: &Arc<dyn LanguageModel>) -> LanguageModelS
     LanguageModelSelection {
         provider: model.provider_id().to_string().into(),
         model: model.id().0.to_string(),
+        enable_thinking: false,
     }
 }
 

crates/agent_ui/src/text_thread_editor.rs 🔗

@@ -319,11 +319,13 @@ impl TextThreadEditor {
                         move |model, cx| {
                             update_settings_file(fs.clone(), cx, move |settings, _| {
                                 let provider = model.provider_id().0.to_string();
+                                let enable_thinking = model.supports_thinking();
                                 let model = model.id().0.to_string();
                                 settings.agent.get_or_insert_default().set_model(
                                     LanguageModelSelection {
                                         provider: LanguageModelProviderSetting(provider),
                                         model,
+                                        enable_thinking,
                                     },
                                 )
                             });

crates/settings_content/src/agent.rs 🔗

@@ -151,6 +151,7 @@ impl AgentSettingsContent {
         self.inline_assistant_model = Some(LanguageModelSelection {
             provider: provider.into(),
             model,
+            enable_thinking: false,
         });
     }
 
@@ -262,6 +263,8 @@ pub enum NotifyWhenAgentWaiting {
 pub struct LanguageModelSelection {
     pub provider: LanguageModelProviderSetting,
     pub model: String,
+    #[serde(default)]
+    pub enable_thinking: bool,
 }
 
 #[with_fallible_options]