mirror of
https://github.com/openai/codex.git
synced 2026-08-23 13:09:46 +00:00
Search selected plugin apps before falling back (#38484)
## What changed - When an explicitly selected plugin has apps available, instruct the model to use `tool_search` to discover relevant tools before falling back to unrelated or built-in tools. - Scope the guidance to the request that selected the plugin and omit it for plugins without available apps. ## Testing - Cover app-specific rendering, non-app plugins, bounded instruction output, and app enablement in dual-surface plugin requests. GitOrigin-RevId: 1b9501cc403d2817334a9307e683e99c140a794a
This commit is contained in:
@@ -24,6 +24,17 @@ pub(crate) fn render_explicit_plugin_instructions(
|
||||
plugin.display_name
|
||||
)];
|
||||
|
||||
if !available_apps.is_empty() {
|
||||
lines.push(
|
||||
concat!(
|
||||
"- For the user request that explicitly selected this plugin, and only for that ",
|
||||
"request, if `tool_search` is available and an app from this plugin may help, ",
|
||||
"search for its tools before falling back to unrelated or built-in tools."
|
||||
)
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
if plugin.has_skills {
|
||||
let skill_namespace = plugin
|
||||
.plugin_namespace
|
||||
@@ -34,17 +45,6 @@ pub(crate) fn render_explicit_plugin_instructions(
|
||||
));
|
||||
}
|
||||
|
||||
if !available_mcp_servers.is_empty() {
|
||||
lines.push(format!(
|
||||
"- MCP servers from this plugin available in this session: {}.",
|
||||
available_mcp_servers
|
||||
.iter()
|
||||
.map(|server| format!("`{server}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
));
|
||||
}
|
||||
|
||||
if !available_apps.is_empty() {
|
||||
lines.push(format!(
|
||||
"- Apps from this plugin available in this session: {}.",
|
||||
@@ -56,6 +56,17 @@ pub(crate) fn render_explicit_plugin_instructions(
|
||||
));
|
||||
}
|
||||
|
||||
if !available_mcp_servers.is_empty() {
|
||||
lines.push(format!(
|
||||
"- MCP servers from this plugin available in this session: {}.",
|
||||
available_mcp_servers
|
||||
.iter()
|
||||
.map(|server| format!("`{server}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
));
|
||||
}
|
||||
|
||||
if lines.len() == 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,31 @@ fn explicit_plugin_instructions_use_manifest_namespace_for_skills() {
|
||||
|
||||
assert!(rendered.contains("`acme.tools:`"));
|
||||
assert!(!rendered.contains("`Acme Developer Tools:`"));
|
||||
assert!(!rendered.contains("tool_search"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_plugin_instructions_search_available_apps_before_fallback() {
|
||||
let rendered = render_explicit_plugin_instructions(
|
||||
&PluginCapabilitySummary {
|
||||
config_name: "app-adobe@openai-curated-remote".to_string(),
|
||||
display_name: "Adobe".to_string(),
|
||||
..PluginCapabilitySummary::default()
|
||||
},
|
||||
&[],
|
||||
&["Adobe".to_string()],
|
||||
)
|
||||
.expect("app capability should render");
|
||||
|
||||
assert_eq!(
|
||||
rendered,
|
||||
"Capabilities from the `Adobe` plugin:\n\
|
||||
- For the user request that explicitly selected this plugin, and only for that request, \
|
||||
if `tool_search` is available and an app from this plugin may help, search for its \
|
||||
tools before falling back to unrelated or built-in tools.\n\
|
||||
- Apps from this plugin available in this session: `Adobe`.\n\
|
||||
Use these plugin-associated capabilities to help solve the task."
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -47,18 +72,26 @@ fn explicit_plugin_instructions_are_bounded() {
|
||||
let servers = (0..1_024)
|
||||
.map(|index| format!("server-{index}"))
|
||||
.collect::<Vec<_>>();
|
||||
let apps = (0..1_024)
|
||||
.map(|index| format!("app-{index}"))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let rendered = render_explicit_plugin_instructions(
|
||||
&PluginCapabilitySummary {
|
||||
config_name: "sample@test".to_string(),
|
||||
display_name: "sample".to_string(),
|
||||
has_skills: true,
|
||||
..PluginCapabilitySummary::default()
|
||||
},
|
||||
&servers,
|
||||
&[],
|
||||
&apps,
|
||||
)
|
||||
.expect("MCP capability should render");
|
||||
|
||||
assert!(rendered.len() <= MAX_EXPLICIT_PLUGIN_INSTRUCTIONS_BYTES);
|
||||
assert!(rendered.contains("only for that request"));
|
||||
assert!(rendered.contains("if `tool_search` is available"));
|
||||
assert!(rendered.contains("Skills from this plugin"));
|
||||
assert!(rendered.contains("`app-0`"));
|
||||
assert!(rendered.ends_with(TRUNCATED_PLUGIN_INSTRUCTIONS_SUFFIX));
|
||||
}
|
||||
|
||||
@@ -1134,6 +1134,13 @@ async fn explicit_plugin_mentions_use_apps_for_chatgpt_dual_surface_plugins(
|
||||
app_enabled,
|
||||
"plugin app guidance should match app enablement: {developer_messages:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
developer_messages
|
||||
.iter()
|
||||
.any(|text| text.contains("if `tool_search` is available")),
|
||||
app_enabled,
|
||||
"plugin app search guidance should match app enablement: {developer_messages:?}"
|
||||
);
|
||||
assert!(
|
||||
request
|
||||
.tool_by_name(SAMPLE_PLUGIN_MCP_NAMESPACE, "echo")
|
||||
|
||||
Reference in New Issue
Block a user