mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
Add explicit background control to image generation (#47484)
## What changed Add the boolean `transparent_background` argument to `image_gen.imagegen` for generation and editing. Map `true` to `transparent` and `false` or omission to `opaque`, replacing the previous `auto` background setting. Update tool guidance to request transparency for background removal and cutouts, and to preserve existing transparency during edits unless the user asks to change it. ## Testing Add integration coverage for transparent, opaque, and omitted background arguments across generation, editing, and code-mode generation. Verify that `null`, string, and numeric values return a validation error without dispatching an image request. GitOrigin-RevId: b10ac200a619c72cc1787da41b49d65d0cde05dd
This commit is contained in:
@@ -62,6 +62,7 @@ async fn omitted_references_generate_with_fixed_defaults() {
|
||||
request_for_call_args(
|
||||
&ImagegenArgs {
|
||||
prompt: "paint a moonlit lake".to_string(),
|
||||
transparent_background: false,
|
||||
referenced_image_paths: None,
|
||||
num_last_images_to_include: None,
|
||||
},
|
||||
@@ -72,7 +73,7 @@ async fn omitted_references_generate_with_fixed_defaults() {
|
||||
.expect("generation request should build"),
|
||||
ImageRequest::Generate(ImageGenerationRequest {
|
||||
prompt: "paint a moonlit lake".to_string(),
|
||||
background: Some(ImageBackground::Auto),
|
||||
background: Some(ImageBackground::Opaque),
|
||||
model: "gpt-image-2".to_string(),
|
||||
n: None,
|
||||
quality: Some(ImageQuality::Auto),
|
||||
@@ -151,6 +152,7 @@ async fn recent_image_fallback_selects_newest_images_in_chronological_order() {
|
||||
request_for_call_args(
|
||||
&ImagegenArgs {
|
||||
prompt: "change the lighting".to_string(),
|
||||
transparent_background: false,
|
||||
referenced_image_paths: None,
|
||||
num_last_images_to_include: Some(5),
|
||||
},
|
||||
@@ -172,6 +174,7 @@ async fn recent_image_fallback_rejects_file_backed_image_in_requested_window() {
|
||||
let error = request_for_call_args(
|
||||
&ImagegenArgs {
|
||||
prompt: "change the lighting".to_string(),
|
||||
transparent_background: false,
|
||||
referenced_image_paths: None,
|
||||
num_last_images_to_include: Some(1),
|
||||
},
|
||||
@@ -208,6 +211,7 @@ async fn recent_image_fallback_rejects_file_backed_tool_output_in_requested_wind
|
||||
let error = request_for_call_args(
|
||||
&ImagegenArgs {
|
||||
prompt: "change the lighting".to_string(),
|
||||
transparent_background: false,
|
||||
referenced_image_paths: None,
|
||||
num_last_images_to_include: Some(1),
|
||||
},
|
||||
@@ -252,6 +256,7 @@ async fn conflicting_image_selectors_return_tool_error() {
|
||||
let error = request_for_call_args(
|
||||
&ImagegenArgs {
|
||||
prompt: "change the lighting".to_string(),
|
||||
transparent_background: false,
|
||||
referenced_image_paths: Some(vec![
|
||||
"/tmp/image.png"
|
||||
.try_into()
|
||||
@@ -276,6 +281,7 @@ async fn too_many_referenced_image_paths_return_tool_error() {
|
||||
let error = request_for_call_args(
|
||||
&ImagegenArgs {
|
||||
prompt: "change the lighting".to_string(),
|
||||
transparent_background: false,
|
||||
referenced_image_paths: Some(
|
||||
(0..6)
|
||||
.map(|index| {
|
||||
@@ -304,6 +310,7 @@ async fn recent_image_fallback_requires_requested_count() {
|
||||
let error = request_for_call_args(
|
||||
&ImagegenArgs {
|
||||
prompt: "change the lighting".to_string(),
|
||||
transparent_background: false,
|
||||
referenced_image_paths: None,
|
||||
num_last_images_to_include: Some(2),
|
||||
},
|
||||
@@ -430,7 +437,7 @@ fn expected_edit_request(prompt: &str, images: &[&str]) -> ImageEditRequest {
|
||||
})
|
||||
.collect(),
|
||||
prompt: prompt.to_string(),
|
||||
background: Some(ImageBackground::Auto),
|
||||
background: Some(ImageBackground::Opaque),
|
||||
model: "gpt-image-2".to_string(),
|
||||
n: None,
|
||||
quality: Some(ImageQuality::Auto),
|
||||
|
||||
@@ -89,6 +89,9 @@ impl ImageGenerationTool {
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct ImagegenArgs {
|
||||
prompt: String,
|
||||
/// Whether the output should have a transparent background. Defaults to false.
|
||||
#[serde(default)]
|
||||
transparent_background: bool,
|
||||
#[schemars(length(max = 5))]
|
||||
referenced_image_paths: Option<Vec<AbsolutePathBuf>>,
|
||||
#[schemars(range(min = 1, max = 5))]
|
||||
@@ -120,7 +123,7 @@ impl<'call> ToolExecutor<ToolCall<'call>> for ImageGenerationTool {
|
||||
ToolName::namespaced(IMAGE_GEN_NAMESPACE, IMAGEGEN_TOOL_NAME)
|
||||
}
|
||||
|
||||
/// Advertises the model contract: a rewritten prompt and optional edit references.
|
||||
/// Advertises a rewritten prompt, background choice, and optional edit references.
|
||||
fn spec(&self) -> ToolSpec {
|
||||
imagegen_tool_spec()
|
||||
}
|
||||
@@ -427,6 +430,11 @@ async fn request_for_call_args(
|
||||
history: &[ResponseItem],
|
||||
environments: &[ToolEnvironment<'_>],
|
||||
) -> Result<ImageRequest, FunctionCallError> {
|
||||
let background = if args.transparent_background {
|
||||
ImageBackground::Transparent
|
||||
} else {
|
||||
ImageBackground::Opaque
|
||||
};
|
||||
let paths = args.referenced_image_paths.as_deref().unwrap_or_default();
|
||||
if paths.len() > MAX_EDIT_IMAGES {
|
||||
return Err(FunctionCallError::RespondToModel(format!(
|
||||
@@ -437,7 +445,7 @@ async fn request_for_call_args(
|
||||
(true, None) => {
|
||||
return Ok(ImageRequest::Generate(ImageGenerationRequest {
|
||||
prompt: args.prompt.clone(),
|
||||
background: Some(ImageBackground::Auto),
|
||||
background: Some(background),
|
||||
model: IMAGE_MODEL.to_string(),
|
||||
n: None,
|
||||
quality: Some(ImageQuality::Auto),
|
||||
@@ -481,7 +489,7 @@ async fn request_for_call_args(
|
||||
Ok(ImageRequest::Edit(ImageEditRequest {
|
||||
images,
|
||||
prompt: args.prompt.clone(),
|
||||
background: Some(ImageBackground::Auto),
|
||||
background: Some(background),
|
||||
model: IMAGE_MODEL.to_string(),
|
||||
n: None,
|
||||
quality: Some(ImageQuality::Auto),
|
||||
|
||||
Reference in New Issue
Block a user