Split external agent flags (#36499)

Agus Zubiaga created

Release Notes:

- N/A

Change summary

crates/agent_ui/src/agent_panel.rs        | 132 ++++++++++++++----------
crates/feature_flags/src/feature_flags.rs |   6 +
2 files changed, 82 insertions(+), 56 deletions(-)

Detailed changes

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<dyn AgentServer> = 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::<AcpFeatureFlag>() {
+                            return;
+                        }
+                    }
+                    crate::ExternalAgent::ClaudeCode => {
+                        if !cx.has_flag::<ClaudeCodeFeatureFlag>() {
+                            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::<AgentPanel>(cx)
-                                                    {
-                                                        panel.update(cx, |panel, cx| {
-                                                            panel.set_selected_agent(
-                                                                AgentType::Gemini,
-                                                                window,
-                                                                cx,
-                                                            );
-                                                        });
-                                                    }
-                                                });
+                            .when(cx.has_flag::<AcpFeatureFlag>(), |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::<AgentPanel>(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::<AgentPanel>(cx)
-                                                    {
-                                                        panel.update(cx, |panel, cx| {
-                                                            panel.set_selected_agent(
-                                                                AgentType::ClaudeCode,
-                                                                window,
-                                                                cx,
-                                                            );
-                                                        });
-                                                    }
-                                                });
+                                        }),
+                                )
+                            })
+                            .when(cx.has_flag::<ClaudeCodeFeatureFlag>(), |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::<AgentPanel>(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<Self>) -> impl IntoElement {
-        if cx.has_flag::<feature_flags::AcpFeatureFlag>() {
+        if cx.has_flag::<feature_flags::AcpFeatureFlag>()
+            || cx.has_flag::<feature_flags::ClaudeCodeFeatureFlag>()
+        {
             self.render_toolbar_new(window, cx).into_any_element()
         } else {
             self.render_toolbar_old(window, cx).into_any_element()

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<V: 'static> {
     fn observe_flag<T: FeatureFlag, F>(&mut self, window: &Window, callback: F) -> Subscription
     where