mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
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:
committed by
GitHub
Unverified
parent
4a210faf33
commit
05b967c79a
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user