From e092aed253a7814f3fb04b4b700e9b65c80ec993 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 19 Aug 2025 14:25:25 -0300 Subject: [PATCH] Split external agent flags (#36499) Release Notes: - N/A --- crates/agent_ui/src/agent_panel.rs | 132 +++++++++++++--------- crates/feature_flags/src/feature_flags.rs | 6 + 2 files changed, 82 insertions(+), 56 deletions(-) diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 55d07ed495..995bf771e2 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -4,7 +4,6 @@ use std::rc::Rc; use std::sync::Arc; use std::time::Duration; -use agent_servers::AgentServer; use db::kvp::{Dismissable, KEY_VALUE_STORE}; use serde::{Deserialize, Serialize}; @@ -44,7 +43,7 @@ use assistant_tool::ToolWorkingSet; use client::{UserStore, zed_urls}; use cloud_llm_client::{CompletionIntent, Plan, UsageLimit}; use editor::{Anchor, AnchorRangeExt as _, Editor, EditorEvent, MultiBuffer}; -use feature_flags::{self, FeatureFlagAppExt}; +use feature_flags::{self, AcpFeatureFlag, ClaudeCodeFeatureFlag, FeatureFlagAppExt}; use fs::Fs; use gpui::{ Action, Animation, AnimationExt as _, AnyElement, App, AsyncWindowContext, ClipboardItem, @@ -971,7 +970,7 @@ impl AgentPanel { let text_thread_store = self.context_store.clone(); cx.spawn_in(window, async move |this, cx| { - let server: Rc = match agent_choice { + let ext_agent = match agent_choice { Some(agent) => { cx.background_spawn(async move { if let Some(serialized) = @@ -985,10 +984,10 @@ impl AgentPanel { }) .detach(); - agent.server(fs) + agent } - None => cx - .background_spawn(async move { + None => { + cx.background_spawn(async move { KEY_VALUE_STORE.read_kvp(LAST_USED_EXTERNAL_AGENT_KEY) }) .await @@ -999,10 +998,25 @@ impl AgentPanel { }) .unwrap_or_default() .agent - .server(fs), + } }; + let server = ext_agent.server(fs); + this.update_in(cx, |this, window, cx| { + match ext_agent { + crate::ExternalAgent::Gemini | crate::ExternalAgent::NativeAgent => { + if !cx.has_flag::() { + return; + } + } + crate::ExternalAgent::ClaudeCode => { + if !cx.has_flag::() { + return; + } + } + } + let thread_view = cx.new(|cx| { crate::acp::AcpThreadView::new( server, @@ -2320,56 +2334,60 @@ impl AgentPanel { ) .separator() .header("External Agents") - .item( - ContextMenuEntry::new("New Gemini Thread") - .icon(IconName::AiGemini) - .icon_color(Color::Muted) - .handler({ - let workspace = workspace.clone(); - move |window, cx| { - if let Some(workspace) = workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - if let Some(panel) = - workspace.panel::(cx) - { - panel.update(cx, |panel, cx| { - panel.set_selected_agent( - AgentType::Gemini, - window, - cx, - ); - }); - } - }); + .when(cx.has_flag::(), |menu| { + menu.item( + ContextMenuEntry::new("New Gemini Thread") + .icon(IconName::AiGemini) + .icon_color(Color::Muted) + .handler({ + let workspace = workspace.clone(); + move |window, cx| { + if let Some(workspace) = workspace.upgrade() { + workspace.update(cx, |workspace, cx| { + if let Some(panel) = + workspace.panel::(cx) + { + panel.update(cx, |panel, cx| { + panel.set_selected_agent( + AgentType::Gemini, + window, + cx, + ); + }); + } + }); + } } - } - }), - ) - .item( - ContextMenuEntry::new("New Claude Code Thread") - .icon(IconName::AiClaude) - .icon_color(Color::Muted) - .handler({ - let workspace = workspace.clone(); - move |window, cx| { - if let Some(workspace) = workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - if let Some(panel) = - workspace.panel::(cx) - { - panel.update(cx, |panel, cx| { - panel.set_selected_agent( - AgentType::ClaudeCode, - window, - cx, - ); - }); - } - }); + }), + ) + }) + .when(cx.has_flag::(), |menu| { + menu.item( + ContextMenuEntry::new("New Claude Code Thread") + .icon(IconName::AiClaude) + .icon_color(Color::Muted) + .handler({ + let workspace = workspace.clone(); + move |window, cx| { + if let Some(workspace) = workspace.upgrade() { + workspace.update(cx, |workspace, cx| { + if let Some(panel) = + workspace.panel::(cx) + { + panel.update(cx, |panel, cx| { + panel.set_selected_agent( + AgentType::ClaudeCode, + window, + cx, + ); + }); + } + }); + } } - } - }), - ); + }), + ) + }); menu })) } @@ -2439,7 +2457,9 @@ impl AgentPanel { } fn render_toolbar(&self, window: &mut Window, cx: &mut Context) -> impl IntoElement { - if cx.has_flag::() { + if cx.has_flag::() + || cx.has_flag::() + { self.render_toolbar_new(window, cx).into_any_element() } else { self.render_toolbar_old(window, cx).into_any_element() diff --git a/crates/feature_flags/src/feature_flags.rs b/crates/feature_flags/src/feature_flags.rs index f87932bfaf..7c12571f24 100644 --- a/crates/feature_flags/src/feature_flags.rs +++ b/crates/feature_flags/src/feature_flags.rs @@ -95,6 +95,12 @@ impl FeatureFlag for AcpFeatureFlag { const NAME: &'static str = "acp"; } +pub struct ClaudeCodeFeatureFlag; + +impl FeatureFlag for ClaudeCodeFeatureFlag { + const NAME: &'static str = "claude-code"; +} + pub trait FeatureFlagViewExt { fn observe_flag(&mut self, window: &Window, callback: F) -> Subscription where