Use agent name from extension (#44496)
Previously this rendered `mistral-vibe` and not `Mistral Vibe`: <img width="242" height="199" alt="Screenshot 2025-12-09 at 2 52 48 PM" src="https://github.com/user-attachments/assets/f85cbf20-91d1-4c05-8b3a-fa5b544acb1c" /> Release Notes: - Render agent display names from extension in menu
This commit is contained in:
@@ -977,7 +977,10 @@ impl AgentConfiguration {
|
||||
} else {
|
||||
AgentIcon::Name(IconName::Ai)
|
||||
};
|
||||
(name, icon)
|
||||
let display_name = agent_server_store
|
||||
.agent_display_name(&name)
|
||||
.unwrap_or_else(|| name.0.clone());
|
||||
(name, icon, display_name)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -1084,6 +1087,7 @@ impl AgentConfiguration {
|
||||
.child(self.render_agent_server(
|
||||
AgentIcon::Name(IconName::AiClaude),
|
||||
"Claude Code",
|
||||
"Claude Code",
|
||||
false,
|
||||
cx,
|
||||
))
|
||||
@@ -1091,6 +1095,7 @@ impl AgentConfiguration {
|
||||
.child(self.render_agent_server(
|
||||
AgentIcon::Name(IconName::AiOpenAi),
|
||||
"Codex CLI",
|
||||
"Codex CLI",
|
||||
false,
|
||||
cx,
|
||||
))
|
||||
@@ -1098,16 +1103,23 @@ impl AgentConfiguration {
|
||||
.child(self.render_agent_server(
|
||||
AgentIcon::Name(IconName::AiGemini),
|
||||
"Gemini CLI",
|
||||
"Gemini CLI",
|
||||
false,
|
||||
cx,
|
||||
))
|
||||
.map(|mut parent| {
|
||||
for (name, icon) in user_defined_agents {
|
||||
for (name, icon, display_name) in user_defined_agents {
|
||||
parent = parent
|
||||
.child(
|
||||
Divider::horizontal().color(DividerColor::BorderFaded),
|
||||
)
|
||||
.child(self.render_agent_server(icon, name, true, cx));
|
||||
.child(self.render_agent_server(
|
||||
icon,
|
||||
name,
|
||||
display_name,
|
||||
true,
|
||||
cx,
|
||||
));
|
||||
}
|
||||
parent
|
||||
}),
|
||||
@@ -1118,11 +1130,13 @@ impl AgentConfiguration {
|
||||
fn render_agent_server(
|
||||
&self,
|
||||
icon: AgentIcon,
|
||||
name: impl Into<SharedString>,
|
||||
id: impl Into<SharedString>,
|
||||
display_name: impl Into<SharedString>,
|
||||
external: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let name = name.into();
|
||||
let id = id.into();
|
||||
let display_name = display_name.into();
|
||||
let icon = match icon {
|
||||
AgentIcon::Name(icon_name) => Icon::new(icon_name)
|
||||
.size(IconSize::Small)
|
||||
@@ -1132,12 +1146,15 @@ impl AgentConfiguration {
|
||||
.color(Color::Muted),
|
||||
};
|
||||
|
||||
let tooltip_id = SharedString::new(format!("agent-source-{}", name));
|
||||
let tooltip_message = format!("The {} agent was installed from an extension.", name);
|
||||
let tooltip_id = SharedString::new(format!("agent-source-{}", id));
|
||||
let tooltip_message = format!(
|
||||
"The {} agent was installed from an extension.",
|
||||
display_name
|
||||
);
|
||||
|
||||
let agent_server_name = ExternalAgentServerName(name.clone());
|
||||
let agent_server_name = ExternalAgentServerName(id.clone());
|
||||
|
||||
let uninstall_btn_id = SharedString::from(format!("uninstall-{}", name));
|
||||
let uninstall_btn_id = SharedString::from(format!("uninstall-{}", id));
|
||||
let uninstall_button = IconButton::new(uninstall_btn_id, IconName::Trash)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
@@ -1161,7 +1178,7 @@ impl AgentConfiguration {
|
||||
h_flex()
|
||||
.gap_1p5()
|
||||
.child(icon)
|
||||
.child(Label::new(name))
|
||||
.child(Label::new(display_name))
|
||||
.when(external, |this| {
|
||||
this.child(
|
||||
div()
|
||||
|
||||
@@ -2083,8 +2083,11 @@ impl AgentPanel {
|
||||
|
||||
for agent_name in agent_names {
|
||||
let icon_path = agent_server_store.agent_icon(&agent_name);
|
||||
let display_name = agent_server_store
|
||||
.agent_display_name(&agent_name)
|
||||
.unwrap_or_else(|| agent_name.0.clone());
|
||||
|
||||
let mut entry = ContextMenuEntry::new(agent_name.clone());
|
||||
let mut entry = ContextMenuEntry::new(display_name);
|
||||
|
||||
if let Some(icon_path) = icon_path {
|
||||
entry = entry.custom_icon_svg(icon_path);
|
||||
|
||||
@@ -137,6 +137,7 @@ pub struct AgentServerStore {
|
||||
state: AgentServerStoreState,
|
||||
external_agents: HashMap<ExternalAgentServerName, Box<dyn ExternalAgentServer>>,
|
||||
agent_icons: HashMap<ExternalAgentServerName, SharedString>,
|
||||
agent_display_names: HashMap<ExternalAgentServerName, SharedString>,
|
||||
}
|
||||
|
||||
pub struct AgentServersUpdated;
|
||||
@@ -155,6 +156,7 @@ mod ext_agent_tests {
|
||||
state: AgentServerStoreState::Collab,
|
||||
external_agents: HashMap::default(),
|
||||
agent_icons: HashMap::default(),
|
||||
agent_display_names: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,6 +260,7 @@ impl AgentServerStore {
|
||||
self.external_agents.retain(|name, agent| {
|
||||
if agent.downcast_mut::<LocalExtensionArchiveAgent>().is_some() {
|
||||
self.agent_icons.remove(name);
|
||||
self.agent_display_names.remove(name);
|
||||
false
|
||||
} else {
|
||||
// Keep the hardcoded external agents that don't come from extensions
|
||||
@@ -275,6 +278,12 @@ impl AgentServerStore {
|
||||
for (ext_id, manifest) in manifests {
|
||||
for (agent_name, agent_entry) in &manifest.agent_servers {
|
||||
// Store absolute icon path if provided, resolving symlinks for dev extensions
|
||||
// Store display name from manifest
|
||||
self.agent_display_names.insert(
|
||||
ExternalAgentServerName(agent_name.clone().into()),
|
||||
SharedString::from(agent_entry.name.clone()),
|
||||
);
|
||||
|
||||
let icon_path = if let Some(icon) = &agent_entry.icon {
|
||||
let icon_path = extensions_dir.join(ext_id).join(icon);
|
||||
// Canonicalize to resolve symlinks (dev extensions are symlinked)
|
||||
@@ -310,6 +319,12 @@ impl AgentServerStore {
|
||||
let mut agents = vec![];
|
||||
for (ext_id, manifest) in manifests {
|
||||
for (agent_name, agent_entry) in &manifest.agent_servers {
|
||||
// Store display name from manifest
|
||||
self.agent_display_names.insert(
|
||||
ExternalAgentServerName(agent_name.clone().into()),
|
||||
SharedString::from(agent_entry.name.clone()),
|
||||
);
|
||||
|
||||
// Store absolute icon path if provided, resolving symlinks for dev extensions
|
||||
let icon = if let Some(icon) = &agent_entry.icon {
|
||||
let icon_path = extensions_dir.join(ext_id).join(icon);
|
||||
@@ -369,6 +384,10 @@ impl AgentServerStore {
|
||||
self.agent_icons.get(name).cloned()
|
||||
}
|
||||
|
||||
pub fn agent_display_name(&self, name: &ExternalAgentServerName) -> Option<SharedString> {
|
||||
self.agent_display_names.get(name).cloned()
|
||||
}
|
||||
|
||||
pub fn init_remote(session: &AnyProtoClient) {
|
||||
session.add_entity_message_handler(Self::handle_external_agents_updated);
|
||||
session.add_entity_message_handler(Self::handle_loading_status_updated);
|
||||
@@ -559,6 +578,7 @@ impl AgentServerStore {
|
||||
},
|
||||
external_agents: Default::default(),
|
||||
agent_icons: Default::default(),
|
||||
agent_display_names: Default::default(),
|
||||
};
|
||||
if let Some(_events) = extension::ExtensionEvents::try_global(cx) {}
|
||||
this.agent_servers_settings_changed(cx);
|
||||
@@ -609,6 +629,7 @@ impl AgentServerStore {
|
||||
},
|
||||
external_agents: external_agents.into_iter().collect(),
|
||||
agent_icons: HashMap::default(),
|
||||
agent_display_names: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -617,6 +638,7 @@ impl AgentServerStore {
|
||||
state: AgentServerStoreState::Collab,
|
||||
external_agents: Default::default(),
|
||||
agent_icons: Default::default(),
|
||||
agent_display_names: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2040,6 +2062,7 @@ mod extension_agent_tests {
|
||||
state: AgentServerStoreState::Collab,
|
||||
external_agents: HashMap::default(),
|
||||
agent_icons: HashMap::default(),
|
||||
agent_display_names: HashMap::default(),
|
||||
};
|
||||
|
||||
// Seed with extension agents (contain ": ") and custom agents (don't contain ": ")
|
||||
|
||||
Reference in New Issue
Block a user