[codex] Add use_responses_lite 'override' logic (#26487)

## Summary

- add a defaulted `ModelInfo.use_responses_lite` catalog field
- support serializing `reasoning.context` while preserving the existing
effort and summary path
- has not been turned on for any models yet

I've added an override to parallel tools if responses_lite is on. I've
also forced persistent reasoning when using responses_lite. It would be
ideal if we could centralize all the responses_lite plumbing, but I
think this is best for now to keep the plumbing & diffs small.

## Testing

- `cargo test -p codex-protocol
model_info_defaults_availability_nux_to_none_when_omitted`
- `RUST_MIN_STACK=8388608 cargo test -p codex-core
responses_lite_sets_all_turns_context_and_disables_parallel_tool_calls`
- `RUST_MIN_STACK=8388608 cargo test -p codex-core
configured_reasoning_summary_is_sent`
- `cargo check -p codex-core --tests`
- `RUST_MIN_STACK=8388608 cargo clippy -p codex-core --tests` (passes
with pre-existing warnings in `codex-code-mode` and
`codex-core-plugins`)
This commit is contained in:
rka-oai
2026-06-04 18:49:51 -07:00
committed by GitHub
Unverified
parent ecae412740
commit e0096db6dc
17 changed files with 104 additions and 1 deletions
@@ -52,6 +52,7 @@ fn preset_to_info(preset: &ModelPreset, priority: i32) -> ModelInfo {
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
+10
View File
@@ -110,12 +110,22 @@ pub enum ResponseEvent {
ModelsEtag(String),
}
#[derive(Debug, Serialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ReasoningContext {
Auto,
CurrentTurn,
AllTurns,
}
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct Reasoning {
#[serde(skip_serializing_if = "Option::is_none")]
pub effort: Option<ReasoningEffortConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<ReasoningSummaryConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<ReasoningContext>,
}
#[derive(Debug, Serialize, Default, Clone, PartialEq)]
+1
View File
@@ -30,6 +30,7 @@ pub use crate::common::OpenAiVerbosity;
pub use crate::common::RawMemory;
pub use crate::common::RawMemoryMetadata;
pub use crate::common::Reasoning;
pub use crate::common::ReasoningContext;
pub use crate::common::ResponseCreateWsRequest;
pub use crate::common::ResponseEvent;
pub use crate::common::ResponseStream;
@@ -98,6 +98,7 @@ async fn models_client_hits_models_endpoint() {
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
+8 -1
View File
@@ -44,6 +44,7 @@ use codex_api::RawMemory as ApiRawMemory;
use codex_api::RealtimeCallClient as ApiRealtimeCallClient;
use codex_api::RealtimeSessionConfig as ApiRealtimeSessionConfig;
use codex_api::Reasoning;
use codex_api::ReasoningContext;
use codex_api::RequestTelemetry;
use codex_api::ReqwestTransport;
use codex_api::ResponseCreateWsRequest;
@@ -609,6 +610,7 @@ impl ModelClient {
reasoning: effort.map(|effort| Reasoning {
effort: Some(effort),
summary: None,
context: None,
}),
};
@@ -727,6 +729,11 @@ impl ModelClient {
} 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
@@ -775,7 +782,7 @@ impl ModelClient {
input,
tools,
tool_choice: "auto".to_string(),
parallel_tool_calls: prompt.parallel_tool_calls,
parallel_tool_calls: prompt.parallel_tool_calls && !model_info.use_responses_lite,
reasoning,
store: provider.is_azure_responses_endpoint(),
stream: true,
+1
View File
@@ -231,6 +231,7 @@ fn remote_model_with_auto_review_override(slug: &str, review_model: &str) -> Mod
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: Some(review_model.to_string()),
tool_mode: None,
multi_agent_version: None,
+65
View File
@@ -1872,6 +1872,71 @@ async fn configured_reasoning_summary_is_sent() -> anyhow::Result<()> {
.and_then(|value| value.as_str()),
Some("concise")
);
pretty_assertions::assert_eq!(
request_body
.get("reasoning")
.and_then(|reasoning| reasoning.get("context")),
None
);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn responses_lite_sets_all_turns_context_and_disables_parallel_tool_calls()
-> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
let server = MockServer::start().await;
let resp_mock = mount_sse_once(
&server,
sse(vec![ev_response_created("resp1"), ev_completed("resp1")]),
)
.await;
let mut model_catalog = bundled_models_response()
.unwrap_or_else(|err| panic!("bundled models.json should parse: {err}"));
let model = model_catalog
.models
.iter_mut()
.find(|model| model.slug == "gpt-5.4")
.expect("gpt-5.4 exists in bundled models.json");
model.use_responses_lite = true;
model.supports_parallel_tool_calls = true;
let TestCodex { codex, .. } = test_codex()
.with_model("gpt-5.4")
.with_config(move |config| {
config.model_catalog = Some(model_catalog);
})
.build(&server)
.await?;
codex
.submit(Op::UserInput {
environments: None,
items: vec![UserInput::Text {
text: "hello".into(),
text_elements: Vec::new(),
}],
final_output_json_schema: None,
responsesapi_client_metadata: None,
additional_context: Default::default(),
thread_settings: Default::default(),
})
.await?;
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
let request_body = resp_mock.single_request().body_json();
pretty_assertions::assert_eq!(
request_body
.get("reasoning")
.and_then(|reasoning| reasoning.get("context"))
.and_then(|value| value.as_str()),
Some("all_turns")
);
pretty_assertions::assert_eq!(request_body.get("parallel_tool_calls"), Some(&json!(false)));
Ok(())
}
@@ -112,6 +112,7 @@ fn test_model_info(
input_modalities,
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -932,6 +933,7 @@ async fn model_switch_to_smaller_model_updates_token_context_window() -> Result<
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -370,6 +370,7 @@ fn test_remote_model(slug: &str, priority: i32) -> ModelInfo {
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
+2
View File
@@ -592,6 +592,7 @@ async fn remote_model_friendly_personality_instructions_with_feature() -> anyhow
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -705,6 +706,7 @@ async fn user_turn_personality_remote_model_template_includes_update_message() -
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -478,6 +478,7 @@ async fn remote_models_remote_model_uses_unified_exec() -> Result<()> {
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -730,6 +731,7 @@ async fn remote_models_apply_remote_base_instructions() -> Result<()> {
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -1216,6 +1218,7 @@ fn test_remote_model_with_policy(
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
+1
View File
@@ -1349,6 +1349,7 @@ async fn stdio_image_responses_are_sanitized_for_text_only_model() -> anyhow::Re
input_modalities: vec![InputModality::Text],
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -60,6 +60,7 @@ fn test_model_info(
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
+1
View File
@@ -1355,6 +1355,7 @@ async fn view_image_tool_returns_unsupported_message_for_text_only_model() -> an
input_modalities: vec![InputModality::Text],
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -99,6 +99,7 @@ pub fn model_info_from_slug(slug: &str) -> ModelInfo {
input_modalities: default_input_modalities(),
used_fallback_model_metadata: true, // this is the fallback model metadata
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
+4
View File
@@ -404,6 +404,8 @@ pub struct ModelInfo {
pub used_fallback_model_metadata: bool,
#[serde(default)]
pub supports_search_tool: bool,
#[serde(default)]
pub use_responses_lite: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub auto_review_model_override: Option<String>,
#[serde(
@@ -674,6 +676,7 @@ mod tests {
input_modalities: default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,
@@ -936,6 +939,7 @@ mod tests {
assert!(!model.supports_image_detail_original);
assert_eq!(model.web_search_tool_type, WebSearchToolType::Text);
assert!(!model.supports_search_tool);
assert!(!model.use_responses_lite);
assert_eq!(model.auto_review_model_override, None);
assert_eq!(model.tool_mode, None);
}
+1
View File
@@ -44,6 +44,7 @@ fn model_with_shell_type(shell_type: ConfigShellToolType) -> ModelInfo {
input_modalities: codex_protocol::openai_models::default_input_modalities(),
used_fallback_model_metadata: false,
supports_search_tool: false,
use_responses_lite: false,
auto_review_model_override: None,
tool_mode: None,
multi_agent_version: None,