@@ -84,19 +84,12 @@ impl AgentServer for CustomAgentServer {
let config_id = config_id.to_string();
let value_id = value_id.to_string();
- update_settings_file(fs, cx, move |settings, _| {
+ update_settings_file(fs, cx, move |settings, cx| {
let settings = settings
.agent_servers
.get_or_insert_default()
.entry(name.to_string())
- .or_insert_with(|| settings::CustomAgentServerSettings::Extension {
- default_model: None,
- default_mode: None,
- env: Default::default(),
- favorite_models: Vec::new(),
- default_config_options: Default::default(),
- favorite_config_option_values: Default::default(),
- });
+ .or_insert_with(|| default_settings_for_agent(&name, cx));
match settings {
settings::CustomAgentServerSettings::Custom {
@@ -132,19 +125,12 @@ impl AgentServer for CustomAgentServer {
fn set_default_mode(&self, mode_id: Option<acp::SessionModeId>, fs: Arc<dyn Fs>, cx: &mut App) {
let name = self.name();
- update_settings_file(fs, cx, move |settings, _| {
+ update_settings_file(fs, cx, move |settings, cx| {
let settings = settings
.agent_servers
.get_or_insert_default()
.entry(name.to_string())
- .or_insert_with(|| settings::CustomAgentServerSettings::Extension {
- default_model: None,
- default_mode: None,
- env: Default::default(),
- favorite_models: Vec::new(),
- default_config_options: Default::default(),
- favorite_config_option_values: Default::default(),
- });
+ .or_insert_with(|| default_settings_for_agent(&name, cx));
match settings {
settings::CustomAgentServerSettings::Custom { default_mode, .. }
@@ -171,19 +157,12 @@ impl AgentServer for CustomAgentServer {
fn set_default_model(&self, model_id: Option<acp::ModelId>, fs: Arc<dyn Fs>, cx: &mut App) {
let name = self.name();
- update_settings_file(fs, cx, move |settings, _| {
+ update_settings_file(fs, cx, move |settings, cx| {
let settings = settings
.agent_servers
.get_or_insert_default()
.entry(name.to_string())
- .or_insert_with(|| settings::CustomAgentServerSettings::Extension {
- default_model: None,
- default_mode: None,
- env: Default::default(),
- favorite_models: Vec::new(),
- default_config_options: Default::default(),
- favorite_config_option_values: Default::default(),
- });
+ .or_insert_with(|| default_settings_for_agent(&name, cx));
match settings {
settings::CustomAgentServerSettings::Custom { default_model, .. }
@@ -222,19 +201,12 @@ impl AgentServer for CustomAgentServer {
cx: &App,
) {
let name = self.name();
- update_settings_file(fs, cx, move |settings, _| {
+ update_settings_file(fs, cx, move |settings, cx| {
let settings = settings
.agent_servers
.get_or_insert_default()
.entry(name.to_string())
- .or_insert_with(|| settings::CustomAgentServerSettings::Extension {
- default_model: None,
- default_mode: None,
- env: Default::default(),
- favorite_models: Vec::new(),
- default_config_options: Default::default(),
- favorite_config_option_values: Default::default(),
- });
+ .or_insert_with(|| default_settings_for_agent(&name, cx));
let favorite_models = match settings {
settings::CustomAgentServerSettings::Custom {
@@ -282,19 +254,12 @@ impl AgentServer for CustomAgentServer {
let name = self.name();
let config_id = config_id.to_string();
let value_id = value_id.map(|s| s.to_string());
- update_settings_file(fs, cx, move |settings, _| {
+ update_settings_file(fs, cx, move |settings, cx| {
let settings = settings
.agent_servers
.get_or_insert_default()
.entry(name.to_string())
- .or_insert_with(|| settings::CustomAgentServerSettings::Extension {
- default_model: None,
- default_mode: None,
- env: Default::default(),
- favorite_models: Vec::new(),
- default_config_options: Default::default(),
- favorite_config_option_values: Default::default(),
- });
+ .or_insert_with(|| default_settings_for_agent(&name, cx));
match settings {
settings::CustomAgentServerSettings::Custom {
@@ -332,45 +297,27 @@ impl AgentServer for CustomAgentServer {
.unwrap_or_else(|| name.clone());
let default_mode = self.default_mode(cx);
let default_model = self.default_model(cx);
- let is_previous_built_in =
- matches!(name.as_ref(), CLAUDE_AGENT_NAME | CODEX_NAME | GEMINI_NAME);
- let (default_config_options, is_registry_agent) =
- cx.read_global(|settings: &SettingsStore, _| {
- let agent_settings = settings
- .get::<AllAgentServersSettings>(None)
- .get(self.name().as_ref());
-
- let is_registry = agent_settings
- .map(|s| {
- matches!(
- s,
- project::agent_server_store::CustomAgentServerSettings::Registry { .. }
- )
- })
- .unwrap_or(false);
-
- let config_options = agent_settings
- .map(|s| match s {
- project::agent_server_store::CustomAgentServerSettings::Custom {
- default_config_options,
- ..
- }
- | project::agent_server_store::CustomAgentServerSettings::Extension {
- default_config_options,
- ..
- }
- | project::agent_server_store::CustomAgentServerSettings::Registry {
- default_config_options,
- ..
- } => default_config_options.clone(),
- })
- .unwrap_or_default();
-
- (config_options, is_registry)
- });
-
- // Intermediate step to allow for previous built-ins to also be triggered if they aren't in settings yet.
- let is_registry_agent = is_registry_agent || is_previous_built_in;
+ let is_registry_agent = is_registry_agent(&name, cx);
+ let default_config_options = cx.read_global(|settings: &SettingsStore, _| {
+ settings
+ .get::<AllAgentServersSettings>(None)
+ .get(self.name().as_ref())
+ .map(|s| match s {
+ project::agent_server_store::CustomAgentServerSettings::Custom {
+ default_config_options,
+ ..
+ }
+ | project::agent_server_store::CustomAgentServerSettings::Extension {
+ default_config_options,
+ ..
+ }
+ | project::agent_server_store::CustomAgentServerSettings::Registry {
+ default_config_options,
+ ..
+ } => default_config_options.clone(),
+ })
+ .unwrap_or_default()
+ });
if is_registry_agent {
if let Some(registry_store) = project::AgentRegistryStore::try_global(cx) {
@@ -458,3 +405,222 @@ fn api_key_for_gemini_cli(cx: &mut App) -> Task<Result<String>> {
)
})
}
+
+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);
+ let is_settings_registry = cx.read_global(|settings: &SettingsStore, _| {
+ settings
+ .get::<AllAgentServersSettings>(None)
+ .get(name)
+ .is_some_and(|s| {
+ matches!(
+ s,
+ project::agent_server_store::CustomAgentServerSettings::Registry { .. }
+ )
+ })
+ });
+ is_previous_built_in || is_in_registry || is_settings_registry
+}
+
+fn default_settings_for_agent(name: &str, cx: &App) -> settings::CustomAgentServerSettings {
+ if is_registry_agent(name, cx) {
+ settings::CustomAgentServerSettings::Registry {
+ default_model: None,
+ default_mode: None,
+ env: Default::default(),
+ favorite_models: Vec::new(),
+ default_config_options: Default::default(),
+ favorite_config_option_values: Default::default(),
+ }
+ } else {
+ settings::CustomAgentServerSettings::Extension {
+ default_model: None,
+ default_mode: None,
+ env: Default::default(),
+ favorite_models: Vec::new(),
+ default_config_options: Default::default(),
+ favorite_config_option_values: Default::default(),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use collections::HashMap;
+ use gpui::TestAppContext;
+ use project::agent_registry_store::{
+ AgentRegistryStore, RegistryAgent, RegistryAgentMetadata, RegistryNpxAgent,
+ };
+ use settings::Settings as _;
+
+ fn init_test(cx: &mut TestAppContext) {
+ cx.update(|cx| {
+ let settings_store = SettingsStore::test(cx);
+ cx.set_global(settings_store);
+ });
+ }
+
+ fn init_registry_with_agents(cx: &mut TestAppContext, agent_ids: &[&str]) {
+ let agents: Vec<RegistryAgent> = agent_ids
+ .iter()
+ .map(|id| {
+ let id = SharedString::from(id.to_string());
+ RegistryAgent::Npx(RegistryNpxAgent {
+ metadata: RegistryAgentMetadata {
+ id: id.clone(),
+ name: id.clone(),
+ description: SharedString::from(""),
+ version: SharedString::from("1.0.0"),
+ repository: None,
+ icon_path: None,
+ },
+ package: id,
+ args: Vec::new(),
+ env: HashMap::default(),
+ })
+ })
+ .collect();
+ cx.update(|cx| {
+ AgentRegistryStore::init_test_global(cx, agents);
+ });
+ }
+
+ fn set_agent_server_settings(
+ cx: &mut TestAppContext,
+ entries: Vec<(&str, settings::CustomAgentServerSettings)>,
+ ) {
+ cx.update(|cx| {
+ AllAgentServersSettings::override_global(
+ project::agent_server_store::AllAgentServersSettings(
+ entries
+ .into_iter()
+ .map(|(name, settings)| (name.to_string(), settings.into()))
+ .collect(),
+ ),
+ cx,
+ );
+ });
+ }
+
+ #[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);
+ cx.update(|cx| {
+ assert!(!is_registry_agent("my-custom-agent", cx));
+ });
+ }
+
+ #[gpui::test]
+ fn test_agent_in_registry_store_is_registry(cx: &mut TestAppContext) {
+ init_test(cx);
+ init_registry_with_agents(cx, &["some-new-registry-agent"]);
+ cx.update(|cx| {
+ assert!(is_registry_agent("some-new-registry-agent", cx));
+ assert!(!is_registry_agent("not-in-registry", cx));
+ });
+ }
+
+ #[gpui::test]
+ fn test_agent_with_registry_settings_type_is_registry(cx: &mut TestAppContext) {
+ init_test(cx);
+ set_agent_server_settings(
+ cx,
+ vec![(
+ "agent-from-settings",
+ settings::CustomAgentServerSettings::Registry {
+ env: HashMap::default(),
+ default_mode: None,
+ default_model: None,
+ favorite_models: Vec::new(),
+ default_config_options: HashMap::default(),
+ favorite_config_option_values: HashMap::default(),
+ },
+ )],
+ );
+ cx.update(|cx| {
+ assert!(is_registry_agent("agent-from-settings", cx));
+ });
+ }
+
+ #[gpui::test]
+ fn test_agent_with_extension_settings_type_is_not_registry(cx: &mut TestAppContext) {
+ init_test(cx);
+ set_agent_server_settings(
+ cx,
+ vec![(
+ "my-extension-agent",
+ settings::CustomAgentServerSettings::Extension {
+ env: HashMap::default(),
+ default_mode: None,
+ default_model: None,
+ favorite_models: Vec::new(),
+ default_config_options: HashMap::default(),
+ favorite_config_option_values: HashMap::default(),
+ },
+ )],
+ );
+ cx.update(|cx| {
+ assert!(!is_registry_agent("my-extension-agent", cx));
+ });
+ }
+
+ #[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);
+ cx.update(|cx| {
+ assert!(matches!(
+ default_settings_for_agent("some-extension-agent", cx),
+ settings::CustomAgentServerSettings::Extension { .. }
+ ));
+ });
+ }
+
+ #[gpui::test]
+ fn test_default_settings_for_agent_in_registry(cx: &mut TestAppContext) {
+ init_test(cx);
+ init_registry_with_agents(cx, &["new-registry-agent"]);
+ cx.update(|cx| {
+ assert!(matches!(
+ default_settings_for_agent("new-registry-agent", cx),
+ settings::CustomAgentServerSettings::Registry { .. }
+ ));
+ assert!(matches!(
+ default_settings_for_agent("not-in-registry", cx),
+ settings::CustomAgentServerSettings::Extension { .. }
+ ));
+ });
+ }
+}