mirror of
https://github.com/openai/codex.git
synced 2026-11-14 21:40:39 +00:00
Add opt-in concise hints for explicitly selected plugins (#57317)
## What changed Add the `features.simplified_selection_hints` flag, disabled by default. When enabled, replace detailed plugin capability instructions with a concise developer message identifying the selected plugin and directing the model to use its available skills and tools. Continue omitting hints for plugins without available capabilities and bounding hint length. Preserve the existing detailed instructions when the flag is disabled. ## Testing Cover plugin refresh in an existing thread with the flag enabled and disabled. Verify that explicit skill prompts precede the simplified plugin hint and that the hint uses the developer role. GitOrigin-RevId: 64fc3347bd49fffe675f343a4733ced1b4e5e88c
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use codex_connectors::metadata::connector_display_label;
|
||||
use codex_features::Features;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
|
||||
use crate::connectors;
|
||||
@@ -15,13 +16,13 @@ pub(crate) fn build_plugin_injections(
|
||||
mentioned_plugins: &[PluginCapabilitySummary],
|
||||
mcp_tools: &[ToolInfo],
|
||||
available_connectors: &[connectors::AppInfo],
|
||||
features: &Features,
|
||||
) -> Vec<ResponseItem> {
|
||||
if mentioned_plugins.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// Turn each explicit plugin mention into a developer hint that points the
|
||||
// model at the plugin's visible MCP servers, enabled apps, and skill prefix.
|
||||
// Turn each explicit plugin mention with available capabilities into a developer hint.
|
||||
mentioned_plugins
|
||||
.iter()
|
||||
.filter_map(|plugin| {
|
||||
@@ -51,9 +52,14 @@ pub(crate) fn build_plugin_injections(
|
||||
.collect::<BTreeSet<String>>()
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
render_explicit_plugin_instructions(plugin, &available_mcp_servers, &available_apps)
|
||||
.map(PluginInstructions::new)
|
||||
.map(ContextualUserFragment::into)
|
||||
render_explicit_plugin_instructions(
|
||||
plugin,
|
||||
&available_mcp_servers,
|
||||
&available_apps,
|
||||
features,
|
||||
)
|
||||
.map(PluginInstructions::new)
|
||||
.map(ContextualUserFragment::into)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ use crate::context::AvailablePluginsInstructions;
|
||||
#[cfg(test)]
|
||||
use crate::context::ContextualUserFragment;
|
||||
use crate::plugins::PluginCapabilitySummary;
|
||||
use codex_features::Feature;
|
||||
use codex_features::Features;
|
||||
#[cfg(test)]
|
||||
use codex_protocol_test_support::ContentItemTestExt;
|
||||
use codex_utils_string::take_bytes_at_char_boundary;
|
||||
@@ -20,7 +22,21 @@ pub(crate) fn render_explicit_plugin_instructions(
|
||||
plugin: &PluginCapabilitySummary,
|
||||
available_mcp_servers: &[String],
|
||||
available_apps: &[String],
|
||||
features: &Features,
|
||||
) -> Option<String> {
|
||||
if features.enabled(Feature::SimplifiedSelectionHints) {
|
||||
return (plugin.has_skills || !available_apps.is_empty() || !available_mcp_servers.is_empty())
|
||||
.then(|| {
|
||||
bound_explicit_plugin_instructions(
|
||||
format!(
|
||||
"The user selected the `{}` plugin. Use its available skills and tools to complete this request.",
|
||||
plugin.display_name
|
||||
),
|
||||
"\n[Plugin selection truncated to fit the context limit.]",
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
let mut lines = vec![format!(
|
||||
"Capabilities from the `{}` plugin:",
|
||||
plugin.display_name
|
||||
@@ -75,18 +91,21 @@ pub(crate) fn render_explicit_plugin_instructions(
|
||||
|
||||
lines.push("Use these plugin-associated capabilities to help solve the task.".to_string());
|
||||
|
||||
Some(bound_explicit_plugin_instructions(lines.join("\n")))
|
||||
Some(bound_explicit_plugin_instructions(
|
||||
lines.join("\n"),
|
||||
TRUNCATED_PLUGIN_INSTRUCTIONS_SUFFIX,
|
||||
))
|
||||
}
|
||||
|
||||
fn bound_explicit_plugin_instructions(rendered: String) -> String {
|
||||
fn bound_explicit_plugin_instructions(rendered: String, truncation_suffix: &str) -> String {
|
||||
if rendered.len() <= MAX_EXPLICIT_PLUGIN_INSTRUCTIONS_BYTES {
|
||||
return rendered;
|
||||
}
|
||||
|
||||
let max_prefix_bytes = MAX_EXPLICIT_PLUGIN_INSTRUCTIONS_BYTES
|
||||
.saturating_sub(TRUNCATED_PLUGIN_INSTRUCTIONS_SUFFIX.len());
|
||||
let max_prefix_bytes =
|
||||
MAX_EXPLICIT_PLUGIN_INSTRUCTIONS_BYTES.saturating_sub(truncation_suffix.len());
|
||||
let prefix = take_bytes_at_char_boundary(&rendered, max_prefix_bytes);
|
||||
format!("{prefix}{TRUNCATED_PLUGIN_INSTRUCTIONS_SUFFIX}")
|
||||
format!("{prefix}{truncation_suffix}")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -35,6 +35,7 @@ fn explicit_plugin_instructions_use_manifest_namespace_for_skills() {
|
||||
},
|
||||
&[],
|
||||
&[],
|
||||
&Features::default(),
|
||||
)
|
||||
.expect("skill capability should render");
|
||||
|
||||
@@ -53,6 +54,7 @@ fn explicit_plugin_instructions_search_available_apps_before_fallback() {
|
||||
},
|
||||
&[],
|
||||
&["Adobe".to_string()],
|
||||
&Features::default(),
|
||||
)
|
||||
.expect("app capability should render");
|
||||
|
||||
@@ -85,6 +87,7 @@ fn explicit_plugin_instructions_are_bounded() {
|
||||
},
|
||||
&servers,
|
||||
&apps,
|
||||
&Features::default(),
|
||||
)
|
||||
.expect("MCP capability should render");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user