Use model catalog approval messages (#31312)

## Why

Approval guidance is currently assembled entirely by the client. Model
Messages V2 needs model catalogs to provide model-specific `on_request`
guidance for both user-reviewed and auto-reviewed approval flows while
retaining the existing generated prompt as a compatibility fallback.

## What changed

- add nullable `on_request` and `on_request_auto_review` catalog
messages
- select the message matching the active approvals reviewer for
`on_request` policies
- replace the complete legacy approval section when the selected catalog
value exists, including support for an empty string that suppresses the
section
- retain legacy rendering when the object or selected key is absent, and
for non-`on_request` policies
- preserve approval messages when base-instruction or personality
overrides clear instruction templates
- refresh permissions instructions when the active model changes
- pass catalog messages through initial and incremental permissions
construction

## Relationship to reviewer persistence

PR #31309 independently persists the approvals reviewer in turn context
and refreshes permissions when that reviewer changes. This PR is based
directly on `main` and does not duplicate that rollout migration; once
both land, reviewer switches will also select and append the new catalog
variant.

## Testing

- `just test -p codex-protocol`
- `just test -p codex-prompts`
- `just test -p codex-models-manager`
- `just test -p codex-core permissions_messages`
This commit is contained in:
Dylan Hurd authored and GitHub committed 2026-07-07 10:52:38 -07:00
1 parent 1345c16dd7
commit 358575465c
13 files changed
+419 -20

No files matched your search

+13 -2
View File
@@ -54,14 +54,24 @@ pub fn with_config_overrides(mut model: ModelInfo, config: &ModelsManagerConfig)
if let Some(base_instructions) = &config.base_instructions {
model.base_instructions = base_instructions.clone();
model.model_messages = None;
clear_instruction_messages(&mut model);
} else if !config.personality_enabled {
model.model_messages = None;
clear_instruction_messages(&mut model);
}
model
}
fn clear_instruction_messages(model: &mut ModelInfo) {
if let Some(model_messages) = &mut model.model_messages {
model_messages.instructions_template = None;
model_messages.instructions_variables = None;
if model_messages.approvals.is_none() {
model.model_messages = None;
}
}
}
/// Build a minimal fallback model descriptor for missing/unknown slugs.
pub fn model_info_from_slug(slug: &str) -> ModelInfo {
warn!("Unknown model {slug} is used. This will use fallback model metadata.");
@@ -119,6 +129,7 @@ fn local_personality_messages_for_slug(slug: &str) -> Option<ModelMessages> {
personality_friendly: Some(LOCAL_FRIENDLY_TEMPLATE.to_string()),
personality_pragmatic: Some(LOCAL_PRAGMATIC_TEMPLATE.to_string()),
}),
approvals: None,
}),
_ => None,
}