From 331b17f6a3d6ec181f643ee1321e8ff7b1a2e527 Mon Sep 17 00:00:00 2001 From: bigcat88 <13381981+bigcat88@users.noreply.github.com> Date: Mon, 9 Nov 2026 12:18:52 +0000 Subject: [PATCH] chore: sync vendored Comfy Router spec from cloud@525af8ca --- spec/router-openapi.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/router-openapi.yaml b/spec/router-openapi.yaml index 247be6b..a4e13f4 100644 --- a/spec/router-openapi.yaml +++ b/spec/router-openapi.yaml @@ -202,7 +202,7 @@ paths: /v2/models/{provider}/{model}/estimate: post: summary: Price a model call before running it, without running it. - description: 'Returns a pre-flight estimate, in US dollars, of what running this body on this model will cost, priced at Comfy''s standard list price (a model billed the cost its vendor reports is estimated from the vendor''s published price list instead). It does not reflect contract or customer-specific rates: a workspace with negotiated pricing is quoted the list price and charged its contract rate, and `source: exact` then means exact at list price, not that workspace''s charge. It is an estimate, not the final charge: the settled charge in your workspace''s usage and billing records is what you pay. The body is validated against the model''s input schema first, as a default run (no `strict_mode`, no `reject_unknown_fields`) validates it, so a body that fails the model''s schema is the same `422` here as on the run; nothing is dispatched to a provider and nothing is charged. The answer is not a price lock: it is priced at the rates in force at `pricing_as_of`, and a run is charged at the rates in force when it is rated. If estimates are switched off for a deployment the route answers `403` with `error_type: not_enabled`; a model Router cannot run yet answers the same `403` with the run route''s own `detail`, so read `detail` to tell the two apart. For a request that names `model_provider`, or a multipart body Router sends to a sibling operation, this route can price a different body than the one dispatched and can still label that figure `exact`, and a caller cannot tell when a multipart body is sent to a sibling operation. So for those calls there is no accurate pre-flight quote, and `source` on this route''s answer does not describe the run, even when it reads `exact`. The `estimate` on the queued submit''s `201` is priced on the dispatched body, but it is not a pre-flight price: it arrives only after the run is admitted and queued, and that run is charged unless it is cancelled before dispatch.' + description: 'Returns a pre-flight estimate, in US dollars, of what running this body on this model will cost, priced at Comfy''s standard list price (a model billed the cost its vendor reports is estimated from the vendor''s published price list instead). It does not reflect contract or customer-specific rates: a workspace with negotiated pricing is quoted the list price and charged its contract rate, and `source: exact` then means exact at list price, not that workspace''s charge. It is an estimate, not the final charge: the settled charge in your workspace''s usage and billing records is what you pay. The body is validated against the model''s input schema first, as a default run (no `strict_mode`, no `reject_unknown_fields`) validates it, so a body that fails the model''s schema is the same `422` here as on the run; nothing is dispatched to a provider and nothing is charged. The answer is not a price lock: it is priced at the rates in force at `pricing_as_of`, and a run is charged at the rates in force when it is rated. If estimates are switched off for a deployment the route answers `403` with `error_type: not_enabled`; a model Router cannot run yet answers the same `403` with the run route''s own `detail`, so read `detail` to tell the two apart. The body is priced as Router would dispatch it: translated for the `model_provider` leg it names and retargeted to the operation it runs on, in the same order as the `estimate` on the queued submit''s `201`. That `estimate` is not a pre-flight price, though: it arrives only after the run is admitted and queued, and that run is charged unless it is cancelled before dispatch.' operationId: estimateRouterModelCost tags: - Comfy Router @@ -246,6 +246,8 @@ paths: $ref: '#/components/responses/RouterRateLimited' '503': $ref: '#/components/responses/RouterRequestUnavailable' + '504': + $ref: '#/components/responses/RouterRequestError' /v2/models/{provider}/{model}/openapi.json: get: summary: Read one partner model's input and output schemas as an OpenAPI document. @@ -356,6 +358,8 @@ paths: $ref: '#/components/responses/RouterQueueSubmitTooManyRequests' '503': $ref: '#/components/responses/RouterRequestUnavailable' + '504': + $ref: '#/components/responses/RouterRequestError' /v2/models/{provider}/{model}/requests/{request_id}: get: summary: Collect the result of one submitted request. @@ -535,7 +539,7 @@ components: example: unknown RouterCostEstimate: type: object - description: 'A pre-flight estimate of what this call will cost, in US dollars, priced before dispatch at Comfy''s standard list price (or, for a model billed the cost its vendor reports, estimated from the vendor''s published price list). It does not reflect contract or customer-specific rates: a workspace with negotiated pricing is quoted the list price and charged its contract rate, and `source: exact` then means exact at list price, not that workspace''s charge. It is not the final charge: the settled charge in your workspace''s usage and billing records is what you pay. `X-Comfy-Credits-Used`, reported after the run, is a rounded post-hoc figure, not a receipt. `source` says how much to trust the number: `exact` carries `amount`; `free` carries `amount` "0" (the rate card prices this request at zero); `estimated` carries `min_amount` and `max_amount` and no `amount`; `unknown` carries neither and a `reason`. Never read an absent `amount` as free. Not a price lock: see `pricing_as_of`.' + description: 'A pre-flight estimate of what this call will cost, in US dollars, priced before dispatch at Comfy''s standard list price, or — for a model billed the cost its vendor reports — from the vendor''s published price list. For that vendor-reported case, `source: exact` is returned only for a small opted-in set of models, and only when the published price list fully determines the figure (every price-driving field was stated, or left at a default that cannot change it); every other vendor-reported quote is `estimated`, including some the list would fully determine. Either way the run is still billed the amount the vendor reports after it completes, never the quoted figure verbatim. It does not reflect contract or customer-specific rates: a workspace with negotiated pricing is quoted the list price and charged its contract rate, and `source: exact` then means exact at list price, not that workspace''s charge. It is not the final charge: the settled charge in your workspace''s usage and billing records is what you pay. `X-Comfy-Credits-Used`, reported after the run, is a rounded post-hoc figure, not a receipt. `source` says how much to trust the number: `exact` carries `amount`; `free` carries `amount` "0" (the rate card prices this request at zero); `estimated` carries `min_amount` and `max_amount` and no `amount`; `unknown` carries neither and a `reason`. Never read an absent `amount` as free. Not a price lock: see `pricing_as_of`.' required: - source - currency @@ -597,7 +601,7 @@ components: $ref: '#/components/schemas/RouterErrorType' upstream_detail: type: string - description: A bounded, sanitized reason the model provider gave for rejecting the request, present only when `error_type` is `invalid_input` and `X-Comfy-Upstream-Status` is a provider `4xx` or `2xx` - i.e. the provider refused the request as malformed and said why. Usually that status is a `4xx`; it is a `2xx` for a provider that reports a rejected generation inside a success envelope (a BytePlus failed-task poll is HTTP `200` with the reason in its body). Absent on every other failure, including provider `5xx`, transport failures, content-policy refusals and any refusal Router raised about itself. It mirrors the `X-Comfy-Upstream-Detail` header. + description: 'A bounded, sanitized reason the model provider gave for rejecting the request, present only when `error_type` is `invalid_input` and `X-Comfy-Upstream-Status` is a provider `4xx` or `2xx` - i.e. the provider refused the request as malformed and said why. Usually that status is a `4xx`; it is a `2xx` for a provider that reports a rejected generation inside a success envelope (a BytePlus failed-task poll is HTTP `200` with the reason in its body). Absent on every other failure, including provider `5xx`, transport failures, content-policy refusals and any refusal Router raised about itself. It mirrors the `X-Comfy-Upstream-Detail` header. The queued collect (`GET /v2/models/{provider}/{model}/requests/{request_id}`) of a run that ended `invalid_input` carries the same reason in this field on its first collect, which then deletes it from the request: a later collect normally answers the same `error_type` and `detail` without it, so read it from the first collect. That read sends neither header.' refusal_subject: type: string description: 'Which input or output a content-policy refusal was about, as a Router-level closed vocabulary: `input`, `output`, `input_text`, `input_image`, `input_video`, `input_audio`, `output_text`, `output_image`, `output_video`, `output_audio`. The bare `input` / `output` values name the side when the provider did not name a modality. Present only when `error_type` is `content_policy_violation` and the provider named the refused subject with a machine-readable code; absent otherwise. Never provider text. Named today for BytePlus, Runway, BFL, Gemini, Veo, Vertex, xAI and Wan refusals, and for the MiniMax Router''s Nano Banana legs'' Gemini refusals; a provider whose refusal does not say which side it was about leaves it absent. It mirrors the `X-Comfy-Refusal-Subject` header.'