fix(ai): preserve Codex image edit validation

This commit is contained in:
elky
2026-08-13 11:31:17 +08:00
parent ca35e09eaa
commit f3a12c1008
5 changed files with 183 additions and 83 deletions
@@ -1314,21 +1314,19 @@ async fn resolve_local_gemini_image_to_openai_image_candidate_payload_parts(
.as_object_mut()?
.insert("stream".to_string(), Value::Bool(true));
}
provider_request_body = project_openai_image_api_request_body(
&provider_request_body,
&prepared_candidate.mapped_model,
converted.operation,
crate::image_capabilities::openai_image_provider_max_generation_count_for_model(
transport.provider.provider_type.as_str(),
Some(prepared_candidate.mapped_model.as_str()),
),
)?;
if is_codex {
provider_request_body = project_codex_openai_image_api_request_body(
provider_request_body = if is_codex {
project_codex_openai_image_api_request_body(&provider_request_body, converted.operation)?
} else {
project_openai_image_api_request_body(
&provider_request_body,
&prepared_candidate.mapped_model,
converted.operation,
)?;
}
crate::image_capabilities::openai_image_provider_max_generation_count_for_model(
transport.provider.provider_type.as_str(),
Some(prepared_candidate.mapped_model.as_str()),
),
)?
};
let request_path = match converted.operation {
OpenAiImageOperation::Generate => "/v1/images/generations",
OpenAiImageOperation::Edit => "/v1/images/edits",
@@ -1417,38 +1417,20 @@ async fn resolve_openai_chat_to_openai_image_payload_parts(
return Ok(None);
};
if !is_chatgpt_web {
let Some(projected) = project_openai_image_api_request_body(
&provider_request_body,
&prepared_candidate.mapped_model,
operation,
crate::image_capabilities::openai_image_provider_max_generation_count_for_model(
transport.provider.provider_type.as_str(),
Some(prepared_candidate.mapped_model.as_str()),
),
) else {
mark_skipped_local_openai_chat_candidate_with_extra_data(
state,
input,
trace_id,
candidate,
candidate_index,
candidate_id,
"provider_request_body_build_failed",
request_body_build_failure_extra_data(
body_json,
"openai:chat",
provider_api_format,
let projected = if is_codex {
project_codex_openai_image_api_request_body(&provider_request_body, operation)
} else {
project_openai_image_api_request_body(
&provider_request_body,
&prepared_candidate.mapped_model,
operation,
crate::image_capabilities::openai_image_provider_max_generation_count_for_model(
transport.provider.provider_type.as_str(),
Some(prepared_candidate.mapped_model.as_str()),
),
)
.await;
return Ok(None);
};
provider_request_body = projected;
}
if is_codex {
let Some(projected) =
project_codex_openai_image_api_request_body(&provider_request_body, operation)
else {
let Some(projected) = projected else {
mark_skipped_local_openai_chat_candidate_with_extra_data(
state,
input,
@@ -1395,7 +1395,10 @@ async fn resolve_openai_responses_to_openai_image_payload_parts(
return None;
};
let operation = openai_image_operation_from_summary(&image_request_summary)?;
if !is_chatgpt_web {
if is_codex {
provider_request_body =
project_codex_openai_image_api_request_body(&provider_request_body, operation)?;
} else if !is_chatgpt_web {
provider_request_body = project_openai_image_api_request_body(
&provider_request_body,
&prepared_candidate.mapped_model,
@@ -1406,10 +1409,6 @@ async fn resolve_openai_responses_to_openai_image_payload_parts(
),
)?;
}
if is_codex {
provider_request_body =
project_codex_openai_image_api_request_body(&provider_request_body, operation)?;
}
let upstream_url = if is_chatgpt_web {
chatgpt_web_image_internal_url(&transport.endpoint.base_url)
@@ -412,7 +412,8 @@ async fn gateway_converts_gemini_image_sync_to_openai_image_provider_impl() {
authorization: String,
model: String,
prompt: String,
image_url: String,
images: serde_json::Value,
has_legacy_image_field: bool,
request_stream: bool,
body_stream: Option<bool>,
}
@@ -605,12 +606,8 @@ async fn gateway_converts_gemini_image_sync_to_openai_image_provider_impl() {
.and_then(|value| value.as_str())
.unwrap_or_default()
.to_string(),
image_url: body_json
.get("image")
.and_then(|value| value.get("image_url"))
.and_then(|value| value.as_str())
.unwrap_or_default()
.to_string(),
images: body_json.get("images").cloned().unwrap_or_default(),
has_legacy_image_field: body_json.get("image").is_some(),
request_stream: payload
.get("stream")
.and_then(|value| value.as_bool())
@@ -735,9 +732,10 @@ async fn gateway_converts_gemini_image_sync_to_openai_image_provider_impl() {
"Change the background"
);
assert_eq!(
seen_execution_runtime_request.image_url,
"data:image/png;base64,aGVsbG8="
seen_execution_runtime_request.images,
json!([{"image_url": "data:image/png;base64,aGVsbG8="}])
);
assert!(!seen_execution_runtime_request.has_legacy_image_field);
assert!(!seen_execution_runtime_request.request_stream);
assert_eq!(seen_execution_runtime_request.body_stream, None);