feat(media): add OrcaRouter image provider - #6723
Conversation
|
🧪 This PR has changes that need a manual QA pass before merge — please hold off self-merging for now; we'll loop QA in once it's merge-ready (and design/product have signed off, where applicable). |
mrcfps
left a comment
There was a problem hiding this comment.
Thanks @Marc-oss-hub — nice, tightly scoped OrcaRouter media provider addition. The daemon path (env keys, catalog entries, OpenAI-compatible /v1/images/generations renderer with prefix stripping) looks consistent with the existing ImageRouter/OpenAI patterns, and the Settings media section + icon wiring are in good shape.
I found one non-blocking gap that blocks the New Project model picker from actually listing these models, even though the catalog entries land correctly. Details in the inline comment.
🔁 Powered by Looper · runner=reviewer · agent=grok-build · An autonomous AI dev team for your GitHub repos.
| { id: 'orcarouter/openai/gpt-image-2', label: 'openai/gpt-image-2 (OrcaRouter)', hint: 'OrcaRouter · routed GPT Image', provider: 'orcarouter', caps: ['t2i'] }, | ||
| { id: 'orcarouter/google/gemini-2.5-flash-image', label: 'gemini-2.5-flash-image (OrcaRouter)', hint: 'OrcaRouter · Gemini', provider: 'orcarouter', caps: ['t2i'] }, | ||
| { id: 'orcarouter/grok/grok-imagine-image', label: 'grok-imagine-image (OrcaRouter)', hint: 'OrcaRouter · xAI', provider: 'orcarouter', caps: ['t2i'] }, |
There was a problem hiding this comment.
Non-blocking: catalog is registered, but New Project picker will still hide these models
These three entries correctly add provider: 'orcarouter' to IMAGE_MODELS, and Settings will surface the provider because settingsVisible: true + integrated: true is enough for SettingsDialog.
However, the New Project image picker does not use the catalog alone. It goes through supportedModels() in apps/web/src/components/NewProjectPanel.tsx, which hard-filters providers:
image: new Set(['openai', 'codex', 'volcengine', 'grok', 'nanobanana', 'openrouter', 'imagerouter', 'leonardo', 'custom-image', 'aihubmix', 'minimax']),orcarouter is absent, so supportedModels('image', IMAGE_MODELS) drops every OrcaRouter model. That contradicts the PR description (“the new-project model picker lists OrcaRouter image models…”) and is the same gate OpenRouter had to pass (see apps/web/tests/components/NewProjectPanel.test.ts for the existing openrouter regression coverage).
Why it matters: users who configure an OrcaRouter key in Settings still cannot pick the new models from New Project. Daemon/CLI generation may work if the id is known, but the primary UI discovery path claimed in this PR does not.
Suggested fix:
- Add
'orcarouter'to theimageset insupportedModels(). - Extend
apps/web/tests/components/NewProjectPanel.test.tswith a sibling assertion:
expect(models.some((model) => model.provider === 'orcarouter')).toBe(true).
Optional related polish (not blocking): in HomeHero’s brand helper, slash-containing model ids currently fall through to the ImageRouter (IR) badge after the OpenRouter check. Adding an explicit orcarouter branch before the imagerouter || '/' fallback would keep the home badge consistent with the new icon.
🔁 Powered by Looper · runner=reviewer · agent=grok-build · An autonomous AI dev team for your GitHub repos.
|
Thanks @Marc-oss-hub — this is a nice, focused provider addition. We’ve already routed the product/design/QA follow-ups, and the current actionable code feedback is covered in @mrcfps’s comment above, so the next useful step is addressing that picker gap and pushing an update when ready.
|
xxiaoxiong
left a comment
There was a problem hiding this comment.
LGTM. Adds OrcaRouter as a first-class OpenAI-compatible image provider — mirrors the existing imagerouter/openrouter pattern: ENV keys, default base URL,.MEDIA_PROVIDERS row, three routed models (openai/gpt-image-2, google/gemini-2.5-flash-image, grok/grok-imagine-image), an OrcaRouter SVG monogram, modelProviderIcon substring match, and a vitest covering the icon lookup. The render path strips the orcarouter/ catalogue prefix before the wire call and reuses openaiSizeFor / parseOpenAICompatibleJson / bytesFromOpenAICompatibleData — no new HTTP contract.
xxiaoxiong
left a comment
There was a problem hiding this comment.
LGTM — proper OpenAI-compatible image provider addition.
Verified the wiring: orcarouter listed in ENV_KEYS (with both OD_ORCAROUTER_API_KEY and ORCAROUTER_API_KEY fallback, matching the convention of other providers), default base URL https://api.orcarouter.ai/v1, MEDIA_PROVIDERS entry with credentialsRequired, settingsVisible, supportsCustomModel, and a useful customModelPlaceholder. Dispatch hook in generateMedia is placed next to imagerouter. renderOrcaRouterImage properly strips the orcarouter/ catalogue prefix so the wire model name matches OrcaRouter's canonical vendor slug, and openaiSizeFor is called with the bare model name for sizing. Fetch / parse / bytesFrom* helpers are all reused from existing code, no duplication.
|
Thanks @Marc-oss-hub — design is waiting on the current-head visuals @xiaoche-hub requested above. Once you add those screenshots or recording for both surfaces (Settings → Media and the New Project model picker), that should unblock the design pass and keep the rest of the review moving. |
|
Thanks @Marc-oss-hub — one important update from design: please refresh this PR against current Once that updated UI + visuals are in place (alongside the earlier picker feedback from @mrcfps), @xiaoche-hub can take another pass. |






















































