Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
20 changes: 16 additions & 4 deletions codex-rs/core/src/tools/handlers/request_plugin_install_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ pub(crate) fn create_request_plugin_install_tool(
(
"plugin_id".to_string(),
JsonSchema::string(Some(
"Plugin id from the `<recommended_plugins>` list.".to_string(),
"The parenthesized plugin ID from the `<recommended_plugins>` list."
.to_string(),
)),
),
(
Expand All @@ -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 `<recommended_plugins>` 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 `<recommended_plugins>`.\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(),
),
};

Expand Down Expand Up @@ -144,19 +145,30 @@ 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 `<recommended_plugins>`.\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 `<recommended_plugins>` 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(
BTreeMap::from([
(
"plugin_id".to_string(),
JsonSchema::string(Some(
"Plugin id from the `<recommended_plugins>` list.".to_string(),
"The parenthesized plugin ID from the `<recommended_plugins>` list."
.to_string(),
)),
),
(
Expand Down
8 changes: 6 additions & 2 deletions codex-rs/core/src/tools/spec_plan_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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 `<recommended_plugins>` list"));
assert!(request_description.contains("listed in `<recommended_plugins>`"));
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"));
Expand Down
Loading