From 956c6eaa1e6c52ed0a09c43f94992ab32ab8e5a0 Mon Sep 17 00:00:00 2001 From: mattmillerai <7741082+mattmillerai@users.noreply.github.com> Date: Fri, 18 Sep 2026 05:03:49 +0000 Subject: [PATCH] chore: sync Comfy API v2 specification and Comfy Router pages from cloud@b51a526 --- development/comfy-router/models.mdx | 4 + .../models/openai/gpt-image-1-5/code.mdx | 61 +- .../models/openai/gpt-image-1/code.mdx | 61 +- .../openai/gpt-image-2-5-flare/code.mdx | 61 +- .../openai/gpt-image-2-5-sunburst/code.mdx | 61 +- .../models/openai/gpt-image-2/code.mdx | 61 +- .../openrouter/chat-completions/code.mdx | 682 ++++++++++++++++++ docs.json | 6 + router-schemas/openai/gpt-image-1.5.json | 2 +- router-schemas/openai/gpt-image-1.json | 2 +- .../openai/gpt-image-2.5-flare.json | 2 +- .../openai/gpt-image-2.5-sunburst.json | 2 +- router-schemas/openai/gpt-image-2.json | 2 +- .../openrouter/chat-completions.json | 1 + 14 files changed, 868 insertions(+), 140 deletions(-) create mode 100644 development/comfy-router/models/openrouter/chat-completions/code.mdx create mode 100644 router-schemas/openrouter/chat-completions.json diff --git a/development/comfy-router/models.mdx b/development/comfy-router/models.mdx index d77f3f4f5..8fb02cf1e 100644 --- a/development/comfy-router/models.mdx +++ b/development/comfy-router/models.mdx @@ -203,6 +203,10 @@ Every model below is served by the same route, `POST /v2/models/{provider}/{mode - [o3](/development/comfy-router/models/openai/o3/code): `openai/o3` - [o4-mini](/development/comfy-router/models/openai/o4-mini/code): `openai/o4-mini` +## Openrouter + +- [Chat Completions](/development/comfy-router/models/openrouter/chat-completions/code): `openrouter/chat-completions` + ## Pruna - [P Video 2](/development/comfy-router/models/pruna/p-video-2/code): `pruna/p-video-2` diff --git a/development/comfy-router/models/openai/gpt-image-1-5/code.mdx b/development/comfy-router/models/openai/gpt-image-1-5/code.mdx index 4ecf74cda..af89404fd 100644 --- a/development/comfy-router/models/openai/gpt-image-1-5/code.mdx +++ b/development/comfy-router/models/openai/gpt-image-1-5/code.mdx @@ -30,8 +30,8 @@ with Comfy() as client: result = client.models.run( "openai/gpt-image-1.5", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -46,8 +46,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // The SDK automatically creates an idempotency key and reuses it for automatic retries. const { data } = await comfy.models.run("openai/gpt-image-1.5", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -60,7 +60,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1.5 \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" ``` @@ -77,8 +77,8 @@ with Comfy() as client: handle = client.models.submit( "openai/gpt-image-1.5", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -102,8 +102,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // Each submit() call mints its own Idempotency-Key and reuses it for automatic retries. const handle = await comfy.models.submit("openai/gpt-image-1.5", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -126,7 +126,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1.5/requests \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" # 2. Poll until status is COMPLETED, waiting the Retry-After seconds each response names. REQUEST_ID="" @@ -151,8 +151,21 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1.5/requests/$REQUEST_ID \ Possible values: `transparent`, `opaque` + + The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation. +Accepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching. + + + + One image, as either an https URL Router fetches on the caller's behalf or a `data:image/;base64,` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause. +Prefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely. +THE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused. +The example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working. +Each image is capped at 25 MiB and one request's images at 64 MiB in total. + + - The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst) + The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this. @@ -163,10 +176,14 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1.5/requests/$REQUEST_ID \ The number of images to generate (1-10). + + Range: `1` to `10` Compression level for JPEG or WebP (0-100) + + Range: `0` to `100` @@ -176,31 +193,19 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1.5/requests/$REQUEST_ID \ - A text description of the desired image + A text description of the image to generate, or of the edit to make to `image`. - The quality of the generated image + The quality of the generated or edited image Possible values: `low`, `medium`, `high`, `standard`, `hd` - - Response format of image data - - Possible values: `url`, `b64_json` - - Size of the image (e.g., 1024x1024, 1536x1024, auto) - - Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12. - - Possible values: `vivid`, `natural` - - A unique identifier for end-user monitoring @@ -293,8 +298,10 @@ Generated from the schema Router serves at `GET /v2/models/openai/gpt-image-1.5/ ```json { - "n": 1, - "prompt": "a red circle", + "image": [ + "https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png" + ], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024" } diff --git a/development/comfy-router/models/openai/gpt-image-1/code.mdx b/development/comfy-router/models/openai/gpt-image-1/code.mdx index 5ad9b1d07..e83e8a2c5 100644 --- a/development/comfy-router/models/openai/gpt-image-1/code.mdx +++ b/development/comfy-router/models/openai/gpt-image-1/code.mdx @@ -30,8 +30,8 @@ with Comfy() as client: result = client.models.run( "openai/gpt-image-1", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -46,8 +46,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // The SDK automatically creates an idempotency key and reuses it for automatic retries. const { data } = await comfy.models.run("openai/gpt-image-1", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -60,7 +60,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1 \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" ``` @@ -77,8 +77,8 @@ with Comfy() as client: handle = client.models.submit( "openai/gpt-image-1", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -102,8 +102,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // Each submit() call mints its own Idempotency-Key and reuses it for automatic retries. const handle = await comfy.models.submit("openai/gpt-image-1", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -126,7 +126,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1/requests \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" # 2. Poll until status is COMPLETED, waiting the Retry-After seconds each response names. REQUEST_ID="" @@ -151,8 +151,21 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1/requests/$REQUEST_ID \ Possible values: `transparent`, `opaque` + + The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation. +Accepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching. + + + + One image, as either an https URL Router fetches on the caller's behalf or a `data:image/;base64,` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause. +Prefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely. +THE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused. +The example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working. +Each image is capped at 25 MiB and one request's images at 64 MiB in total. + + - The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst) + The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this. @@ -163,10 +176,14 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1/requests/$REQUEST_ID \ The number of images to generate (1-10). + + Range: `1` to `10` Compression level for JPEG or WebP (0-100) + + Range: `0` to `100` @@ -176,31 +193,19 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-1/requests/$REQUEST_ID \ - A text description of the desired image + A text description of the image to generate, or of the edit to make to `image`. - The quality of the generated image + The quality of the generated or edited image Possible values: `low`, `medium`, `high`, `standard`, `hd` - - Response format of image data - - Possible values: `url`, `b64_json` - - Size of the image (e.g., 1024x1024, 1536x1024, auto) - - Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12. - - Possible values: `vivid`, `natural` - - A unique identifier for end-user monitoring @@ -293,8 +298,10 @@ Generated from the schema Router serves at `GET /v2/models/openai/gpt-image-1/op ```json { - "n": 1, - "prompt": "a red circle", + "image": [ + "https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png" + ], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024" } diff --git a/development/comfy-router/models/openai/gpt-image-2-5-flare/code.mdx b/development/comfy-router/models/openai/gpt-image-2-5-flare/code.mdx index 4ed57fc19..6d61851a8 100644 --- a/development/comfy-router/models/openai/gpt-image-2-5-flare/code.mdx +++ b/development/comfy-router/models/openai/gpt-image-2-5-flare/code.mdx @@ -30,8 +30,8 @@ with Comfy() as client: result = client.models.run( "openai/gpt-image-2.5-flare", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -46,8 +46,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // The SDK automatically creates an idempotency key and reuses it for automatic retries. const { data } = await comfy.models.run("openai/gpt-image-2.5-flare", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -60,7 +60,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-flare \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" ``` @@ -77,8 +77,8 @@ with Comfy() as client: handle = client.models.submit( "openai/gpt-image-2.5-flare", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -102,8 +102,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // Each submit() call mints its own Idempotency-Key and reuses it for automatic retries. const handle = await comfy.models.submit("openai/gpt-image-2.5-flare", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -126,7 +126,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-flare/requests \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" # 2. Poll until status is COMPLETED, waiting the Retry-After seconds each response names. REQUEST_ID="" @@ -151,8 +151,21 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-flare/requests/$REQUES Possible values: `transparent`, `opaque` + + The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation. +Accepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching. + + + + One image, as either an https URL Router fetches on the caller's behalf or a `data:image/;base64,` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause. +Prefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely. +THE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused. +The example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working. +Each image is capped at 25 MiB and one request's images at 64 MiB in total. + + - The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst) + The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this. @@ -163,10 +176,14 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-flare/requests/$REQUES The number of images to generate (1-10). + + Range: `1` to `10` Compression level for JPEG or WebP (0-100) + + Range: `0` to `100` @@ -176,31 +193,19 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-flare/requests/$REQUES - A text description of the desired image + A text description of the image to generate, or of the edit to make to `image`. - The quality of the generated image + The quality of the generated or edited image Possible values: `low`, `medium`, `high`, `standard`, `hd` - - Response format of image data - - Possible values: `url`, `b64_json` - - Size of the image (e.g., 1024x1024, 1536x1024, auto) - - Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12. - - Possible values: `vivid`, `natural` - - A unique identifier for end-user monitoring @@ -293,8 +298,10 @@ Generated from the schema Router serves at `GET /v2/models/openai/gpt-image-2.5- ```json { - "n": 1, - "prompt": "a red circle", + "image": [ + "https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png" + ], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024" } diff --git a/development/comfy-router/models/openai/gpt-image-2-5-sunburst/code.mdx b/development/comfy-router/models/openai/gpt-image-2-5-sunburst/code.mdx index 22ca07e49..7576d01f3 100644 --- a/development/comfy-router/models/openai/gpt-image-2-5-sunburst/code.mdx +++ b/development/comfy-router/models/openai/gpt-image-2-5-sunburst/code.mdx @@ -30,8 +30,8 @@ with Comfy() as client: result = client.models.run( "openai/gpt-image-2.5-sunburst", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -46,8 +46,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // The SDK automatically creates an idempotency key and reuses it for automatic retries. const { data } = await comfy.models.run("openai/gpt-image-2.5-sunburst", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -60,7 +60,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-sunburst \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" ``` @@ -77,8 +77,8 @@ with Comfy() as client: handle = client.models.submit( "openai/gpt-image-2.5-sunburst", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -102,8 +102,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // Each submit() call mints its own Idempotency-Key and reuses it for automatic retries. const handle = await comfy.models.submit("openai/gpt-image-2.5-sunburst", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -126,7 +126,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-sunburst/requests \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" # 2. Poll until status is COMPLETED, waiting the Retry-After seconds each response names. REQUEST_ID="" @@ -151,8 +151,21 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-sunburst/requests/$REQ Possible values: `transparent`, `opaque` + + The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation. +Accepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching. + + + + One image, as either an https URL Router fetches on the caller's behalf or a `data:image/;base64,` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause. +Prefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely. +THE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused. +The example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working. +Each image is capped at 25 MiB and one request's images at 64 MiB in total. + + - The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst) + The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this. @@ -163,10 +176,14 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-sunburst/requests/$REQ The number of images to generate (1-10). + + Range: `1` to `10` Compression level for JPEG or WebP (0-100) + + Range: `0` to `100` @@ -176,31 +193,19 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2.5-sunburst/requests/$REQ - A text description of the desired image + A text description of the image to generate, or of the edit to make to `image`. - The quality of the generated image + The quality of the generated or edited image Possible values: `low`, `medium`, `high`, `standard`, `hd` - - Response format of image data - - Possible values: `url`, `b64_json` - - Size of the image (e.g., 1024x1024, 1536x1024, auto) - - Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12. - - Possible values: `vivid`, `natural` - - A unique identifier for end-user monitoring @@ -293,8 +298,10 @@ Generated from the schema Router serves at `GET /v2/models/openai/gpt-image-2.5- ```json { - "n": 1, - "prompt": "a red circle", + "image": [ + "https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png" + ], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024" } diff --git a/development/comfy-router/models/openai/gpt-image-2/code.mdx b/development/comfy-router/models/openai/gpt-image-2/code.mdx index 62c6a5e4e..572fd9739 100644 --- a/development/comfy-router/models/openai/gpt-image-2/code.mdx +++ b/development/comfy-router/models/openai/gpt-image-2/code.mdx @@ -30,8 +30,8 @@ with Comfy() as client: result = client.models.run( "openai/gpt-image-2", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -46,8 +46,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // The SDK automatically creates an idempotency key and reuses it for automatic retries. const { data } = await comfy.models.run("openai/gpt-image-2", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -60,7 +60,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2 \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" ``` @@ -77,8 +77,8 @@ with Comfy() as client: handle = client.models.submit( "openai/gpt-image-2", { - "n": 1, - "prompt": "a red circle", + "image": ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024", }, @@ -102,8 +102,8 @@ import { comfy } from "@comfyorg/sdk"; // Reads COMFY_API_KEY from the environment. // Each submit() call mints its own Idempotency-Key and reuses it for automatic retries. const handle = await comfy.models.submit("openai/gpt-image-2", { - n: 1, - prompt: "a red circle", + image: ["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"], + prompt: "give the rocketship rainbow coloring", quality: "low", size: "1024x1024", }); @@ -126,7 +126,7 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2/requests \ -H "X-API-Key: $COMFY_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ - -d "{\"n\": 1, \"prompt\": \"a red circle\", \"quality\": \"low\", \"size\": \"1024x1024\"}" + -d "{\"image\": [\"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png\"], \"prompt\": \"give the rocketship rainbow coloring\", \"quality\": \"low\", \"size\": \"1024x1024\"}" # 2. Poll until status is COMPLETED, waiting the Retry-After seconds each response names. REQUEST_ID="" @@ -151,8 +151,21 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2/requests/$REQUEST_ID \ Possible values: `transparent`, `opaque` + + The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation. +Accepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching. + + + + One image, as either an https URL Router fetches on the caller's behalf or a `data:image/;base64,` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause. +Prefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely. +THE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused. +The example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working. +Each image is capped at 25 MiB and one request's images at 64 MiB in total. + + - The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst) + The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this. @@ -163,10 +176,14 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2/requests/$REQUEST_ID \ The number of images to generate (1-10). + + Range: `1` to `10` Compression level for JPEG or WebP (0-100) + + Range: `0` to `100` @@ -176,31 +193,19 @@ curl https://api.comfy.org/v2/models/openai/gpt-image-2/requests/$REQUEST_ID \ - A text description of the desired image + A text description of the image to generate, or of the edit to make to `image`. - The quality of the generated image + The quality of the generated or edited image Possible values: `low`, `medium`, `high`, `standard`, `hd` - - Response format of image data - - Possible values: `url`, `b64_json` - - Size of the image (e.g., 1024x1024, 1536x1024, auto) - - Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12. - - Possible values: `vivid`, `natural` - - A unique identifier for end-user monitoring @@ -293,8 +298,10 @@ Generated from the schema Router serves at `GET /v2/models/openai/gpt-image-2/op ```json { - "n": 1, - "prompt": "a red circle", + "image": [ + "https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png" + ], + "prompt": "give the rocketship rainbow coloring", "quality": "low", "size": "1024x1024" } diff --git a/development/comfy-router/models/openrouter/chat-completions/code.mdx b/development/comfy-router/models/openrouter/chat-completions/code.mdx new file mode 100644 index 000000000..465aba361 --- /dev/null +++ b/development/comfy-router/models/openrouter/chat-completions/code.mdx @@ -0,0 +1,682 @@ +--- +title: "Use Chat Completions with Comfy Router" +description: "Call openrouter/chat-completions through Comfy Router: endpoint, request shape and the response Router returns." +sidebarTitle: "Chat Completions" +--- + +{/* GENERATED FILE. Generated from router-schemas/openrouter/chat-completions.json by `pnpm code-pages:gen`. */} + +import RouterCodeFooter from "/snippets/comfy-router/model-code-footer.mdx"; + +API Reference for `openrouter/chat-completions`, served by Comfy Router from Openrouter. + +## Request setup + +Create a key in [your Comfy workspace](https://platform.comfy.org/profile/api-keys) and export it as `COMFY_API_KEY`. For Python, run `pip install comfy-sdk`. For TypeScript, run `npm install @comfyorg/sdk`. cURL uses raw HTTP. + +**Model ID:** `openrouter/chat-completions` + +**Endpoint:** `POST https://api.comfy.org/v2/models/openrouter/chat-completions` + + +This model has no runnable request example. Build the body from the input documentation below, then use it with the [Router quickstart](/development/comfy-router/quickstart). + + +## Schema + +### Input + + + Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. Currently supported for Anthropic Claude models. + + + + Possible values: `5m`, `1h` + + + + Possible values: `ephemeral` + + + + Debug options for inspecting request transformations (streaming only) + + + + If true, includes the transformed upstream request body in a debug chunk at the start of the stream. Only works with streaming mode. + + + + Frequency penalty (-2.0 to 2.0) + + Format: `double` + + + + + + + + Token logit bias adjustments + + + + Return log probabilities + + + + Maximum tokens in completion + + + + Maximum tokens (deprecated, use max_completion_tokens). Note: some providers enforce a minimum of 16. + + + + List of messages for the conversation + + + + Key-value pairs for additional object information (max 16 pairs, 64 char keys, 512 char values) + + + + Output modalities for the response. Supported values are "text", "image", and "audio". + + + + Model to use for completion + + + + Models to use for completion + + + + Whether to enable parallel function calling during tool use. When true, the model may generate multiple tool calls in a single response. + + + + Plugins you want to enable for this request, including their settings. + + + + Presence penalty (-2.0 to 2.0) + + Format: `double` + + + + When multiple model providers are available, optionally indicate your routing preference. + + + + Whether to allow backup providers to serve requests +- true: (default) when the primary provider (or your custom providers in "order") is unavailable, use the next best provider. +- false: use only the primary/custom provider, and return the upstream error if it's unavailable. + + + + Data collection setting. If no available model provider meets the requirement, your request will return an error. +- allow: (default) allow providers which store user data non-transiently and may train on it + +- deny: use only providers which do not collect user data. + + + + Whether to restrict routing to only models that allow text distillation. When true, only models where the author has allowed distillation will be used. + + + + List of provider slugs to ignore. If provided, this list is merged with your account-wide ignored provider settings for this request. + + + + The object specifying the maximum price you want to pay for this request. USD price per million tokens, for prompt and completion. + + + + Price per million prompt tokens + + + + Price per million prompt tokens + + + + Price per million prompt tokens + + + + Price per million prompt tokens + + + + Price per million prompt tokens + + + + List of provider slugs to allow. If provided, this list is merged with your account-wide allowed provider settings for this request. + + + + An ordered list of provider slugs. The router will attempt to use the first provider in the subset of this list that supports your requested model, and fall back to the next if it is unavailable. If no providers are available, the request will fail with an error message. + + + + Preferred maximum latency (in seconds). Can be a number (applies to p50) or an object with percentile-specific cutoffs. Endpoints above the threshold(s) may still be used, but are deprioritized in routing. When using fallback models, this may cause a fallback model to be used instead of the primary model if it meets the threshold. + + + + Preferred minimum throughput (in tokens per second). Can be a number (applies to p50) or an object with percentile-specific cutoffs. Endpoints below the threshold(s) may still be used, but are deprioritized in routing. When using fallback models, this may cause a fallback model to be used instead of the primary model if it meets the threshold. + + + + A list of quantization levels to filter the provider by. + + + + Whether to filter providers to only those that support the parameters you've provided. If this setting is omitted or set to false, then providers will receive only the parameters they support, and ignore the rest. + + + + The sorting strategy to use for this request, if "order" is not specified. When set, no load balancing is performed. + + + + Whether to restrict routing to only ZDR (Zero Data Retention) endpoints. When true, only endpoints that do not retain prompts will be used. + + + + Configuration options for reasoning models + + + + Constrains effort on reasoning for reasoning models + + + + Possible values: `auto`, `concise`, `detailed` + + + + Response format configuration + + + + Any type + + + + Random seed for deterministic outputs + + + + The service tier to use for processing this request. + + + + A unique identifier for grouping related requests (e.g., a conversation or agent workflow) for observability. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters. + + + + Stop sequences (up to 4) + + + + Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`. + + + + Enable streaming response + + + + Streaming configuration options + + + + Deprecated: This field has no effect. Full usage details are always included. + + + + Sampling temperature (0-2) + + Format: `double` + + + + Tool choice configuration + + + + Available tools for function calling + + + + Number of top log probabilities to return (0-20) + + + + Nucleus sampling parameter (0-1) + + Format: `double` + + + + Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations. + + + + + + + + + + + + + + + + + + + + + + + + Unique user identifier + + +Generated from the schema Router serves at `GET /v2/models/openrouter/chat-completions/openapi.json`, the same document it validates a call against before the request reaches the provider. + +### Output + + + List of completion choices + + + + Possible values: `tool_calls`, `stop`, `length`, `content_filter`, `error` + + + + Choice index + + + + Log probabilities for the completion + + + + Log probabilities for content tokens + + + + UTF-8 bytes of the token + + + + Log probability of the token + + Format: `double` + + + + The token + + + + Top alternative tokens with probabilities + + + + + + + + Format: `double` + + + + + + + + Log probabilities for refusal tokens + + + + UTF-8 bytes of the token + + + + Log probability of the token + + Format: `double` + + + + The token + + + + Top alternative tokens with probabilities + + + + + + + + Format: `double` + + + + + + + + Assistant message for requests and responses + + + + Audio output data or reference + + + + Base64 encoded audio data + + + + Audio expiration timestamp + + + + Audio output identifier + + + + Audio transcript + + + + Assistant message content + + + + Generated images from image generation models + + + + + + + + URL or base64-encoded data of the generated image + + + + Optional name for the assistant + + + + Reasoning output + + + + Reasoning details for extended thinking models + + + + Refusal message if content was refused + + + + Tool calls made by the assistant + + + + + + + + Function arguments as JSON string + + + + Function name to call + + + + Tool call identifier + + + + Possible values: `function` + + + + Unix timestamp of creation + + + + Unique completion identifier + + + + Model used for completion + + + + Possible values: `chat.completion` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Format: `double` + + + + Format: `double` + + + + + + + + + + + + Format: `double` + + + + + + + + + + + + + + + + + + + + + + + + Categorical kind of a pipeline stage. Multiple plugins can share a type (e.g. all guardrail-level plugins emit `guardrail`); the `name` field disambiguates which plugin emitted it. + + Possible values: `guardrail`, `plugin`, `server_tools`, `response_healing`, `context_compression` + + + + + + + + + + + + Possible values: `direct`, `auto`, `free`, `latest`, `alias`, `fallback`, `pareto`, `bodybuilder`, `fusion` + + + + + + + + The service tier used by the upstream provider for this request + + + + System fingerprint + + + + Token usage statistics + + + + Number of tokens in the completion + + + + Detailed completion token usage + + + + Cost of the completion + + Format: `double` + + + + Breakdown of upstream inference costs + + + + Format: `double` + + + + Format: `double` + + + + Format: `double` + + + + Whether a request was made using a Bring Your Own Key configuration + + + + Number of tokens in the prompt + + + + Detailed prompt token usage + + + + Total number of tokens + + +## Examples + +### Output + +```json +{ + "choices": [ + { + "finish_reason": "stop", + "index": 0, + "message": {} + } + ], + "created": 1750000000, + "id": "gen-0000000000-examplecompletion", + "model": "anthropic/claude-sonnet-4.5", + "object": "chat.completion", + "system_fingerprint": null, + "usage": { + "completion_tokens": 128, + "cost": 0.00123, + "prompt_tokens": 42, + "total_tokens": 170 + } +} +``` + + + diff --git a/docs.json b/docs.json index 8beffcb6a..8696604be 100644 --- a/docs.json +++ b/docs.json @@ -3403,6 +3403,12 @@ "development/comfy-router/models/openai/o4-mini/code" ] }, + { + "group": "Openrouter", + "pages": [ + "development/comfy-router/models/openrouter/chat-completions/code" + ] + }, { "group": "Pruna", "pages": [ diff --git a/router-schemas/openai/gpt-image-1.5.json b/router-schemas/openai/gpt-image-1.5.json index 53c7d8a78..edf3551f9 100644 --- a/router-schemas/openai/gpt-image-1.5.json +++ b/router-schemas/openai/gpt-image-1.5.json @@ -1 +1 @@ -{"openapi":"3.0.2","info":{"title":"openai/gpt-image-1.5","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-1.5\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"f1af9ad5eaf0"},"paths":{"/v2/models/openai/gpt-image-1.5":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-1.5 synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"n":1,"prompt":"a red circle","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"model":{"description":"The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst)","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the desired image","example":"Draw a rocket in front of a blackhole in deep space","type":"string"},"quality":{"description":"The quality of the generated image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"response_format":{"description":"Response format of image data","enum":["url","b64_json"],"example":"b64_json","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"style":{"deprecated":true,"description":"Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12.","enum":["vivid","natural"],"example":"vivid","type":"string","x-deprecated-reason":"dall-e-3-only; those model ids were retired on 2026-05-12 and no model this operation still admits reads it."},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-1.5","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} +{"openapi":"3.0.2","info":{"title":"openai/gpt-image-1.5","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-1.5\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"8cb014e74a98"},"paths":{"/v2/models/openai/gpt-image-1.5":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-1.5 synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"image":["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"],"prompt":"give the rocketship rainbow coloring","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"image":{"$ref":"#/components/schemas/OpenAIImageRouterSource"},"mask":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"}],"description":"Optional. Marks the region to edit: its fully transparent areas are what the model replaces. Must be a PNG with an alpha channel, under 4 MiB -- the bound routerOpenAIMaskMaxBytes ENFORCES on the resolved bytes, so an oversize mask is refused here by its size rather than relayed from the provider -- and matching the dimensions of the first `image`. Same accepted forms as `image`. Ignored -- and meaningless -- when `image` is absent, because there is nothing to mask: Router strips it from the request rather than forwarding it to the text-to-image operation, which would reject it as an unknown parameter."},"model":{"description":"The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this.","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"maximum":10,"minimum":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"maximum":100,"minimum":0,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the image to generate, or of the edit to make to `image`.","example":"Give the rocketship rainbow coloring","type":"string"},"quality":{"description":"The quality of the generated or edited image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"},"OpenAIImageRouterMedia":{"description":"One image, as either an https URL Router fetches on the caller's behalf or a `data:image/\u003cformat\u003e;base64,\u003cpayload\u003e` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause.\nPrefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely.\nTHE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused.\nThe example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working.\nEach image is capped at 25 MiB and one request's images at 64 MiB in total.","example":"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png","type":"string"},"OpenAIImageRouterSource":{"description":"The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation.\nAccepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching.","oneOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},{"items":{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},"maxItems":16,"minItems":1,"type":"array"}]}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-1.5","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} diff --git a/router-schemas/openai/gpt-image-1.json b/router-schemas/openai/gpt-image-1.json index 76df14df4..74508c43c 100644 --- a/router-schemas/openai/gpt-image-1.json +++ b/router-schemas/openai/gpt-image-1.json @@ -1 +1 @@ -{"openapi":"3.0.2","info":{"title":"openai/gpt-image-1","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-1\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"f1af9ad5eaf0"},"paths":{"/v2/models/openai/gpt-image-1":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-1 synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"n":1,"prompt":"a red circle","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"model":{"description":"The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst)","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the desired image","example":"Draw a rocket in front of a blackhole in deep space","type":"string"},"quality":{"description":"The quality of the generated image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"response_format":{"description":"Response format of image data","enum":["url","b64_json"],"example":"b64_json","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"style":{"deprecated":true,"description":"Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12.","enum":["vivid","natural"],"example":"vivid","type":"string","x-deprecated-reason":"dall-e-3-only; those model ids were retired on 2026-05-12 and no model this operation still admits reads it."},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-1","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} +{"openapi":"3.0.2","info":{"title":"openai/gpt-image-1","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-1\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"8cb014e74a98"},"paths":{"/v2/models/openai/gpt-image-1":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-1 synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"image":["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"],"prompt":"give the rocketship rainbow coloring","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"image":{"$ref":"#/components/schemas/OpenAIImageRouterSource"},"mask":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"}],"description":"Optional. Marks the region to edit: its fully transparent areas are what the model replaces. Must be a PNG with an alpha channel, under 4 MiB -- the bound routerOpenAIMaskMaxBytes ENFORCES on the resolved bytes, so an oversize mask is refused here by its size rather than relayed from the provider -- and matching the dimensions of the first `image`. Same accepted forms as `image`. Ignored -- and meaningless -- when `image` is absent, because there is nothing to mask: Router strips it from the request rather than forwarding it to the text-to-image operation, which would reject it as an unknown parameter."},"model":{"description":"The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this.","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"maximum":10,"minimum":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"maximum":100,"minimum":0,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the image to generate, or of the edit to make to `image`.","example":"Give the rocketship rainbow coloring","type":"string"},"quality":{"description":"The quality of the generated or edited image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"},"OpenAIImageRouterMedia":{"description":"One image, as either an https URL Router fetches on the caller's behalf or a `data:image/\u003cformat\u003e;base64,\u003cpayload\u003e` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause.\nPrefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely.\nTHE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused.\nThe example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working.\nEach image is capped at 25 MiB and one request's images at 64 MiB in total.","example":"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png","type":"string"},"OpenAIImageRouterSource":{"description":"The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation.\nAccepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching.","oneOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},{"items":{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},"maxItems":16,"minItems":1,"type":"array"}]}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-1","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} diff --git a/router-schemas/openai/gpt-image-2.5-flare.json b/router-schemas/openai/gpt-image-2.5-flare.json index 0e97fa448..5b26b02ad 100644 --- a/router-schemas/openai/gpt-image-2.5-flare.json +++ b/router-schemas/openai/gpt-image-2.5-flare.json @@ -1 +1 @@ -{"openapi":"3.0.2","info":{"title":"openai/gpt-image-2.5-flare","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-2.5-flare\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"f1af9ad5eaf0"},"paths":{"/v2/models/openai/gpt-image-2.5-flare":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-2.5-flare synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"n":1,"prompt":"a red circle","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"model":{"description":"The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst)","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the desired image","example":"Draw a rocket in front of a blackhole in deep space","type":"string"},"quality":{"description":"The quality of the generated image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"response_format":{"description":"Response format of image data","enum":["url","b64_json"],"example":"b64_json","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"style":{"deprecated":true,"description":"Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12.","enum":["vivid","natural"],"example":"vivid","type":"string","x-deprecated-reason":"dall-e-3-only; those model ids were retired on 2026-05-12 and no model this operation still admits reads it."},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-2.5-flare","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} +{"openapi":"3.0.2","info":{"title":"openai/gpt-image-2.5-flare","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-2.5-flare\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"8cb014e74a98"},"paths":{"/v2/models/openai/gpt-image-2.5-flare":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-2.5-flare synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"image":["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"],"prompt":"give the rocketship rainbow coloring","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"image":{"$ref":"#/components/schemas/OpenAIImageRouterSource"},"mask":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"}],"description":"Optional. Marks the region to edit: its fully transparent areas are what the model replaces. Must be a PNG with an alpha channel, under 4 MiB -- the bound routerOpenAIMaskMaxBytes ENFORCES on the resolved bytes, so an oversize mask is refused here by its size rather than relayed from the provider -- and matching the dimensions of the first `image`. Same accepted forms as `image`. Ignored -- and meaningless -- when `image` is absent, because there is nothing to mask: Router strips it from the request rather than forwarding it to the text-to-image operation, which would reject it as an unknown parameter."},"model":{"description":"The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this.","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"maximum":10,"minimum":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"maximum":100,"minimum":0,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the image to generate, or of the edit to make to `image`.","example":"Give the rocketship rainbow coloring","type":"string"},"quality":{"description":"The quality of the generated or edited image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"},"OpenAIImageRouterMedia":{"description":"One image, as either an https URL Router fetches on the caller's behalf or a `data:image/\u003cformat\u003e;base64,\u003cpayload\u003e` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause.\nPrefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely.\nTHE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused.\nThe example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working.\nEach image is capped at 25 MiB and one request's images at 64 MiB in total.","example":"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png","type":"string"},"OpenAIImageRouterSource":{"description":"The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation.\nAccepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching.","oneOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},{"items":{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},"maxItems":16,"minItems":1,"type":"array"}]}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-2.5-flare","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} diff --git a/router-schemas/openai/gpt-image-2.5-sunburst.json b/router-schemas/openai/gpt-image-2.5-sunburst.json index 43f389cc0..ff8e2618c 100644 --- a/router-schemas/openai/gpt-image-2.5-sunburst.json +++ b/router-schemas/openai/gpt-image-2.5-sunburst.json @@ -1 +1 @@ -{"openapi":"3.0.2","info":{"title":"openai/gpt-image-2.5-sunburst","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-2.5-sunburst\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"f1af9ad5eaf0"},"paths":{"/v2/models/openai/gpt-image-2.5-sunburst":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-2.5-sunburst synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"n":1,"prompt":"a red circle","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"model":{"description":"The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst)","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the desired image","example":"Draw a rocket in front of a blackhole in deep space","type":"string"},"quality":{"description":"The quality of the generated image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"response_format":{"description":"Response format of image data","enum":["url","b64_json"],"example":"b64_json","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"style":{"deprecated":true,"description":"Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12.","enum":["vivid","natural"],"example":"vivid","type":"string","x-deprecated-reason":"dall-e-3-only; those model ids were retired on 2026-05-12 and no model this operation still admits reads it."},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-2.5-sunburst","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} +{"openapi":"3.0.2","info":{"title":"openai/gpt-image-2.5-sunburst","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-2.5-sunburst\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"8cb014e74a98"},"paths":{"/v2/models/openai/gpt-image-2.5-sunburst":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-2.5-sunburst synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"image":["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"],"prompt":"give the rocketship rainbow coloring","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"image":{"$ref":"#/components/schemas/OpenAIImageRouterSource"},"mask":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"}],"description":"Optional. Marks the region to edit: its fully transparent areas are what the model replaces. Must be a PNG with an alpha channel, under 4 MiB -- the bound routerOpenAIMaskMaxBytes ENFORCES on the resolved bytes, so an oversize mask is refused here by its size rather than relayed from the provider -- and matching the dimensions of the first `image`. Same accepted forms as `image`. Ignored -- and meaningless -- when `image` is absent, because there is nothing to mask: Router strips it from the request rather than forwarding it to the text-to-image operation, which would reject it as an unknown parameter."},"model":{"description":"The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this.","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"maximum":10,"minimum":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"maximum":100,"minimum":0,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the image to generate, or of the edit to make to `image`.","example":"Give the rocketship rainbow coloring","type":"string"},"quality":{"description":"The quality of the generated or edited image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"},"OpenAIImageRouterMedia":{"description":"One image, as either an https URL Router fetches on the caller's behalf or a `data:image/\u003cformat\u003e;base64,\u003cpayload\u003e` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause.\nPrefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely.\nTHE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused.\nThe example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working.\nEach image is capped at 25 MiB and one request's images at 64 MiB in total.","example":"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png","type":"string"},"OpenAIImageRouterSource":{"description":"The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation.\nAccepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching.","oneOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},{"items":{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},"maxItems":16,"minItems":1,"type":"array"}]}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-2.5-sunburst","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} diff --git a/router-schemas/openai/gpt-image-2.json b/router-schemas/openai/gpt-image-2.json index 394124262..545a8537b 100644 --- a/router-schemas/openai/gpt-image-2.json +++ b/router-schemas/openai/gpt-image-2.json @@ -1 +1 @@ -{"openapi":"3.0.2","info":{"title":"openai/gpt-image-2","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-2\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"f1af9ad5eaf0"},"paths":{"/v2/models/openai/gpt-image-2":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-2 synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"n":1,"prompt":"a red circle","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"model":{"description":"The model to use for image generation (e.g., gpt-image-1, gpt-image-1.5, gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst)","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the desired image","example":"Draw a rocket in front of a blackhole in deep space","type":"string"},"quality":{"description":"The quality of the generated image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"response_format":{"description":"Response format of image data","enum":["url","b64_json"],"example":"b64_json","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"style":{"deprecated":true,"description":"Style of the image. Unused by the gpt-image models this operation admits; it was a dall-e-3-only parameter and those ids were retired when OpenAI shut them down on 2026-05-12.","enum":["vivid","natural"],"example":"vivid","type":"string","x-deprecated-reason":"dall-e-3-only; those model ids were retired on 2026-05-12 and no model this operation still admits reads it."},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-2","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} +{"openapi":"3.0.2","info":{"title":"openai/gpt-image-2","description":"The request body Comfy Router accepts for the model \"openai/gpt-image-2\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"8cb014e74a98"},"paths":{"/v2/models/openai/gpt-image-2":{"post":{"operationId":"runRouterModel","summary":"Run openai/gpt-image-2 synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"example":{"image":["https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png"],"prompt":"give the rocketship rainbow coloring","quality":"low","size":"1024x1024"},"properties":{"background":{"description":"Background transparency","enum":["transparent","opaque"],"example":"opaque","type":"string"},"image":{"$ref":"#/components/schemas/OpenAIImageRouterSource"},"mask":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"}],"description":"Optional. Marks the region to edit: its fully transparent areas are what the model replaces. Must be a PNG with an alpha channel, under 4 MiB -- the bound routerOpenAIMaskMaxBytes ENFORCES on the resolved bytes, so an oversize mask is refused here by its size rather than relayed from the provider -- and matching the dimensions of the first `image`. Same accepted forms as `image`. Ignored -- and meaningless -- when `image` is absent, because there is nothing to mask: Router strips it from the request rather than forwarding it to the text-to-image operation, which would reject it as an unknown parameter."},"model":{"description":"The gpt-image model to run. Router splices the addressed model id in, so a caller addressing /v2/models/openai/gpt-image-2 does not send this.","example":"gpt-image-2.5-flare","type":"string"},"moderation":{"description":"Content moderation setting","enum":["low","auto"],"example":"auto","type":"string"},"n":{"description":"The number of images to generate (1-10).","example":1,"maximum":10,"minimum":1,"type":"integer"},"output_compression":{"description":"Compression level for JPEG or WebP (0-100)","example":100,"maximum":100,"minimum":0,"type":"integer"},"output_format":{"description":"Format of the output image","enum":["png","webp","jpeg"],"example":"png","type":"string"},"prompt":{"description":"A text description of the image to generate, or of the edit to make to `image`.","example":"Give the rocketship rainbow coloring","type":"string"},"quality":{"description":"The quality of the generated or edited image","enum":["low","medium","high","standard","hd"],"example":"high","type":"string"},"size":{"description":"Size of the image (e.g., 1024x1024, 1536x1024, auto)","example":"1024x1536","type":"string"},"user":{"description":"A unique identifier for end-user monitoring","example":"user-1234","type":"string"}},"required":["prompt"],"type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OpenAIImageGenerationResponse"},{"properties":{"background":{"description":"Whether the generated image's background is opaque or transparent. Populated on the fal-served branch only, which reports `opaque`.","type":"string"},"created":{"description":"Unix timestamp, in seconds, of when the generation completed. Declared `int64` because a present-day epoch value is close enough to 2^31 that an unformatted `integer` generates a 32-bit field in many SDK generators.","format":"int64","type":"integer"},"output_format":{"description":"The encoding of the bytes in `data[].b64_json` (for example `png`). Populated on the fal-served branch; absent on the OpenAI-served one, where the caller's requested `output_format` is authoritative.","type":"string"},"quality":{"description":"The quality tier the generation actually ran at. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"},"size":{"description":"The pixel dimensions the generation actually ran at, as `\u003cwidth\u003ex\u003cheight\u003e`. Populated on the fal-served branch when it can resolve one; absent otherwise.","type":"string"}},"type":"object"}],"description":"Comfy Router output schema for the OpenAI gpt-image models: OpenAI's own image-generation response, forwarded unchanged. The operation is direct-return (`routerresult/classification.go` classifies `openai /images/generations` as ReturnModeDirect with no poll route), so the body a caller receives is this finished document from the one call. That row also raises the read limit to `BinaryResultMaxBytes`, because the images can arrive INLINE and `n` admits up to 10 of them at a `size` and `quality` the operation does not bound.\nThe generated images are in `data`, always INLINE at `data[].b64_json`: these five ids have no `url` response format at all, so `url` is never populated on this surface even though the shared response component declares it. That also means the bytes are durable in the only sense that matters here — they are in the body, not behind a link that expires. `revised_prompt` is the prompt OpenAI rewrote rather than an asset, and it is present on a response whose image never arrived, so it must not be read as one. `usage` is OpenAI's own token accounting — OpenAI's numbers, not the Comfy charge.\n`openai/gpt-image-2` has a SECOND producer for this document. When a request is eligible, Comfy may serve it through fal rather than through OpenAI, synthesising this envelope rather than forwarding one. Both producers answer the same asset leaf — one `data` entry per image, each carrying `b64_json` and never `url` — which is what makes the contract above hold whichever partner ran. The bodies are not byte-identical, though, and this document does not promise they are: the fal-served envelope omits `usage` and populates the top-level `created`, `output_format` and `background` fields (plus `quality` and `size` when it can resolve them), while the OpenAI-served one forwards `usage` through. Branch on the keys a response actually carries rather than on an assumed producer; which partner serves a given request is a Comfy routing decision that can change without notice, and is not part of this contract.","example":{"created":1767225600,"data":[{"b64_json":"PGJhc2U2ND4="}],"usage":{"input_tokens":12,"output_tokens":1056,"total_tokens":1068}}}}}}}}}},"components":{"schemas":{"OpenAIImageGenerationResponse":{"properties":{"data":{"items":{"properties":{"b64_json":{"description":"Base64 encoded image data","type":"string"},"revised_prompt":{"description":"Revised prompt","type":"string"},"url":{"description":"URL of the image","type":"string"}},"type":"object"},"type":"array"},"usage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"output_tokens":{"type":"integer"},"output_tokens_details":{"properties":{"image_tokens":{"type":"integer"},"text_tokens":{"type":"integer"}},"type":"object"},"total_tokens":{"type":"integer"}},"type":"object"}},"type":"object"},"OpenAIImageRouterMedia":{"description":"One image, as either an https URL Router fetches on the caller's behalf or a `data:image/\u003cformat\u003e;base64,\u003cpayload\u003e` URI carrying the bytes inline. Accepted image types are png, webp and jpeg, and that set is ENFORCED at resolve time rather than left to the provider -- an svg, gif, avif or tiff is refused here, naming the image you sent, instead of becoming a partner error two hops from the cause.\nPrefer the URL form. A base64 payload inflates roughly 4/3 and the whole request body is capped at 10 MiB, so the inline form caps out near a 7.5 MB source image; a URL sidesteps that entirely.\nTHE URL MUST RESOLVE WITHOUT YOUR CREDENTIALS. Router fetches it server-side and sends no caller credential with the request, so a Comfy-signed asset URL -- one whose signature is in the query string -- is the supported form. An authenticated endpoint such as `/api/assets/{id}/content` answers Router 401 rather than the image; request that URL yourself and pass the signed URL it redirects to. The fetch is confined to Comfy's own asset buckets rather than the open internet, on every redirect hop as well as the URL you send, so a third-party or redirecting URL is refused.\nThe example below shows the shape only: a real value also carries the signing query parameters, which are deliberately omitted here because a published example lives in the spec forever and a real signature is both a leaked credential and a link that stops working.\nEach image is capped at 25 MiB and one request's images at 64 MiB in total.","example":"https://storage.googleapis.com/comfy-cloud-assets/0199b3f4-1d2e-7a3b-8c4d-5e6f70819234.png","type":"string"},"OpenAIImageRouterSource":{"description":"The source image(s) to edit. PRESENCE OF THIS FIELD SELECTS THE EDIT OPERATION -- omit it entirely for text-to-image generation.\nAccepts one image or an array of them; gpt-image-1 and later take up to 16, which Router enforces from this schema before dispatching.","oneOf":[{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},{"items":{"$ref":"#/components/schemas/OpenAIImageRouterMedia"},"maxItems":16,"minItems":1,"type":"array"}]}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openai/gpt-image-2","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true} diff --git a/router-schemas/openrouter/chat-completions.json b/router-schemas/openrouter/chat-completions.json new file mode 100644 index 000000000..caf5b57da --- /dev/null +++ b/router-schemas/openrouter/chat-completions.json @@ -0,0 +1 @@ +{"openapi":"3.0.2","info":{"title":"openrouter/chat-completions","description":"The request body Comfy Router accepts for the model \"openrouter/chat-completions\", and the response body it returns. The INPUT schema is the same schema the server validates a call against before it reaches the provider, so what is published and what is enforced cannot differ. The OUTPUT schema describes the provider's native result document exactly as Router returns it: Router does not validate, narrow or re-envelope the response, so the output schema is descriptive rather than enforced, and Comfy owns no output shape of its own.","version":"47163e176c0f"},"paths":{"/v2/models/openrouter/chat-completions":{"post":{"operationId":"runRouterModel","summary":"Run openrouter/chat-completions synchronously.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"description":"Chat completion request parameters.\n\n`model` is CALLER-CHOSEN and is not resolved by Comfy Router: the Router model ID `openrouter/chat-completions` names this operation, not a model, and whatever you put in `model` (or in the `models` fallback list) is forwarded to OpenRouter unchanged. Use OpenRouter's own model IDs - `anthropic/claude-sonnet-4.5`, `openai/gpt-5` - which carry characters a `{provider}/{model}` Router ID cannot spell, which is why the operation rather than the model is what Router enumerates. A request with no `model` is rejected with a 400 — and `models` alone does NOT satisfy that: the fallback list is forwarded, but the attribution model is read from `model`, so send `model` and use `models` to say what to fall back to.\n\n`stream` is not available on either ingress. Comfy Router forces it to `false` on the forwarded request and serves the completed JSON document; the `/proxy/` route rejects `stream: true` with a 400.","properties":{"cache_control":{"$ref":"#/components/schemas/OpenRouterAnthropicCacheControlDirective"},"debug":{"$ref":"#/components/schemas/OpenRouterChatDebugOptions"},"frequency_penalty":{"description":"Frequency penalty (-2.0 to 2.0)","format":"double","nullable":true,"type":"number"},"image_config":{"$ref":"#/components/schemas/OpenRouterImageConfig"},"logit_bias":{"additionalProperties":{"format":"double","type":"number"},"description":"Token logit bias adjustments","nullable":true,"type":"object"},"logprobs":{"description":"Return log probabilities","nullable":true,"type":"boolean"},"max_completion_tokens":{"description":"Maximum tokens in completion","nullable":true,"type":"integer"},"max_tokens":{"description":"Maximum tokens (deprecated, use max_completion_tokens). Note: some providers enforce a minimum of 16.","nullable":true,"type":"integer"},"messages":{"description":"List of messages for the conversation","items":{"$ref":"#/components/schemas/OpenRouterChatMessages"},"type":"array"},"metadata":{"additionalProperties":{"type":"string"},"description":"Key-value pairs for additional object information (max 16 pairs, 64 char keys, 512 char values)","type":"object"},"modalities":{"description":"Output modalities for the response. Supported values are \"text\", \"image\", and \"audio\".","items":{"$ref":"#/components/schemas/OpenRouterChatRequestModalitiesItems"},"type":"array"},"model":{"$ref":"#/components/schemas/OpenRouterModelName"},"models":{"$ref":"#/components/schemas/OpenRouterChatModelNames"},"parallel_tool_calls":{"description":"Whether to enable parallel function calling during tool use. When true, the model may generate multiple tool calls in a single response.","nullable":true,"type":"boolean"},"plugins":{"description":"Plugins you want to enable for this request, including their settings.","items":{"$ref":"#/components/schemas/OpenRouterChatRequestPluginsItems"},"type":"array"},"presence_penalty":{"description":"Presence penalty (-2.0 to 2.0)","format":"double","nullable":true,"type":"number"},"provider":{"$ref":"#/components/schemas/OpenRouterProviderPreferences"},"reasoning":{"$ref":"#/components/schemas/OpenRouterChatRequestReasoning"},"response_format":{"$ref":"#/components/schemas/OpenRouterChatRequestResponseFormat"},"route":{"description":"Any type"},"seed":{"description":"Random seed for deterministic outputs","nullable":true,"type":"integer"},"service_tier":{"description":"The service tier to use for processing this request.","oneOf":[{"$ref":"#/components/schemas/OpenRouterChatRequestServiceTier"}]},"session_id":{"description":"A unique identifier for grouping related requests (e.g., a conversation or agent workflow) for observability. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters.","type":"string"},"stop":{"$ref":"#/components/schemas/OpenRouterChatRequestStop"},"stop_server_tools_when":{"$ref":"#/components/schemas/OpenRouterStopServerToolsWhen"},"stream":{"default":false,"description":"Enable streaming response","type":"boolean"},"stream_options":{"$ref":"#/components/schemas/OpenRouterChatStreamOptions"},"temperature":{"description":"Sampling temperature (0-2)","format":"double","nullable":true,"type":"number"},"tool_choice":{"$ref":"#/components/schemas/OpenRouterChatToolChoice"},"tools":{"description":"Available tools for function calling","items":{"$ref":"#/components/schemas/OpenRouterChatFunctionTool"},"type":"array"},"top_logprobs":{"description":"Number of top log probabilities to return (0-20)","nullable":true,"type":"integer"},"top_p":{"description":"Nucleus sampling parameter (0-1)","format":"double","nullable":true,"type":"number"},"trace":{"$ref":"#/components/schemas/OpenRouterTraceConfig"},"user":{"description":"Unique user identifier","type":"string"}},"required":["messages"],"title":"ChatRequest","type":"object"}}}},"responses":{"200":{"description":"OK - the model's native JSON output, returned unchanged; the schema describes the provider's terminal result document as Router returns it.","content":{"application/json":{"schema":{"description":"Chat completion response, forwarded from OpenRouter unchanged. `model` names the model OpenRouter actually ran, which is the caller's `model` unless a `models` fallback list selected another one. `usage.cost` is what Comfy meters the call on.","example":{"choices":[{"finish_reason":"stop","index":0,"message":{}}],"created":1750000000,"id":"gen-0000000000-examplecompletion","model":"anthropic/claude-sonnet-4.5","object":"chat.completion","system_fingerprint":null,"usage":{"completion_tokens":128,"cost":0.00123,"prompt_tokens":42,"total_tokens":170}},"properties":{"choices":{"description":"List of completion choices","items":{"$ref":"#/components/schemas/OpenRouterChatChoice"},"type":"array"},"created":{"description":"Unix timestamp of creation","type":"integer"},"id":{"description":"Unique completion identifier","type":"string"},"model":{"description":"Model used for completion","type":"string"},"object":{"$ref":"#/components/schemas/OpenRouterChatResultObject"},"openrouter_metadata":{"$ref":"#/components/schemas/OpenRouterMetadata"},"service_tier":{"description":"The service tier used by the upstream provider for this request","nullable":true,"type":"string"},"system_fingerprint":{"description":"System fingerprint","nullable":true,"type":"string"},"usage":{"$ref":"#/components/schemas/OpenRouterChatUsage"}},"required":["choices","created","id","model","object","system_fingerprint"],"title":"ChatResult","type":"object"}}}}}}}},"components":{"schemas":{"ImageGenerationServerTool_OpenRouter":{"description":"OpenRouter built-in server tool: generates images from text prompts using an image generation model","properties":{"parameters":{"$ref":"#/components/schemas/OpenRouterImageGenerationServerToolConfig"},"type":{"$ref":"#/components/schemas/OpenRouterImageGenerationServerToolOpenRouterType"}},"required":["type"],"title":"ImageGenerationServerTool_OpenRouter","type":"object"},"OpenRouterAnthropicCacheControlDirective":{"description":"Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. Currently supported for Anthropic Claude models.","properties":{"ttl":{"$ref":"#/components/schemas/OpenRouterAnthropicCacheControlTtl"},"type":{"$ref":"#/components/schemas/OpenRouterAnthropicCacheControlDirectiveType"}},"required":["type"],"title":"AnthropicCacheControlDirective","type":"object"},"OpenRouterAnthropicCacheControlDirectiveType":{"enum":["ephemeral"],"title":"AnthropicCacheControlDirectiveType","type":"string"},"OpenRouterAnthropicCacheControlTtl":{"enum":["5m","1h"],"title":"AnthropicCacheControlTtl","type":"string"},"OpenRouterBigNumberUnion":{"description":"Price per million prompt tokens","title":"BigNumberUnion","type":"string"},"OpenRouterChatAssistantImages":{"description":"Generated images from image generation models","items":{"$ref":"#/components/schemas/OpenRouterChatAssistantImagesItems"},"title":"ChatAssistantImages","type":"array"},"OpenRouterChatAssistantImagesItems":{"properties":{"image_url":{"$ref":"#/components/schemas/OpenRouterChatAssistantImagesItemsImageUrl"}},"required":["image_url"],"title":"ChatAssistantImagesItems","type":"object"},"OpenRouterChatAssistantImagesItemsImageUrl":{"properties":{"url":{"description":"URL or base64-encoded data of the generated image","type":"string"}},"required":["url"],"title":"ChatAssistantImagesItemsImageUrl","type":"object"},"OpenRouterChatAssistantMessage":{"description":"Assistant message for requests and responses","properties":{"audio":{"$ref":"#/components/schemas/OpenRouterChatAudioOutput"},"content":{"$ref":"#/components/schemas/OpenRouterChatMessagesDiscriminatorMappingAssistantContent"},"images":{"$ref":"#/components/schemas/OpenRouterChatAssistantImages"},"name":{"description":"Optional name for the assistant","type":"string"},"reasoning":{"description":"Reasoning output","nullable":true,"type":"string"},"reasoning_details":{"$ref":"#/components/schemas/OpenRouterChatReasoningDetails"},"refusal":{"description":"Refusal message if content was refused","nullable":true,"type":"string"},"tool_calls":{"description":"Tool calls made by the assistant","items":{"$ref":"#/components/schemas/OpenRouterChatToolCall"},"type":"array"}},"title":"ChatAssistantMessage","type":"object"},"OpenRouterChatAudioOutput":{"description":"Audio output data or reference","properties":{"data":{"description":"Base64 encoded audio data","type":"string"},"expires_at":{"description":"Audio expiration timestamp","type":"integer"},"id":{"description":"Audio output identifier","type":"string"},"transcript":{"description":"Audio transcript","type":"string"}},"title":"ChatAudioOutput","type":"object"},"OpenRouterChatChoice":{"description":"Chat completion choice","properties":{"finish_reason":{"$ref":"#/components/schemas/OpenRouterChatFinishReasonEnum"},"index":{"description":"Choice index","type":"integer"},"logprobs":{"$ref":"#/components/schemas/OpenRouterChatTokenLogprobs"},"message":{"$ref":"#/components/schemas/OpenRouterChatAssistantMessage"}},"required":["finish_reason","index","message"],"title":"ChatChoice","type":"object"},"OpenRouterChatContentCacheControl":{"description":"Cache control for the content part","properties":{"ttl":{"$ref":"#/components/schemas/OpenRouterAnthropicCacheControlTtl"},"type":{"$ref":"#/components/schemas/OpenRouterChatContentCacheControlType"}},"required":["type"],"title":"ChatContentCacheControl","type":"object"},"OpenRouterChatContentCacheControlType":{"enum":["ephemeral"],"title":"ChatContentCacheControlType","type":"string"},"OpenRouterChatContentItems":{"description":"Content part for chat completion messages","oneOf":[{"description":"File content part for document processing","properties":{"file":{"$ref":"#/components/schemas/OpenRouterChatContentItemsDiscriminatorMappingFileFile"},"type":{"description":"Discriminator value: file","enum":["file"],"type":"string"}},"required":["type","file"],"type":"object"},{"description":"Image content part for vision models","properties":{"image_url":{"$ref":"#/components/schemas/OpenRouterChatContentItemsDiscriminatorMappingImageUrlImageUrl"},"type":{"description":"Discriminator value: image_url","enum":["image_url"],"type":"string"}},"required":["type","image_url"],"type":"object"},{"description":"Audio input content part. Supported audio formats vary by provider.","properties":{"input_audio":{"$ref":"#/components/schemas/OpenRouterChatContentItemsDiscriminatorMappingInputAudioInputAudio"},"type":{"description":"Discriminator value: input_audio","enum":["input_audio"],"type":"string"}},"required":["type","input_audio"],"type":"object"},{"description":"Video input content part (legacy format - deprecated)","properties":{"type":{"$ref":"#/components/schemas/OpenRouterLegacyChatContentVideoType"},"video_url":{"$ref":"#/components/schemas/OpenRouterChatContentVideoInput"}},"required":["type","video_url"],"type":"object"},{"description":"Text content part","properties":{"cache_control":{"$ref":"#/components/schemas/OpenRouterChatContentCacheControl"},"text":{"type":"string"},"type":{"$ref":"#/components/schemas/OpenRouterChatContentTextType"}},"required":["type","text"],"type":"object"},{"description":"Video input content part","properties":{"type":{"$ref":"#/components/schemas/OpenRouterChatContentVideoType"},"video_url":{"$ref":"#/components/schemas/OpenRouterChatContentVideoInput"}},"required":["type","video_url"],"type":"object"}],"title":"ChatContentItems"},"OpenRouterChatContentItemsDiscriminatorMappingFileFile":{"properties":{"file_data":{"description":"File content as base64 data URL or URL","type":"string"},"file_id":{"description":"File ID for previously uploaded files","type":"string"},"filename":{"description":"Original filename","type":"string"}},"title":"ChatContentItemsDiscriminatorMappingFileFile","type":"object"},"OpenRouterChatContentItemsDiscriminatorMappingImageUrlImageUrl":{"properties":{"detail":{"$ref":"#/components/schemas/OpenRouterChatContentItemsDiscriminatorMappingImageUrlImageUrlDetail"},"url":{"description":"URL of the image (data: URLs supported)","type":"string"}},"required":["url"],"title":"ChatContentItemsDiscriminatorMappingImageUrlImageUrl","type":"object"},"OpenRouterChatContentItemsDiscriminatorMappingImageUrlImageUrlDetail":{"description":"Image detail level for vision models","enum":["auto","low","high"],"title":"ChatContentItemsDiscriminatorMappingImageUrlImageUrlDetail","type":"string"},"OpenRouterChatContentItemsDiscriminatorMappingInputAudioInputAudio":{"properties":{"data":{"description":"Base64 encoded audio data","type":"string"},"format":{"description":"Audio format (e.g., wav, mp3, flac, m4a, ogg, aiff, aac, pcm16, pcm24). Supported formats vary by provider.","type":"string"}},"required":["data","format"],"title":"ChatContentItemsDiscriminatorMappingInputAudioInputAudio","type":"object"},"OpenRouterChatContentText":{"description":"Text content part","properties":{"cache_control":{"$ref":"#/components/schemas/OpenRouterChatContentCacheControl"},"text":{"type":"string"},"type":{"$ref":"#/components/schemas/OpenRouterChatContentTextType"}},"required":["text","type"],"title":"ChatContentText","type":"object"},"OpenRouterChatContentTextType":{"enum":["text"],"title":"ChatContentTextType","type":"string"},"OpenRouterChatContentVideoInput":{"description":"Video input object","properties":{"url":{"description":"URL of the video (data: URLs supported)","type":"string"}},"required":["url"],"title":"ChatContentVideoInput","type":"object"},"OpenRouterChatContentVideoType":{"enum":["video_url"],"title":"ChatContentVideoType","type":"string"},"OpenRouterChatDebugOptions":{"description":"Debug options for inspecting request transformations (streaming only)","properties":{"echo_upstream_body":{"description":"If true, includes the transformed upstream request body in a debug chunk at the start of the stream. Only works with streaming mode.","type":"boolean"}},"title":"ChatDebugOptions","type":"object"},"OpenRouterChatFinishReasonEnum":{"enum":["tool_calls","stop","length","content_filter","error"],"title":"ChatFinishReasonEnum","type":"string"},"OpenRouterChatFunctionTool":{"description":"Tool definition for function calling (regular function or OpenRouter built-in server tool)","oneOf":[{"$ref":"#/components/schemas/OpenRouterChatFunctionTool0"},{"$ref":"#/components/schemas/OpenRouterDatetimeServerTool"},{"$ref":"#/components/schemas/ImageGenerationServerTool_OpenRouter"},{"$ref":"#/components/schemas/OpenRouterChatSearchModelsServerTool"},{"$ref":"#/components/schemas/OpenRouterWebFetchServerTool"},{"$ref":"#/components/schemas/OpenRouterWebSearchServerTool"},{"$ref":"#/components/schemas/OpenRouterChatWebSearchShorthand"}],"title":"ChatFunctionTool"},"OpenRouterChatFunctionTool0":{"properties":{"cache_control":{"$ref":"#/components/schemas/OpenRouterChatContentCacheControl"},"function":{"$ref":"#/components/schemas/OpenRouterChatFunctionToolOneOf0Function"},"type":{"$ref":"#/components/schemas/OpenRouterChatFunctionToolOneOf0Type"}},"required":["function","type"],"title":"ChatFunctionTool0","type":"object"},"OpenRouterChatFunctionToolOneOf0Function":{"description":"Function definition for tool calling","properties":{"description":{"description":"Function description for the model","type":"string"},"name":{"description":"Function name (a-z, A-Z, 0-9, underscores, dashes, max 64 chars)","type":"string"},"parameters":{"additionalProperties":{"description":"Any type"},"description":"Function parameters as JSON Schema object","type":"object"},"strict":{"description":"Enable strict schema adherence","nullable":true,"type":"boolean"}},"required":["name"],"title":"ChatFunctionToolOneOf0Function","type":"object"},"OpenRouterChatFunctionToolOneOf0Type":{"enum":["function"],"title":"ChatFunctionToolOneOf0Type","type":"string"},"OpenRouterChatJsonSchemaConfig":{"description":"JSON Schema configuration object","properties":{"description":{"description":"Schema description for the model","type":"string"},"name":{"description":"Schema name (a-z, A-Z, 0-9, underscores, dashes, max 64 chars)","type":"string"},"schema":{"additionalProperties":{"description":"Any type"},"description":"JSON Schema object","type":"object"},"strict":{"description":"Enable strict schema adherence","nullable":true,"type":"boolean"}},"required":["name"],"title":"ChatJsonSchemaConfig","type":"object"},"OpenRouterChatMessages":{"description":"Chat completion message with role-based discrimination","oneOf":[{"description":"Assistant message for requests and responses","properties":{"audio":{"$ref":"#/components/schemas/OpenRouterChatAudioOutput"},"content":{"$ref":"#/components/schemas/OpenRouterChatMessagesDiscriminatorMappingAssistantContent"},"images":{"$ref":"#/components/schemas/OpenRouterChatAssistantImages"},"name":{"description":"Optional name for the assistant","type":"string"},"reasoning":{"description":"Reasoning output","nullable":true,"type":"string"},"reasoning_details":{"$ref":"#/components/schemas/OpenRouterChatReasoningDetails"},"refusal":{"description":"Refusal message if content was refused","nullable":true,"type":"string"},"role":{"description":"Discriminator value: assistant","enum":["assistant"],"type":"string"},"tool_calls":{"description":"Tool calls made by the assistant","items":{"$ref":"#/components/schemas/OpenRouterChatToolCall"},"type":"array"}},"required":["role"],"type":"object"},{"description":"Developer message","properties":{"content":{"$ref":"#/components/schemas/OpenRouterChatMessagesDiscriminatorMappingDeveloperContent"},"name":{"description":"Optional name for the developer message","type":"string"},"role":{"description":"Discriminator value: developer","enum":["developer"],"type":"string"}},"required":["role","content"],"type":"object"},{"description":"System message for setting behavior","properties":{"content":{"$ref":"#/components/schemas/OpenRouterChatSystemMessageContent"},"name":{"description":"Optional name for the system message","type":"string"},"role":{"$ref":"#/components/schemas/OpenRouterChatSystemMessageRole"}},"required":["role","content"],"type":"object"},{"description":"Tool response message","properties":{"content":{"$ref":"#/components/schemas/OpenRouterChatToolMessageContent"},"role":{"$ref":"#/components/schemas/OpenRouterChatToolMessageRole"},"tool_call_id":{"description":"ID of the assistant message tool call this message responds to","type":"string"}},"required":["role","content","tool_call_id"],"type":"object"},{"description":"User message","properties":{"content":{"$ref":"#/components/schemas/OpenRouterChatUserMessageContent"},"name":{"description":"Optional name for the user","type":"string"},"role":{"$ref":"#/components/schemas/OpenRouterChatUserMessageRole"}},"required":["role","content"],"type":"object"}],"title":"ChatMessages"},"OpenRouterChatMessagesDiscriminatorMappingAssistantContent":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/OpenRouterChatMessagesDiscriminatorMappingAssistantContent1"},{"description":"Any type"}],"description":"Assistant message content","title":"ChatMessagesDiscriminatorMappingAssistantContent"},"OpenRouterChatMessagesDiscriminatorMappingAssistantContent1":{"items":{"$ref":"#/components/schemas/OpenRouterChatContentItems"},"title":"ChatMessagesDiscriminatorMappingAssistantContent1","type":"array"},"OpenRouterChatMessagesDiscriminatorMappingDeveloperContent":{"description":"Developer message content","oneOf":[{"type":"string"},{"$ref":"#/components/schemas/OpenRouterChatMessagesDiscriminatorMappingDeveloperContent1"}],"title":"ChatMessagesDiscriminatorMappingDeveloperContent"},"OpenRouterChatMessagesDiscriminatorMappingDeveloperContent1":{"items":{"$ref":"#/components/schemas/OpenRouterChatContentText"},"title":"ChatMessagesDiscriminatorMappingDeveloperContent1","type":"array"},"OpenRouterChatModelNames":{"description":"Models to use for completion","items":{"$ref":"#/components/schemas/OpenRouterModelName"},"title":"ChatModelNames","type":"array"},"OpenRouterChatNamedToolChoice":{"description":"Named tool choice for specific function","properties":{"function":{"$ref":"#/components/schemas/OpenRouterChatNamedToolChoiceFunction"},"type":{"$ref":"#/components/schemas/OpenRouterChatNamedToolChoiceType"}},"required":["function","type"],"title":"ChatNamedToolChoice","type":"object"},"OpenRouterChatNamedToolChoiceFunction":{"properties":{"name":{"description":"Function name to call","type":"string"}},"required":["name"],"title":"ChatNamedToolChoiceFunction","type":"object"},"OpenRouterChatNamedToolChoiceType":{"enum":["function"],"title":"ChatNamedToolChoiceType","type":"string"},"OpenRouterChatReasoningDetails":{"description":"Reasoning details for extended thinking models","items":{"$ref":"#/components/schemas/OpenRouterReasoningDetailUnion"},"title":"ChatReasoningDetails","type":"array"},"OpenRouterChatReasoningSummaryVerbosityEnum":{"enum":["auto","concise","detailed"],"title":"ChatReasoningSummaryVerbosityEnum","type":"string"},"OpenRouterChatRequestModalitiesItems":{"enum":["text","image","audio"],"title":"ChatRequestModalitiesItems","type":"string"},"OpenRouterChatRequestPluginsItems":{"oneOf":[{"description":"auto-router variant","properties":{"allowed_models":{"description":"List of model patterns to filter which models the auto-router can route between. Supports wildcards (e.g., \"anthropic/*\" matches all Anthropic models). When not specified, uses the default supported models list.","items":{"type":"string"},"type":"array"},"enabled":{"description":"Set to false to disable the auto-router plugin for this request. Defaults to true.","type":"boolean"},"id":{"description":"Discriminator value: auto-router","enum":["auto-router"],"type":"string"}},"required":["id"],"type":"object"},{"description":"context-compression variant","properties":{"enabled":{"description":"Set to false to disable the context-compression plugin for this request. Defaults to true.","type":"boolean"},"engine":{"$ref":"#/components/schemas/OpenRouterContextCompressionEngine"},"id":{"description":"Discriminator value: context-compression","enum":["context-compression"],"type":"string"}},"required":["id"],"type":"object"},{"description":"file-parser variant","properties":{"enabled":{"description":"Set to false to disable the file-parser plugin for this request. Defaults to true.","type":"boolean"},"id":{"description":"Discriminator value: file-parser","enum":["file-parser"],"type":"string"},"pdf":{"$ref":"#/components/schemas/OpenRouterPDFParserOptions"}},"required":["id"],"type":"object"},{"description":"fusion variant","properties":{"analysis_models":{"description":"Slugs of models to run in parallel as the \"expert panel\" the judge analyzes. Each model receives the same user prompt with web_search + web_fetch enabled. Capped at 8 models to bound cost amplification. When omitted, defaults to the Quality preset from the /labs/fusion UI (~anthropic/claude-opus-latest, ~openai/gpt-latest, ~google/gemini-pro-latest).","items":{"type":"string"},"type":"array"},"enabled":{"description":"Set to false to disable the fusion plugin for this request. Defaults to true.","type":"boolean"},"id":{"description":"Discriminator value: fusion","enum":["fusion"],"type":"string"},"max_tool_calls":{"description":"Maximum number of tool-calling steps each panelist (analysis model) and the judge model may take during their agentic web-research loop. Models with web_search/web_fetch enabled iterate until they produce a text response or hit this ceiling. Defaults to 8. Capped at 16.","type":"integer"},"model":{"description":"Slug of the model that performs both the judge step (with web_search + web_fetch) and the final synthesis. When omitted, defaults to the first model in the Quality preset.","type":"string"}},"required":["id"],"type":"object"},{"description":"moderation variant","properties":{"id":{"description":"Discriminator value: moderation","enum":["moderation"],"type":"string"}},"required":["id"],"type":"object"},{"description":"pareto-router variant","properties":{"enabled":{"description":"Set to false to disable the pareto-router plugin for this request. Defaults to true.","type":"boolean"},"id":{"description":"Discriminator value: pareto-router","enum":["pareto-router"],"type":"string"},"min_coding_score":{"description":"Minimum desired coding score between 0 and 1, where 1 is best. Higher values select from stronger coding models (sourced from Artificial Analysis coding percentiles). Maps internally to one of three tiers (low, medium, high). Omit to use the router default tier.","format":"double","type":"number"}},"required":["id"],"type":"object"},{"description":"response-healing variant","properties":{"enabled":{"description":"Set to false to disable the response-healing plugin for this request. Defaults to true.","type":"boolean"},"id":{"description":"Discriminator value: response-healing","enum":["response-healing"],"type":"string"}},"required":["id"],"type":"object"},{"description":"web variant","properties":{"enabled":{"description":"Set to false to disable the web-search plugin for this request. Defaults to true.","type":"boolean"},"engine":{"$ref":"#/components/schemas/OpenRouterWebSearchEngine"},"exclude_domains":{"description":"A list of domains to exclude from web search results. Supports wildcards (e.g. \"*.substack.com\") and path filtering (e.g. \"openai.com/blog\").","items":{"type":"string"},"type":"array"},"id":{"$ref":"#/components/schemas/OpenRouterWebSearchPluginId"},"include_domains":{"description":"A list of domains to restrict web search results to. Supports wildcards (e.g. \"*.substack.com\") and path filtering (e.g. \"openai.com/blog\").","items":{"type":"string"},"type":"array"},"max_results":{"type":"integer"},"max_uses":{"description":"Maximum number of times the model can invoke web search in a single turn. Passed through to native providers that support it (e.g. Anthropic).","type":"integer"},"search_prompt":{"type":"string"},"user_location":{"$ref":"#/components/schemas/OpenRouterWebSearchPluginUserLocation"}},"required":["id"],"type":"object"},{"description":"web-fetch variant","properties":{"allowed_domains":{"description":"Only fetch from these domains.","items":{"type":"string"},"type":"array"},"blocked_domains":{"description":"Never fetch from these domains.","items":{"type":"string"},"type":"array"},"id":{"$ref":"#/components/schemas/OpenRouterWebFetchPluginId"},"max_content_tokens":{"description":"Maximum content length in approximate tokens. Content exceeding this limit is truncated.","type":"integer"},"max_uses":{"description":"Maximum number of web fetches per request. Once exceeded, the tool returns an error.","type":"integer"}},"required":["id"],"type":"object"}],"title":"ChatRequestPluginsItems"},"OpenRouterChatRequestReasoning":{"description":"Configuration options for reasoning models","properties":{"effort":{"description":"Constrains effort on reasoning for reasoning models","oneOf":[{"$ref":"#/components/schemas/OpenRouterChatRequestReasoningEffort"}]},"summary":{"$ref":"#/components/schemas/OpenRouterChatReasoningSummaryVerbosityEnum"}},"title":"ChatRequestReasoning","type":"object"},"OpenRouterChatRequestReasoningEffort":{"description":"Constrains effort on reasoning for reasoning models","enum":["xhigh","high","medium","low","minimal","none"],"title":"ChatRequestReasoningEffort","type":"string"},"OpenRouterChatRequestResponseFormat":{"description":"Response format configuration","oneOf":[{"description":"Custom grammar response format","properties":{"grammar":{"description":"Custom grammar for text generation","type":"string"},"type":{"description":"Discriminator value: grammar","enum":["grammar"],"type":"string"}},"required":["type","grammar"],"type":"object"},{"description":"JSON object response format","properties":{"type":{"$ref":"#/components/schemas/OpenRouterFormatJsonObjectConfigType"}},"required":["type"],"type":"object"},{"description":"JSON Schema response format for structured outputs","properties":{"json_schema":{"$ref":"#/components/schemas/OpenRouterChatJsonSchemaConfig"},"type":{"description":"Discriminator value: json_schema","enum":["json_schema"],"type":"string"}},"required":["type","json_schema"],"type":"object"},{"description":"Python code response format","properties":{"type":{"description":"Discriminator value: python","enum":["python"],"type":"string"}},"required":["type"],"type":"object"},{"description":"Default text response format","properties":{"type":{"description":"Discriminator value: text","enum":["text"],"type":"string"}},"required":["type"],"type":"object"}],"title":"ChatRequestResponseFormat"},"OpenRouterChatRequestServiceTier":{"description":"The service tier to use for processing this request.","enum":["auto","default","flex","priority","scale"],"title":"ChatRequestServiceTier","type":"string"},"OpenRouterChatRequestStop":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"description":"Any type"}],"description":"Stop sequences (up to 4)","title":"ChatRequestStop"},"OpenRouterChatResultObject":{"enum":["chat.completion"],"title":"ChatResultObject","type":"string"},"OpenRouterChatSearchModelsServerTool":{"description":"OpenRouter built-in server tool: searches and filters AI models available on OpenRouter","properties":{"parameters":{"$ref":"#/components/schemas/OpenRouterSearchModelsServerToolConfig"},"type":{"$ref":"#/components/schemas/OpenRouterChatSearchModelsServerToolType"}},"required":["type"],"title":"ChatSearchModelsServerTool","type":"object"},"OpenRouterChatSearchModelsServerToolType":{"enum":["openrouter:experimental__search_models"],"title":"ChatSearchModelsServerToolType","type":"string"},"OpenRouterChatStreamOptions":{"description":"Streaming configuration options","properties":{"include_usage":{"description":"Deprecated: This field has no effect. Full usage details are always included.","type":"boolean"}},"title":"ChatStreamOptions","type":"object"},"OpenRouterChatSystemMessageContent":{"description":"System message content","oneOf":[{"type":"string"},{"$ref":"#/components/schemas/OpenRouterChatSystemMessageContent1"}],"title":"ChatSystemMessageContent"},"OpenRouterChatSystemMessageContent1":{"items":{"$ref":"#/components/schemas/OpenRouterChatContentText"},"title":"ChatSystemMessageContent1","type":"array"},"OpenRouterChatSystemMessageRole":{"enum":["system"],"title":"ChatSystemMessageRole","type":"string"},"OpenRouterChatTokenLogprob":{"description":"Token log probability information","properties":{"bytes":{"description":"UTF-8 bytes of the token","items":{"type":"integer"},"nullable":true,"type":"array"},"logprob":{"description":"Log probability of the token","format":"double","type":"number"},"token":{"description":"The token","type":"string"},"top_logprobs":{"description":"Top alternative tokens with probabilities","items":{"$ref":"#/components/schemas/OpenRouterChatTokenLogprobTopLogprobsItems"},"type":"array"}},"required":["bytes","logprob","token","top_logprobs"],"title":"ChatTokenLogprob","type":"object"},"OpenRouterChatTokenLogprobTopLogprobsItems":{"properties":{"bytes":{"items":{"type":"integer"},"nullable":true,"type":"array"},"logprob":{"format":"double","type":"number"},"token":{"type":"string"}},"required":["bytes","logprob","token"],"title":"ChatTokenLogprobTopLogprobsItems","type":"object"},"OpenRouterChatTokenLogprobs":{"description":"Log probabilities for the completion","properties":{"content":{"description":"Log probabilities for content tokens","items":{"$ref":"#/components/schemas/OpenRouterChatTokenLogprob"},"nullable":true,"type":"array"},"refusal":{"description":"Log probabilities for refusal tokens","items":{"$ref":"#/components/schemas/OpenRouterChatTokenLogprob"},"nullable":true,"type":"array"}},"required":["content"],"title":"ChatTokenLogprobs","type":"object"},"OpenRouterChatToolCall":{"description":"Tool call made by the assistant","properties":{"function":{"$ref":"#/components/schemas/OpenRouterChatToolCallFunction"},"id":{"description":"Tool call identifier","type":"string"},"type":{"$ref":"#/components/schemas/OpenRouterChatToolCallType"}},"required":["function","id","type"],"title":"ChatToolCall","type":"object"},"OpenRouterChatToolCallFunction":{"properties":{"arguments":{"description":"Function arguments as JSON string","type":"string"},"name":{"description":"Function name to call","type":"string"}},"required":["arguments","name"],"title":"ChatToolCallFunction","type":"object"},"OpenRouterChatToolCallType":{"enum":["function"],"title":"ChatToolCallType","type":"string"},"OpenRouterChatToolChoice":{"description":"Tool choice configuration","oneOf":[{"$ref":"#/components/schemas/OpenRouterChatToolChoice0"},{"$ref":"#/components/schemas/OpenRouterChatToolChoice1"},{"$ref":"#/components/schemas/OpenRouterChatToolChoice2"},{"$ref":"#/components/schemas/OpenRouterChatNamedToolChoice"}],"title":"ChatToolChoice"},"OpenRouterChatToolChoice0":{"enum":["none"],"title":"ChatToolChoice0","type":"string"},"OpenRouterChatToolChoice1":{"enum":["auto"],"title":"ChatToolChoice1","type":"string"},"OpenRouterChatToolChoice2":{"enum":["required"],"title":"ChatToolChoice2","type":"string"},"OpenRouterChatToolMessageContent":{"description":"Tool response content","oneOf":[{"type":"string"},{"$ref":"#/components/schemas/OpenRouterChatToolMessageContent1"}],"title":"ChatToolMessageContent"},"OpenRouterChatToolMessageContent1":{"items":{"$ref":"#/components/schemas/OpenRouterChatContentItems"},"title":"ChatToolMessageContent1","type":"array"},"OpenRouterChatToolMessageRole":{"enum":["tool"],"title":"ChatToolMessageRole","type":"string"},"OpenRouterChatUsage":{"description":"Token usage statistics","properties":{"completion_tokens":{"description":"Number of tokens in the completion","type":"integer"},"completion_tokens_details":{"description":"Detailed completion token usage","oneOf":[{"$ref":"#/components/schemas/OpenRouterChatUsageCompletionTokensDetails"}]},"cost":{"description":"Cost of the completion","format":"double","nullable":true,"type":"number"},"cost_details":{"$ref":"#/components/schemas/OpenRouterCostDetails"},"is_byok":{"description":"Whether a request was made using a Bring Your Own Key configuration","type":"boolean"},"prompt_tokens":{"description":"Number of tokens in the prompt","type":"integer"},"prompt_tokens_details":{"description":"Detailed prompt token usage","oneOf":[{"$ref":"#/components/schemas/OpenRouterChatUsagePromptTokensDetails"}]},"total_tokens":{"description":"Total number of tokens","type":"integer"}},"required":["completion_tokens","prompt_tokens","total_tokens"],"title":"ChatUsage","type":"object"},"OpenRouterChatUsageCompletionTokensDetails":{"description":"Detailed completion token usage","properties":{"accepted_prediction_tokens":{"description":"Accepted prediction tokens","nullable":true,"type":"integer"},"audio_tokens":{"description":"Tokens used for audio output","nullable":true,"type":"integer"},"reasoning_tokens":{"description":"Tokens used for reasoning","nullable":true,"type":"integer"},"rejected_prediction_tokens":{"description":"Rejected prediction tokens","nullable":true,"type":"integer"}},"title":"ChatUsageCompletionTokensDetails","type":"object"},"OpenRouterChatUsagePromptTokensDetails":{"description":"Detailed prompt token usage","properties":{"audio_tokens":{"description":"Audio input tokens","type":"integer"},"cache_write_tokens":{"description":"Tokens written to cache. Only returned for models with explicit caching and cache write pricing.","type":"integer"},"cached_tokens":{"description":"Cached prompt tokens","type":"integer"},"video_tokens":{"description":"Video input tokens","type":"integer"}},"title":"ChatUsagePromptTokensDetails","type":"object"},"OpenRouterChatUserMessageContent":{"description":"User message content","oneOf":[{"type":"string"},{"$ref":"#/components/schemas/OpenRouterChatUserMessageContent1"}],"title":"ChatUserMessageContent"},"OpenRouterChatUserMessageContent1":{"items":{"$ref":"#/components/schemas/OpenRouterChatContentItems"},"title":"ChatUserMessageContent1","type":"array"},"OpenRouterChatUserMessageRole":{"enum":["user"],"title":"ChatUserMessageRole","type":"string"},"OpenRouterChatWebSearchShorthand":{"description":"Web search tool using OpenAI Responses API syntax. Automatically converted to openrouter:web_search.","properties":{"allowed_domains":{"description":"Limit search results to these domains. Supported by Exa, Firecrawl, Parallel, and most native providers (Anthropic, OpenAI, xAI). Not supported with Perplexity. Cannot be used with excluded_domains.","items":{"type":"string"},"type":"array"},"engine":{"$ref":"#/components/schemas/OpenRouterWebSearchEngineEnum"},"excluded_domains":{"description":"Exclude search results from these domains. Supported by Exa, Firecrawl, Parallel, Anthropic, and xAI. Not supported with OpenAI (silently ignored) or Perplexity. Cannot be used with allowed_domains.","items":{"type":"string"},"type":"array"},"max_results":{"description":"Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, and Parallel engines; ignored with native provider search.","type":"integer"},"max_total_results":{"description":"Maximum total number of search results across all search calls in a single request. Once this limit is reached, the tool will stop returning new results. Useful for controlling cost and context size in agentic loops. Defaults to 50 when not specified.","type":"integer"},"parameters":{"$ref":"#/components/schemas/OpenRouterWebSearchConfig"},"search_context_size":{"$ref":"#/components/schemas/OpenRouterSearchQualityLevel"},"type":{"$ref":"#/components/schemas/OpenRouterChatWebSearchShorthandType"},"user_location":{"$ref":"#/components/schemas/OpenRouterWebSearchUserLocationServerTool"}},"required":["type"],"title":"ChatWebSearchShorthand","type":"object"},"OpenRouterChatWebSearchShorthandType":{"enum":["web_search","web_search_preview","web_search_preview_2025_03_11","web_search_2025_08_26"],"title":"ChatWebSearchShorthandType","type":"string"},"OpenRouterContextCompressionEngine":{"description":"The compression engine to use. Defaults to \"middle-out\".","enum":["middle-out"],"title":"ContextCompressionEngine","type":"string"},"OpenRouterCostDetails":{"description":"Breakdown of upstream inference costs","properties":{"upstream_inference_completions_cost":{"format":"double","type":"number"},"upstream_inference_cost":{"format":"double","nullable":true,"type":"number"},"upstream_inference_prompt_cost":{"format":"double","type":"number"}},"required":["upstream_inference_completions_cost","upstream_inference_prompt_cost"],"title":"CostDetails","type":"object"},"OpenRouterDatetimeServerTool":{"description":"OpenRouter built-in server tool: returns the current date and time","properties":{"parameters":{"$ref":"#/components/schemas/OpenRouterDatetimeServerToolConfig"},"type":{"$ref":"#/components/schemas/OpenRouterDatetimeServerToolType"}},"required":["type"],"title":"DatetimeServerTool","type":"object"},"OpenRouterDatetimeServerToolConfig":{"description":"Configuration for the openrouter:datetime server tool","properties":{"timezone":{"description":"IANA timezone name (e.g. \"America/New_York\"). Defaults to UTC.","type":"string"}},"title":"DatetimeServerToolConfig","type":"object"},"OpenRouterDatetimeServerToolType":{"enum":["openrouter:datetime"],"title":"DatetimeServerToolType","type":"string"},"OpenRouterEndpointInfo":{"properties":{"model":{"type":"string"},"provider":{"type":"string"},"selected":{"type":"boolean"}},"required":["model","provider","selected"],"title":"EndpointInfo","type":"object"},"OpenRouterEndpointsMetadata":{"properties":{"available":{"items":{"$ref":"#/components/schemas/OpenRouterEndpointInfo"},"type":"array"},"total":{"type":"integer"}},"required":["available","total"],"title":"EndpointsMetadata","type":"object"},"OpenRouterFormatJsonObjectConfigType":{"enum":["json_object"],"title":"FormatJsonObjectConfigType","type":"string"},"OpenRouterImageConfig":{"anyOf":[{"additionalProperties":true,"properties":{"aspect_ratio":{"description":"Output aspect ratio, e.g. \"16:9\".","type":"string"},"background":{"description":"Background treatment for the generated image.","type":"string"},"moderation":{"description":"Moderation strength applied to image generation.","type":"string"},"output_compression":{"description":"Compression level for the encoded output.","type":"integer"},"output_format":{"description":"Encoding of the returned image, e.g. \"png\".","type":"string"},"quality":{"description":"Rendering quality preset.","type":"string"},"size":{"description":"Output size, e.g. \"1024x1024\".","type":"string"}},"type":"object"},{"type":"string"},{"format":"double","type":"number"},{"items":{"description":"Any type"},"type":"array"}],"title":"ImageConfig"},"OpenRouterImageGenerationServerToolConfig":{"description":"Configuration for the openrouter:image_generation server tool. Accepts all image_config params (aspect_ratio, quality, size, background, output_format, output_compression, moderation, etc.) plus a model field.","properties":{"model":{"description":"Which image generation model to use (e.g. \"openai/gpt-5-image\"). Defaults to \"openai/gpt-5-image\".","type":"string"}},"title":"ImageGenerationServerToolConfig","type":"object"},"OpenRouterImageGenerationServerToolOpenRouterType":{"enum":["openrouter:image_generation"],"title":"ImageGenerationServerToolOpenRouterType","type":"string"},"OpenRouterLegacyChatContentVideoType":{"enum":["input_video"],"title":"LegacyChatContentVideoType","type":"string"},"OpenRouterMetadata":{"properties":{"attempt":{"type":"integer"},"attempts":{"items":{"$ref":"#/components/schemas/OpenRouterRouterAttempt"},"type":"array"},"endpoints":{"$ref":"#/components/schemas/OpenRouterEndpointsMetadata"},"is_byok":{"type":"boolean"},"params":{"$ref":"#/components/schemas/OpenRouterRouterParams"},"pipeline":{"items":{"$ref":"#/components/schemas/OpenRouterPipelineStage"},"type":"array"},"region":{"nullable":true,"type":"string"},"requested":{"type":"string"},"strategy":{"$ref":"#/components/schemas/OpenRouterRoutingStrategy"},"summary":{"type":"string"}},"required":["attempt","endpoints","is_byok","region","requested","strategy","summary"],"title":"OpenRouterMetadata","type":"object"},"OpenRouterModelName":{"description":"Model to use for completion","title":"ModelName","type":"string"},"OpenRouterPDFParserEngine":{"description":"The engine to use for parsing PDF files. \"pdf-text\" is deprecated and automatically redirected to \"cloudflare-ai\".","oneOf":[{"$ref":"#/components/schemas/OpenRouterPdfParserEngine0"},{"$ref":"#/components/schemas/OpenRouterPdfParserEngine1"}],"title":"PDFParserEngine"},"OpenRouterPDFParserOptions":{"description":"Options for PDF parsing.","properties":{"engine":{"$ref":"#/components/schemas/OpenRouterPDFParserEngine"}},"title":"PDFParserOptions","type":"object"},"OpenRouterPdfParserEngine0":{"enum":["mistral-ocr","native","cloudflare-ai"],"title":"PdfParserEngine0","type":"string"},"OpenRouterPdfParserEngine1":{"enum":["pdf-text"],"title":"PdfParserEngine1","type":"string"},"OpenRouterPercentileLatencyCutoffs":{"description":"Percentile-based latency cutoffs. All specified cutoffs must be met for an endpoint to be preferred.","properties":{"p50":{"description":"Maximum p50 latency (seconds)","format":"double","nullable":true,"type":"number"},"p75":{"description":"Maximum p75 latency (seconds)","format":"double","nullable":true,"type":"number"},"p90":{"description":"Maximum p90 latency (seconds)","format":"double","nullable":true,"type":"number"},"p99":{"description":"Maximum p99 latency (seconds)","format":"double","nullable":true,"type":"number"}},"title":"PercentileLatencyCutoffs","type":"object"},"OpenRouterPercentileThroughputCutoffs":{"description":"Percentile-based throughput cutoffs. All specified cutoffs must be met for an endpoint to be preferred.","properties":{"p50":{"description":"Minimum p50 throughput (tokens/sec)","format":"double","nullable":true,"type":"number"},"p75":{"description":"Minimum p75 throughput (tokens/sec)","format":"double","nullable":true,"type":"number"},"p90":{"description":"Minimum p90 throughput (tokens/sec)","format":"double","nullable":true,"type":"number"},"p99":{"description":"Minimum p99 throughput (tokens/sec)","format":"double","nullable":true,"type":"number"}},"title":"PercentileThroughputCutoffs","type":"object"},"OpenRouterPipelineStage":{"properties":{"cost_usd":{"format":"double","nullable":true,"type":"number"},"data":{"additionalProperties":{"description":"Any type"},"type":"object"},"guardrail_id":{"type":"string"},"guardrail_scope":{"type":"string"},"name":{"type":"string"},"summary":{"type":"string"},"type":{"$ref":"#/components/schemas/OpenRouterPipelineStageType"}},"required":["name","type"],"title":"PipelineStage","type":"object"},"OpenRouterPipelineStageType":{"description":"Categorical kind of a pipeline stage. Multiple plugins can share a type (e.g. all guardrail-level plugins emit `guardrail`); the `name` field disambiguates which plugin emitted it.","enum":["guardrail","plugin","server_tools","response_healing","context_compression"],"title":"PipelineStageType","type":"string"},"OpenRouterPreferredMaxLatency":{"anyOf":[{"format":"double","type":"number"},{"$ref":"#/components/schemas/OpenRouterPercentileLatencyCutoffs"},{"description":"Any type"}],"description":"Preferred maximum latency (in seconds). Can be a number (applies to p50) or an object with percentile-specific cutoffs. Endpoints above the threshold(s) may still be used, but are deprioritized in routing. When using fallback models, this may cause a fallback model to be used instead of the primary model if it meets the threshold.","title":"PreferredMaxLatency"},"OpenRouterPreferredMinThroughput":{"anyOf":[{"format":"double","type":"number"},{"$ref":"#/components/schemas/OpenRouterPercentileThroughputCutoffs"},{"description":"Any type"}],"description":"Preferred minimum throughput (in tokens per second). Can be a number (applies to p50) or an object with percentile-specific cutoffs. Endpoints below the threshold(s) may still be used, but are deprioritized in routing. When using fallback models, this may cause a fallback model to be used instead of the primary model if it meets the threshold.","title":"PreferredMinThroughput"},"OpenRouterProviderName":{"enum":["AkashML","AI21","AionLabs","Alibaba","Ambient","Baidu","Amazon Bedrock","Amazon Nova","Anthropic","Arcee AI","AtlasCloud","Avian","Azure","BaseTen","BytePlus","Black Forest Labs","Cerebras","Chutes","Cirrascale","Clarifai","Cloudflare","Cohere","Crucible","Crusoe","DeepInfra","DeepSeek","DekaLLM","Featherless","Fireworks","Friendli","GMICloud","Google","Google AI Studio","Groq","Hyperbolic","Inception","Inceptron","InferenceNet","Ionstream","Infermatic","Io Net","Inflection","Liquid","Mara","Mancer 2","Minimax","ModelRun","Mistral","Modular","Moonshot AI","Morph","NCompass","Nebius","Nex AGI","NextBit","Novita","Nvidia","OpenAI","OpenInference","Parasail","Poolside","Perceptron","Perplexity","Phala","Recraft","Reka","Relace","SambaNova","Seed","SiliconFlow","Sourceful","StepFun","Stealth","StreamLake","Switchpoint","Together","Upstage","Venice","WandB","Xiaomi","xAI","Z.AI","FakeProvider"],"title":"ProviderName","type":"string"},"OpenRouterProviderPreferences":{"description":"When multiple model providers are available, optionally indicate your routing preference.","properties":{"allow_fallbacks":{"description":"Whether to allow backup providers to serve requests\n- true: (default) when the primary provider (or your custom providers in \"order\") is unavailable, use the next best provider.\n- false: use only the primary/custom provider, and return the upstream error if it's unavailable.\n","nullable":true,"type":"boolean"},"data_collection":{"description":"Data collection setting. If no available model provider meets the requirement, your request will return an error.\n- allow: (default) allow providers which store user data non-transiently and may train on it\n\n- deny: use only providers which do not collect user data.","oneOf":[{"$ref":"#/components/schemas/OpenRouterProviderPreferencesDataCollection"}]},"enforce_distillable_text":{"description":"Whether to restrict routing to only models that allow text distillation. When true, only models where the author has allowed distillation will be used.","nullable":true,"type":"boolean"},"ignore":{"description":"List of provider slugs to ignore. If provided, this list is merged with your account-wide ignored provider settings for this request.","items":{"$ref":"#/components/schemas/OpenRouterProviderPreferencesIgnoreItems"},"nullable":true,"type":"array"},"max_price":{"$ref":"#/components/schemas/OpenRouterProviderPreferencesMaxPrice"},"only":{"description":"List of provider slugs to allow. If provided, this list is merged with your account-wide allowed provider settings for this request.","items":{"$ref":"#/components/schemas/OpenRouterProviderPreferencesOnlyItems"},"nullable":true,"type":"array"},"order":{"description":"An ordered list of provider slugs. The router will attempt to use the first provider in the subset of this list that supports your requested model, and fall back to the next if it is unavailable. If no providers are available, the request will fail with an error message.","items":{"$ref":"#/components/schemas/OpenRouterProviderPreferencesOrderItems"},"nullable":true,"type":"array"},"preferred_max_latency":{"$ref":"#/components/schemas/OpenRouterPreferredMaxLatency"},"preferred_min_throughput":{"$ref":"#/components/schemas/OpenRouterPreferredMinThroughput"},"quantizations":{"description":"A list of quantization levels to filter the provider by.","items":{"$ref":"#/components/schemas/OpenRouterQuantization"},"nullable":true,"type":"array"},"require_parameters":{"description":"Whether to filter providers to only those that support the parameters you've provided. If this setting is omitted or set to false, then providers will receive only the parameters they support, and ignore the rest.","nullable":true,"type":"boolean"},"sort":{"$ref":"#/components/schemas/OpenRouterProviderPreferencesSort"},"zdr":{"description":"Whether to restrict routing to only ZDR (Zero Data Retention) endpoints. When true, only endpoints that do not retain prompts will be used.","nullable":true,"type":"boolean"}},"title":"ProviderPreferences","type":"object"},"OpenRouterProviderPreferencesDataCollection":{"description":"Data collection setting. If no available model provider meets the requirement, your request will return an error.\n- allow: (default) allow providers which store user data non-transiently and may train on it\n\n- deny: use only providers which do not collect user data.","enum":["deny","allow"],"title":"ProviderPreferencesDataCollection","type":"string"},"OpenRouterProviderPreferencesIgnoreItems":{"anyOf":[{"$ref":"#/components/schemas/OpenRouterProviderName"},{"type":"string"}],"title":"ProviderPreferencesIgnoreItems"},"OpenRouterProviderPreferencesMaxPrice":{"description":"The object specifying the maximum price you want to pay for this request. USD price per million tokens, for prompt and completion.","properties":{"audio":{"$ref":"#/components/schemas/OpenRouterBigNumberUnion"},"completion":{"$ref":"#/components/schemas/OpenRouterBigNumberUnion"},"image":{"$ref":"#/components/schemas/OpenRouterBigNumberUnion"},"prompt":{"$ref":"#/components/schemas/OpenRouterBigNumberUnion"},"request":{"$ref":"#/components/schemas/OpenRouterBigNumberUnion"}},"title":"ProviderPreferencesMaxPrice","type":"object"},"OpenRouterProviderPreferencesOnlyItems":{"anyOf":[{"$ref":"#/components/schemas/OpenRouterProviderName"},{"type":"string"}],"title":"ProviderPreferencesOnlyItems"},"OpenRouterProviderPreferencesOrderItems":{"anyOf":[{"$ref":"#/components/schemas/OpenRouterProviderName"},{"type":"string"}],"title":"ProviderPreferencesOrderItems"},"OpenRouterProviderPreferencesSort":{"anyOf":[{"$ref":"#/components/schemas/OpenRouterProviderSort"},{"$ref":"#/components/schemas/OpenRouterProviderSortConfig"},{"description":"Any type"}],"description":"The sorting strategy to use for this request, if \"order\" is not specified. When set, no load balancing is performed.","title":"ProviderPreferencesSort"},"OpenRouterProviderSort":{"description":"The provider sorting strategy (price, throughput, latency)","enum":["price","throughput","latency","exacto"],"title":"ProviderSort","type":"string"},"OpenRouterProviderSortConfig":{"description":"The provider sorting strategy (price, throughput, latency)","properties":{"by":{"description":"The provider sorting strategy (price, throughput, latency)","oneOf":[{"$ref":"#/components/schemas/OpenRouterProviderSortConfigBy"}]},"partition":{"description":"Partitioning strategy for sorting: \"model\" (default) groups endpoints by model before sorting (fallback models remain fallbacks), \"none\" sorts all endpoints together regardless of model.","oneOf":[{"$ref":"#/components/schemas/OpenRouterProviderSortConfigPartition"}]}},"title":"ProviderSortConfig","type":"object"},"OpenRouterProviderSortConfigBy":{"description":"The provider sorting strategy (price, throughput, latency)","enum":["price","throughput","latency","exacto"],"title":"ProviderSortConfigBy","type":"string"},"OpenRouterProviderSortConfigPartition":{"description":"Partitioning strategy for sorting: \"model\" (default) groups endpoints by model before sorting (fallback models remain fallbacks), \"none\" sorts all endpoints together regardless of model.","enum":["model","none"],"title":"ProviderSortConfigPartition","type":"string"},"OpenRouterQuantization":{"enum":["int4","int8","fp4","fp6","fp8","fp16","bf16","fp32","unknown"],"title":"Quantization","type":"string"},"OpenRouterReasoningDetailUnion":{"anyOf":[{"description":"Reasoning detail encrypted schema","properties":{"data":{"type":"string"},"format":{"$ref":"#/components/schemas/OpenRouterReasoningFormat"},"id":{"nullable":true,"type":"string"},"index":{"type":"integer"},"type":{"description":"Discriminator value: reasoning.encrypted","type":"string"}},"required":["type","data"],"type":"object"},{"description":"Reasoning detail summary schema","properties":{"format":{"$ref":"#/components/schemas/OpenRouterReasoningFormat"},"id":{"nullable":true,"type":"string"},"index":{"type":"integer"},"summary":{"type":"string"},"type":{"description":"Discriminator value: reasoning.summary","type":"string"}},"required":["type","summary"],"type":"object"},{"description":"Reasoning detail text schema","properties":{"format":{"$ref":"#/components/schemas/OpenRouterReasoningFormat"},"id":{"nullable":true,"type":"string"},"index":{"type":"integer"},"signature":{"nullable":true,"type":"string"},"text":{"nullable":true,"type":"string"},"type":{"description":"Discriminator value: reasoning.text","type":"string"}},"required":["type"],"type":"object"}],"description":"Reasoning detail union schema","title":"ReasoningDetailUnion"},"OpenRouterReasoningFormat":{"enum":["unknown","openai-responses-v1","azure-openai-responses-v1","xai-responses-v1","anthropic-claude-v1","google-gemini-v1"],"title":"ReasoningFormat","type":"string"},"OpenRouterRouterAttempt":{"properties":{"model":{"type":"string"},"provider":{"type":"string"},"status":{"type":"integer"}},"required":["model","provider","status"],"title":"RouterAttempt","type":"object"},"OpenRouterRouterParams":{"properties":{"quality_floor":{"format":"double","type":"number"},"throughput_floor":{"format":"double","type":"number"},"version_group":{"type":"string"}},"title":"RouterParams","type":"object"},"OpenRouterRoutingStrategy":{"enum":["direct","auto","free","latest","alias","fallback","pareto","bodybuilder","fusion"],"title":"RoutingStrategy","type":"string"},"OpenRouterSearchModelsServerToolConfig":{"description":"Configuration for the openrouter:experimental__search_models server tool","properties":{"max_results":{"description":"Maximum number of models to return. Defaults to 5, max 20.","type":"integer"}},"title":"SearchModelsServerToolConfig","type":"object"},"OpenRouterSearchQualityLevel":{"description":"How much context to retrieve per result. Applies to Exa and Parallel engines; ignored with native provider search and Firecrawl. For Exa, pins a fixed per-result character cap (low=5,000, medium=15,000, high=30,000); when omitted, Exa picks an adaptive size per query and document (typically ~2,000–4,000 characters per result). For Parallel, controls the total characters across all results; when omitted, Parallel uses its own default size.","enum":["low","medium","high"],"title":"SearchQualityLevel","type":"string"},"OpenRouterStopServerToolsWhen":{"description":"Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`.","items":{"$ref":"#/components/schemas/OpenRouterStopServerToolsWhenCondition"},"title":"StopServerToolsWhen","type":"array"},"OpenRouterStopServerToolsWhenCondition":{"description":"A single condition that, when met, halts the server-tool agent loop.","oneOf":[{"description":"Stop when the upstream model emits this finish reason (e.g. `length`).","properties":{"reason":{"type":"string"},"type":{"$ref":"#/components/schemas/OpenRouterStopServerToolsWhenFinishReasonIsType"}},"required":["type","reason"],"type":"object"},{"description":"Stop after a tool with this name has been called.","properties":{"tool_name":{"type":"string"},"type":{"$ref":"#/components/schemas/OpenRouterStopServerToolsWhenHasToolCallType"}},"required":["type","tool_name"],"type":"object"},{"description":"Stop once cumulative cost across the loop exceeds this dollar threshold.","properties":{"max_cost_in_dollars":{"format":"double","type":"number"},"type":{"$ref":"#/components/schemas/OpenRouterStopServerToolsWhenMaxCostType"}},"required":["type","max_cost_in_dollars"],"type":"object"},{"description":"Stop once cumulative token usage across the loop exceeds this threshold.","properties":{"max_tokens":{"type":"integer"},"type":{"$ref":"#/components/schemas/OpenRouterStopServerToolsWhenMaxTokensUsedType"}},"required":["type","max_tokens"],"type":"object"},{"description":"Stop after the agent loop has executed this many steps.","properties":{"step_count":{"type":"integer"},"type":{"$ref":"#/components/schemas/OpenRouterStopServerToolsWhenStepCountIsType"}},"required":["type","step_count"],"type":"object"}],"title":"StopServerToolsWhenCondition"},"OpenRouterStopServerToolsWhenFinishReasonIsType":{"enum":["finish_reason_is"],"title":"StopServerToolsWhenFinishReasonIsType","type":"string"},"OpenRouterStopServerToolsWhenHasToolCallType":{"enum":["has_tool_call"],"title":"StopServerToolsWhenHasToolCallType","type":"string"},"OpenRouterStopServerToolsWhenMaxCostType":{"enum":["max_cost"],"title":"StopServerToolsWhenMaxCostType","type":"string"},"OpenRouterStopServerToolsWhenMaxTokensUsedType":{"enum":["max_tokens_used"],"title":"StopServerToolsWhenMaxTokensUsedType","type":"string"},"OpenRouterStopServerToolsWhenStepCountIsType":{"enum":["step_count_is"],"title":"StopServerToolsWhenStepCountIsType","type":"string"},"OpenRouterTraceConfig":{"description":"Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations.","properties":{"generation_name":{"type":"string"},"parent_span_id":{"type":"string"},"span_name":{"type":"string"},"trace_id":{"type":"string"},"trace_name":{"type":"string"}},"title":"TraceConfig","type":"object"},"OpenRouterWebFetchEngineEnum":{"description":"Which fetch engine to use. \"auto\" (default) uses native if the provider supports it, otherwise Exa. \"native\" forces the provider's built-in fetch. \"exa\" uses Exa Contents API. \"openrouter\" uses direct HTTP fetch. \"firecrawl\" uses Firecrawl scrape (requires BYOK).","enum":["auto","native","openrouter","firecrawl","exa"],"title":"WebFetchEngineEnum","type":"string"},"OpenRouterWebFetchPluginId":{"enum":["web-fetch"],"title":"WebFetchPluginId","type":"string"},"OpenRouterWebFetchServerTool":{"description":"OpenRouter built-in server tool: fetches full content from a URL (web page or PDF)","properties":{"parameters":{"$ref":"#/components/schemas/OpenRouterWebFetchServerToolConfig"},"type":{"$ref":"#/components/schemas/OpenRouterWebFetchServerToolType"}},"required":["type"],"title":"WebFetchServerTool","type":"object"},"OpenRouterWebFetchServerToolConfig":{"description":"Configuration for the openrouter:web_fetch server tool","properties":{"allowed_domains":{"description":"Only fetch from these domains.","items":{"type":"string"},"type":"array"},"blocked_domains":{"description":"Never fetch from these domains.","items":{"type":"string"},"type":"array"},"engine":{"$ref":"#/components/schemas/OpenRouterWebFetchEngineEnum"},"max_content_tokens":{"description":"Maximum content length in approximate tokens. Content exceeding this limit is truncated.","type":"integer"},"max_uses":{"description":"Maximum number of web fetches per request. Once exceeded, the tool returns an error.","type":"integer"}},"title":"WebFetchServerToolConfig","type":"object"},"OpenRouterWebFetchServerToolType":{"enum":["openrouter:web_fetch"],"title":"WebFetchServerToolType","type":"string"},"OpenRouterWebSearchConfig":{"properties":{"allowed_domains":{"description":"Limit search results to these domains. Supported by Exa, Firecrawl, Parallel, and most native providers (Anthropic, OpenAI, xAI). Not supported with Perplexity. Cannot be used with excluded_domains.","items":{"type":"string"},"type":"array"},"engine":{"$ref":"#/components/schemas/OpenRouterWebSearchEngineEnum"},"excluded_domains":{"description":"Exclude search results from these domains. Supported by Exa, Firecrawl, Parallel, Anthropic, and xAI. Not supported with OpenAI (silently ignored) or Perplexity. Cannot be used with allowed_domains.","items":{"type":"string"},"type":"array"},"max_results":{"description":"Maximum number of search results to return per search call. Defaults to 5. Applies to Exa, Firecrawl, and Parallel engines; ignored with native provider search.","type":"integer"},"max_total_results":{"description":"Maximum total number of search results across all search calls in a single request. Once this limit is reached, the tool will stop returning new results. Useful for controlling cost and context size in agentic loops. Defaults to 50 when not specified.","type":"integer"},"search_context_size":{"$ref":"#/components/schemas/OpenRouterSearchQualityLevel"},"user_location":{"$ref":"#/components/schemas/OpenRouterWebSearchUserLocationServerTool"}},"title":"WebSearchConfig","type":"object"},"OpenRouterWebSearchEngine":{"description":"The search engine to use for web search.","enum":["native","exa","firecrawl","parallel"],"title":"WebSearchEngine","type":"string"},"OpenRouterWebSearchEngineEnum":{"description":"Which search engine to use. \"auto\" (default) uses native if the provider supports it, otherwise Exa. \"native\" forces the provider's built-in search. \"exa\" forces the Exa search API. \"firecrawl\" uses Firecrawl (requires BYOK). \"parallel\" uses the Parallel search API.","enum":["auto","native","exa","firecrawl","parallel"],"title":"WebSearchEngineEnum","type":"string"},"OpenRouterWebSearchPluginId":{"enum":["web"],"title":"WebSearchPluginId","type":"string"},"OpenRouterWebSearchPluginUserLocation":{"description":"Approximate user location for location-biased search results. Passed through to native providers that support it (e.g. Anthropic).","properties":{"city":{"nullable":true,"type":"string"},"country":{"nullable":true,"type":"string"},"region":{"nullable":true,"type":"string"},"timezone":{"nullable":true,"type":"string"},"type":{"$ref":"#/components/schemas/OpenRouterWebSearchPluginUserLocationType"}},"required":["type"],"title":"WebSearchPluginUserLocation","type":"object"},"OpenRouterWebSearchPluginUserLocationType":{"enum":["approximate"],"title":"WebSearchPluginUserLocationType","type":"string"},"OpenRouterWebSearchServerTool":{"description":"OpenRouter built-in server tool: searches the web for current information","properties":{"parameters":{"$ref":"#/components/schemas/OpenRouterWebSearchConfig"},"type":{"$ref":"#/components/schemas/OpenRouterWebSearchServerToolType"}},"required":["type"],"title":"OpenRouterWebSearchServerTool","type":"object"},"OpenRouterWebSearchServerToolType":{"enum":["openrouter:web_search"],"title":"OpenRouterWebSearchServerToolType","type":"string"},"OpenRouterWebSearchUserLocationServerTool":{"description":"Approximate user location for location-biased results.","properties":{"city":{"nullable":true,"type":"string"},"country":{"nullable":true,"type":"string"},"region":{"nullable":true,"type":"string"},"timezone":{"nullable":true,"type":"string"},"type":{"$ref":"#/components/schemas/OpenRouterWebSearchUserLocationServerToolType"}},"title":"WebSearchUserLocationServerTool","type":"object"},"OpenRouterWebSearchUserLocationServerToolType":{"enum":["approximate"],"title":"WebSearchUserLocationServerToolType","type":"string"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"x-comfy-router-model-id":"openrouter/chat-completions","x-comfy-input-schema-authored":true,"x-comfy-output-schema-authored":true}