Skip to content

fix: complete Responses image generation calls with results#596

Open
SantaDiegoKairos wants to merge 2 commits into
justlovemaki:mainfrom
SantaDiegoKairos:fix-image-generation-completed-status
Open

fix: complete Responses image generation calls with results#596
SantaDiegoKairos wants to merge 2 commits into
justlovemaki:mainfrom
SantaDiegoKairos:fix-image-generation-completed-status

Conversation

@SantaDiegoKairos
Copy link
Copy Markdown
Contributor

Summary

Normalize OpenAI Responses image_generation_call items that already contain a final result so they are returned with status: "completed" instead of preserving an upstream/intermediate status: "generating".

Why

Some Responses image generation flows can produce a completed response and a valid base64 PNG in image_generation_call.result, while the output item still has status: "generating".

That shape is confusing for strict Responses clients: the image payload is present, but the item still looks unfinished. In practice this can lead clients to treat the image result as blank or still pending.

The affected shapes are:

  • non-stream response.output[]
  • stream response.output_item.done.item
  • stream response.completed.response.output[]

The fix is intentionally conservative: only image_generation_call items with a non-empty result are marked completed. In-progress image calls without a result are left unchanged.

Validation

node --check src/utils/common.js
npm test -- --runInBand tests/responses-image-status-normalize.test.js

Local result:

PASS tests/responses-image-status-normalize.test.js
4 passed

Also validated against a live OpenAI Responses-compatible route:

  • non-stream image response: top-level response.status=completed, image item has non-empty result, normalized to status=completed
  • stream image response: response.output_item.done.item.status=completed
  • stream completed response: response.completed.output[0].status=completed
  • decoded image payload is a valid PNG

@justlovemaki
Copy link
Copy Markdown
Owner

@codex

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs 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".

@justlovemaki
Copy link
Copy Markdown
Owner

if (item.type === 'image_generation_call' && hasNonEmptyString(item.result))

The judgment is too simplistic and does not cover all scenarios.

@SantaDiegoKairos SantaDiegoKairos force-pushed the fix-image-generation-completed-status branch from 7b6576b to 10c9751 Compare May 15, 2026 17:21
@SantaDiegoKairos
Copy link
Copy Markdown
Contributor Author

SantaDiegoKairos commented May 15, 2026

Thanks, agreed — the previous check was too broad. I updated the branch to make the normalization terminal-context/status-aware instead of inferring completion from result alone.

Now it only marks image_generation_call items as completed for terminal payloads (response.output_item.done, response.completed, or a non-stream response with status=completed), preserves failed/incomplete/cancelled statuses, and leaves non-terminal/progress items unchanged even if a provider includes a result-like value. Added regression coverage for those cases.

@justlovemaki
Copy link
Copy Markdown
Owner

If this situation only occurs in codex, as a special case, it should be modified within the relevant method in codex, rather than being applied globally.

@SantaDiegoKairos
Copy link
Copy Markdown
Contributor Author

Thanks — I re-checked the scope more carefully.

I don’t think this is only a Codex client/UI rendering issue.

In our production deployment we currently have a small local normalizer, so the public HTTP endpoint already returns the corrected shape. With that local fix enabled, image generation works correctly for clients: the image result is present and the terminal image_generation_call item is returned as completed.

To avoid that local fix masking the original behavior, I ran a clean probe that bypasses the final HTTP response normalizer and inspects the raw adapter/converter result.

The same terminal mismatch was observed from two different agent environments:

  1. Codex / Codex App path

Historical session evidence showed:

  • top-level response was completed
  • image_generation_call.result contained a valid non-empty PNG
  • but image_generation_call.status was still generating
  1. Factory AI / Droid environment

A clean direct adapter/converter probe from the Factory AI environment reproduced the same shape, without going through our final normalizer.

Non-stream:

  • response status: completed
  • image item status: generating
  • result: present, non-empty
  • mismatch: yes

Stream:

  • response.output_item.done

    • image item status: generating
    • result: present, non-empty
    • mismatch: yes
  • response.completed

    • image item status: generating
    • result: present, non-empty
    • mismatch: yes

No production files were edited and the container was not restarted during this verification. The probe was only used to inspect the raw result before our local final-response normalization.

So my current understanding is:

  • with our local normalizer: clients receive the expected completed image item;
  • without that normalizer / when bypassing it: a terminal Responses image item can contain a final image result while still reporting status: generating;
  • this is reproducible outside the Codex client as well, from the Factory AI/Droid environment;
  • so it does not look like a Codex client-specific rendering quirk.

It may still be specific to the underlying model / Responses image-generation route we are using, but based on this check it does not appear to be specific to one agent/client.

I also updated the implementation after your earlier feedback. It no longer treats any non-empty result as completed. The current logic only normalizes terminal contexts:

  • response.output_item.done
  • response.completed
  • non-stream response with top-level status: completed

And it preserves explicit non-success terminal statuses:

  • failed
  • incomplete
  • cancelled / canceled
  • error

If you still prefer this to be scoped more narrowly, I can move the normalization closer to the Responses image-generation handling path. I mainly wanted to clarify that the reproduced issue is not limited to the Codex client itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants