feat(openrouter): add image generation provider#67668
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d0037e8900
ℹ️ 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".
Greptile SummaryAdds an image generation provider to the bundled OpenRouter extension, routing to Gemini image models via OpenRouter's OpenAI-compatible chat completions endpoint. The implementation closely follows the established provider pattern (
Confidence Score: 4/5Safe to merge after fixing the count/n mismatch; other findings are minor. One clear P1 functional gap: maxCount: 4 is declared but req.count is never forwarded to the API, so multi-image requests silently return one image. The P2 findings (ignored timeoutMs, dead b64_json fallback) do not block correctness. extensions/openrouter/image-generation-provider.ts — the generateImage request body is missing req.count forwarding. Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/openrouter/image-generation-provider.ts
Line: 219-229
Comment:
**`req.count` not forwarded — `maxCount: 4` is unreachable**
`ImageGenerationRequest` carries a `count` field, and the capabilities declare `maxCount: 4`, but the request body never includes `n`. Every `count > 1` request silently returns a single image. Every other provider that declares `maxCount > 1` (fal, openai, vydra, minimax, comfy) passes `req.count` (or `n: req.count ?? 1`) to the downstream API.
```suggestion
body: {
model,
messages: [{ role: "user", content: contentParts }],
modalities: ["image", "text"],
max_tokens: 4096,
...(req.count && req.count > 1 ? { n: req.count } : {}),
...(Object.keys(imageConfig).length > 0 ? { image_config: imageConfig } : {}),
},
```
If OpenRouter's chat-completions image path does not support `n > 1`, set `maxCount: 1` (and remove `maxCount` from the edit capability too) so callers don't assume multiple images are supported.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/openrouter/image-generation-provider.ts
Line: 212-229
Comment:
**`req.timeoutMs` ignored — hardcoded to 90 s**
`ImageGenerationRequest.timeoutMs` is part of the public interface. Five other image-generation providers (fal, openai, vydra, minimax, comfy) forward it to `postJsonRequest`; this one hardcodes 90 000 ms and silently discards the caller value. Consider using `req.timeoutMs ?? 90_000` so callers can apply shorter timeouts (e.g. in tests or when orchestrating parallel requests).
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/openrouter/image-generation-provider.ts
Line: 105-128
Comment:
**`b64_json` fallback checks the wrong object**
Inside the `type === "image_url"` branch, `iu` is `p.image_url ?? p.imageUrl`. The code then checks `iu?.b64_json`, but `b64_json` is not a standard sub-field of an `image_url` object — it would normally appear directly on the part (`p.b64_json`) or in a `b64_json`-typed part. The check at line 119 is effectively unreachable, so the fallback offers no real coverage. If you want to handle raw `b64_json` parts, check `p.b64_json` directly (outside the `type === "image_url"` block).
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat(openrouter): add image generation p..." | Re-trigger Greptile |
d0037e8 to
20ac963
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 20ac96343d
ℹ️ 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".
9116e34 to
f408066
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f408066738
ℹ️ 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".
| model, | ||
| n: count, | ||
| messages: [{ role: "user", content: contentParts }], | ||
| modalities: ["image", "text"], |
There was a problem hiding this comment.
Use image-only modalities for image-only OpenRouter models
The request body always sends modalities: ["image", "text"], but OpenRouter’s image-generation contract distinguishes image+text models from image-only models. For image-only models (for example Flux/Sourceful variants), this payload can be rejected or produce unreliable behavior because text output is requested when the model only supports image output. Since this provider is intended to be model-agnostic, the modalities should be derived from the selected model’s output capabilities (or at least allow an image-only path) instead of being hardcoded.
Useful? React with 👍 / 👎.
|
Codex review: still useful as the likely implementation path for #55066, but not mergeable as-is. The current diff fixed the earlier |
f408066 to
ff6f24e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ff6f24efac
ℹ️ 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".
| resolveProviderHttpRequestConfig({ | ||
| baseUrl: req.cfg?.models?.providers?.openrouter?.baseUrl, | ||
| defaultBaseUrl: OPENROUTER_BASE_URL, |
There was a problem hiding this comment.
Pass configured OpenRouter request overrides to image calls
This request setup only forwards baseUrl and default headers, but never passes req.cfg?.models?.providers?.openrouter?.request into resolveProviderHttpRequestConfig. As a result, image generation ignores configured transport/auth overrides (for example proxy/TLS/private-network/header settings), so environments that depend on provider-level request policy can have normal OpenRouter chat traffic succeed while image_generate fails. Include the sanitized request overrides in this config call to keep behavior consistent with provider request settings.
Useful? React with 👍 / 👎.
|
Landed via squash merge onto main.
Thanks @notamicrodose! |
Summary
/chat/completionsendpoint (modalities: ["image", "text"])image_configmessage.images[].image_url.url) with robust fallbacks for other response structuresChange Type
Scope
Root Cause
message.content), requiring custom parsing logicUser-visible / Behavior Changes
image_generatetoolIssues
Resolves: #55066, #50485, #55277, #55011
Repro + Verification
Environment
openrouter/google/gemini-3-pro-image-previewVerified
imageGenerationProviderIdsand satisfiesrequireGenerateImageimage-generation.runtime.live.test.tspasses for OpenRouter (generate + edit)image_generatetool produces valid images with correct formats and configurationsBuild Note
postJsonRequest,assertOkOrThrowHttpError) consistent with other providers