Pretty plugin labels, preserve plugin app provenance during MCP tool refresh (#15606)

- Prefer plugin manifest `interface.displayName` for plugin labels.
- Preserve plugin provenance when handling `list_mcp_tools` so connector
`plugin_display_names` are not clobbered.
- Add a TUI test to ensure plugin-owned app mentions are deduped
correctly.
This commit is contained in:
canvrno-oai
2026-03-24 10:34:19 -07:00
committed by GitHub
Unverified
parent f1658ab642
commit 66edc347ae
3 changed files with 65 additions and 2 deletions
+8 -1
View File
@@ -1550,7 +1550,14 @@ fn load_plugin(
};
let manifest_paths = &manifest.paths;
loaded_plugin.manifest_name = Some(manifest.name.clone());
loaded_plugin.manifest_name = manifest
.interface
.as_ref()
.and_then(|interface| interface.display_name.as_deref())
.map(str::trim)
.filter(|display_name| !display_name.is_empty())
.map(str::to_string)
.or_else(|| Some(manifest.name.clone()));
loaded_plugin.manifest_description = manifest.description.clone();
loaded_plugin.skill_roots = plugin_skill_roots(plugin_root.as_path(), manifest_paths);
let resolved_skills = load_plugin_skills(
@@ -5500,6 +5500,56 @@ mod tests {
);
}
#[test]
fn mention_items_hide_plugin_owned_app_duplicates_when_provenance_matches() {
let (tx, _rx) = unbounded_channel::<AppEvent>();
let sender = AppEventSender::new(tx);
let mut composer = ChatComposer::new(
true,
sender,
false,
"Ask Codex to do anything".to_string(),
false,
);
composer.set_connectors_enabled(true);
composer.set_text_content("$goog".to_string(), Vec::new(), Vec::new());
composer.set_plugin_mentions(Some(vec![PluginCapabilitySummary {
config_name: "google-calendar@debug".to_string(),
display_name: "Google Calendar".to_string(),
description: None,
has_skills: false,
mcp_server_names: vec!["google-calendar".to_string()],
app_connector_ids: vec![codex_core::plugins::AppConnectorId(
"google_calendar".to_string(),
)],
}]));
composer.set_connector_mentions(Some(ConnectorsSnapshot {
connectors: vec![AppInfo {
id: "google_calendar".to_string(),
name: "Google Calendar".to_string(),
description: Some("Look up events and availability".to_string()),
logo_url: None,
logo_url_dark: None,
distribution_channel: None,
branding: None,
app_metadata: None,
labels: None,
install_url: Some("https://example.test/google-calendar".to_string()),
is_accessible: true,
is_enabled: true,
plugin_display_names: vec!["Google Calendar".to_string()],
}],
}));
let mentions = composer.mention_items();
assert_eq!(mentions.len(), 1);
assert_eq!(mentions[0].category_tag, Some("[Plugin]".to_string()));
assert_eq!(
mentions[0].path,
Some("plugin://google-calendar@debug".to_string())
);
}
#[test]
fn plugin_mention_popup_snapshot() {
snapshot_composer_state("plugin_mention_popup", false, |composer| {
+7 -1
View File
@@ -8946,6 +8946,10 @@ impl ChatWidget {
fn on_list_mcp_tools(&mut self, ev: McpListToolsResponseEvent) {
if self.connectors_enabled() {
let plugin_provenance = McpManager::new(Arc::new(PluginsManager::new(
self.config.codex_home.clone(),
)))
.tool_plugin_provenance(&self.config);
let mut connectors_by_id: HashMap<String, connectors::AppInfo> = HashMap::new();
for tool in ev.tools.values() {
let Some(meta) = tool.meta.as_ref().and_then(serde_json::Value::as_object) else {
@@ -8988,7 +8992,9 @@ impl ChatWidget {
install_url: None,
is_accessible: true,
is_enabled: true,
plugin_display_names: Vec::new(),
plugin_display_names: plugin_provenance
.plugin_display_names_for_connector_id(connector_id)
.to_vec(),
}
});
}