assistant2: Define built-in agent profiles in the default settings (#27251)

Marshall Bowers created

This PR moves the definitions of the built-in agent profiles into the
default `settings.json`.

It also changes the behavior of how this setting is treated when merging
settings such that the set of profiles will be merged. This is so users
don't clobber the built-in profiles when adding profiles of their own.

Release Notes:

- N/A

Change summary

assets/settings/default.json                        | 31 +++++++++++
crates/assistant2/src/tool_selector.rs              | 15 -----
crates/assistant_settings/src/agent_profile.rs      | 39 ---------------
crates/assistant_settings/src/assistant_settings.rs | 33 +++++------
4 files changed, 47 insertions(+), 71 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -614,6 +614,37 @@
       "provider": "zed.dev",
       // The model to use.
       "model": "claude-3-5-sonnet-latest"
+    },
+    "profiles": {
+      "read-only": {
+        "name": "Read-only",
+        "tools": {
+          "diagnostics": true,
+          "fetch": true,
+          "list-directory": true,
+          "now": true,
+          "path-search": true,
+          "read-file": true,
+          "regex-search": true,
+          "thinking": true
+        }
+      },
+      "code-writer": {
+        "name": "Code Writer",
+        "tools": {
+          "bash": true,
+          "delete-path": true,
+          "diagnostics": true,
+          "edit-files": true,
+          "fetch": true,
+          "list-directory": true,
+          "now": true,
+          "path-search": true,
+          "read-file": true,
+          "regex-search": true,
+          "thinking": true
+        }
+      }
     }
   },
   // The settings for slash commands.

crates/assistant2/src/tool_selector.rs 🔗

@@ -32,21 +32,8 @@ impl ToolSelector {
 
     fn refresh_profiles(&mut self, cx: &mut Context<Self>) {
         let settings = AssistantSettings::get_global(cx);
-        let mut profiles = BTreeMap::from_iter(settings.profiles.clone());
 
-        const READ_ONLY_ID: &str = "read-only";
-        let read_only = AgentProfile::read_only();
-        if !profiles.contains_key(READ_ONLY_ID) {
-            profiles.insert(READ_ONLY_ID.into(), read_only);
-        }
-
-        const CODE_WRITER_ID: &str = "code-writer";
-        let code_writer = AgentProfile::code_writer();
-        if !profiles.contains_key(CODE_WRITER_ID) {
-            profiles.insert(CODE_WRITER_ID.into(), code_writer);
-        }
-
-        self.profiles = profiles;
+        self.profiles = BTreeMap::from_iter(settings.profiles.clone());
     }
 
     fn build_context_menu(

crates/assistant_settings/src/agent_profile.rs 🔗

@@ -18,42 +18,3 @@ pub struct ContextServerPreset {
     #[allow(dead_code)]
     pub tools: HashMap<Arc<str>, bool>,
 }
-
-impl AgentProfile {
-    pub fn read_only() -> Self {
-        Self {
-            name: "Read-only".into(),
-            tools: HashMap::from_iter([
-                ("diagnostics".into(), true),
-                ("fetch".into(), true),
-                ("list-directory".into(), true),
-                ("now".into(), true),
-                ("path-search".into(), true),
-                ("read-file".into(), true),
-                ("regex-search".into(), true),
-                ("thinking".into(), true),
-            ]),
-            context_servers: HashMap::default(),
-        }
-    }
-
-    pub fn code_writer() -> Self {
-        Self {
-            name: "Code Writer".into(),
-            tools: HashMap::from_iter([
-                ("bash".into(), true),
-                ("delete-path".into(), true),
-                ("diagnostics".into(), true),
-                ("edit-files".into(), true),
-                ("fetch".into(), true),
-                ("list-directory".into(), true),
-                ("now".into(), true),
-                ("path-search".into(), true),
-                ("read-file".into(), true),
-                ("regex-search".into(), true),
-                ("thinking".into(), true),
-            ]),
-            context_servers: HashMap::default(),
-        }
-    }
-}

crates/assistant_settings/src/assistant_settings.rs 🔗

@@ -499,24 +499,21 @@ impl Settings for AssistantSettings {
                 &mut settings.enable_experimental_live_diffs,
                 value.enable_experimental_live_diffs,
             );
-            merge(
-                &mut settings.profiles,
-                value.profiles.map(|profiles| {
-                    profiles
-                        .into_iter()
-                        .map(|(id, profile)| {
-                            (
-                                id,
-                                AgentProfile {
-                                    name: profile.name.into(),
-                                    tools: profile.tools,
-                                    context_servers: HashMap::default(),
-                                },
-                            )
-                        })
-                        .collect()
-                }),
-            );
+
+            if let Some(profiles) = value.profiles {
+                settings
+                    .profiles
+                    .extend(profiles.into_iter().map(|(id, profile)| {
+                        (
+                            id,
+                            AgentProfile {
+                                name: profile.name.into(),
+                                tools: profile.tools,
+                                context_servers: HashMap::default(),
+                            },
+                        )
+                    }));
+            }
         }
 
         Ok(settings)