Always send reasoning parameters in Responses requests (#32206)

## What changed

- Build a reasoning payload for every Responses request and always include `reasoning.encrypted_content`.
- Remove `supports_reasoning_summaries` from model metadata and retire the `model_supports_reasoning_summaries` configuration override.
- Use configured or model-default reasoning effort without a capability gate, including for guardian reviews and tracing.

GitOrigin-RevId: 2c9f194a5d2d4d688a2235299e6358f82ab8e1ea
This commit is contained in:
pakrym-oai
2026-07-10 16:11:58 +00:00
committed by copyberry
parent 2b9c050460
commit d2d00b6632
35 changed files with 25 additions and 143 deletions
@@ -35,7 +35,6 @@ fn preset_to_info(preset: &ModelPreset, priority: i32) -> ModelInfo {
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -186,7 +186,6 @@ async fn list_models_uses_chatgpt_remote_catalog_as_source_of_truth() -> Result<
"priority": 0,
"upgrade": null,
"base_instructions": "base instructions",
"supports_reasoning_summaries": false,
"support_verbosity": false,
"default_verbosity": null,
"apply_patch_tool_type": null,
@@ -209,7 +209,6 @@ mod tests {
"priority": 1,
"upgrade": null,
"base_instructions": "base instructions",
"supports_reasoning_summaries": false,
"support_verbosity": false,
"default_verbosity": null,
"apply_patch_tool_type": null,
@@ -81,7 +81,6 @@ async fn models_client_hits_models_endpoint() {
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
-3
View File
@@ -355,9 +355,6 @@ pub struct ConfigToml {
/// Optional verbosity control for GPT-5 models (Responses API `text.verbosity`).
pub model_verbosity: Option<Verbosity>,
/// Override to force-enable reasoning summaries for the configured model.
pub model_supports_reasoning_summaries: Option<bool>,
/// Optional path to a JSON model catalog (applied on startup only).
/// Per-thread `config` overrides are accepted but do not reapply this (no-ops).
pub model_catalog_json: Option<AbsolutePathBuf>,
-4
View File
@@ -5292,10 +5292,6 @@
"model_reasoning_summary": {
"$ref": "#/definitions/ReasoningSummary"
},
"model_supports_reasoning_summaries": {
"description": "Override to force-enable reasoning summaries for the configured model.",
"type": "boolean"
},
"model_verbosity": {
"allOf": [
{
+17 -25
View File
@@ -804,25 +804,21 @@ impl ModelClient {
model_info: &ModelInfo,
effort: Option<ReasoningEffortConfig>,
summary: ReasoningSummaryConfig,
) -> Option<Reasoning> {
if model_info.supports_reasoning_summaries {
Some(Reasoning {
effort: effort
.or_else(|| model_info.default_reasoning_level.clone())
.map(reasoning_effort_for_request),
summary: if summary == ReasoningSummaryConfig::None {
None
} else {
Some(summary)
},
// When Responses Lite is disabled, omit context so Responses uses the default,
// which is currently `current_turn`.
context: model_info
.use_responses_lite
.then_some(ReasoningContext::AllTurns),
})
} else {
None
) -> Reasoning {
Reasoning {
effort: effort
.or_else(|| model_info.default_reasoning_level.clone())
.map(reasoning_effort_for_request),
summary: if summary == ReasoningSummaryConfig::None {
None
} else {
Some(summary)
},
// When Responses Lite is disabled, omit context so Responses uses the default,
// which is currently `current_turn`.
context: model_info
.use_responses_lite
.then_some(ReasoningContext::AllTurns),
}
}
@@ -871,12 +867,8 @@ impl ModelClient {
.then_some(StreamOptions {
reasoning_summary_delivery: codex_api::ReasoningSummaryDelivery::SequentialCutoff,
});
let reasoning = Self::build_reasoning(model_info, effort, summary);
let include = if reasoning.is_some() {
vec!["reasoning.encrypted_content".to_string()]
} else {
Vec::new()
};
let reasoning = Some(Self::build_reasoning(model_info, effort, summary));
let include = vec!["reasoning.encrypted_content".to_string()];
let verbosity = if model_info.support_verbosity {
self.state.model_verbosity.or(model_info.default_verbosity)
} else {
-1
View File
@@ -262,7 +262,6 @@ fn test_model_info() -> ModelInfo {
"upgrade": null,
"base_instructions": "base instructions",
"model_messages": null,
"supports_reasoning_summaries": false,
"support_verbosity": false,
"default_verbosity": null,
"apply_patch_tool_type": null,
-5
View File
@@ -952,9 +952,6 @@ pub struct Config {
/// using the Responses API. When unset, the model catalog default is used.
pub model_reasoning_summary: Option<ReasoningSummary>,
/// Optional override to force-enable reasoning summaries for the configured model.
pub model_supports_reasoning_summaries: Option<bool>,
/// Optional full model catalog loaded from `model_catalog_json`.
/// When set, this replaces the bundled catalog for the current process.
pub model_catalog: Option<ModelsResponse>,
@@ -1476,7 +1473,6 @@ impl Config {
tool_output_token_limit: self.tool_output_token_limit,
base_instructions: self.base_instructions.clone(),
personality_enabled: self.features.enabled(Feature::Personality),
model_supports_reasoning_summaries: self.model_supports_reasoning_summaries,
model_catalog: self.model_catalog.clone(),
}
}
@@ -3903,7 +3899,6 @@ impl Config {
model_reasoning_effort: cfg.model_reasoning_effort,
plan_mode_reasoning_effort: cfg.plan_mode_reasoning_effort,
model_reasoning_summary: cfg.model_reasoning_summary,
model_supports_reasoning_summaries: cfg.model_supports_reasoning_summaries,
model_catalog,
model_verbosity: cfg.model_verbosity,
chatgpt_base_url: cfg
+4 -8
View File
@@ -720,14 +720,10 @@ async fn run_review_on_session(
&params.spawn_config.to_models_manager_config(),
)
.await;
let guardian_reasoning_effort = if model_info.supports_reasoning_summaries {
params
.reasoning_effort
.clone()
.or_else(|| model_info.default_reasoning_level.clone())
} else {
None
};
let guardian_reasoning_effort = params
.reasoning_effort
.clone()
.or_else(|| model_info.default_reasoning_level.clone());
let mut analytics_result =
GuardianReviewAnalyticsResult::from_session(GuardianReviewSessionAnalyticsParams {
guardian_thread_id: review_session.codex.session.thread_id.to_string(),
+3 -7
View File
@@ -177,13 +177,9 @@ impl TurnContext {
}
pub(crate) fn effective_reasoning_effort(&self) -> Option<ReasoningEffortConfig> {
if self.model_info.supports_reasoning_summaries {
self.reasoning_effort
.clone()
.or_else(|| self.model_info.default_reasoning_level.clone())
} else {
None
}
self.reasoning_effort
.clone()
.or_else(|| self.model_info.default_reasoning_level.clone())
}
pub(crate) fn effective_reasoning_effort_for_tracing(&self) -> String {
-1
View File
@@ -348,7 +348,6 @@ async fn responses_respects_model_info_overrides_from_config() {
config.model = Some("gpt-3.5-turbo".to_string());
config.model_provider_id = provider.name.clone();
config.model_provider = provider.clone();
config.model_supports_reasoning_summaries = Some(true);
config.model_reasoning_summary = Some(ReasoningSummary::Detailed);
let effort = config.model_reasoning_effort.clone();
let summary = config.model_reasoning_summary;
-1
View File
@@ -245,7 +245,6 @@ fn remote_model_with_auto_review_override(slug: &str, review_model: &str) -> Mod
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
-2
View File
@@ -2539,7 +2539,6 @@ async fn user_turn_explicit_reasoning_summary_overrides_model_catalog_default()
.iter_mut()
.find(|model| model.slug == "gpt-5.4")
.expect("gpt-5.4 exists in bundled models.json");
model.supports_reasoning_summaries = true;
model.default_reasoning_summary = ReasoningSummary::Detailed;
let TestCodex {
@@ -2662,7 +2661,6 @@ async fn reasoning_summary_none_overrides_model_catalog_default() -> anyhow::Res
.iter_mut()
.find(|model| model.slug == "gpt-5.4")
.expect("gpt-5.4 exists in bundled models.json");
model.supports_reasoning_summaries = true;
model.default_reasoning_summary = ReasoningSummary::Detailed;
let TestCodex { codex, .. } = test_codex()
@@ -681,8 +681,7 @@ async fn responses_websocket_sends_responses_lite_metadata_per_request() {
.await;
let harness = websocket_harness(&server).await;
let mut normal_model_info = harness.model_info.clone();
normal_model_info.supports_reasoning_summaries = true;
let normal_model_info = harness.model_info.clone();
let mut lite_model_info = normal_model_info.clone();
lite_model_info.use_responses_lite = true;
let mut session = harness.client.new_session();
@@ -98,7 +98,6 @@ fn test_model_info(
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -926,7 +925,6 @@ async fn model_switch_to_smaller_model_updates_token_context_window() -> Result<
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -368,7 +368,6 @@ fn test_remote_model(slug: &str, priority: i32) -> ModelInfo {
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -27,7 +27,6 @@ const PROACTIVE_TEXT: &str = "Proactive multi-agent delegation is active.";
const CUSTOM_MODE_HINT_TEXT: &str = "Use the configured delegation policy.";
fn add_ultra_reasoning(model_info: &mut ModelInfo) {
model_info.supports_reasoning_summaries = true;
model_info
.supported_reasoning_levels
.push(ReasoningEffortPreset {
-2
View File
@@ -566,7 +566,6 @@ async fn remote_model_friendly_personality_instructions_with_feature() -> anyhow
approvals: None,
}),
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -683,7 +682,6 @@ async fn user_turn_personality_remote_model_template_includes_update_message() -
approvals: None,
}),
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -346,7 +346,6 @@ async fn remote_models_long_model_slug_is_sent_with_custom_reasoning() -> Result
description: custom_reasoning_effort.to_string(),
},
];
remote_model.supports_reasoning_summaries = true;
remote_model.default_reasoning_summary = ReasoningSummary::Detailed;
mount_models_once(
&server,
@@ -491,7 +490,6 @@ async fn remote_models_remote_model_uses_unified_exec() -> Result<()> {
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -745,7 +743,6 @@ async fn remote_models_apply_remote_base_instructions() -> Result<()> {
base_instructions: remote_base.to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -1272,7 +1269,6 @@ fn test_remote_model_with_policy(
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
-1
View File
@@ -1653,7 +1653,6 @@ async fn stdio_image_responses_are_sanitized_for_text_only_model() -> anyhow::Re
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -72,7 +72,6 @@ fn test_model_info(
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
-1
View File
@@ -1375,7 +1375,6 @@ async fn view_image_tool_returns_unsupported_message_for_text_only_model() -> an
base_instructions: "base instructions".to_string(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
-1
View File
@@ -421,7 +421,6 @@ mod tests {
"priority": 0,
"upgrade": null,
"base_instructions": "base instructions",
"supports_reasoning_summaries": false,
"support_verbosity": false,
"default_verbosity": null,
"apply_patch_tool_type": null,
File diff suppressed because one or more lines are too long
-1
View File
@@ -7,6 +7,5 @@ pub struct ModelsManagerConfig {
pub tool_output_token_limit: Option<usize>,
pub base_instructions: Option<String>,
pub personality_enabled: bool,
pub model_supports_reasoning_summaries: Option<bool>,
pub model_catalog: Option<ModelsResponse>,
}
@@ -51,7 +51,6 @@ fn remote_model_with_visibility(
"priority": priority,
"upgrade": null,
"base_instructions": "base instructions",
"supports_reasoning_summaries": false,
"support_verbosity": false,
"default_verbosity": null,
"apply_patch_tool_type": null,
@@ -21,11 +21,6 @@ const LOCAL_PRAGMATIC_TEMPLATE: &str = "You are a deeply pragmatic, effective so
const PERSONALITY_PLACEHOLDER: &str = "{{ personality }}";
pub fn with_config_overrides(mut model: ModelInfo, config: &ModelsManagerConfig) -> ModelInfo {
if let Some(supports_reasoning_summaries) = config.model_supports_reasoning_summaries
&& supports_reasoning_summaries
{
model.supports_reasoning_summaries = true;
}
if let Some(context_window) = config.model_context_window {
model.context_window = Some(
model
@@ -93,7 +88,6 @@ pub fn model_info_from_slug(slug: &str) -> ModelInfo {
base_instructions: BASE_INSTRUCTIONS.to_string(),
model_messages: local_personality_messages_for_slug(slug),
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -3,48 +3,6 @@ use crate::ModelsManagerConfig;
use codex_protocol::openai_models::ApprovalMessages;
use pretty_assertions::assert_eq;
#[test]
fn reasoning_summaries_override_true_enables_support() {
let model = model_info_from_slug("unknown-model");
let config = ModelsManagerConfig {
model_supports_reasoning_summaries: Some(true),
..Default::default()
};
let updated = with_config_overrides(model.clone(), &config);
let mut expected = model;
expected.supports_reasoning_summaries = true;
assert_eq!(updated, expected);
}
#[test]
fn reasoning_summaries_override_false_does_not_disable_support() {
let mut model = model_info_from_slug("unknown-model");
model.supports_reasoning_summaries = true;
let config = ModelsManagerConfig {
model_supports_reasoning_summaries: Some(false),
..Default::default()
};
let updated = with_config_overrides(model.clone(), &config);
assert_eq!(updated, model);
}
#[test]
fn reasoning_summaries_override_false_is_noop_when_model_is_false() {
let model = model_info_from_slug("unknown-model");
let config = ModelsManagerConfig {
model_supports_reasoning_summaries: Some(false),
..Default::default()
};
let updated = with_config_overrides(model.clone(), &config);
assert_eq!(updated, model);
}
#[test]
fn base_instruction_override_preserves_catalog_approval_messages() {
let mut model = model_info_from_slug("unknown-model");
-3
View File
@@ -375,7 +375,6 @@ pub struct ModelInfo {
pub model_messages: Option<ModelMessages>,
#[serde(default)]
pub include_skills_usage_instructions: bool,
pub supports_reasoning_summaries: bool,
#[serde(default)]
pub default_reasoning_summary: ReasoningSummary,
pub support_verbosity: bool,
@@ -678,7 +677,6 @@ mod tests {
base_instructions: "base".to_string(),
model_messages: spec,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: ReasoningSummary::Auto,
support_verbosity: false,
default_verbosity: None,
@@ -981,7 +979,6 @@ mod tests {
"upgrade": null,
"base_instructions": "base",
"model_messages": null,
"supports_reasoning_summaries": false,
"default_reasoning_summary": "auto",
"support_verbosity": false,
"default_verbosity": null,
@@ -260,7 +260,6 @@ fn new_config(model: Option<String>, arg0_paths: Arg0DispatchPaths) -> anyhow::R
model_reasoning_effort: None,
plan_mode_reasoning_effort: None,
model_reasoning_summary: None,
model_supports_reasoning_summaries: None,
model_catalog: None,
model_verbosity: None,
chatgpt_base_url: "https://chatgpt.com/backend-api/".to_string(),
-1
View File
@@ -20,7 +20,6 @@ fn model_info() -> ModelInfo {
"upgrade": null,
"base_instructions": "base",
"model_messages": null,
"supports_reasoning_summaries": false,
"default_reasoning_summary": "auto",
"support_verbosity": false,
"default_verbosity": null,
-1
View File
@@ -28,7 +28,6 @@ fn model_with_shell_type(shell_type: ConfigShellToolType) -> ModelInfo {
base_instructions: String::new(),
model_messages: None,
include_skills_usage_instructions: false,
supports_reasoning_summaries: false,
default_reasoning_summary: Default::default(),
support_verbosity: false,
default_verbosity: None,
@@ -276,7 +276,6 @@ fn test_model_info(slug: &str, priority: i32, supports_fast_mode: bool) -> Model
"availability_nux": null,
"upgrade": null,
"base_instructions": "base instructions",
"supports_reasoning_summaries": false,
"default_reasoning_summary": "none",
"support_verbosity": false,
"default_verbosity": null,
-1
View File
@@ -2320,7 +2320,6 @@ fn reasoning_summary_block_returns_reasoning_cell_when_feature_disabled() {
async fn reasoning_summary_block_respects_config_overrides() {
let mut config = test_config().await;
config.model = Some("gpt-3.5-turbo".to_string());
config.model_supports_reasoning_summaries = Some(true);
let cell = new_reasoning_summary_block(
vec!["**High level reasoning**\n\nDetailed reasoning goes here.".to_string()],
&test_cwd(),