core: strip image detail from Responses Lite requests (#27246)

## Summary

- Strip image `detail` fields from every Responses Lite request.
- Apply stripping to message images and function/custom tool-output
images.
- Transform only the formatted request copy without mutating stored
history.
- Preserve image URLs byte-for-byte, including HTTP(S) URLs, without
downloading, validating, or resizing them.
- Preserve all image `detail` fields for non-Responses-Lite models.

## Motivation

Responses Lite does not support image `detail` tags, so Codex must omit
them whenever `model_info.use_responses_lite` is enabled. This transport
requirement is independent of the `resize_all_images` feature.

Stored history retains the original detail values. This keeps
request-specific formatting isolated from conversation state and
preserves the information for local image preparation and
non-Responses-Lite requests.


#### [git stack](https://github.com/magus/git-stack-cli)
-  `1` https://github.com/openai/codex/pull/27245
-  `2` https://github.com/openai/codex/pull/27247
- 👉 `3` https://github.com/openai/codex/pull/27246
-  `4` https://github.com/openai/codex/pull/27266
This commit is contained in:
Curtis 'Fjord' Hawthorne
2026-06-10 20:43:03 -07:00
committed by GitHub
parent e614fad02e
commit 4435ff2810
4 changed files with 196 additions and 1 deletions
+85
View File
@@ -3,10 +3,95 @@ use codex_api::ResponsesApiRequest;
use codex_api::TextControls;
use codex_api::create_text_param_for_request;
use codex_protocol::config_types::ServiceTier;
use codex_protocol::models::FunctionCallOutputPayload;
use codex_protocol::models::ImageDetail;
use pretty_assertions::assert_eq;
use super::*;
fn prompt_with_image_outputs() -> Prompt {
Prompt {
input: vec![
ResponseItem::Message {
id: None,
role: "user".to_string(),
content: vec![ContentItem::InputImage {
image_url: "https://example.com/image.png".to_string(),
detail: Some(ImageDetail::Original),
}],
phase: None,
},
ResponseItem::FunctionCallOutput {
call_id: "function-call".to_string(),
output: FunctionCallOutputPayload::from_content_items(vec![
FunctionCallOutputContentItem::InputImage {
image_url: "data:image/png;base64,function".to_string(),
detail: Some(ImageDetail::High),
},
]),
},
ResponseItem::CustomToolCallOutput {
call_id: "custom-call".to_string(),
name: None,
output: FunctionCallOutputPayload::from_content_items(vec![
FunctionCallOutputContentItem::InputImage {
image_url: "data:image/png;base64,custom".to_string(),
detail: Some(ImageDetail::Auto),
},
]),
},
],
..Default::default()
}
}
#[test]
fn responses_lite_request_copies_strip_image_details() {
let prompt = prompt_with_image_outputs();
let original = prompt.input.clone();
let stripped = prompt.get_formatted_input_for_request(/*use_responses_lite*/ true);
assert_eq!(
stripped,
vec![
ResponseItem::Message {
id: None,
role: "user".to_string(),
content: vec![ContentItem::InputImage {
image_url: "https://example.com/image.png".to_string(),
detail: None,
}],
phase: None,
},
ResponseItem::FunctionCallOutput {
call_id: "function-call".to_string(),
output: FunctionCallOutputPayload::from_content_items(vec![
FunctionCallOutputContentItem::InputImage {
image_url: "data:image/png;base64,function".to_string(),
detail: None,
},
]),
},
ResponseItem::CustomToolCallOutput {
call_id: "custom-call".to_string(),
name: None,
output: FunctionCallOutputPayload::from_content_items(vec![
FunctionCallOutputContentItem::InputImage {
image_url: "data:image/png;base64,custom".to_string(),
detail: None,
},
]),
},
]
);
assert_eq!(prompt.input, original);
assert_eq!(
prompt.get_formatted_input_for_request(/*use_responses_lite*/ false),
original
);
}
#[test]
fn serializes_text_verbosity_when_set() {
let input: Vec<ResponseItem> = vec![];