Skip to content

Route extension image generation through the native image completion pipeline#24972

Merged
won-openai merged 5 commits into
mainfrom
imagegenUX
May 29, 2026
Merged

Route extension image generation through the native image completion pipeline#24972
won-openai merged 5 commits into
mainfrom
imagegenUX

Conversation

@won-openai

@won-openai won-openai commented May 28, 2026

Copy link
Copy Markdown
Collaborator

Why

The standalone image_gen.imagegen extension should behave like native image generation for artifact persistence and UI completion, while returning its save-location guidance as part of the tool result instead of injecting a developer message.

What Changed

  • Added an image-generation completion hook for extension tools so core can persist generated images and emit the existing ImageGeneration lifecycle events.
  • Reused core image artifact persistence for extension output and removed extension-local save-path/file-writing logic.
  • Split shared image persistence from built-in finalization so native image generation keeps its existing developer-message instruction behavior.
  • Returned the generated image save-location instruction through the extension FunctionCallOutput, alongside the generated image input for model follow-up.
  • Preserved the existing image-generation event shape for current UI and replay compatibility.
  • Avoided cloning the full generated-image base64 payload when emitting the in-progress image item.
  • Removed dependencies no longer needed after moving persistence out of the extension crate.

Fast Follow

  • Adjust the existing Extension API and add a general TurnItem finalization path for re-usability of code

Validation

  • Ran just fmt.
  • Ran just bazel-lock-update.
  • Ran just bazel-lock-check.
  • Ran just test -p codex-tools -p codex-extension-api -p codex-image-generation-extension.
  • Ran just test -p codex-core image_generation_publication_is_finalized_by_core.
  • Ran just test -p codex-core handle_output_item_done_records_image_save_history_message.
  • Ran just fix -p codex-tools -p codex-extension-api -p codex-core -p codex-image-generation-extension.

@won-openai won-openai requested a review from a team as a code owner May 28, 2026 22:22
@won-openai won-openai marked this pull request as draft May 28, 2026 22:23
@won-openai

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@won-openai won-openai marked this pull request as ready for review May 29, 2026 01:05

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ad8939d49

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 96 to +100
"image generation returned no image data".to_string(),
));
};
let output_hint =
match persist_generated_image(&self.output_dir, &call.call_id, &result).await {
Ok(output_hint) => Some(output_hint),
Err(err) => {
tracing::warn!(
call_id = %call.call_id,
output_dir = %self.output_dir.display(),
"failed to save generated image: {err}"
);
None
}
};
let output_hint = call
.turn_item_emitter

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Emit image generation start before awaiting the backend

For long generate/edit requests, this is the first point where the extension publishes a native image-generation item, but it runs only after backend.generate/edit(...).await has already returned. CoreTurnItemEmitter::image_generation_completed then emits ItemStarted and ItemCompleted back-to-back, so users do not get the native in-progress image-generation UI while the image API call is actually running. Consider emitting the started image item before awaiting the backend and only completing it here.

Useful? React with 👍 / 👎.

})
}

fn image_generation_completed<'a>(

@sayan-oai sayan-oai May 29, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want to reuse the core persistence logic. that is what this does (good), but IMO its a smell that we're defining such imagegen-persistence-specific logic in the generic extension_tool.rs and tool_call.rs.

could we adjust the extension API (as @jif-oai suggested here and i punted 🙃) so an extension can publish an unfinalized item into the existing core TurnItem processing logic? then both hosted ResponseItem and extension TurnItem processing could use the same path.

i imagine the extension could still own the new save-location info in the functioncall output.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I would like something a bit cleaner here...
We can discuss it further on Slack but basically extension-api should be agnostic of those types

@jif-oai jif-oai changed the title Route extension image generation through the native image completion pipeline Finalize extension image generation in core May 29, 2026
@jif-oai jif-oai changed the title Finalize extension image generation in core Route extension image generation through the native image completion pipeline May 29, 2026

@jif-oai jif-oai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very hacky! The follow-up will be very important

Comment on lines +17 to +18
use pretty_assertions::assert_eq;
use tokio as _; // Keep dev-dep for cargo-shear; tests use #[tokio::test].

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wtf? Just drop the dependency then, why keeping this like that?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

codex thought we still used tokio::test and cargo-shear was hallucinating lol it was the other way around, merging after removing this

pub type TurnItemEmissionFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;

/// Future returned when an image-generation extension publishes completed image bytes.
pub type ImageGenerationCompletionFuture<'a> =

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for the record, this also needs to drop in the follow-up

@won-openai won-openai enabled auto-merge (squash) May 29, 2026 17:29
@won-openai won-openai merged commit 10b0399 into main May 29, 2026
31 checks passed
@won-openai won-openai deleted the imagegenUX branch May 29, 2026 17:33
@github-actions github-actions Bot locked and limited conversation to collaborators May 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants