diff --git a/codex-rs/core/src/context/available_plugins_instructions.rs b/codex-rs/core/src/context/available_plugins_instructions.rs index b2c12c759..683d939aa 100644 --- a/codex-rs/core/src/context/available_plugins_instructions.rs +++ b/codex-rs/core/src/context/available_plugins_instructions.rs @@ -40,27 +40,17 @@ impl ContextualUserFragment for AvailablePluginsInstructions { fn body(&self) -> String { let mut lines = vec![ "## Plugins".to_string(), - "A plugin is a local bundle of skills, MCP servers, and apps. Below is the list of plugins that are enabled and available in this session.".to_string(), - "### Available plugins".to_string(), + "A plugin is a local bundle of skills, MCP servers, and apps.".to_string(), ]; - lines.extend( - self.plugins - .iter() - .map(|plugin| match plugin.description.as_deref() { - Some(description) => format!("- `{}`: {description}", plugin.display_name), - None => format!("- `{}`", plugin.display_name), - }), - ); - lines.push("### How to use plugins".to_string()); lines.push( - r###"- Discovery: The list above is the plugins available in this session. -- Skill naming: If a plugin contributes skills, those skill entries are prefixed with `plugin_name:` in the Skills list. + r###"- Skill naming: If a plugin contributes skills, those skill entries are prefixed with `plugin_name:` in the Skills list. +- MCP naming: Plugin-provided MCP tools keep standard MCP identifiers such as `mcp__server__tool`; use tool provenance to tell which plugin they come from. - Trigger rules: If the user explicitly names a plugin, prefer capabilities associated with that plugin for that turn. - Relationship to capabilities: Plugins are not invoked directly. Use their underlying skills, MCP tools, and app tools to help solve the task. -- Preference: When a relevant plugin is available, prefer using capabilities associated with that plugin over standalone capabilities that provide similar functionality. -- Missing/blocked: If the user requests a plugin that is not listed above, or the plugin does not have relevant callable capabilities for the task, say so briefly and continue with the best fallback."### +- Relevance: Determine what a plugin can help with from explicit user mention or from the plugin-associated skills, MCP tools, and apps exposed elsewhere in this turn. +- Missing/blocked: If the user requests a plugin that does not have relevant callable capabilities for the task, say so briefly and continue with the best fallback."### .to_string(), ); diff --git a/codex-rs/core/src/plugins/render_tests.rs b/codex-rs/core/src/plugins/render_tests.rs index a0ec53120..ee7ea8c81 100644 --- a/codex-rs/core/src/plugins/render_tests.rs +++ b/codex-rs/core/src/plugins/render_tests.rs @@ -7,7 +7,7 @@ fn render_plugins_section_returns_none_for_empty_plugins() { } #[test] -fn render_plugins_section_includes_descriptions_and_skill_naming_guidance() { +fn render_plugins_section_keeps_plugin_usage_guidance_without_listing_plugins() { let rendered = render_plugins_section(&[PluginCapabilitySummary { config_name: "sample@test".to_string(), display_name: "sample".to_string(), @@ -17,7 +17,7 @@ fn render_plugins_section_includes_descriptions_and_skill_naming_guidance() { }]) .expect("plugin section should render"); - let expected = "\n## Plugins\nA plugin is a local bundle of skills, MCP servers, and apps. Below is the list of plugins that are enabled and available in this session.\n### Available plugins\n- `sample`: inspect sample data\n### How to use plugins\n- Discovery: The list above is the plugins available in this session.\n- Skill naming: If a plugin contributes skills, those skill entries are prefixed with `plugin_name:` in the Skills list.\n- Trigger rules: If the user explicitly names a plugin, prefer capabilities associated with that plugin for that turn.\n- Relationship to capabilities: Plugins are not invoked directly. Use their underlying skills, MCP tools, and app tools to help solve the task.\n- Preference: When a relevant plugin is available, prefer using capabilities associated with that plugin over standalone capabilities that provide similar functionality.\n- Missing/blocked: If the user requests a plugin that is not listed above, or the plugin does not have relevant callable capabilities for the task, say so briefly and continue with the best fallback.\n"; + let expected = "\n## Plugins\nA plugin is a local bundle of skills, MCP servers, and apps.\n### How to use plugins\n- Skill naming: If a plugin contributes skills, those skill entries are prefixed with `plugin_name:` in the Skills list.\n- MCP naming: Plugin-provided MCP tools keep standard MCP identifiers such as `mcp__server__tool`; use tool provenance to tell which plugin they come from.\n- Trigger rules: If the user explicitly names a plugin, prefer capabilities associated with that plugin for that turn.\n- Relationship to capabilities: Plugins are not invoked directly. Use their underlying skills, MCP tools, and app tools to help solve the task.\n- Relevance: Determine what a plugin can help with from explicit user mention or from the plugin-associated skills, MCP tools, and apps exposed elsewhere in this turn.\n- Missing/blocked: If the user requests a plugin that does not have relevant callable capabilities for the task, say so briefly and continue with the best fallback.\n"; assert_eq!(rendered, expected); } diff --git a/codex-rs/core/tests/suite/plugins.rs b/codex-rs/core/tests/suite/plugins.rs index 412b5edbb..e78e865e5 100644 --- a/codex-rs/core/tests/suite/plugins.rs +++ b/codex-rs/core/tests/suite/plugins.rs @@ -210,12 +210,8 @@ async fn capability_sections_render_in_developer_message_in_order() -> Result<() "expected Apps -> Skills -> Plugins order: {developer_messages:?}" ); assert!( - developer_text.contains("`sample`"), - "expected enabled plugin name in developer message: {developer_messages:?}" - ); - assert!( - developer_text.contains("`sample`: inspect sample data"), - "expected plugin description in developer message: {developer_messages:?}" + !developer_text.contains("`sample`: inspect sample data"), + "did not expect plugin description in developer message: {developer_messages:?}" ); assert!( developer_text.contains("skill entries are prefixed with `plugin_name:`"),