Remove image_generation tools from OpenAI image bridges

This commit is contained in:
fawney19
2026-05-20 00:20:56 +08:00
parent 25c7bb935e
commit f4d0d5904a
2 changed files with 78 additions and 35 deletions

View File

@@ -986,20 +986,15 @@ fn build_openai_image_provider_body_from_openai_chat_body(
} else { } else {
"edit" "edit"
}; };
let mut tool = serde_json::Map::new(); let mut image_options = serde_json::Map::new();
tool.insert( copy_openai_chat_image_option(body_json, &mut image_options, "size");
"type".to_string(), copy_openai_chat_image_option(body_json, &mut image_options, "quality");
Value::String("image_generation".to_string()), copy_openai_chat_image_option(body_json, &mut image_options, "background");
); copy_openai_chat_image_option(body_json, &mut image_options, "output_format");
tool.insert("action".to_string(), Value::String(operation.to_string())); copy_openai_chat_image_option(body_json, &mut image_options, "output_compression");
copy_openai_chat_image_tool_option(body_json, &mut tool, "size"); copy_openai_chat_image_option(body_json, &mut image_options, "moderation");
copy_openai_chat_image_tool_option(body_json, &mut tool, "quality"); copy_openai_chat_image_option(body_json, &mut image_options, "input_fidelity");
copy_openai_chat_image_tool_option(body_json, &mut tool, "background"); copy_openai_chat_image_option(body_json, &mut image_options, "partial_images");
copy_openai_chat_image_tool_option(body_json, &mut tool, "output_format");
copy_openai_chat_image_tool_option(body_json, &mut tool, "output_compression");
copy_openai_chat_image_tool_option(body_json, &mut tool, "moderation");
copy_openai_chat_image_tool_option(body_json, &mut tool, "input_fidelity");
copy_openai_chat_image_tool_option(body_json, &mut tool, "partial_images");
let input = if images.is_empty() { let input = if images.is_empty() {
serde_json::json!([{ serde_json::json!([{
@@ -1032,10 +1027,6 @@ fn build_openai_image_provider_body_from_openai_chat_body(
body.insert("model".to_string(), Value::String(model.to_string())); body.insert("model".to_string(), Value::String(model.to_string()));
} }
body.insert("input".to_string(), input); body.insert("input".to_string(), input);
body.insert(
"tools".to_string(),
Value::Array(vec![Value::Object(tool.clone())]),
);
if upstream_is_stream { if upstream_is_stream {
body.insert("stream".to_string(), Value::Bool(true)); body.insert("stream".to_string(), Value::Bool(true));
} }
@@ -1054,7 +1045,7 @@ fn build_openai_image_provider_body_from_openai_chat_body(
Value::String(operation.to_string()), Value::String(operation.to_string()),
); );
for key in ["output_format", "partial_images", "size", "quality"] { for key in ["output_format", "partial_images", "size", "quality"] {
if let Some(value) = tool.get(key) { if let Some(value) = image_options.get(key) {
summary.insert(key.to_string(), value.clone()); summary.insert(key.to_string(), value.clone());
} }
} }
@@ -1122,13 +1113,13 @@ fn build_chatgpt_web_image_provider_body_from_openai_chat_body(
Some((body, summary)) Some((body, summary))
} }
fn copy_openai_chat_image_tool_option( fn copy_openai_chat_image_option(
body_json: &Value, body_json: &Value,
tool: &mut serde_json::Map<String, Value>, image_options: &mut serde_json::Map<String, Value>,
key: &str, key: &str,
) { ) {
if let Some(value) = body_json.get(key) { if let Some(value) = body_json.get(key) {
tool.insert(key.to_string(), value.clone()); image_options.insert(key.to_string(), value.clone());
} }
} }
@@ -1514,4 +1505,27 @@ mod tests {
assert_eq!(summary["operation"], "edit"); assert_eq!(summary["operation"], "edit");
assert_eq!(summary["output_format"], "webp"); assert_eq!(summary["output_format"], "webp");
} }
#[test]
fn openai_chat_image_bridge_body_does_not_inject_tools() {
let body_json = json!({
"model": "gpt-image-2",
"messages": [
{"role": "user", "content": "Draw a glass city"}
],
"size": "1024x1024",
"output_format": "png"
});
let (provider_body, summary) =
build_openai_image_provider_body_from_openai_chat_body(&body_json, "gpt-image-2", true)
.expect("chat image body should convert");
assert!(provider_body.get("tools").is_none());
assert_eq!(provider_body["model"], "gpt-image-2");
assert_eq!(provider_body["stream"], true);
assert_eq!(provider_body["input"][0]["content"], "Draw a glass city");
assert_eq!(summary["operation"], "generate");
assert_eq!(summary["output_format"], "png");
}
} }

View File

@@ -811,20 +811,10 @@ fn build_openai_image_provider_body_from_openai_responses_body(
) -> Option<(Value, Value)> { ) -> Option<(Value, Value)> {
let object = body_json.as_object()?; let object = body_json.as_object()?;
let input = object.get("input")?.clone(); let input = object.get("input")?.clone();
let mut tool = openai_responses_image_generation_tool(object).unwrap_or_else(|| { let tool = openai_responses_image_generation_tool(object);
serde_json::Map::from_iter([("type".to_string(), json!("image_generation"))])
});
tool.entry("type".to_string())
.or_insert_with(|| json!("image_generation"));
tool.entry("action".to_string())
.or_insert_with(|| json!("generate"));
let mut body = serde_json::Map::new(); let mut body = serde_json::Map::new();
body.insert("input".to_string(), input); body.insert("input".to_string(), input);
body.insert(
"tools".to_string(),
Value::Array(vec![Value::Object(tool.clone())]),
);
if let Some(model) = object if let Some(model) = object
.get("model") .get("model")
.and_then(Value::as_str) .and_then(Value::as_str)
@@ -857,12 +847,14 @@ fn build_openai_image_provider_body_from_openai_responses_body(
let mut summary = serde_json::Map::new(); let mut summary = serde_json::Map::new();
summary.insert( summary.insert(
"operation".to_string(), "operation".to_string(),
tool.get("action") tool.as_ref()
.and_then(|tool| tool.get("action"))
.cloned() .cloned()
.unwrap_or_else(|| json!("generate")), .unwrap_or_else(|| json!("generate")),
); );
for key in ["output_format", "partial_images", "size", "quality"] { for key in ["output_format", "partial_images", "size", "quality"] {
if let Some(value) = tool.get(key).or_else(|| object.get(key)) { let tool_value = tool.as_ref().and_then(|tool| tool.get(key));
if let Some(value) = tool_value.or_else(|| object.get(key)) {
summary.insert(key.to_string(), value.clone()); summary.insert(key.to_string(), value.clone());
} }
} }
@@ -1228,3 +1220,40 @@ async fn build_kiro_openai_responses_payload_parts(
image_request_summary: None, image_request_summary: None,
}) })
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn openai_responses_image_bridge_body_does_not_inject_tools() {
let body_json = json!({
"model": "gpt-image-2",
"input": "Draw a glass city",
"tools": [
{
"type": "image_generation",
"size": "1024x1024",
"output_format": "png"
}
],
"tool_choice": {
"type": "image_generation"
}
});
let (provider_body, summary) = build_openai_image_provider_body_from_openai_responses_body(
&body_json,
"gpt-image-2",
true,
)
.expect("responses image body should convert");
assert!(provider_body.get("tools").is_none());
assert_eq!(provider_body["model"], "gpt-image-2");
assert_eq!(provider_body["input"], "Draw a glass city");
assert_eq!(provider_body["stream"], true);
assert_eq!(summary["operation"], "generate");
assert_eq!(summary["output_format"], "png");
}
}