Why
I use Open Design for quick image generation loops and recently wanted to route image generation through OrcaRouter, an OpenAI-compatible gateway that exposes 160+ models (OpenAI, Gemini, xAI, and more) behind a single key. Open Design already shipped a named
openrouterprovider, so anorcarouterprovider is a natural addition — the same class of "one API key, many image models" gateway, wired through the same OpenAI-standard/v1/images/generationscontract the daemon already speaks for OpenAI and ImageRouter.The pain being addressed: users who hold an OrcaRouter key currently have no first-class surface in Settings or the model picker. They could work around it by hand-writing a custom OpenAI-compatible endpoint, but that loses the named provider UX (label, docs link, key hint, catalog models) every other integrated gateway gets.
I'm an engineer on the OrcaRouter team. OrcaRouter is a drop-in OpenAI-compatible API gateway —
https://api.orcarouter.ai/v1with ansk-orca-key — that exposes 160+ models through one endpoint. It also runs gateway-level, zero-trust security for AI agents on the same endpoint — screening every prompt/response and governing every tool call on a default-deny basis, with no application code changes.What users will see
https://api.orcarouter.ai/v1, a link to the key page, and a custom-model field.openai/gpt-image-2,google/gemini-2.5-flash-image, andgrok/grok-imagine-image(labeled "(OrcaRouter)") — with the OrcaRouter brand mark.ORCAROUTER_API_KEYenv var (orOD_ORCAROUTER_API_KEY, following the daemon's per-provider naming) lights up image generation through the gateway; the provider note on generated images reportsorcarouter/<wire-model>.The provider renders through the daemon's existing OpenAI-standard Images API path (
POST /v1/images/generations), so it inherits the same size mapping, error surfacing, and output handling as the OpenAI/ImageRouter providers.Surface area
apps/web/src/media/models.ts,apps/web/public/model-icons/orcarouter.svg)OD_ORCAROUTER_API_KEY/ORCAROUTER_API_KEYenv vars (apps/daemon/src/media/config.ts)Screenshots
No UI screenshot attached — the change adds a provider entry in the existing Settings → Media list and model-picker rows; both render through the existing provider/model list components with no new layout.
Bug fix verification
Not a bug fix — feature addition. The render path is anchored by the existing OpenAI-standard contract (verified live against the gateway:
POST /v1/images/generationsreturnsdata[0].b64_json, and the dispatcher wrote a valid PNG through the repo's owngenerateMediapath).Validation
node scripts/verify-media-models.mjs→ OK (web/daemon registries in sync)pnpm --filter @open-design/daemon typecheck→ passpnpm --filter @open-design/web typecheck→ passpnpm guard→ passmedia-adapters(30),media-generate-multi-image,media-generate-prompt-file,memory-media-provider-fallback(7) → passmodelProviderIcon(5),SettingsDialog.media,HomeView.media-options→ passgenerateMedia({ surface: 'image', model: 'orcarouter/openai/gpt-image-2' })with a real key → 907 KB PNG written,providerNote: orcarouter/openai/gpt-image-2 · 1024x1024