From b019a5577c9a7daecd1d36b863890b96e385d4a2 Mon Sep 17 00:00:00 2001 From: Matthew Zeng Date: Tue, 14 Jul 2026 04:25:24 +0000 Subject: [PATCH] Tighten recommended plugin install suggestions (#32949) ## What changed - Limit `request_plugin_install` guidance to explicitly requested plugins after tool search has been exhausted. - Exclude adjacent capabilities, broad recommendations, and plugins that only seem potentially useful. - Clarify that `plugin_id` is the parenthesized ID from `` and prohibit parallel tool calls. - Keep the recommendation context focused on listing available plugins while the tool specification owns the installation criteria. ## Testing - Update tool specification tests to verify the stricter eligibility and serialization guidance. GitOrigin-RevId: 6ebfdd864a76316ab59a0624dc4d7d3abda39a98 --- .../recommended_plugins_instructions.rs | 3 ++- .../handlers/request_plugin_install_spec.rs | 20 +++++++++++++++---- codex-rs/core/src/tools/spec_plan_tests.rs | 8 ++++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/codex-rs/core/src/context/recommended_plugins_instructions.rs b/codex-rs/core/src/context/recommended_plugins_instructions.rs index 9ad3c9a0d783..b8f4b998c2dc 100644 --- a/codex-rs/core/src/context/recommended_plugins_instructions.rs +++ b/codex-rs/core/src/context/recommended_plugins_instructions.rs @@ -1,7 +1,8 @@ use super::ContextualUserFragment; use codex_tools::DiscoverableTool; -const RECOMMENDED_PLUGINS_INTRO: &str = "Here is a list of plugins that are available but not installed. If the user's query would benefit from one of these plugins, use the `request_plugin_install` tool to suggest that they install it. Pass the parenthesized ID as `plugin_id`. For example, suggest the Google Drive plugin if the query could possibly be better answered with access to Google Drive."; +const RECOMMENDED_PLUGINS_INTRO: &str = + "Here is a list of plugins that are available but not installed."; const MAX_RECOMMENDED_PLUGINS: usize = 50; #[derive(Debug, Clone, PartialEq)] diff --git a/codex-rs/core/src/tools/handlers/request_plugin_install_spec.rs b/codex-rs/core/src/tools/handlers/request_plugin_install_spec.rs index e37e223832c4..ec09be075fc5 100644 --- a/codex-rs/core/src/tools/handlers/request_plugin_install_spec.rs +++ b/codex-rs/core/src/tools/handlers/request_plugin_install_spec.rs @@ -53,7 +53,8 @@ pub(crate) fn create_request_plugin_install_tool( ( "plugin_id".to_string(), JsonSchema::string(Some( - "Plugin id from the `` list.".to_string(), + "The parenthesized plugin ID from the `` list." + .to_string(), )), ), ( @@ -65,7 +66,7 @@ pub(crate) fn create_request_plugin_install_tool( ), ]), vec!["plugin_id".to_string(), "suggest_reason".to_string()], - "# Suggest a recommended plugin installation\n\nSuggest installing a plugin from the `` list when it would help with the user's current request. Briefly explain why in `suggest_reason`.".to_string(), + "# Suggest a recommended plugin installation\n\nUse this tool only when all of the following are true:\n- The user explicitly asks to use a specific plugin that is not already available in the current context or active `tools` list.\n- Tool search has already been exhausted and did not find or make the requested tool callable.\n- The plugin is listed in ``.\n\nDo not use it for adjacent capabilities, broad recommendations, or plugins that merely seem useful. Briefly explain why the plugin can help with the current request in `suggest_reason`.\n\nIMPORTANT: DO NOT call this tool in parallel with other tools.".to_string(), ), }; @@ -144,11 +145,21 @@ mod tests { #[test] fn recommendation_context_uses_simplified_plugin_wire_shape() { + let expected_description = concat!( + "# Suggest a recommended plugin installation\n\n", + "Use this tool only when all of the following are true:\n", + "- The user explicitly asks to use a specific plugin that is not already available in the current context or active `tools` list.\n", + "- Tool search has already been exhausted and did not find or make the requested tool callable.\n", + "- The plugin is listed in ``.\n\n", + "Do not use it for adjacent capabilities, broad recommendations, or plugins that merely seem useful. Briefly explain why the plugin can help with the current request in `suggest_reason`.\n\n", + "IMPORTANT: DO NOT call this tool in parallel with other tools.", + ); + assert_eq!( create_request_plugin_install_tool(ToolSuggestPresentation::RecommendationContext), ToolSpec::Function(ResponsesApiTool { name: "request_plugin_install".to_string(), - description: "# Suggest a recommended plugin installation\n\nSuggest installing a plugin from the `` list when it would help with the user's current request. Briefly explain why in `suggest_reason`.".to_string(), + description: expected_description.to_string(), strict: false, defer_loading: None, parameters: JsonSchema::object( @@ -156,7 +167,8 @@ mod tests { ( "plugin_id".to_string(), JsonSchema::string(Some( - "Plugin id from the `` list.".to_string(), + "The parenthesized plugin ID from the `` list." + .to_string(), )), ), ( diff --git a/codex-rs/core/src/tools/spec_plan_tests.rs b/codex-rs/core/src/tools/spec_plan_tests.rs index e03a5c969fb4..94ab06253ab7 100644 --- a/codex-rs/core/src/tools/spec_plan_tests.rs +++ b/codex-rs/core/src/tools/spec_plan_tests.rs @@ -993,7 +993,7 @@ async fn request_plugin_install_stays_visible_without_tool_search() { } #[tokio::test] -async fn request_plugin_install_description_refers_to_recommended_plugins_hint() { +async fn request_plugin_install_description_requires_exhausting_tool_search() { let plan = probe_with( |turn| { set_features( @@ -1018,7 +1018,11 @@ async fn request_plugin_install_description_refers_to_recommended_plugins_hint() else { panic!("expected request_plugin_install function spec"); }; - assert!(request_description.contains("the `` list")); + assert!(request_description.contains("listed in ``")); + assert!(request_description.contains("explicitly asks to use a specific plugin")); + assert!(request_description.contains("Tool search has already been exhausted")); + assert!(!request_description.contains("`tool_search`")); + assert!(request_description.contains("DO NOT call this tool in parallel with other tools")); assert!(!request_description.contains("list_available_plugins_to_install")); assert!(!request_description.contains("github")); assert!(has_parameter(request_spec, "plugin_id"));