From 154b01c5fe55192d5f319c1858556f3246f49952 Mon Sep 17 00:00:00 2001 From: Finn Evers Date: Fri, 19 Sep 2025 17:05:39 +0200 Subject: [PATCH] Dismiss agent panel when `disable_ai` is toggled to `true` (#38461) Closes https://github.com/zed-industries/zed/issues/38331 This fixes an issue where we would not dismiss the panel once the user toggled the setting, leaving them in an awkward state where closing the panel would become hard. Also takes care of one more check for the `Fix with assistant` action and consolidates some of the `AgentSettings` and `DisableAiSetting` checks into one method to make the code more readable. Release Notes: - N/A --- Cargo.lock | 1 + crates/agent_settings/Cargo.toml | 1 + crates/agent_settings/src/agent_settings.rs | 5 +++ crates/agent_ui/src/agent_panel.rs | 44 ++++++++++++++++++--- crates/agent_ui/src/inline_assistant.rs | 8 ++-- crates/git_ui/src/git_panel.rs | 22 ++++------- crates/zed/src/zed/quick_action_bar.rs | 18 +++------ 7 files changed, 61 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3acfed9bd7cfa8bc2742bb4f006c38a4f65a1f0e..ed1e9bef3f1797201dd791a7b4616509bbbc5036 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,6 +337,7 @@ dependencies = [ "gpui", "language_model", "paths", + "project", "schemars 1.0.1", "serde", "serde_json", diff --git a/crates/agent_settings/Cargo.toml b/crates/agent_settings/Cargo.toml index 8af76053c2aabead30413c98e482ed97dbdbc361..a8b457a9dddb1f8932d015f895e6d2064944bfe9 100644 --- a/crates/agent_settings/Cargo.toml +++ b/crates/agent_settings/Cargo.toml @@ -19,6 +19,7 @@ convert_case.workspace = true fs.workspace = true gpui.workspace = true language_model.workspace = true +project.workspace = true schemars.workspace = true serde.workspace = true settings.workspace = true diff --git a/crates/agent_settings/src/agent_settings.rs b/crates/agent_settings/src/agent_settings.rs index e416ce73e5451e840af8c36e8ffee301bacc79b3..d862cacee18ea53f81cdc91981b22f5531f2d75e 100644 --- a/crates/agent_settings/src/agent_settings.rs +++ b/crates/agent_settings/src/agent_settings.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use collections::IndexMap; use gpui::{App, Pixels, px}; use language_model::LanguageModel; +use project::DisableAiSettings; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{ @@ -53,6 +54,10 @@ pub struct AgentSettings { } impl AgentSettings { + pub fn enabled(&self, cx: &App) -> bool { + self.enabled && !DisableAiSettings::get_global(cx).disable_ai + } + pub fn temperature_for_model(model: &Arc, cx: &App) -> Option { let settings = Self::get_global(cx); for setting in settings.model_parameters.iter().rev() { diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index ee9ac73b2ee23a8b4326ddbc4e60c345ef4a3526..ba71fd84ab5b9d666256afeb0a2c5677aac9adb1 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -1,4 +1,4 @@ -use std::ops::{Not, Range}; +use std::ops::Range; use std::path::Path; use std::rc::Rc; use std::sync::Arc; @@ -662,6 +662,43 @@ impl AgentPanel { ) }); + let mut old_disable_ai = false; + cx.observe_global_in::(window, move |panel, window, cx| { + let disable_ai = DisableAiSettings::get_global(cx).disable_ai; + if old_disable_ai != disable_ai { + let agent_panel_id = cx.entity_id(); + let agent_panel_visible = panel + .workspace + .update(cx, |workspace, cx| { + let agent_dock_position = panel.position(window, cx); + let agent_dock = workspace.dock_at_position(agent_dock_position); + let agent_panel_focused = agent_dock + .read(cx) + .active_panel() + .is_some_and(|panel| panel.panel_id() == agent_panel_id); + + let active_panel_visible = agent_dock + .read(cx) + .visible_panel() + .is_some_and(|panel| panel.panel_id() == agent_panel_id); + + if agent_panel_focused { + cx.dispatch_action(&ToggleFocus); + } + + active_panel_visible + }) + .unwrap_or_default(); + + if agent_panel_visible { + cx.emit(PanelEvent::Close); + } + + old_disable_ai = disable_ai; + } + }) + .detach(); + Self { active_view, workspace, @@ -674,11 +711,9 @@ impl AgentPanel { prompt_store, configuration: None, configuration_subscription: None, - inline_assist_context_store, previous_view: None, history_store: history_store.clone(), - new_thread_menu_handle: PopoverMenuHandle::default(), agent_panel_menu_handle: PopoverMenuHandle::default(), assistant_navigation_menu_handle: PopoverMenuHandle::default(), @@ -703,7 +738,6 @@ impl AgentPanel { if workspace .panel::(cx) .is_some_and(|panel| panel.read(cx).enabled(cx)) - && !DisableAiSettings::get_global(cx).disable_ai { workspace.toggle_panel_focus::(window, cx); } @@ -1499,7 +1533,7 @@ impl Panel for AgentPanel { } fn enabled(&self, cx: &App) -> bool { - DisableAiSettings::get_global(cx).disable_ai.not() && AgentSettings::get_global(cx).enabled + AgentSettings::get_global(cx).enabled(cx) } fn is_zoomed(&self, _window: &Window, _cx: &App) -> bool { diff --git a/crates/agent_ui/src/inline_assistant.rs b/crates/agent_ui/src/inline_assistant.rs index 79e092b709dd2778c89a79e1d6ce36802c853eb6..98e7276dc4fd3f94b01df82219f116a07cafa304 100644 --- a/crates/agent_ui/src/inline_assistant.rs +++ b/crates/agent_ui/src/inline_assistant.rs @@ -144,8 +144,7 @@ impl InlineAssistant { let Some(terminal_panel) = workspace.read(cx).panel::(cx) else { return; }; - let enabled = !DisableAiSettings::get_global(cx).disable_ai - && AgentSettings::get_global(cx).enabled; + let enabled = AgentSettings::get_global(cx).enabled(cx); terminal_panel.update(cx, |terminal_panel, cx| { terminal_panel.set_assistant_enabled(enabled, cx) }); @@ -257,8 +256,7 @@ impl InlineAssistant { window: &mut Window, cx: &mut Context, ) { - let settings = AgentSettings::get_global(cx); - if !settings.enabled || DisableAiSettings::get_global(cx).disable_ai { + if !AgentSettings::get_global(cx).enabled(cx) { return; } @@ -1788,7 +1786,7 @@ impl CodeActionProvider for AssistantCodeActionProvider { _: &mut Window, cx: &mut App, ) -> Task>> { - if !AgentSettings::get_global(cx).enabled { + if !AgentSettings::get_global(cx).enabled(cx) { return Task::ready(Ok(Vec::new())); } diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 76671eba7b577e86d5049add743e965d11acd6c4..47dcc68d2137f75666ae04d2b8ffe4e87cb478f8 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -46,7 +46,7 @@ use panel::{ panel_icon_button, }; use project::{ - DisableAiSettings, Fs, Project, ProjectPath, + Fs, Project, ProjectPath, git_store::{GitStoreEvent, Repository, RepositoryEvent, RepositoryId}, }; use serde::{Deserialize, Serialize}; @@ -405,15 +405,11 @@ impl GitPanel { let scroll_handle = UniformListScrollHandle::new(); - let mut assistant_enabled = AgentSettings::get_global(cx).enabled; - let mut was_ai_disabled = DisableAiSettings::get_global(cx).disable_ai; + let mut was_ai_enabled = AgentSettings::get_global(cx).enabled(cx); let _settings_subscription = cx.observe_global::(move |_, cx| { - let is_ai_disabled = DisableAiSettings::get_global(cx).disable_ai; - if assistant_enabled != AgentSettings::get_global(cx).enabled - || was_ai_disabled != is_ai_disabled - { - assistant_enabled = AgentSettings::get_global(cx).enabled; - was_ai_disabled = is_ai_disabled; + let is_ai_enabled = AgentSettings::get_global(cx).enabled(cx); + if was_ai_enabled != is_ai_enabled { + was_ai_enabled = is_ai_enabled; cx.notify(); } }); @@ -1739,10 +1735,7 @@ impl GitPanel { /// Generates a commit message using an LLM. pub fn generate_commit_message(&mut self, cx: &mut Context) { - if !self.can_commit() - || DisableAiSettings::get_global(cx).disable_ai - || !agent_settings::AgentSettings::get_global(cx).enabled - { + if !self.can_commit() || !AgentSettings::get_global(cx).enabled(cx) { return; } @@ -2996,8 +2989,7 @@ impl GitPanel { &self, cx: &Context, ) -> Option { - if !agent_settings::AgentSettings::get_global(cx).enabled - || DisableAiSettings::get_global(cx).disable_ai + if !agent_settings::AgentSettings::get_global(cx).enabled(cx) || LanguageModelRegistry::read_global(cx) .commit_message_model() .is_none() diff --git a/crates/zed/src/zed/quick_action_bar.rs b/crates/zed/src/zed/quick_action_bar.rs index a6f85000e9b2fd2b853880a9045984938b6a7445..df1a417f5815753698a18b077d69c81c5b7ba3ed 100644 --- a/crates/zed/src/zed/quick_action_bar.rs +++ b/crates/zed/src/zed/quick_action_bar.rs @@ -15,7 +15,6 @@ use gpui::{ FocusHandle, Focusable, InteractiveElement, ParentElement, Render, Styled, Subscription, WeakEntity, Window, anchored, deferred, point, }; -use project::DisableAiSettings; use project::project_settings::DiagnosticSeverity; use search::{BufferSearchBar, buffer_search}; use settings::{Settings, SettingsStore}; @@ -48,20 +47,15 @@ impl QuickActionBar { workspace: &Workspace, cx: &mut Context, ) -> Self { - let mut was_ai_disabled = DisableAiSettings::get_global(cx).disable_ai; - let mut was_agent_enabled = AgentSettings::get_global(cx).enabled; + let mut was_agent_enabled = AgentSettings::get_global(cx).enabled(cx); let mut was_agent_button = AgentSettings::get_global(cx).button; let ai_settings_subscription = cx.observe_global::(move |_, cx| { - let is_ai_disabled = DisableAiSettings::get_global(cx).disable_ai; let agent_settings = AgentSettings::get_global(cx); + let is_agent_enabled = agent_settings.enabled(cx); - if was_ai_disabled != is_ai_disabled - || was_agent_enabled != agent_settings.enabled - || was_agent_button != agent_settings.button - { - was_ai_disabled = is_ai_disabled; - was_agent_enabled = agent_settings.enabled; + if was_agent_enabled != is_agent_enabled || was_agent_button != agent_settings.button { + was_agent_enabled = is_agent_enabled; was_agent_button = agent_settings.button; cx.notify(); } @@ -597,9 +591,7 @@ impl Render for QuickActionBar { .children(self.render_preview_button(self.workspace.clone(), cx)) .children(search_button) .when( - AgentSettings::get_global(cx).enabled - && AgentSettings::get_global(cx).button - && !DisableAiSettings::get_global(cx).disable_ai, + AgentSettings::get_global(cx).enabled(cx) && AgentSettings::get_global(cx).button, |bar| bar.child(assistant_button), ) .children(code_actions_dropdown)