Skip to content

Route image edits through referenced file paths#26486

Merged
won-openai merged 6 commits into
mainfrom
imggenext_tool
Jun 8, 2026
Merged

Route image edits through referenced file paths#26486
won-openai merged 6 commits into
mainfrom
imggenext_tool

Conversation

@won-openai

@won-openai won-openai commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Why

Image edits should use the exact images selected by the model instead of inferring edit inputs from conversation history.

What changed

  • Replaced the image tool's action argument with optional referenced_image_paths.
  • Treats omitted or empty references as generation and populated references as editing.
  • Reads referenced absolute image paths and packages them as image data URLs for the edit request.
  • Removed the previous history-selection and image-count heuristics.
  • Updated direct and code-mode tool instructions and calls.
  • Added an app-server integration test covering an attached image routed to the image edit endpoint.

Validation

  • Tested end-to-end on local just codex with copy pasted image, attached image, etc.
  • just test -p codex-image-generation-extension
  • just test -p codex-app-server standalone_image_edit_uses_attached_model_visible_image
  • just fix -p codex-image-generation-extension
  • just bazel-lock-check

@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: 0165dbf6ed

ℹ️ 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 +169 to +170
fn image_url(path: &AbsolutePathBuf) -> Result<ImageUrl, FunctionCallError> {
let bytes = std::fs::read(path).map_err(|error| {

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.

P1 Badge Validate image references before reading model-supplied paths

When a prompt-injected or mistaken model call includes any absolute path here, the tool now reads that path and forwards the decoded image to the image edit backend without checking that the path was one of the local images or generated artifacts exposed in the current conversation. In contexts where the process can read other valid image files on disk, this lets the model exfiltrate those images simply by setting referenced_image_paths; the description-only instruction is not an enforcement boundary. Please allowlist the requested paths against the conversation’s known image paths before calling std::fs::read.

Useful? React with 👍 / 👎.

codex-protocol = { workspace = true }
codex-tools = { workspace = true }
codex-utils-absolute-path = { workspace = true }
codex-utils-image = { workspace = true }

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 Refresh Bazel lock after adding crate dependency

This adds a new Rust dependency edge for codex-image-generation-extension, but the diff only updates Cargo.lock and does not include MODULE.bazel.lock, so Bazel-based builds/checks can see stale cargo metadata. The repo guidance requires running just bazel-lock-update and including the refreshed lockfile whenever Cargo.toml or Cargo.lock changes (AGENTS.md lines 34-35).

Useful? React with 👍 / 👎.

enum ImagegenAction {
Generate,
Edit,
referenced_image_paths: Option<Vec<AbsolutePathBuf>>,

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 Preserve edits for remote image inputs

In app-server/TUI flows where the user input is a UserInput::Image remote/data URL, the model still sees an image but there is no local path it can place in referenced_image_paths; this new argument shape has no way to carry the existing image URL, so those edit requests either turn into generations when the list is omitted/empty or force the user to re-upload. The old selector used ContentItem::InputImage from history, so remote-image edits that were already in the conversation regress.

Useful? React with 👍 / 👎.

Comment thread codex-rs/ext/image-generation/src/tool.rs Outdated
enum ImagegenAction {
Generate,
Edit,
referenced_image_paths: Option<Vec<AbsolutePathBuf>>,

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 Accept relative referenced image paths

When a user attaches an image with a relative path, for example through the CLI path that forwards --image ./foo.png as a raw PathBuf, the prompt can show that same relative path but this field deserializes as AbsolutePathBuf without an AbsolutePathBufGuard, which rejects non-absolute paths before the edit can run. The previous edit path used the already-materialized InputImage from history, so relative local-image edits now fail unless the user happened to provide an absolute path.

Useful? React with 👍 / 👎.

enum ImagegenAction {
Generate,
Edit,
referenced_image_paths: Option<Vec<AbsolutePathBuf>>,

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 Keep legacy imagegen action arguments resumable

Existing rollouts that were interrupted after the model emitted an imagegen call but before the tool output was recorded can still contain the old {"action":"generate"|"edit","prompt":...} arguments; after this schema change, deny_unknown_fields makes those resumed calls fail as soon as action is parsed. The repo’s breaking-change review surface includes “resuming sessions from existing rollouts” (AGENTS.md lines 92-99), so please keep a compatibility path for legacy action calls.

Useful? React with 👍 / 👎.

@sayan-oai sayan-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.

lgtm, get jimmy's review.

@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.

Good after my comment

path.display()
))
})?;
let image = load_for_prompt_bytes(path.as_path(), bytes, PromptImageMode::Original).map_err(

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 still isn’t using the exact image snapshot the model saw. Local images are already converted into ContentItem::InputImage before the model request, but the edit path rereads the file later
So if the file is deleted/replaced/... before the tc, we edit could different bytes

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.

hm ok we can parse through convo history and attach the image snapshot that's in the ContentItem::InputImage i think!

"`num_last_images_to_include` must be between 1 and {MAX_EDIT_IMAGES}"
)));
}
let images = recent_images(history, count);

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.

num_last_images_to_include still can’t identify the exact pathless image the model selected. If the target is the second-most-recent image, count = 2 also sends the unrelated newest image to /image(s)/edit. Can we use stable image refs or indices so only the selected images are sent?

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.

left a comment in code

@won-openai

Copy link
Copy Markdown
Collaborator Author

good to go for now

@won-openai won-openai enabled auto-merge (squash) June 8, 2026 16:37
@won-openai won-openai disabled auto-merge June 8, 2026 16:37
@won-openai won-openai merged commit 123cf62 into main Jun 8, 2026
31 checks passed
@won-openai won-openai deleted the imggenext_tool branch June 8, 2026 21:23
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 8, 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