mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
agent_ui: Add section for skills and rules in ellipsis menu (#57404)
Closes AI-291 This PR adds some new menu items in the agent panel's ellipsis menu to make it easier to 1) create a new skill, 2) manage all existing skills through the settings window, 3) open project and global AGENTS.md file, if it exists. Minor UI note: I'm adding an ellipsis character to the menu items in which you need to do something else in a different view to fulfill the item's label. For example, "Create Skill…" takes the ellipsis because clicking on the menu item itself doesn't create the skill, but it takes you to the place where you'll do that. <img width="600" alt="Screenshot 2026-05-21 at 10 32@2x" src="https://github.com/user-attachments/assets/1bfdd423-bd75-4c62-97ba-84130035ede8" /> Release Notes: - N/A
This commit is contained in:
parent
7ec36d3661
commit
d61ffb8e6b
1 changed files with 104 additions and 13 deletions
|
|
@ -10,7 +10,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use acp_thread::{AcpThread, AcpThreadEvent, MentionUri, ThreadStatus};
|
use acp_thread::{AcpThread, AcpThreadEvent, MentionUri, ThreadStatus};
|
||||||
use agent::{ContextServerRegistry, SharedThread, ThreadStore};
|
use agent::{ContextServerRegistry, SharedThread, ThreadStore, UserAgentsMd};
|
||||||
use agent_client_protocol::schema as acp;
|
use agent_client_protocol::schema as acp;
|
||||||
use agent_servers::AgentServer;
|
use agent_servers::AgentServer;
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
|
|
@ -4780,6 +4780,28 @@ impl AgentPanel {
|
||||||
.active_conversation_view()
|
.active_conversation_view()
|
||||||
.is_some_and(|conversation_view| conversation_view.read(cx).supports_logout(cx));
|
.is_some_and(|conversation_view| conversation_view.read(cx).supports_logout(cx));
|
||||||
|
|
||||||
|
let project_agents_md_path: Option<PathBuf> = self
|
||||||
|
.project
|
||||||
|
.read(cx)
|
||||||
|
.visible_worktrees(cx)
|
||||||
|
.next()
|
||||||
|
.and_then(|worktree| {
|
||||||
|
let worktree = worktree.read(cx);
|
||||||
|
let rel_path = util::rel_path::RelPath::unix("AGENTS.md").ok()?;
|
||||||
|
let entry = worktree.entry_for_path(rel_path)?;
|
||||||
|
if entry.is_file() {
|
||||||
|
Some(worktree.absolutize(rel_path))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let global_agents_md_loaded = UserAgentsMd::global(cx)
|
||||||
|
.and_then(|md| md.content())
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
let workspace = self.workspace.clone();
|
||||||
|
|
||||||
PopoverMenu::new("agent-options-menu")
|
PopoverMenu::new("agent-options-menu")
|
||||||
.trigger_with_tooltip(
|
.trigger_with_tooltip(
|
||||||
IconButton::new("agent-options-menu", IconName::Ellipsis)
|
IconButton::new("agent-options-menu", IconName::Ellipsis)
|
||||||
|
|
@ -4821,8 +4843,9 @@ impl AgentPanel {
|
||||||
if !showing_terminal {
|
if !showing_terminal {
|
||||||
menu = menu
|
menu = menu
|
||||||
.header("MCP Servers")
|
.header("MCP Servers")
|
||||||
|
.action("Add Custom Server…", Box::new(AddContextServer))
|
||||||
.action(
|
.action(
|
||||||
"View Server Extensions",
|
"Install New Servers…",
|
||||||
Box::new(zed_actions::Extensions {
|
Box::new(zed_actions::Extensions {
|
||||||
category_filter: Some(
|
category_filter: Some(
|
||||||
zed_actions::ExtensionCategoryFilter::ContextServers,
|
zed_actions::ExtensionCategoryFilter::ContextServers,
|
||||||
|
|
@ -4830,16 +4853,81 @@ impl AgentPanel {
|
||||||
id: None,
|
id: None,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action("Add Custom Server…", Box::new(AddContextServer))
|
.separator()
|
||||||
|
.header("Skills")
|
||||||
|
.entry(
|
||||||
|
"Create Skill…",
|
||||||
|
Some(Box::new(OpenRulesLibrary::default())),
|
||||||
|
|window, cx| {
|
||||||
|
window.dispatch_action(Box::new(OpenSkillCreator), cx);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.entry("Manage Skills…", None, |window, cx| {
|
||||||
|
window.dispatch_action(
|
||||||
|
Box::new(zed_actions::OpenSettingsAt {
|
||||||
|
path: "agent.skills".to_string(),
|
||||||
|
}),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
})
|
||||||
.separator();
|
.separator();
|
||||||
|
|
||||||
menu = menu.entry(
|
if project_agents_md_path.is_some() || global_agents_md_loaded {
|
||||||
"Skills",
|
menu = menu.header("Rules");
|
||||||
Some(Box::new(OpenRulesLibrary::default())),
|
|
||||||
|window, cx| {
|
if global_agents_md_loaded {
|
||||||
window.dispatch_action(Box::new(OpenSkillCreator), cx);
|
let workspace = workspace.clone();
|
||||||
},
|
menu = menu.entry(
|
||||||
);
|
"Open Global AGENTS.md",
|
||||||
|
None,
|
||||||
|
move |window, cx| {
|
||||||
|
workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace
|
||||||
|
.open_abs_path(
|
||||||
|
paths::agents_file().clone(),
|
||||||
|
workspace::OpenOptions {
|
||||||
|
focus: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.detach_and_log_err(cx);
|
||||||
|
})
|
||||||
|
.log_err();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = project_agents_md_path.clone() {
|
||||||
|
let workspace = workspace.clone();
|
||||||
|
menu = menu.entry(
|
||||||
|
"Open Project AGENTS.md",
|
||||||
|
None,
|
||||||
|
move |window, cx| {
|
||||||
|
let path = path.clone();
|
||||||
|
workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace
|
||||||
|
.open_abs_path(
|
||||||
|
path,
|
||||||
|
workspace::OpenOptions {
|
||||||
|
focus: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.detach_and_log_err(cx);
|
||||||
|
})
|
||||||
|
.log_err();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu = menu.separator();
|
||||||
|
}
|
||||||
|
|
||||||
menu = menu.action("Profiles", Box::new(ManageProfiles::default()));
|
menu = menu.action("Profiles", Box::new(ManageProfiles::default()));
|
||||||
}
|
}
|
||||||
|
|
@ -4849,6 +4937,9 @@ impl AgentPanel {
|
||||||
.separator()
|
.separator()
|
||||||
.action("Toggle Threads Sidebar", Box::new(ToggleWorkspaceSidebar));
|
.action("Toggle Threads Sidebar", Box::new(ToggleWorkspaceSidebar));
|
||||||
|
|
||||||
|
if has_auth_methods || supports_logout {
|
||||||
|
menu = menu.separator()
|
||||||
|
}
|
||||||
if has_auth_methods {
|
if has_auth_methods {
|
||||||
menu = menu.action("Reauthenticate", Box::new(ReauthenticateAgent))
|
menu = menu.action("Reauthenticate", Box::new(ReauthenticateAgent))
|
||||||
}
|
}
|
||||||
|
|
@ -8173,12 +8264,12 @@ mod tests {
|
||||||
cx.run_until_parked();
|
cx.run_until_parked();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
cx.debug_bounds("MENU_ITEM-Skills").is_some(),
|
cx.debug_bounds("MENU_ITEM-Create Skill…").is_some(),
|
||||||
"Skills menu item should be visible"
|
"Create Skill… menu item should be visible"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
cx.debug_bounds("KEY_BINDING-l").is_some(),
|
cx.debug_bounds("KEY_BINDING-l").is_some(),
|
||||||
"Skills menu item should show the OpenRulesLibrary shortcut"
|
"Create Skill… menu item should show the OpenRulesLibrary shortcut"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue