From 2b915a2eed8c6238a3a5da59479b896dfdabd460 Mon Sep 17 00:00:00 2001 From: rhan-oai Date: Wed, 5 Aug 2026 19:57:53 +0000 Subject: [PATCH] Gate Apps usage instructions by model capability (#37145) ## What changed - Add `include_apps_usage_instructions` to model metadata, defaulting to true for compatibility with existing metadata. - Emit generic Apps guidance only when apps are available and the selected model enables it. - Enable the capability for interactive model presets while leaving `codex-auto-review` and local models opted out. ## Testing - Verify that missing metadata defaults to enabled and an explicit opt-out survives serialization. GitOrigin-RevId: 6a20573cddfd3b80083d2b4b015829b49e6cc283 --- codex-rs/app-server/tests/common/models_cache.rs | 1 + codex-rs/codex-api/tests/models_integration.rs | 1 + codex-rs/core/src/session/world_state.rs | 6 +++++- codex-rs/core/tests/suite/auto_review.rs | 1 + codex-rs/core/tests/suite/model_switching.rs | 2 ++ codex-rs/core/tests/suite/models_cache_ttl.rs | 1 + codex-rs/core/tests/suite/personality.rs | 2 ++ codex-rs/core/tests/suite/remote_models.rs | 3 +++ codex-rs/core/tests/suite/rmcp_client.rs | 1 + .../core/tests/suite/spawn_agent_description.rs | 1 + codex-rs/core/tests/suite/view_image.rs | 1 + codex-rs/models-manager/models.json | 8 ++++++++ codex-rs/models-manager/src/model_info.rs | 1 + codex-rs/protocol/src/openai_models.rs | 14 ++++++++++++++ codex-rs/tools/src/tool_config_tests.rs | 1 + 15 files changed, 43 insertions(+), 1 deletion(-) diff --git a/codex-rs/app-server/tests/common/models_cache.rs b/codex-rs/app-server/tests/common/models_cache.rs index e26a5d1134..61b72e72e3 100644 --- a/codex-rs/app-server/tests/common/models_cache.rs +++ b/codex-rs/app-server/tests/common/models_cache.rs @@ -44,6 +44,7 @@ fn preset_to_info(preset: &ModelPreset, priority: i32) -> ModelInfo { }), include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/codex-api/tests/models_integration.rs b/codex-rs/codex-api/tests/models_integration.rs index a484a5ca3c..f26a44d6cf 100644 --- a/codex-rs/codex-api/tests/models_integration.rs +++ b/codex-rs/codex-api/tests/models_integration.rs @@ -82,6 +82,7 @@ async fn models_client_hits_models_endpoint() { model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/core/src/session/world_state.rs b/codex-rs/core/src/session/world_state.rs index d5cdac746d..083f582c99 100644 --- a/codex-rs/core/src/session/world_state.rs +++ b/codex-rs/core/src/session/world_state.rs @@ -204,7 +204,11 @@ impl Session { } else { false }; - world_state.add_section(AppsInstructionsState::new(apps_available)); + let apps_usage_instructions_available = + apps_available && turn_context.model_info.include_apps_usage_instructions; + world_state.add_section(AppsInstructionsState::new( + apps_usage_instructions_available, + )); let plugins_usage_instructions_available = step_context.mcp.plugins_available() && turn_context.model_info.include_plugin_usage_instructions; world_state.add_section(PluginsInstructionsState::new( diff --git a/codex-rs/core/tests/suite/auto_review.rs b/codex-rs/core/tests/suite/auto_review.rs index 6fc6a17644..a0d4df6483 100644 --- a/codex-rs/core/tests/suite/auto_review.rs +++ b/codex-rs/core/tests/suite/auto_review.rs @@ -272,6 +272,7 @@ fn remote_model_with_auto_review_override(slug: &str, review_model: &str) -> Mod model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/core/tests/suite/model_switching.rs b/codex-rs/core/tests/suite/model_switching.rs index 08f42d8952..ce5f8fc9ba 100644 --- a/codex-rs/core/tests/suite/model_switching.rs +++ b/codex-rs/core/tests/suite/model_switching.rs @@ -101,6 +101,7 @@ fn test_model_info( model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, @@ -966,6 +967,7 @@ async fn model_switch_to_smaller_model_updates_token_context_window() -> Result< model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/core/tests/suite/models_cache_ttl.rs b/codex-rs/core/tests/suite/models_cache_ttl.rs index e777774cd9..60a82bd80c 100644 --- a/codex-rs/core/tests/suite/models_cache_ttl.rs +++ b/codex-rs/core/tests/suite/models_cache_ttl.rs @@ -513,6 +513,7 @@ fn test_remote_model(slug: &str, priority: i32) -> ModelInfo { }), include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/core/tests/suite/personality.rs b/codex-rs/core/tests/suite/personality.rs index 1f1a501f24..fa61fc1303 100644 --- a/codex-rs/core/tests/suite/personality.rs +++ b/codex-rs/core/tests/suite/personality.rs @@ -648,6 +648,7 @@ async fn remote_model_friendly_personality_instructions_with_feature() -> anyhow }), include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, @@ -770,6 +771,7 @@ async fn user_turn_personality_remote_model_template_includes_update_message() - }), include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/core/tests/suite/remote_models.rs b/codex-rs/core/tests/suite/remote_models.rs index b59b7990c8..5e8950a43f 100644 --- a/codex-rs/core/tests/suite/remote_models.rs +++ b/codex-rs/core/tests/suite/remote_models.rs @@ -539,6 +539,7 @@ async fn remote_models_remote_model_uses_unified_exec() -> Result<()> { model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, @@ -802,6 +803,7 @@ async fn remote_models_apply_legacy_instructions() -> Result<()> { }), include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, @@ -1378,6 +1380,7 @@ fn test_remote_model_with_policy( model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/core/tests/suite/rmcp_client.rs b/codex-rs/core/tests/suite/rmcp_client.rs index 6bb23a3221..6efcf10a02 100644 --- a/codex-rs/core/tests/suite/rmcp_client.rs +++ b/codex-rs/core/tests/suite/rmcp_client.rs @@ -2210,6 +2210,7 @@ async fn stdio_image_responses_are_sanitized_for_text_only_model() -> anyhow::Re model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/core/tests/suite/spawn_agent_description.rs b/codex-rs/core/tests/suite/spawn_agent_description.rs index 20bd890519..0143427f6e 100644 --- a/codex-rs/core/tests/suite/spawn_agent_description.rs +++ b/codex-rs/core/tests/suite/spawn_agent_description.rs @@ -82,6 +82,7 @@ fn test_model_info( model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/core/tests/suite/view_image.rs b/codex-rs/core/tests/suite/view_image.rs index 8f03468036..be4083c094 100644 --- a/codex-rs/core/tests/suite/view_image.rs +++ b/codex-rs/core/tests/suite/view_image.rs @@ -1481,6 +1481,7 @@ async fn view_image_tool_returns_unsupported_message_for_text_only_model() -> an model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/models-manager/models.json b/codex-rs/models-manager/models.json index 9dfc0a3910..fef0db08bd 100644 --- a/codex-rs/models-manager/models.json +++ b/codex-rs/models-manager/models.json @@ -22,6 +22,7 @@ "use_responses_lite": true, "include_skills_usage_instructions": false, "include_plugin_usage_instructions": true, + "include_apps_usage_instructions": true, "auto_review_model_override": null, "context_window": 272000, "max_context_window": 272000, @@ -136,6 +137,7 @@ "use_responses_lite": true, "include_skills_usage_instructions": false, "include_plugin_usage_instructions": true, + "include_apps_usage_instructions": true, "auto_review_model_override": null, "context_window": 272000, "max_context_window": 272000, @@ -248,6 +250,7 @@ "use_responses_lite": true, "include_skills_usage_instructions": false, "include_plugin_usage_instructions": true, + "include_apps_usage_instructions": true, "auto_review_model_override": null, "context_window": 272000, "max_context_window": 272000, @@ -356,6 +359,7 @@ "use_responses_lite": false, "include_skills_usage_instructions": true, "include_plugin_usage_instructions": true, + "include_apps_usage_instructions": true, "auto_review_model_override": null, "context_window": 272000, "max_context_window": 272000, @@ -462,6 +466,7 @@ "use_responses_lite": false, "include_skills_usage_instructions": true, "include_plugin_usage_instructions": true, + "include_apps_usage_instructions": true, "auto_review_model_override": null, "context_window": 272000, "max_context_window": 1000000, @@ -566,6 +571,7 @@ "use_responses_lite": false, "include_skills_usage_instructions": true, "include_plugin_usage_instructions": true, + "include_apps_usage_instructions": true, "auto_review_model_override": null, "context_window": 272000, "max_context_window": 272000, @@ -665,6 +671,7 @@ "use_responses_lite": false, "include_skills_usage_instructions": true, "include_plugin_usage_instructions": true, + "include_apps_usage_instructions": true, "auto_review_model_override": null, "context_window": 272000, "max_context_window": 272000, @@ -761,6 +768,7 @@ "use_responses_lite": false, "include_skills_usage_instructions": true, "include_plugin_usage_instructions": false, + "include_apps_usage_instructions": false, "auto_review_model_override": null, "context_window": 272000, "max_context_window": 1000000, diff --git a/codex-rs/models-manager/src/model_info.rs b/codex-rs/models-manager/src/model_info.rs index 9bb05872c7..5c1356fbf7 100644 --- a/codex-rs/models-manager/src/model_info.rs +++ b/codex-rs/models-manager/src/model_info.rs @@ -155,6 +155,7 @@ pub fn model_info_from_slug(slug: &str) -> ModelInfo { model_messages: Some(local_model_messages_for_slug(slug)), include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, diff --git a/codex-rs/protocol/src/openai_models.rs b/codex-rs/protocol/src/openai_models.rs index 34994ac970..a915199ba2 100644 --- a/codex-rs/protocol/src/openai_models.rs +++ b/codex-rs/protocol/src/openai_models.rs @@ -394,6 +394,8 @@ pub struct ModelInfo { pub include_skills_usage_instructions: bool, #[serde(default)] pub include_plugin_usage_instructions: bool, + #[serde(default = "default_true")] + pub include_apps_usage_instructions: bool, /// Whether the model accepts the Responses API `reasoning.summary` parameter. #[serde(default = "default_true", skip_serializing_if = "is_true")] pub supports_reasoning_summary_parameter: bool, @@ -831,6 +833,7 @@ mod tests { model_messages: spec, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: ReasoningSummary::Auto, support_verbosity: false, @@ -1424,6 +1427,7 @@ mod tests { ); assert!(!model.include_skills_usage_instructions); assert!(!model.include_plugin_usage_instructions); + assert!(model.include_apps_usage_instructions); assert!(model.supports_reasoning_summary_parameter); assert!(!model.supports_image_detail_original); assert_eq!(model.web_search_tool_type, WebSearchToolType::Text); @@ -1434,6 +1438,16 @@ mod tests { assert_eq!(model.tool_mode, None); } + #[test] + fn model_info_preserves_explicit_apps_guidance_opt_out() { + let value = serde_json::to_value(test_model(/*spec*/ None)) + .expect("serialize model info with explicit apps guidance opt-out"); + assert_eq!(value["include_apps_usage_instructions"], false); + + let model = serde_json::from_value::(value).expect("deserialize model info"); + assert!(!model.include_apps_usage_instructions); + } + #[test] fn model_info_deserializes_known_tool_mode() { let mut value = diff --git a/codex-rs/tools/src/tool_config_tests.rs b/codex-rs/tools/src/tool_config_tests.rs index efd4bb9158..89d21f06f2 100644 --- a/codex-rs/tools/src/tool_config_tests.rs +++ b/codex-rs/tools/src/tool_config_tests.rs @@ -28,6 +28,7 @@ fn model_with_shell_type(shell_type: ConfigShellToolType) -> ModelInfo { model_messages: None, include_skills_usage_instructions: false, include_plugin_usage_instructions: false, + include_apps_usage_instructions: false, supports_reasoning_summary_parameter: true, default_reasoning_summary: Default::default(), support_verbosity: false,