From efd3f8a8f14483b8a5b92a8a59c8885624b4352d Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 19 Mar 2025 17:48:14 -0400 Subject: [PATCH] assistant2: Add initial concept of profiles (#27123) This PR adds the initial concept of agent profiles to Assistant 2. Right now these are just collections of tools that can quickly be enabled together: https://github.com/user-attachments/assets/7c7f9cc8-a5e5-492f-96f7-79697bbf3d72 There are currently two profiles: - `Read-only` - Consists only of tools that do not perform writes. - `Code Writer` - Consists of all tools for writing code, with the exception of the `lua-interpreter`. Release Notes: - N/A --- crates/assistant2/src/agent_profile.rs | 59 ++++++++++++++++++++++++++ crates/assistant2/src/assistant.rs | 1 + crates/assistant2/src/tool_selector.rs | 30 ++++++++++++- 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 crates/assistant2/src/agent_profile.rs diff --git a/crates/assistant2/src/agent_profile.rs b/crates/assistant2/src/agent_profile.rs new file mode 100644 index 0000000000..e707704c7d --- /dev/null +++ b/crates/assistant2/src/agent_profile.rs @@ -0,0 +1,59 @@ +use std::sync::Arc; + +use collections::HashMap; +use gpui::SharedString; + +/// A profile for the Zed Agent that controls its behavior. +#[derive(Debug, Clone)] +pub struct AgentProfile { + /// The name of the profile. + pub name: SharedString, + pub tools: HashMap, bool>, + #[allow(dead_code)] + pub context_servers: HashMap, ContextServerPreset>, +} + +#[derive(Debug, Clone)] +pub struct ContextServerPreset { + #[allow(dead_code)] + pub tools: HashMap, 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(), + } + } +} diff --git a/crates/assistant2/src/assistant.rs b/crates/assistant2/src/assistant.rs index 5224b097cc..d57fe78579 100644 --- a/crates/assistant2/src/assistant.rs +++ b/crates/assistant2/src/assistant.rs @@ -1,4 +1,5 @@ mod active_thread; +mod agent_profile; mod assistant_configuration; mod assistant_model_selector; mod assistant_panel; diff --git a/crates/assistant2/src/tool_selector.rs b/crates/assistant2/src/tool_selector.rs index 38ff11c2db..e14e206c6b 100644 --- a/crates/assistant2/src/tool_selector.rs +++ b/crates/assistant2/src/tool_selector.rs @@ -5,13 +5,19 @@ use gpui::Entity; use scripting_tool::ScriptingTool; use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip}; +use crate::agent_profile::AgentProfile; + pub struct ToolSelector { + profiles: Vec, tools: Arc, } impl ToolSelector { pub fn new(tools: Arc, _cx: &mut Context) -> Self { - Self { tools } + Self { + profiles: vec![AgentProfile::read_only(), AgentProfile::code_writer()], + tools, + } } fn build_context_menu( @@ -19,9 +25,31 @@ impl ToolSelector { window: &mut Window, cx: &mut Context, ) -> Entity { + let profiles = self.profiles.clone(); let tool_set = self.tools.clone(); ContextMenu::build_persistent(window, cx, move |mut menu, _window, cx| { let icon_position = IconPosition::End; + + menu = menu.header("Profiles"); + for profile in profiles.clone() { + menu = menu.toggleable_entry(profile.name.clone(), false, icon_position, None, { + let tools = tool_set.clone(); + move |_window, cx| { + tools.disable_source(ToolSource::Native, cx); + tools.enable( + ToolSource::Native, + &profile + .tools + .iter() + .filter_map(|(tool, enabled)| enabled.then(|| tool.clone())) + .collect::>(), + ); + } + }); + } + + menu = menu.separator(); + let tools_by_source = tool_set.tools_by_source(cx); let all_tools_enabled = tool_set.are_all_tools_enabled();