From 9860106b8e74dcc2149fe051bd62a851c811fb27 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 5 Feb 2026 20:04:53 -0500 Subject: [PATCH] agent: Add support for setting thinking effort for Zed provider (#48545) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds the ability to set the thinking effort of a model. Right now this only applies to Opus 4.6 through the Zed provider. This is gated behind the `cloud-thinking-toggle` feature flag. UI is still rough; needs a design pass: Screenshot 2026-02-05 at 7 45 54 PM Screenshot 2026-02-05 at 7 45 58 PM Release Notes: - N/A --- crates/agent/src/agent.rs | 8 + crates/agent/src/edit_agent.rs | 1 + crates/agent/src/native_agent_server.rs | 1 + crates/agent/src/thread.rs | 26 +++ .../src/acp/thread_view/active_thread.rs | 162 +++++++++++++++--- .../manage_profiles_modal.rs | 3 + crates/agent_ui/src/agent_panel.rs | 1 + crates/agent_ui/src/buffer_codegen.rs | 2 + crates/agent_ui/src/favorite_models.rs | 1 + .../agent_ui/src/terminal_inline_assistant.rs | 1 + crates/agent_ui/src/text_thread_editor.rs | 10 +- crates/anthropic/src/anthropic.rs | 3 +- .../assistant_text_thread/src/text_thread.rs | 1 + .../cloud_llm_client/src/cloud_llm_client.rs | 2 + crates/eval/src/instance.rs | 1 + crates/git_ui/src/git_panel.rs | 3 +- crates/language_model/src/language_model.rs | 8 + crates/language_model/src/request.rs | 1 + .../language_models/src/provider/anthropic.rs | 1 + crates/language_models/src/provider/cloud.rs | 14 +- .../src/provider/copilot_chat.rs | 1 + .../language_models/src/provider/mistral.rs | 2 + .../language_models/src/provider/open_ai.rs | 3 + crates/rules_library/src/rules_library.rs | 1 + crates/settings_content/src/agent.rs | 2 + 25 files changed, 224 insertions(+), 35 deletions(-) diff --git a/crates/agent/src/agent.rs b/crates/agent/src/agent.rs index a938903fe82be85f5dd5ec81f3fa4b2a1f5823b6..b63c1f14cda35f8fa3ca06f1ae56f45294ab005a 100644 --- a/crates/agent/src/agent.rs +++ b/crates/agent/src/agent.rs @@ -1151,8 +1151,15 @@ impl acp_thread::AgentModelSelector for NativeAgentModelSelector { return Task::ready(Err(anyhow!("Invalid model ID {}", model_id))); }; + // We want to reset the effort level when switching models, as the currently-selected effort level may + // not be compatible. + let effort = model + .default_effort_level() + .map(|effort_level| effort_level.value.to_string()); + thread.update(cx, |thread, cx| { thread.set_model(model.clone(), cx); + thread.set_thinking_effort(effort.clone(), cx); }); update_settings_file( @@ -1178,6 +1185,7 @@ impl acp_thread::AgentModelSelector for NativeAgentModelSelector { provider: provider.into(), model, enable_thinking, + effort, }); }, ); diff --git a/crates/agent/src/edit_agent.rs b/crates/agent/src/edit_agent.rs index ce29c3894daaf10f0a25ab7ebca6ea3e69885a7e..cab1f8ca888f879d0e7c7ec9a6f034325abb5409 100644 --- a/crates/agent/src/edit_agent.rs +++ b/crates/agent/src/edit_agent.rs @@ -732,6 +732,7 @@ impl EditAgent { stop: Vec::new(), temperature: None, thinking_allowed: true, + thinking_effort: None, }; Ok(self.model.stream_completion_text(request, cx).await?.stream) diff --git a/crates/agent/src/native_agent_server.rs b/crates/agent/src/native_agent_server.rs index e7e93a977be05dd450be72befe294712fcdece12..4d8bdaf698cb6bc50f6080c9b029954242a56f14 100644 --- a/crates/agent/src/native_agent_server.rs +++ b/crates/agent/src/native_agent_server.rs @@ -108,6 +108,7 @@ fn model_id_to_selection(model_id: &acp::ModelId) -> LanguageModelSelection { provider: provider.to_owned().into(), model: model.to_owned(), enable_thinking: false, + effort: None, } } diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index 9c4df97319ad18192fc84d83d430d64f0cf58f9c..7a97b4e05828452d674a307dd50d2689390e19ce 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -797,6 +797,7 @@ pub struct Thread { model: Option>, summarization_model: Option>, thinking_enabled: bool, + thinking_effort: Option, prompt_capabilities_tx: watch::Sender, pub(crate) prompt_capabilities_rx: watch::Receiver, pub(crate) project: Entity, @@ -833,6 +834,10 @@ impl Thread { .default_model .as_ref() .is_some_and(|model| model.enable_thinking); + let thinking_effort = settings + .default_model + .as_ref() + .and_then(|model| model.effort.clone()); 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())); @@ -865,6 +870,7 @@ impl Thread { model, summarization_model: None, thinking_enabled: enable_thinking, + thinking_effort, prompt_capabilities_tx, prompt_capabilities_rx, project, @@ -892,6 +898,10 @@ impl Thread { .default_model .as_ref() .is_some_and(|model| model.enable_thinking); + let thinking_effort = settings + .default_model + .as_ref() + .and_then(|model| model.effort.clone()); 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()))); @@ -932,6 +942,7 @@ impl Thread { model: Some(model), summarization_model: None, thinking_enabled: enable_thinking, + thinking_effort, prompt_capabilities_tx, prompt_capabilities_rx, project, @@ -1079,6 +1090,10 @@ impl Thread { .default_model .as_ref() .is_some_and(|model| model.enable_thinking); + let thinking_effort = settings + .default_model + .as_ref() + .and_then(|model| model.effort.clone()); let mut model = LanguageModelRegistry::global(cx).update(cx, |registry, cx| { db_thread @@ -1136,6 +1151,7 @@ impl Thread { summarization_model: None, // TODO: Should we persist this on the `DbThread`? thinking_enabled: enable_thinking, + thinking_effort, project, action_log, updated_at: db_thread.updated_at, @@ -1243,6 +1259,15 @@ impl Thread { cx.notify(); } + pub fn thinking_effort(&self) -> Option<&String> { + self.thinking_effort.as_ref() + } + + pub fn set_thinking_effort(&mut self, effort: Option, cx: &mut Context) { + self.thinking_effort = effort; + cx.notify(); + } + pub fn last_message(&self) -> Option { if let Some(message) = self.pending_message.clone() { Some(Message::Agent(message)) @@ -2329,6 +2354,7 @@ impl Thread { stop: Vec::new(), temperature: AgentSettings::temperature_for_model(model, cx), thinking_allowed: self.thinking_enabled, + thinking_effort: self.thinking_effort.clone(), }; log::debug!("Completion request built successfully"); diff --git a/crates/agent_ui/src/acp/thread_view/active_thread.rs b/crates/agent_ui/src/acp/thread_view/active_thread.rs index b9a9df613d6fbecaaeeec5ed1507b252039fa775..9fca0cfe1fb8b6ca5bcd6dc2724e673faba6e363 100644 --- a/crates/agent_ui/src/acp/thread_view/active_thread.rs +++ b/crates/agent_ui/src/acp/thread_view/active_thread.rs @@ -1,5 +1,7 @@ -use gpui::List; +use gpui::{Corner, List}; +use language_model::LanguageModelEffortLevel; use settings::update_settings_file; +use ui::SplitButton; use super::*; @@ -2349,7 +2351,7 @@ impl AcpThreadView { .gap_0p5() .child(self.render_add_context_button(cx)) .child(self.render_follow_toggle(cx)) - .children(self.render_thinking_toggle(cx)), + .children(self.render_thinking_control(cx)), ) .child( h_flex() @@ -2693,14 +2695,15 @@ impl AcpThreadView { } } - fn render_thinking_toggle(&self, cx: &mut Context) -> Option { + fn render_thinking_control(&self, cx: &mut Context) -> Option { if !cx.has_flag::() { return None; } let thread = self.as_native_thread(cx)?.read(cx); + let model = thread.model()?; - let supports_thinking = thread.model()?.supports_thinking(); + let supports_thinking = model.supports_thinking(); if !supports_thinking { return None; } @@ -2715,34 +2718,137 @@ impl AcpThreadView { let focus_handle = self.message_editor.focus_handle(cx); - Some( - IconButton::new("thinking-mode", icon) - .icon_size(IconSize::Small) - .icon_color(Color::Muted) - .toggle_state(thinking) - .tooltip(move |_, cx| { - Tooltip::for_action_in(tooltip_label, &ToggleThinkingMode, &focus_handle, cx) - }) - .on_click(cx.listener(move |this, _, _window, cx| { - if let Some(thread) = this.as_native_thread(cx) { - thread.update(cx, |thread, 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; - } - }); + let thinking_toggle = IconButton::new("thinking-mode", icon) + .icon_size(IconSize::Small) + .icon_color(Color::Muted) + .toggle_state(thinking) + .tooltip(move |_, cx| { + Tooltip::for_action_in(tooltip_label, &ToggleThinkingMode, &focus_handle, cx) + }) + .on_click(cx.listener(move |this, _, _window, cx| { + if let Some(thread) = this.as_native_thread(cx) { + thread.update(cx, |thread, 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; + } }); - } - })), + }); + } + })); + + if model.supported_effort_levels().is_empty() { + return Some(thinking_toggle.into_any_element()); + } + + Some( + SplitButton::new( + thinking_toggle, + self.render_effort_selector( + model.supported_effort_levels(), + thread.thinking_effort().cloned(), + cx, + ) + .into_any_element(), + ) + .style(ui::SplitButtonStyle::Outlined) + .into_any_element(), ) } + fn render_effort_selector( + &self, + supported_effort_levels: Vec, + selected_effort: Option, + cx: &Context, + ) -> impl IntoElement { + let weak_self = cx.weak_entity(); + + let default_effort_level = supported_effort_levels + .iter() + .find(|effort_level| effort_level.is_default) + .cloned(); + + let selected = selected_effort.and_then(|effort| { + supported_effort_levels + .iter() + .find(|level| level.value == effort) + .cloned() + }); + + PopoverMenu::new("effort-selector") + .trigger( + ui::ButtonLike::new_rounded_right("effort-selector-trigger") + .layer(ui::ElevationIndex::ModalSurface) + .size(ui::ButtonSize::None) + .child( + Label::new( + selected + .clone() + .or(default_effort_level) + .map_or("Select Effort".into(), |effort| effort.name), + ) + .size(LabelSize::Small), + ) + .child( + div() + .px_1() + .child(Icon::new(IconName::ChevronDown).size(IconSize::XSmall)), + ), + ) + .menu(move |window, cx| { + Some(ContextMenu::build(window, cx, |mut menu, _window, _cx| { + for effort_level in supported_effort_levels.clone() { + let is_selected = selected + .as_ref() + .is_some_and(|selected| selected.value == effort_level.value); + let entry = ContextMenuEntry::new(effort_level.name) + .toggleable(IconPosition::End, is_selected); + + menu.push_item(entry.handler({ + let effort = effort_level.value.clone(); + let weak_self = weak_self.clone(); + move |_window, cx| { + let effort = effort.clone(); + weak_self + .update(cx, |this, cx| { + if let Some(thread) = this.as_native_thread(cx) { + thread.update(cx, |thread, cx| { + thread.set_thinking_effort( + Some(effort.to_string()), + 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.effort = + Some(effort.to_string()); + } + }); + }); + } + }) + .ok(); + } + })); + } + + menu + })) + }) + .anchor(Corner::BottomRight) + } + fn render_send_button(&self, cx: &mut Context) -> AnyElement { let message_editor = self.message_editor.read(cx); let is_editor_empty = message_editor.is_empty(cx); 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 38eb1da3cf86c4e7b6dad948360dbeb67381fed2..8bb08404f9fbc4cadf78fabc909122a6118c48ec 100644 --- a/crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs +++ b/crates/agent_ui/src/agent_configuration/manage_profiles_modal.rs @@ -265,6 +265,9 @@ impl ManageProfilesModal { provider: LanguageModelProviderSetting(provider.clone()), model: model_id.clone(), enable_thinking: model.supports_thinking(), + effort: model + .default_effort_level() + .map(|effort| effort.value.to_string()), }); } } diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 9a51a1ed1b47a6a54d3f4c73c682b68edb0c8afc..bd9c31a983b723c222987544561cea82a97bad2b 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -1401,6 +1401,7 @@ impl AgentPanel { provider: LanguageModelProviderSetting(provider), model, enable_thinking: false, + effort: None, }) }); } diff --git a/crates/agent_ui/src/buffer_codegen.rs b/crates/agent_ui/src/buffer_codegen.rs index 2dfde13a714196db2407a348d6a384dd7e1e7089..39759f264996ee07a7efd2b2bee8b1d1e3847f51 100644 --- a/crates/agent_ui/src/buffer_codegen.rs +++ b/crates/agent_ui/src/buffer_codegen.rs @@ -544,6 +544,7 @@ impl CodegenAlternative { temperature, messages, thinking_allowed: false, + thinking_effort: None, } })) } @@ -622,6 +623,7 @@ impl CodegenAlternative { temperature, messages: vec![request_message], thinking_allowed: false, + thinking_effort: None, } })) } diff --git a/crates/agent_ui/src/favorite_models.rs b/crates/agent_ui/src/favorite_models.rs index 5b3c8a6ddfd03f1dfe8b5001cdaa178ced435653..5e69808f225f525a3e052fdb01e4095ef38cac03 100644 --- a/crates/agent_ui/src/favorite_models.rs +++ b/crates/agent_ui/src/favorite_models.rs @@ -10,6 +10,7 @@ fn language_model_to_selection(model: &Arc) -> LanguageModelS provider: model.provider_id().to_string().into(), model: model.id().0.to_string(), enable_thinking: false, + effort: None, } } diff --git a/crates/agent_ui/src/terminal_inline_assistant.rs b/crates/agent_ui/src/terminal_inline_assistant.rs index 58a73131e2d20d0776b2cdc49a0b395834b5008f..8ee59a0a096172ad9a81983f3517226e824c43e7 100644 --- a/crates/agent_ui/src/terminal_inline_assistant.rs +++ b/crates/agent_ui/src/terminal_inline_assistant.rs @@ -275,6 +275,7 @@ impl TerminalInlineAssistant { stop: Vec::new(), temperature, thinking_allowed: false, + thinking_effort: None, } })) } diff --git a/crates/agent_ui/src/text_thread_editor.rs b/crates/agent_ui/src/text_thread_editor.rs index b519508bf3275bb1de2195a8c94e49952e11de48..cb7861564b8a545083561f86ad2900217b6c09d4 100644 --- a/crates/agent_ui/src/text_thread_editor.rs +++ b/crates/agent_ui/src/text_thread_editor.rs @@ -319,13 +319,15 @@ 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(); + let model_id = model.id().0.to_string(); settings.agent.get_or_insert_default().set_model( LanguageModelSelection { provider: LanguageModelProviderSetting(provider), - model, - enable_thinking, + model: model_id, + enable_thinking: model.supports_thinking(), + effort: model + .default_effort_level() + .map(|effort| effort.value.to_string()), }, ) }); diff --git a/crates/anthropic/src/anthropic.rs b/crates/anthropic/src/anthropic.rs index fabf07d433c77aa53d77c9c298f3c53558c39260..175b641daf05ea37e2e451da2ea084765fa604a6 100644 --- a/crates/anthropic/src/anthropic.rs +++ b/crates/anthropic/src/anthropic.rs @@ -961,8 +961,9 @@ pub enum Thinking { Adaptive, } -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, EnumString)] #[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] pub enum Effort { Low, Medium, diff --git a/crates/assistant_text_thread/src/text_thread.rs b/crates/assistant_text_thread/src/text_thread.rs index 034314e349a306040fc0cd37dbc3ad9a5ea6e81b..471a4c1db9532647d4c439aa25b6b13a5e372cdc 100644 --- a/crates/assistant_text_thread/src/text_thread.rs +++ b/crates/assistant_text_thread/src/text_thread.rs @@ -2269,6 +2269,7 @@ impl TextThread { stop: Vec::new(), temperature: model.and_then(|model| AgentSettings::temperature_for_model(model, cx)), thinking_allowed: true, + thinking_effort: None, }; for message in self.messages(cx) { if message.status != MessageStatus::Done { diff --git a/crates/cloud_llm_client/src/cloud_llm_client.rs b/crates/cloud_llm_client/src/cloud_llm_client.rs index 882239716676857cfbf65ea9920530591655d819..f3a41ec3816d29b528a816968bb73259361f15a3 100644 --- a/crates/cloud_llm_client/src/cloud_llm_client.rs +++ b/crates/cloud_llm_client/src/cloud_llm_client.rs @@ -309,6 +309,8 @@ pub struct LanguageModel { pub struct SupportedEffortLevel { pub name: Arc, pub value: Arc, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub is_default: Option, } #[derive(Debug, Serialize, Deserialize)] diff --git a/crates/eval/src/instance.rs b/crates/eval/src/instance.rs index 17b5adfc4aa9621ac4638f873c30e62ab6244107..41234bc02c6cd911b31637e6ab67346e4b9677c0 100644 --- a/crates/eval/src/instance.rs +++ b/crates/eval/src/instance.rs @@ -563,6 +563,7 @@ impl ExampleInstance { tool_choice: None, stop: Vec::new(), thinking_allowed: true, + thinking_effort: None, }; let model = model.clone(); diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 24278420a16d23cfa345bc6ea58138c7f1aa29db..a4d26bc5a5a995f7bbc7af7df1cfef18dfe0b3d8 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -2695,13 +2695,14 @@ impl GitPanel { role: Role::User, content: vec![content.into()], cache: false, - reasoning_details: None, + reasoning_details: None, }], tools: Vec::new(), tool_choice: None, stop: Vec::new(), temperature, thinking_allowed: false, + thinking_effort: None, }; let stream = model.stream_completion_text(request, cx); diff --git a/crates/language_model/src/language_model.rs b/crates/language_model/src/language_model.rs index 49b4ee83828761629ad6c2531449d55c874d6f18..a5f6b796afab01c9253987617321313d07465043 100644 --- a/crates/language_model/src/language_model.rs +++ b/crates/language_model/src/language_model.rs @@ -577,6 +577,7 @@ impl Default for LanguageModelTextStream { pub struct LanguageModelEffortLevel { pub name: SharedString, pub value: SharedString, + pub is_default: bool, } pub trait LanguageModel: Send + Sync { @@ -607,6 +608,13 @@ pub trait LanguageModel: Send + Sync { Vec::new() } + /// Returns the default effort level to use when thinking. + fn default_effort_level(&self) -> Option { + self.supported_effort_levels() + .into_iter() + .find(|effort_level| effort_level.is_default) + } + /// Whether this model supports images fn supports_images(&self) -> bool; diff --git a/crates/language_model/src/request.rs b/crates/language_model/src/request.rs index 1d0b536ec43bd9e930c24e3a733448ae12a8d65b..04a61ae79474ea525cfe522dac2ac75048e7510b 100644 --- a/crates/language_model/src/request.rs +++ b/crates/language_model/src/request.rs @@ -451,6 +451,7 @@ pub struct LanguageModelRequest { pub stop: Vec, pub temperature: Option, pub thinking_allowed: bool, + pub thinking_effort: Option, } #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] diff --git a/crates/language_models/src/provider/anthropic.rs b/crates/language_models/src/provider/anthropic.rs index 7f8f7a1efb3aadcfe913c112103b63c3674bc581..5d4f3b9ef3f012b2d008c9e83bd6719f8d7f4542 100644 --- a/crates/language_models/src/provider/anthropic.rs +++ b/crates/language_models/src/provider/anthropic.rs @@ -1165,6 +1165,7 @@ mod tests { tools: vec![], tool_choice: None, thinking_allowed: true, + thinking_effort: None, }; let anthropic_request = into_anthropic( diff --git a/crates/language_models/src/provider/cloud.rs b/crates/language_models/src/provider/cloud.rs index 869c6e765bfd771de463c0182d436aeccd87e56e..6f9f500713ca304bc16c6a563d0ee030169c0586 100644 --- a/crates/language_models/src/provider/cloud.rs +++ b/crates/language_models/src/provider/cloud.rs @@ -34,6 +34,7 @@ pub use settings::ZedDotDevAvailableModel as AvailableModel; pub use settings::ZedDotDevAvailableProvider as AvailableProvider; use smol::io::{AsyncReadExt, BufReader}; use std::pin::Pin; +use std::str::FromStr; use std::sync::Arc; use std::time::Duration; use thiserror::Error; @@ -584,6 +585,7 @@ impl LanguageModel for CloudLanguageModel { .map(|effort_level| LanguageModelEffortLevel { name: effort_level.name.clone().into(), value: effort_level.value.clone().into(), + is_default: effort_level.is_default.unwrap_or(false), }) .collect() } @@ -745,10 +747,14 @@ impl LanguageModel for CloudLanguageModel { } else { thinking_allowed && self.model.id.0.ends_with("-thinking") }; + let effort = request + .thinking_effort + .as_ref() + .and_then(|effort| anthropic::Effort::from_str(effort).ok()); let provider_name = provider_name(&self.model.provider); match self.model.provider { cloud_llm_client::LanguageModelProvider::Anthropic => { - let request = into_anthropic( + let mut request = into_anthropic( request, self.model.id.to_string(), 1.0, @@ -761,6 +767,12 @@ impl LanguageModel for CloudLanguageModel { AnthropicModelMode::Default }, ); + + if enable_thinking && effort.is_some() { + request.thinking = Some(anthropic::Thinking::Adaptive); + request.output_config = Some(anthropic::OutputConfig { effort }); + } + let client = self.client.clone(); let llm_api_token = self.llm_api_token.clone(); let future = self.request_limiter.stream(async move { diff --git a/crates/language_models/src/provider/copilot_chat.rs b/crates/language_models/src/provider/copilot_chat.rs index 94fc71e691c5f65d4b22efb8e6ad11bb3a1eb0d1..1e5f707259e2bc786bc8d7002f3aca8fbe1c565d 100644 --- a/crates/language_models/src/provider/copilot_chat.rs +++ b/crates/language_models/src/provider/copilot_chat.rs @@ -929,6 +929,7 @@ fn into_copilot_responses( stop: _, temperature, thinking_allowed: _, + thinking_effort: _, } = request; let mut input_items: Vec = Vec::new(); diff --git a/crates/language_models/src/provider/mistral.rs b/crates/language_models/src/provider/mistral.rs index 0fa4755ed544b2026b1ce17accf32f712c6026c5..c8f6f71b0c9c73f07cd24712420ebf7543e06e02 100644 --- a/crates/language_models/src/provider/mistral.rs +++ b/crates/language_models/src/provider/mistral.rs @@ -861,6 +861,7 @@ mod tests { intent: None, stop: vec![], thinking_allowed: true, + thinking_effort: None, }; let mistral_request = into_mistral(request, mistral::Model::MistralSmallLatest, None); @@ -894,6 +895,7 @@ mod tests { intent: None, stop: vec![], thinking_allowed: true, + thinking_effort: None, }; let mistral_request = into_mistral(request, mistral::Model::Pixtral12BLatest, None); diff --git a/crates/language_models/src/provider/open_ai.rs b/crates/language_models/src/provider/open_ai.rs index 04b3ded08f970e814c7d7ee9bd30bb73d6c60f0b..87c43fc547bdf1c6c0455214b7281c4df29d0f9c 100644 --- a/crates/language_models/src/provider/open_ai.rs +++ b/crates/language_models/src/provider/open_ai.rs @@ -552,6 +552,7 @@ pub fn into_open_ai_response( stop: _, temperature, thinking_allowed: _, + thinking_effort: _, } = request; let mut input_items = Vec::new(); @@ -1434,6 +1435,7 @@ mod tests { stop: vec![], temperature: None, thinking_allowed: true, + thinking_effort: None, }; // Validate that all models are supported by tiktoken-rs @@ -1570,6 +1572,7 @@ mod tests { stop: vec!["".into()], temperature: None, thinking_allowed: false, + thinking_effort: None, }; let response = into_open_ai_response( diff --git a/crates/rules_library/src/rules_library.rs b/crates/rules_library/src/rules_library.rs index ce8b24d2d1bc6e64372333ed5d17c55dbc1460c0..30a986add52ec935aeb5752d9d2b2fc214d60a84 100644 --- a/crates/rules_library/src/rules_library.rs +++ b/crates/rules_library/src/rules_library.rs @@ -1103,6 +1103,7 @@ impl RulesLibrary { stop: Vec::new(), temperature: None, thinking_allowed: true, + thinking_effort: None, }, cx, ) diff --git a/crates/settings_content/src/agent.rs b/crates/settings_content/src/agent.rs index c0eb919e88abc5cd0d8f2d2b558b0af8da5bfff2..4bd64441863bf0aede39ad3bc4e3fcfa25ac84df 100644 --- a/crates/settings_content/src/agent.rs +++ b/crates/settings_content/src/agent.rs @@ -152,6 +152,7 @@ impl AgentSettingsContent { provider: provider.into(), model, enable_thinking: false, + effort: None, }); } @@ -265,6 +266,7 @@ pub struct LanguageModelSelection { pub model: String, #[serde(default)] pub enable_thinking: bool, + pub effort: Option, } #[with_fallible_options]