From ccfca79fdfe603c41411683e2c23e77885449d52 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 17:04:35 +0000 Subject: [PATCH] docs(openrouter-images): document provider routing preferences and add --provider flag Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- skills/openrouter-images/SKILL.md | 23 +++++++++++++++++++ skills/openrouter-images/scripts/edit.ts | 2 +- skills/openrouter-images/scripts/generate.ts | 2 +- skills/openrouter-images/scripts/lib.ts | 24 ++++++++++++++++---- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/skills/openrouter-images/SKILL.md b/skills/openrouter-images/SKILL.md index 52e1c25..96a186a 100644 --- a/skills/openrouter-images/SKILL.md +++ b/skills/openrouter-images/SKILL.md @@ -103,6 +103,7 @@ Both `generate.ts` and `edit.ts` accept the same flags. Only pass parameters the | `--output-compression ` | Compression 0–100 for webp/jpeg | Model default | | `--n ` | Number of images to generate (1–10, provider permitting) | 1 | | `--seed ` | Seed for deterministic generation (where supported) | Random | +| `--provider ` | Provider routing preferences (`only`, `order`, `ignore`, `sort`, `allow_fallbacks`) | None | | `--provider-options ` | Provider-specific passthrough, keyed by `provider_slug` | None | `--provider-options` takes a JSON object keyed by provider slug, using keys from that endpoint's `allowed_passthrough_parameters`: @@ -113,6 +114,28 @@ cd /scripts && npx tsx generate.ts "a dramatic portrait" \ --provider-options '{"black-forest-labs": {"steps": 40, "guidance": 3}}' ``` +### Provider Routing + +When a model has multiple providers, `--provider` controls which endpoints can serve the request via the request's `provider` object: + +| Field | Meaning | +|---|---| +| `only` | Allow only these provider slugs | +| `order` | Try providers in this order | +| `ignore` | Exclude these provider slugs | +| `sort` | Sort eligible endpoints by `price`, `throughput`, or `latency` | +| `allow_fallbacks` | When `false`, stop after the primary provider instead of trying another | + +Use the `provider_slug` values from `discover.ts ` as slugs: + +```bash +cd /scripts && npx tsx generate.ts "a red panda astronaut" \ + --model google/gemini-3.1-flash-image-preview \ + --provider '{"only": ["google-ai-studio"], "allow_fallbacks": false}' +``` + +The response's `X-Provider-Name` header reports which provider served the request. + ## Output Format ### generate.ts diff --git a/skills/openrouter-images/scripts/edit.ts b/skills/openrouter-images/scripts/edit.ts index 23114fc..01a3252 100644 --- a/skills/openrouter-images/scripts/edit.ts +++ b/skills/openrouter-images/scripts/edit.ts @@ -21,7 +21,7 @@ if (!imagePath || !prompt) { " [--aspect-ratio ] [--resolution <512|1K|2K|4K>] [--size ] [--n ]\n" + " [--quality ] [--output-format ]\n" + " [--background ] [--output-compression ] [--seed ]\n" + - " [--provider-options '']\n\n" + + " [--provider ''] [--provider-options '']\n\n" + "Editing sends the source image as an image-to-image reference, so pick a model\n" + "whose input_modalities include \"image\". Run discover.ts to check." ); diff --git a/skills/openrouter-images/scripts/generate.ts b/skills/openrouter-images/scripts/generate.ts index fbcd92a..085213f 100644 --- a/skills/openrouter-images/scripts/generate.ts +++ b/skills/openrouter-images/scripts/generate.ts @@ -18,7 +18,7 @@ if (!prompt) { " [--aspect-ratio ] [--resolution <512|1K|2K|4K>] [--size ] [--n ]\n" + " [--quality ] [--output-format ]\n" + " [--background ] [--output-compression ] [--seed ]\n" + - " [--provider-options '']\n\n" + + " [--provider ''] [--provider-options '']\n\n" + "Run discover.ts first to see which parameters a model accepts." ); process.exit(1); diff --git a/skills/openrouter-images/scripts/lib.ts b/skills/openrouter-images/scripts/lib.ts index d779802..1a2ea86 100644 --- a/skills/openrouter-images/scripts/lib.ts +++ b/skills/openrouter-images/scripts/lib.ts @@ -190,25 +190,39 @@ export function buildImageParams(args: Map): Record = {}; + + const providerRouting = args.get("provider"); + if (typeof providerRouting === "string") { + Object.assign( + provider, + parseJsonObject(providerRouting, "--provider must be a JSON object of routing preferences.") + ); + } + const providerOptions = args.get("provider-options"); if (typeof providerOptions === "string") { - const parsed = parseProviderOptions(providerOptions); - params.provider = { options: parsed }; + provider.options = parseJsonObject( + providerOptions, + "--provider-options must be a JSON object keyed by provider slug." + ); } + if (Object.keys(provider).length > 0) params.provider = provider; + return params; } -function parseProviderOptions(raw: string): Record { +function parseJsonObject(raw: string, errorMessage: string): Record { let parsed: unknown; try { parsed = JSON.parse(raw); } catch { - console.error("Error: --provider-options must be a JSON object keyed by provider slug."); + console.error(`Error: ${errorMessage}`); process.exit(1); } if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) { - console.error("Error: --provider-options must be a JSON object keyed by provider slug."); + console.error(`Error: ${errorMessage}`); process.exit(1); } return parsed as Record;