Split external agent flags (#36499)

Release Notes:

- N/A
This commit is contained in:
Agus Zubiaga 2025-08-19 14:25:25 -03:00 committed by GitHub
parent d1cabef2bf
commit e092aed253
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 82 additions and 56 deletions

View file

@ -4,7 +4,6 @@ use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use agent_servers::AgentServer;
use db::kvp::{Dismissable, KEY_VALUE_STORE}; use db::kvp::{Dismissable, KEY_VALUE_STORE};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -44,7 +43,7 @@ use assistant_tool::ToolWorkingSet;
use client::{UserStore, zed_urls}; use client::{UserStore, zed_urls};
use cloud_llm_client::{CompletionIntent, Plan, UsageLimit}; use cloud_llm_client::{CompletionIntent, Plan, UsageLimit};
use editor::{Anchor, AnchorRangeExt as _, Editor, EditorEvent, MultiBuffer}; use editor::{Anchor, AnchorRangeExt as _, Editor, EditorEvent, MultiBuffer};
use feature_flags::{self, FeatureFlagAppExt}; use feature_flags::{self, AcpFeatureFlag, ClaudeCodeFeatureFlag, FeatureFlagAppExt};
use fs::Fs; use fs::Fs;
use gpui::{ use gpui::{
Action, Animation, AnimationExt as _, AnyElement, App, AsyncWindowContext, ClipboardItem, Action, Animation, AnimationExt as _, AnyElement, App, AsyncWindowContext, ClipboardItem,
@ -971,7 +970,7 @@ impl AgentPanel {
let text_thread_store = self.context_store.clone(); let text_thread_store = self.context_store.clone();
cx.spawn_in(window, async move |this, cx| { cx.spawn_in(window, async move |this, cx| {
let server: Rc<dyn AgentServer> = match agent_choice { let ext_agent = match agent_choice {
Some(agent) => { Some(agent) => {
cx.background_spawn(async move { cx.background_spawn(async move {
if let Some(serialized) = if let Some(serialized) =
@ -985,10 +984,10 @@ impl AgentPanel {
}) })
.detach(); .detach();
agent.server(fs) agent
} }
None => cx None => {
.background_spawn(async move { cx.background_spawn(async move {
KEY_VALUE_STORE.read_kvp(LAST_USED_EXTERNAL_AGENT_KEY) KEY_VALUE_STORE.read_kvp(LAST_USED_EXTERNAL_AGENT_KEY)
}) })
.await .await
@ -999,10 +998,25 @@ impl AgentPanel {
}) })
.unwrap_or_default() .unwrap_or_default()
.agent .agent
.server(fs), }
}; };
let server = ext_agent.server(fs);
this.update_in(cx, |this, window, cx| { 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| { let thread_view = cx.new(|cx| {
crate::acp::AcpThreadView::new( crate::acp::AcpThreadView::new(
server, server,
@ -2320,56 +2334,60 @@ impl AgentPanel {
) )
.separator() .separator()
.header("External Agents") .header("External Agents")
.item( .when(cx.has_flag::<AcpFeatureFlag>(), |menu| {
ContextMenuEntry::new("New Gemini Thread") menu.item(
.icon(IconName::AiGemini) ContextMenuEntry::new("New Gemini Thread")
.icon_color(Color::Muted) .icon(IconName::AiGemini)
.handler({ .icon_color(Color::Muted)
let workspace = workspace.clone(); .handler({
move |window, cx| { let workspace = workspace.clone();
if let Some(workspace) = workspace.upgrade() { move |window, cx| {
workspace.update(cx, |workspace, cx| { if let Some(workspace) = workspace.upgrade() {
if let Some(panel) = workspace.update(cx, |workspace, cx| {
workspace.panel::<AgentPanel>(cx) if let Some(panel) =
{ workspace.panel::<AgentPanel>(cx)
panel.update(cx, |panel, cx| { {
panel.set_selected_agent( panel.update(cx, |panel, cx| {
AgentType::Gemini, panel.set_selected_agent(
window, AgentType::Gemini,
cx, window,
); cx,
}); );
} });
}); }
});
}
} }
} }),
}), )
) })
.item( .when(cx.has_flag::<ClaudeCodeFeatureFlag>(), |menu| {
ContextMenuEntry::new("New Claude Code Thread") menu.item(
.icon(IconName::AiClaude) ContextMenuEntry::new("New Claude Code Thread")
.icon_color(Color::Muted) .icon(IconName::AiClaude)
.handler({ .icon_color(Color::Muted)
let workspace = workspace.clone(); .handler({
move |window, cx| { let workspace = workspace.clone();
if let Some(workspace) = workspace.upgrade() { move |window, cx| {
workspace.update(cx, |workspace, cx| { if let Some(workspace) = workspace.upgrade() {
if let Some(panel) = workspace.update(cx, |workspace, cx| {
workspace.panel::<AgentPanel>(cx) if let Some(panel) =
{ workspace.panel::<AgentPanel>(cx)
panel.update(cx, |panel, cx| { {
panel.set_selected_agent( panel.update(cx, |panel, cx| {
AgentType::ClaudeCode, panel.set_selected_agent(
window, AgentType::ClaudeCode,
cx, window,
); cx,
}); );
} });
}); }
});
}
} }
} }),
}), )
); });
menu menu
})) }))
} }
@ -2439,7 +2457,9 @@ impl AgentPanel {
} }
fn render_toolbar(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { 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() self.render_toolbar_new(window, cx).into_any_element()
} else { } else {
self.render_toolbar_old(window, cx).into_any_element() self.render_toolbar_old(window, cx).into_any_element()

View file

@ -95,6 +95,12 @@ impl FeatureFlag for AcpFeatureFlag {
const NAME: &'static str = "acp"; const NAME: &'static str = "acp";
} }
pub struct ClaudeCodeFeatureFlag;
impl FeatureFlag for ClaudeCodeFeatureFlag {
const NAME: &'static str = "claude-code";
}
pub trait FeatureFlagViewExt<V: 'static> { pub trait FeatureFlagViewExt<V: 'static> {
fn observe_flag<T: FeatureFlag, F>(&mut self, window: &Window, callback: F) -> Subscription fn observe_flag<T: FeatureFlag, F>(&mut self, window: &Window, callback: F) -> Subscription
where where