Remove provenance filtering in $mentions for apps and skills from plugins (#15700)

- Removes provenance filtering in the mentions feature for apps and
skills that were installed as part of a plugin.
- All skills and apps for a plugin are mentionable with this change.
This commit is contained in:
canvrno-oai
2026-03-24 17:40:14 -07:00
committed by GitHub
Unverified
parent 4a210faf33
commit 05b967c79a
2 changed files with 24 additions and 150 deletions
+12 -100
View File
@@ -3584,41 +3584,8 @@ impl ChatComposer {
fn mention_items(&self) -> Vec<MentionItem> {
let mut mentions = Vec::new();
let plugin_namespaces: HashSet<String> =
self.plugins.as_ref().map_or_else(HashSet::new, |plugins| {
plugins
.iter()
.filter_map(|plugin| {
let (plugin_name, _) = plugin
.config_name
.split_once('@')
.unwrap_or((plugin.config_name.as_str(), ""));
let plugin_name = plugin_name.trim();
if plugin_name.is_empty() {
None
} else {
Some(plugin_name.to_ascii_lowercase())
}
})
.collect()
});
let plugin_display_names: HashSet<String> =
self.plugins.as_ref().map_or_else(HashSet::new, |plugins| {
plugins
.iter()
.map(|plugin| plugin.display_name.to_ascii_lowercase())
.collect()
});
if let Some(skills) = self.skills.as_ref() {
for skill in skills {
let is_plugin_namespaced_skill =
skill.name.split_once(':').is_some_and(|(namespace, _)| {
plugin_namespaces.contains(&namespace.to_ascii_lowercase())
});
if is_plugin_namespaced_skill {
continue;
}
let display_name = skill_display_name(skill).to_string();
let description = skill_description(skill);
let skill_name = skill.name.clone();
@@ -3698,30 +3665,18 @@ impl ChatComposer {
if !connector.is_accessible || !connector.is_enabled {
continue;
}
let plugin_backed_connector = connector
.plugin_display_names
.iter()
.any(|name| plugin_display_names.contains(&name.to_ascii_lowercase()));
if plugin_backed_connector {
continue;
}
let display_name = connectors::connector_display_label(connector);
let description = Some(Self::connector_brief_description(connector));
let slug = codex_core::connectors::connector_mention_slug(connector);
let search_terms = vec![display_name.clone(), connector.id.clone(), slug.clone()];
let connector_id = connector.id.as_str();
let category_tag = if connector.plugin_display_names.is_empty() {
"[App]".to_string()
} else {
"[Plugin]".to_string()
};
mentions.push(MentionItem {
display_name: display_name.clone(),
description,
insert_text: format!("${slug}"),
search_terms,
path: Some(format!("app://{connector_id}")),
category_tag: Some(category_tag),
category_tag: Some("[App]".to_string()),
sort_rank: 1,
});
}
@@ -5428,7 +5383,7 @@ mod tests {
}
#[test]
fn mention_items_hide_plugin_owned_skill_and_app_duplicates() {
fn mention_items_show_plugin_owned_skill_and_app_duplicates() {
let (tx, _rx) = unbounded_channel::<AppEvent>();
let sender = AppEventSender::new(tx);
let mut composer = ChatComposer::new(
@@ -5491,63 +5446,20 @@ mod tests {
}));
let mentions = composer.mention_items();
assert_eq!(mentions.len(), 1);
assert_eq!(mentions.len(), 3);
assert_eq!(mentions[0].category_tag, Some("[Skill]".to_string()));
assert_eq!(
mentions[0].path,
Some("/tmp/repo/google-calendar/SKILL.md".to_string())
);
assert_eq!(mentions[0].display_name, "Google Calendar".to_string());
assert_eq!(mentions[0].category_tag, Some("[Plugin]".to_string()));
assert_eq!(mentions[1].category_tag, Some("[Plugin]".to_string()));
assert_eq!(
mentions[0].path,
Some("plugin://google-calendar@debug".to_string())
);
}
#[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,
mentions[1].path,
Some("plugin://google-calendar@debug".to_string())
);
assert_eq!(mentions[2].category_tag, Some("[App]".to_string()));
assert_eq!(mentions[2].path, Some("app://google_calendar".to_string()));
}
#[test]
@@ -3599,41 +3599,8 @@ impl ChatComposer {
fn mention_items(&self) -> Vec<MentionItem> {
let mut mentions = Vec::new();
let plugin_namespaces: HashSet<String> =
self.plugins.as_ref().map_or_else(HashSet::new, |plugins| {
plugins
.iter()
.filter_map(|plugin| {
let (plugin_name, _) = plugin
.config_name
.split_once('@')
.unwrap_or((plugin.config_name.as_str(), ""));
let plugin_name = plugin_name.trim();
if plugin_name.is_empty() {
None
} else {
Some(plugin_name.to_ascii_lowercase())
}
})
.collect()
});
let plugin_display_names: HashSet<String> =
self.plugins.as_ref().map_or_else(HashSet::new, |plugins| {
plugins
.iter()
.map(|plugin| plugin.display_name.to_ascii_lowercase())
.collect()
});
if let Some(skills) = self.skills.as_ref() {
for skill in skills {
let is_plugin_namespaced_skill =
skill.name.split_once(':').is_some_and(|(namespace, _)| {
plugin_namespaces.contains(&namespace.to_ascii_lowercase())
});
if is_plugin_namespaced_skill {
continue;
}
let display_name = skill_display_name(skill).to_string();
let description = skill_description(skill);
let skill_name = skill.name.clone();
@@ -3713,30 +3680,18 @@ impl ChatComposer {
if !connector.is_accessible || !connector.is_enabled {
continue;
}
let plugin_backed_connector = connector
.plugin_display_names
.iter()
.any(|name| plugin_display_names.contains(&name.to_ascii_lowercase()));
if plugin_backed_connector {
continue;
}
let display_name = connectors::connector_display_label(connector);
let description = Some(Self::connector_brief_description(connector));
let slug = codex_core::connectors::connector_mention_slug(connector);
let search_terms = vec![display_name.clone(), connector.id.clone(), slug.clone()];
let connector_id = connector.id.as_str();
let category_tag = if connector.plugin_display_names.is_empty() {
"[App]".to_string()
} else {
"[Plugin]".to_string()
};
mentions.push(MentionItem {
display_name: display_name.clone(),
description,
insert_text: format!("${slug}"),
search_terms,
path: Some(format!("app://{connector_id}")),
category_tag: Some(category_tag),
category_tag: Some("[App]".to_string()),
sort_rank: 1,
});
}
@@ -5443,7 +5398,7 @@ mod tests {
}
#[test]
fn mention_items_hide_plugin_owned_skill_and_app_duplicates() {
fn mention_items_show_plugin_owned_skill_and_app_duplicates() {
let (tx, _rx) = unbounded_channel::<AppEvent>();
let sender = AppEventSender::new(tx);
let mut composer = ChatComposer::new(
@@ -5506,13 +5461,20 @@ mod tests {
}));
let mentions = composer.mention_items();
assert_eq!(mentions.len(), 1);
assert_eq!(mentions[0].display_name, "Google Calendar".to_string());
assert_eq!(mentions[0].category_tag, Some("[Plugin]".to_string()));
assert_eq!(mentions.len(), 3);
assert_eq!(mentions[0].category_tag, Some("[Skill]".to_string()));
assert_eq!(
mentions[0].path,
Some("/tmp/repo/google-calendar/SKILL.md".to_string())
);
assert_eq!(mentions[0].display_name, "Google Calendar".to_string());
assert_eq!(mentions[1].category_tag, Some("[Plugin]".to_string()));
assert_eq!(
mentions[1].path,
Some("plugin://google-calendar@debug".to_string())
);
assert_eq!(mentions[2].category_tag, Some("[App]".to_string()));
assert_eq!(mentions[2].path, Some("app://google_calendar".to_string()));
}
#[test]