From 753302ef5c297b6625b89d08dc1e4d901a1fc160 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Fri, 23 Jan 2026 13:03:32 +0100 Subject: [PATCH] acp: Promote registry as default way of installing new agents (#47464) Release Notes: - acp: Add the ability to install new Agents via the ACP Registry --- crates/agent_ui/src/agent_configuration.rs | 23 +------ crates/agent_ui/src/agent_panel.rs | 38 +++++++---- crates/agent_ui/src/agent_ui.rs | 5 +- crates/extensions_ui/src/extensions_ui.rs | 3 +- crates/project/src/agent_server_store.rs | 77 +++++++++++----------- crates/zed/src/main.rs | 11 +--- 6 files changed, 71 insertions(+), 86 deletions(-) diff --git a/crates/agent_ui/src/agent_configuration.rs b/crates/agent_ui/src/agent_configuration.rs index b1efc41f1cb0d973ae7fa1699185b419479d7cbe..4e6f38a1eb9e9739f8e55366ec7c6f551bae86c8 100644 --- a/crates/agent_ui/src/agent_configuration.rs +++ b/crates/agent_ui/src/agent_configuration.rs @@ -15,7 +15,6 @@ use context_server::ContextServerId; use editor::{Editor, MultiBufferOffset, SelectionEffects, scroll::Autoscroll}; use extension::ExtensionManifest; use extension_host::ExtensionStore; -use feature_flags::{AcpBetaFeatureFlag, FeatureFlagAppExt as _}; use fs::Fs; use gpui::{ Action, AnyView, App, AsyncWindowContext, Corner, Entity, EventEmitter, FocusHandle, Focusable, @@ -999,26 +998,10 @@ impl AgentConfiguration { ) .menu({ move |window, cx| { - Some(ContextMenu::build(window, cx, |mut menu, _window, _cx| { - if _cx.has_flag::() { - menu = menu.entry("Install from Registry", None, { - |window, cx| { - window.dispatch_action(Box::new(zed_actions::AgentRegistry), cx) - } - }); - } - menu.entry("Install from Extensions", None, { + Some(ContextMenu::build(window, cx, |menu, _window, _cx| { + menu.entry("Install from Registry", None, { |window, cx| { - window.dispatch_action( - zed_actions::Extensions { - category_filter: Some( - ExtensionCategoryFilter::AgentServers, - ), - id: None, - } - .boxed_clone(), - cx, - ) + window.dispatch_action(Box::new(zed_actions::AgentRegistry), cx) } }) .entry("Add Custom Agent", None, { diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 4a1362515587507307278a01af1f9b35f552792c..c502735dd98cc1412ba0bb826dac6acf88f0e76d 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -2046,9 +2046,15 @@ impl AgentPanel { }) .item( ContextMenuEntry::new("Zed Agent") - .when(is_agent_selected(AgentType::NativeAgent) | is_agent_selected(AgentType::TextThread) , |this| { - this.action(Box::new(NewExternalAgentThread { agent: None })) - }) + .when( + is_agent_selected(AgentType::NativeAgent) + | is_agent_selected(AgentType::TextThread), + |this| { + this.action(Box::new(NewExternalAgentThread { + agent: None, + })) + }, + ) .icon(IconName::ZedAgent) .icon_color(Color::Muted) .handler({ @@ -2103,7 +2109,9 @@ impl AgentPanel { .item( ContextMenuEntry::new("Claude Code") .when(is_agent_selected(AgentType::ClaudeCode), |this| { - this.action(Box::new(NewExternalAgentThread { agent: None })) + this.action(Box::new(NewExternalAgentThread { + agent: None, + })) }) .icon(IconName::AiClaude) .disabled(is_via_collab) @@ -2132,7 +2140,9 @@ impl AgentPanel { .item( ContextMenuEntry::new("Codex CLI") .when(is_agent_selected(AgentType::Codex), |this| { - this.action(Box::new(NewExternalAgentThread { agent: None })) + this.action(Box::new(NewExternalAgentThread { + agent: None, + })) }) .icon(IconName::AiOpenAi) .disabled(is_via_collab) @@ -2161,7 +2171,9 @@ impl AgentPanel { .item( ContextMenuEntry::new("Gemini CLI") .when(is_agent_selected(AgentType::Gemini), |this| { - this.action(Box::new(NewExternalAgentThread { agent: None })) + this.action(Box::new(NewExternalAgentThread { + agent: None, + })) }) .icon(IconName::AiGemini) .icon_color(Color::Muted) @@ -2218,7 +2230,9 @@ impl AgentPanel { name: agent_name.0.clone(), }), |this| { - this.action(Box::new(NewExternalAgentThread { agent: None })) + this.action(Box::new(NewExternalAgentThread { + agent: None, + })) }, ) .icon_color(Color::Muted) @@ -2261,12 +2275,10 @@ impl AgentPanel { .icon_color(Color::Muted) .handler({ move |window, cx| { - window.dispatch_action(Box::new(zed_actions::Extensions { - category_filter: Some( - zed_actions::ExtensionCategoryFilter::AgentServers, - ), - id: None, - }), cx) + window.dispatch_action( + Box::new(zed_actions::AgentRegistry), + cx, + ) } }), ) diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index fdde112782bd25c07df4e2ee4603e3cd3fa27a46..5da5bababb69ceaece575ba0bcb771fb528a076f 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -30,7 +30,7 @@ use agent_settings::{AgentProfileId, AgentSettings}; use assistant_slash_command::SlashCommandRegistry; use client::Client; use command_palette_hooks::CommandPaletteFilter; -use feature_flags::{AcpBetaFeatureFlag, AgentV2FeatureFlag, FeatureFlagAppExt as _}; +use feature_flags::{AgentV2FeatureFlag, FeatureFlagAppExt as _}; use fs::Fs; use gpui::{Action, App, Context, Entity, SharedString, Window, actions}; use language::{ @@ -279,9 +279,6 @@ pub fn init( _: &zed_actions::AgentRegistry, window: &mut Window, cx: &mut Context| { - if !cx.has_flag::() { - return; - } let existing = workspace .active_pane() .read(cx) diff --git a/crates/extensions_ui/src/extensions_ui.rs b/crates/extensions_ui/src/extensions_ui.rs index 79ac0653b656f5ed73ae457bf8e72e0d3f4fbbe8..06a88bbcbe2428955c90a48f4b60cdc3d03721ab 100644 --- a/crates/extensions_ui/src/extensions_ui.rs +++ b/crates/extensions_ui/src/extensions_ui.rs @@ -1704,7 +1704,8 @@ impl Render for ExtensionsPage { ) .children(ExtensionProvides::iter().filter_map(|provides| { match provides { - ExtensionProvides::SlashCommands + ExtensionProvides::AgentServers + | ExtensionProvides::SlashCommands | ExtensionProvides::IndexedDocsProviders => return None, _ => {} } diff --git a/crates/project/src/agent_server_store.rs b/crates/project/src/agent_server_store.rs index 44f0373acfb44dd48ce48f39b710e9ca906c273a..ce40356b77ad248dd3e7405823f4fb40066ebf27 100644 --- a/crates/project/src/agent_server_store.rs +++ b/crates/project/src/agent_server_store.rs @@ -723,6 +723,45 @@ impl AgentServerStore { }) .unwrap_or_default(); + // Insert extension agents before custom/registry so registry entries override extensions. + for (agent_name, ext_id, targets, env, icon_path, display_name) in extension_agents.iter() { + let name = ExternalAgentServerName(agent_name.clone().into()); + let mut env = env.clone(); + if let Some(settings_env) = + new_settings + .custom + .get(agent_name.as_ref()) + .and_then(|settings| match settings { + CustomAgentServerSettings::Extension { env, .. } => Some(env.clone()), + _ => None, + }) + { + env.extend(settings_env); + } + let icon = icon_path + .as_ref() + .map(|path| SharedString::from(path.clone())); + + self.external_agents.insert( + name.clone(), + ExternalAgentEntry::new( + Box::new(LocalExtensionArchiveAgent { + fs: fs.clone(), + http_client: http_client.clone(), + node_runtime: node_runtime.clone(), + project_environment: project_environment.clone(), + extension_id: Arc::from(&**ext_id), + targets: targets.clone(), + env, + agent_id: agent_name.clone(), + }) as Box, + ExternalAgentSource::Extension, + icon, + display_name.clone(), + ), + ); + } + for (name, settings) in &new_settings.custom { match settings { CustomAgentServerSettings::Custom { command, .. } => { @@ -803,44 +842,6 @@ impl AgentServerStore { } } - for (agent_name, ext_id, targets, env, icon_path, display_name) in extension_agents.iter() { - let name = ExternalAgentServerName(agent_name.clone().into()); - let mut env = env.clone(); - if let Some(settings_env) = - new_settings - .custom - .get(agent_name.as_ref()) - .and_then(|settings| match settings { - CustomAgentServerSettings::Extension { env, .. } => Some(env.clone()), - _ => None, - }) - { - env.extend(settings_env); - } - let icon = icon_path - .as_ref() - .map(|path| SharedString::from(path.clone())); - - self.external_agents.insert( - name.clone(), - ExternalAgentEntry::new( - Box::new(LocalExtensionArchiveAgent { - fs: fs.clone(), - http_client: http_client.clone(), - node_runtime: node_runtime.clone(), - project_environment: project_environment.clone(), - extension_id: Arc::from(&**ext_id), - targets: targets.clone(), - env, - agent_id: agent_name.clone(), - }) as Box, - ExternalAgentSource::Extension, - icon, - display_name.clone(), - ), - ); - } - *old_settings = Some(new_settings); if let Some((project_id, downstream_client)) = downstream_client { diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 6ab3e51f6eba8d4b639aef4bc32a58e0266a897b..545d030650e7452d71a8ca8d0238647844235e7a 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -17,7 +17,6 @@ use crashes::InitCrashHandler; use db::kvp::{GLOBAL_KEY_VALUE_STORE, KEY_VALUE_STORE}; use editor::Editor; use extension::ExtensionHostProxy; -use feature_flags::{AcpBetaFeatureFlag, FeatureFlagAppExt as _}; use fs::{Fs, RealFs}; use futures::{StreamExt, channel::oneshot, future}; use git::GitHostingProviderRegistry; @@ -624,15 +623,7 @@ fn main() { snippet_provider::init(cx); edit_prediction_registry::init(app_state.client.clone(), app_state.user_store.clone(), cx); let prompt_builder = PromptBuilder::load(app_state.fs.clone(), stdout_is_a_pty(), cx); - if cx.has_flag::() { - project::AgentRegistryStore::init_global(cx); - } - cx.observe_flag::(|is_enabled, cx| { - if is_enabled { - project::AgentRegistryStore::init_global(cx); - } - }) - .detach(); + project::AgentRegistryStore::init_global(cx); agent_ui::init( app_state.fs.clone(), app_state.client.clone(),