diff --git a/crates/agent_servers/src/acp.rs b/crates/agent_servers/src/acp.rs index ba0851565e4ee84e1eb4360a6391a1ad442602cf..e3a442c491fb531491214171138fd9a4d5afda2b 100644 --- a/crates/agent_servers/src/acp.rs +++ b/crates/agent_servers/src/acp.rs @@ -323,7 +323,7 @@ impl AcpConnection { // TODO: Remove this override once Google team releases their official auth methods let auth_methods = if server_name == GEMINI_NAME { let mut args = command.args.clone(); - args.retain(|a| a != "--experimental-acp"); + args.retain(|a| a != "--experimental-acp" && a != "--acp"); let value = serde_json::json!({ "label": "gemini /auth", "command": command.path.to_string_lossy().into_owned(), diff --git a/crates/agent_servers/src/custom.rs b/crates/agent_servers/src/custom.rs index d87b9dc4ece042d94da6e6e0ac99e1474c1ce018..9244b8d891f990c33216bc2c01a2890db20a7465 100644 --- a/crates/agent_servers/src/custom.rs +++ b/crates/agent_servers/src/custom.rs @@ -406,7 +406,6 @@ fn api_key_for_gemini_cli(cx: &mut App) -> Task> { } fn is_registry_agent(name: &str, cx: &App) -> bool { - let is_previous_built_in = matches!(name, CLAUDE_AGENT_NAME | CODEX_NAME | GEMINI_NAME); let is_in_registry = project::AgentRegistryStore::try_global(cx) .map(|store| store.read(cx).agent(name).is_some()) .unwrap_or(false); @@ -421,7 +420,7 @@ fn is_registry_agent(name: &str, cx: &App) -> bool { ) }) }); - is_previous_built_in || is_in_registry || is_settings_registry + is_in_registry || is_settings_registry } fn default_settings_for_agent(name: &str, cx: &App) -> settings::CustomAgentServerSettings { @@ -505,16 +504,6 @@ mod tests { }); } - #[gpui::test] - fn test_previous_builtins_are_registry(cx: &mut TestAppContext) { - init_test(cx); - cx.update(|cx| { - assert!(is_registry_agent(CLAUDE_AGENT_NAME, cx)); - assert!(is_registry_agent(CODEX_NAME, cx)); - assert!(is_registry_agent(GEMINI_NAME, cx)); - }); - } - #[gpui::test] fn test_unknown_agent_is_not_registry(cx: &mut TestAppContext) { init_test(cx); @@ -577,25 +566,6 @@ mod tests { }); } - #[gpui::test] - fn test_default_settings_for_builtin_agent(cx: &mut TestAppContext) { - init_test(cx); - cx.update(|cx| { - assert!(matches!( - default_settings_for_agent(CODEX_NAME, cx), - settings::CustomAgentServerSettings::Registry { .. } - )); - assert!(matches!( - default_settings_for_agent(CLAUDE_AGENT_NAME, cx), - settings::CustomAgentServerSettings::Registry { .. } - )); - assert!(matches!( - default_settings_for_agent(GEMINI_NAME, cx), - settings::CustomAgentServerSettings::Registry { .. } - )); - }); - } - #[gpui::test] fn test_default_settings_for_extension_agent(cx: &mut TestAppContext) { init_test(cx); diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 630411c2400ee925f980b5d3a410cb3574e81cd6..e5a37f56e3343ccfbd3f9806227ef0e7f575d5ae 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -16,10 +16,7 @@ use agent_servers::AgentServer; use collections::HashSet; use db::kvp::{Dismissable, KEY_VALUE_STORE}; use itertools::Itertools; -use project::{ - ExternalAgentServerName, - agent_server_store::{CLAUDE_AGENT_NAME, CODEX_NAME, GEMINI_NAME}, -}; +use project::ExternalAgentServerName; use serde::{Deserialize, Serialize}; use settings::{LanguageModelProviderSetting, LanguageModelSelection}; @@ -643,7 +640,7 @@ enum WhichFontSize { } // TODO unify this with ExternalAgent -#[derive(Debug, Default, Clone, PartialEq, Serialize)] +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] pub enum AgentType { #[default] NativeAgent, @@ -653,63 +650,6 @@ pub enum AgentType { }, } -// Custom impl handles legacy variant names from before the built-in agents were moved to -// the registry: "ClaudeAgent" -> Custom { name: "claude-acp" }, "Codex" -> Custom { name: -// "codex-acp" }, "Gemini" -> Custom { name: "gemini" }. -// Can be removed at some point in the future and go back to #[derive(Deserialize)]. -impl<'de> Deserialize<'de> for AgentType { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let value = serde_json::Value::deserialize(deserializer)?; - - if let Some(s) = value.as_str() { - return match s { - "NativeAgent" => Ok(Self::NativeAgent), - "TextThread" => Ok(Self::TextThread), - "ClaudeAgent" | "ClaudeCode" => Ok(Self::Custom { - name: CLAUDE_AGENT_NAME.into(), - }), - "Codex" => Ok(Self::Custom { - name: CODEX_NAME.into(), - }), - "Gemini" => Ok(Self::Custom { - name: GEMINI_NAME.into(), - }), - other => Err(serde::de::Error::unknown_variant( - other, - &[ - "NativeAgent", - "TextThread", - "Custom", - "ClaudeAgent", - "ClaudeCode", - "Codex", - "Gemini", - ], - )), - }; - } - - if let Some(obj) = value.as_object() { - if let Some(inner) = obj.get("Custom") { - #[derive(Deserialize)] - struct CustomFields { - name: SharedString, - } - let fields: CustomFields = - serde_json::from_value(inner.clone()).map_err(serde::de::Error::custom)?; - return Ok(Self::Custom { name: fields.name }); - } - } - - Err(serde::de::Error::custom( - "expected a string variant or {\"Custom\": {\"name\": ...}}", - )) - } -} - impl AgentType { pub fn is_native(&self) -> bool { matches!(self, Self::NativeAgent) @@ -3842,10 +3782,8 @@ impl AgentPanel { .header("External Agents") .map(|mut menu| { let agent_server_store = agent_server_store.read(cx); - let registry_store = - project::AgentRegistryStore::try_global(cx); - let registry_store_ref = - registry_store.as_ref().map(|s| s.read(cx)); + let registry_store = project::AgentRegistryStore::try_global(cx); + let registry_store_ref = registry_store.as_ref().map(|s| s.read(cx)); struct AgentMenuItem { id: ExternalAgentServerName, @@ -3873,12 +3811,10 @@ impl AgentPanel { .collect::>(); for item in &agent_items { - let mut entry = - ContextMenuEntry::new(item.display_name.clone()); + let mut entry = ContextMenuEntry::new(item.display_name.clone()); - let icon_path = agent_server_store - .agent_icon(&item.id) - .or_else(|| { + let icon_path = + agent_server_store.agent_icon(&item.id).or_else(|| { registry_store_ref .as_ref() .and_then(|store| store.agent(item.id.0.as_str())) @@ -3897,9 +3833,9 @@ impl AgentPanel { name: item.id.0.clone(), }), |this| { - this.action(Box::new( - NewExternalAgentThread { agent: None }, - )) + this.action(Box::new(NewExternalAgentThread { + agent: None, + })) }, ) .icon_color(Color::Muted) @@ -3934,111 +3870,14 @@ impl AgentPanel { menu }) .separator() - .map(|mut menu| { - let agent_server_store = agent_server_store.read(cx); - let registry_store = - project::AgentRegistryStore::try_global(cx); - let registry_store_ref = - registry_store.as_ref().map(|s| s.read(cx)); - - let previous_built_in_ids: &[ExternalAgentServerName] = - &[CLAUDE_AGENT_NAME.into(), CODEX_NAME.into(), GEMINI_NAME.into()]; - - let promoted_items = previous_built_in_ids - .iter() - .filter(|id| { - !agent_server_store.external_agents.contains_key(*id) - }) - .filter_map(|name| { - let display_name = registry_store_ref - .as_ref() - .and_then(|store| store.agent(name.0.as_ref())) - .map(|a| a.name().clone())?; - Some((name.clone(), display_name)) - }) - .sorted_unstable_by_key(|(_, display_name)| display_name.to_lowercase()) - .collect::>(); - - for (agent_id, display_name) in &promoted_items { - let mut entry = - ContextMenuEntry::new(display_name.clone()); - - let icon_path = registry_store_ref - .as_ref() - .and_then(|store| store.agent(agent_id.0.as_str())) - .and_then(|a| a.icon_path().cloned()); - - if let Some(icon_path) = icon_path { - entry = entry.custom_icon_svg(icon_path); - } else { - entry = entry.icon(IconName::Sparkle); - } - - entry = entry - .icon_color(Color::Muted) - .disabled(is_via_collab) - .handler({ - let workspace = workspace.clone(); - let agent_id = agent_id.clone(); - move |window, cx| { - let fs = ::global(cx); - let agent_id_string = - agent_id.to_string(); - settings::update_settings_file( - fs, - cx, - move |settings, _| { - let agent_servers = settings - .agent_servers - .get_or_insert_default(); - agent_servers.entry(agent_id_string).or_insert_with(|| { - settings::CustomAgentServerSettings::Registry { - default_mode: None, - default_model: None, - env: Default::default(), - favorite_models: Vec::new(), - default_config_options: Default::default(), - favorite_config_option_values: Default::default(), - } - }); - }, - ); - - if let Some(workspace) = workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - if let Some(panel) = - workspace.panel::(cx) - { - panel.update(cx, |panel, cx| { - panel.new_agent_thread( - AgentType::Custom { - name: agent_id.0.clone(), - }, - window, - cx, - ); - }); - } - }); - } - } - }); - - menu = menu.item(entry); - } - - menu - }) .item( ContextMenuEntry::new("Add More Agents") .icon(IconName::Plus) .icon_color(Color::Muted) .handler({ move |window, cx| { - window.dispatch_action( - Box::new(zed_actions::AcpRegistry), - cx, - ) + window + .dispatch_action(Box::new(zed_actions::AcpRegistry), cx) } }), ) @@ -6047,35 +5886,7 @@ mod tests { } #[test] - fn test_deserialize_legacy_agent_type_variants() { - assert_eq!( - serde_json::from_str::(r#""ClaudeAgent""#).unwrap(), - AgentType::Custom { - name: CLAUDE_AGENT_NAME.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""ClaudeCode""#).unwrap(), - AgentType::Custom { - name: CLAUDE_AGENT_NAME.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""Codex""#).unwrap(), - AgentType::Custom { - name: CODEX_NAME.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""Gemini""#).unwrap(), - AgentType::Custom { - name: GEMINI_NAME.into(), - }, - ); - } - - #[test] - fn test_deserialize_current_agent_type_variants() { + fn test_deserialize_agent_type_variants() { assert_eq!( serde_json::from_str::(r#""NativeAgent""#).unwrap(), AgentType::NativeAgent, @@ -6091,31 +5902,4 @@ mod tests { }, ); } - - #[test] - fn test_deserialize_legacy_serialized_panel() { - let json = serde_json::json!({ - "width": 300.0, - "selected_agent": "ClaudeAgent", - "last_active_thread": { - "session_id": "test-session", - "agent_type": "Codex", - }, - }); - - let panel: SerializedAgentPanel = serde_json::from_value(json).unwrap(); - assert_eq!( - panel.selected_agent, - Some(AgentType::Custom { - name: CLAUDE_AGENT_NAME.into(), - }), - ); - let thread = panel.last_active_thread.unwrap(); - assert_eq!( - thread.agent_type, - AgentType::Custom { - name: CODEX_NAME.into(), - }, - ); - } } diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index 292db8fc7c0398fdd8c8800b8acc2b3c6df22740..eeec082e50ae25d922368aed3c8ed0562b773b5a 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -214,70 +214,13 @@ pub struct NewNativeAgentThreadFromSummary { } // TODO unify this with AgentType -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExternalAgent { NativeAgent, Custom { name: SharedString }, } -// Custom impl handles legacy variant names from before the built-in agents were moved to -// the registry: "claude_code" -> Custom { name: "claude-acp" }, "codex" -> Custom { name: -// "codex-acp" }, "gemini" -> Custom { name: "gemini" }. -// Can be removed at some point in the future and go back to #[derive(Deserialize)]. -impl<'de> serde::Deserialize<'de> for ExternalAgent { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use project::agent_server_store::{CLAUDE_AGENT_NAME, CODEX_NAME, GEMINI_NAME}; - - let value = serde_json::Value::deserialize(deserializer)?; - - if let Some(s) = value.as_str() { - return match s { - "native_agent" => Ok(Self::NativeAgent), - "claude_code" | "claude_agent" => Ok(Self::Custom { - name: CLAUDE_AGENT_NAME.into(), - }), - "codex" => Ok(Self::Custom { - name: CODEX_NAME.into(), - }), - "gemini" => Ok(Self::Custom { - name: GEMINI_NAME.into(), - }), - other => Err(serde::de::Error::unknown_variant( - other, - &[ - "native_agent", - "custom", - "claude_agent", - "claude_code", - "codex", - "gemini", - ], - )), - }; - } - - if let Some(obj) = value.as_object() { - if let Some(inner) = obj.get("custom") { - #[derive(serde::Deserialize)] - struct CustomFields { - name: SharedString, - } - let fields: CustomFields = - serde_json::from_value(inner.clone()).map_err(serde::de::Error::custom)?; - return Ok(Self::Custom { name: fields.name }); - } - } - - Err(serde::de::Error::custom( - "expected a string variant or {\"custom\": {\"name\": ...}}", - )) - } -} - impl ExternalAgent { pub fn server( &self, @@ -746,31 +689,7 @@ mod tests { } #[test] - fn test_deserialize_legacy_external_agent_variants() { - use project::agent_server_store::{CLAUDE_AGENT_NAME, CODEX_NAME, GEMINI_NAME}; - - assert_eq!( - serde_json::from_str::(r#""claude_code""#).unwrap(), - ExternalAgent::Custom { - name: CLAUDE_AGENT_NAME.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""codex""#).unwrap(), - ExternalAgent::Custom { - name: CODEX_NAME.into(), - }, - ); - assert_eq!( - serde_json::from_str::(r#""gemini""#).unwrap(), - ExternalAgent::Custom { - name: GEMINI_NAME.into(), - }, - ); - } - - #[test] - fn test_deserialize_current_external_agent_variants() { + fn test_deserialize_external_agent_variants() { assert_eq!( serde_json::from_str::(r#""native_agent""#).unwrap(), ExternalAgent::NativeAgent,