Support model catalog overrides for plugin guidance (#58894)

## What changed

- Add `model_messages.plugins` overrides for generic usage guidance, selected-plugin hints, and recommendation introductions, with independent fallback to bundled wording for missing or invalid fields.
- Validate text limits and required template placeholders while keeping plugin identities, available capabilities, and eligibility controlled by the client.
- Track generic guidance changes across model switches and session resume, emitting replacement or retirement notices and supporting legacy snapshots and retained history.

## Testing

Add unit and scenario coverage for sparse overrides, literal text preservation, template validation, UTF-8 size bounds, capability filtering, recommendation fallback, and guidance recovery after resume.

GitOrigin-RevId: 148b658c2d8490c9d0dc208addbee1be5342a5f5
This commit is contained in:
goodman-oai
2026-11-02 14:06:17 +00:00
committed by copyberry
parent 1e8b536dc7
commit aef7d276a4
39 changed files with 3326 additions and 107 deletions
+7 -1
View File
@@ -4983,7 +4983,13 @@ impl Session {
if next_item.is_none()
&& let Some(recommended_plugins) = recommended_plugin_candidates
.as_deref()
.and_then(RecommendedPluginsInstructions::from_plugins)
.and_then(|plugins| {
RecommendedPluginsInstructions::from_plugins(
plugins,
&ResolvedModelMessages::from_model(&step_context.settings.model_info)
.plugin_recommendations(),
)
})
{
developer_sections.push(recommended_plugins.render_fragment());
}
+1
View File
@@ -1271,6 +1271,7 @@ async fn build_skills_and_plugins(
mcp_tools,
&available_connectors,
&turn_context.config.features,
codex_prompts::ResolvedModelMessages::from_model(&step_context.settings.model_info),
);
let mut explicitly_enabled_connectors = collect_explicit_app_ids(user_input);
explicitly_enabled_connectors.extend(skill_connector_ids);
+9 -3
View File
@@ -342,9 +342,15 @@ impl Session {
));
let plugins_usage_instructions_available =
step_context.mcp.plugins_available() && model_info.include_plugin_usage_instructions;
world_state.add_section(PluginsInstructionsState::new(
plugins_usage_instructions_available,
));
let plugins_state = {
let state = self.state.lock().await;
PluginsInstructionsState::new(
plugins_usage_instructions_available,
model_messages.generic_plugin(),
state.history.raw_items(),
)
};
world_state.add_section(plugins_state);
if turn_context
.config
.features