chore: use @plugin instead of $plugin for plaintext mentions (#13921)

change plaintext plugin-mentions from `$plugin` to `@plugin`, ensure TUI
can correctly decode these from history.

tested locally, added/updated tests.
This commit is contained in:
sayan-oai
2026-03-07 17:36:39 -08:00
committed by GitHub
Unverified
parent bf5c2f48a5
commit 590cfa6176
6 changed files with 98 additions and 16 deletions
+1
View File
@@ -55,6 +55,7 @@ pub use mcp_connection_manager::SandboxState;
pub use text_encoding::bytes_to_string_smart;
mod mcp_tool_call;
mod memories;
pub mod mention_syntax;
mod mentions;
mod message_history;
mod model_provider_info;
+4
View File
@@ -0,0 +1,4 @@
// Default plaintext sigil for tools.
pub const TOOL_MENTION_SIGIL: char = '$';
// Plugins use `@` in linked plaintext outside TUI.
pub const PLUGIN_TEXT_MENTION_SIGIL: char = '@';
+31 -6
View File
@@ -5,11 +5,13 @@ use std::path::PathBuf;
use codex_protocol::user_input::UserInput;
use crate::connectors;
use crate::mention_syntax::PLUGIN_TEXT_MENTION_SIGIL;
use crate::mention_syntax::TOOL_MENTION_SIGIL;
use crate::plugins::PluginCapabilitySummary;
use crate::skills::SkillMetadata;
use crate::skills::injection::ToolMentionKind;
use crate::skills::injection::app_id_from_path;
use crate::skills::injection::extract_tool_mentions;
use crate::skills::injection::extract_tool_mentions_with_sigil;
use crate::skills::injection::plugin_config_name_from_path;
use crate::skills::injection::tool_kind_for_path;
@@ -19,10 +21,17 @@ pub(crate) struct CollectedToolMentions {
}
pub(crate) fn collect_tool_mentions_from_messages(messages: &[String]) -> CollectedToolMentions {
collect_tool_mentions_from_messages_with_sigil(messages, TOOL_MENTION_SIGIL)
}
fn collect_tool_mentions_from_messages_with_sigil(
messages: &[String],
sigil: char,
) -> CollectedToolMentions {
let mut plain_names = HashSet::new();
let mut paths = HashSet::new();
for message in messages {
let mentions = extract_tool_mentions(message);
let mentions = extract_tool_mentions_with_sigil(message, sigil);
plain_names.extend(mentions.plain_names().map(str::to_string));
paths.extend(mentions.paths().map(str::to_string));
}
@@ -50,7 +59,7 @@ pub(crate) fn collect_explicit_app_ids(input: &[UserInput]) -> HashSet<String> {
.collect()
}
/// Collect explicit structured `plugin://...` mentions.
/// Collect explicit structured or linked `plugin://...` mentions.
pub(crate) fn collect_explicit_plugin_mentions(
input: &[UserInput],
plugins: &[PluginCapabilitySummary],
@@ -73,7 +82,11 @@ pub(crate) fn collect_explicit_plugin_mentions(
UserInput::Mention { path, .. } => Some(path.clone()),
_ => None,
})
.chain(collect_tool_mentions_from_messages(&messages).paths)
.chain(
// Plugin plaintext links use `@`, not the default `$` tool sigil.
collect_tool_mentions_from_messages_with_sigil(&messages, PLUGIN_TEXT_MENTION_SIGIL)
.paths,
)
.filter(|path| tool_kind_for_path(path.as_str()) == ToolMentionKind::Plugin)
.filter_map(|path| plugin_config_name_from_path(path.as_str()).map(str::to_string))
.collect();
@@ -222,7 +235,7 @@ mod tests {
];
let mentioned = collect_explicit_plugin_mentions(
&[text_input("use [$sample](plugin://sample@test)")],
&[text_input("use [@sample](plugin://sample@test)")],
&plugins,
);
@@ -238,7 +251,7 @@ mod tests {
let mentioned = collect_explicit_plugin_mentions(
&[
text_input("use [$sample](plugin://sample@test)"),
text_input("use [@sample](plugin://sample@test)"),
UserInput::Mention {
name: "sample".to_string(),
path: "plugin://sample@test".to_string(),
@@ -263,4 +276,16 @@ mod tests {
assert_eq!(mentioned, Vec::<PluginCapabilitySummary>::new());
}
#[test]
fn collect_explicit_plugin_mentions_ignores_dollar_linked_plugin_mentions() {
let plugins = vec![plugin("sample@test", "sample")];
let mentioned = collect_explicit_plugin_mentions(
&[text_input("use [$sample](plugin://sample@test)")],
&plugins,
);
assert_eq!(mentioned, Vec::<PluginCapabilitySummary>::new());
}
}
+3 -2
View File
@@ -7,6 +7,7 @@ use crate::analytics_client::InvocationType;
use crate::analytics_client::SkillInvocation;
use crate::analytics_client::TrackEventsContext;
use crate::instructions::SkillInstructions;
use crate::mention_syntax::TOOL_MENTION_SIGIL;
use crate::mentions::build_skill_name_counts;
use crate::skills::SkillMetadata;
use codex_otel::SessionTelemetry;
@@ -232,10 +233,10 @@ pub(crate) fn normalize_skill_path(path: &str) -> &str {
/// resource path is present, it is captured for exact path matching while also tracking
/// the name for fallback matching.
pub(crate) fn extract_tool_mentions(text: &str) -> ToolMentions<'_> {
extract_tool_mentions_with_sigil(text, '$')
extract_tool_mentions_with_sigil(text, TOOL_MENTION_SIGIL)
}
fn extract_tool_mentions_with_sigil(text: &str, sigil: char) -> ToolMentions<'_> {
pub(crate) fn extract_tool_mentions_with_sigil(text: &str, sigil: char) -> ToolMentions<'_> {
let text_bytes = text.as_bytes();
let mut mentioned_names: HashSet<&str> = HashSet::new();
let mut mentioned_paths: HashSet<&str> = HashSet::new();