From 35819e35a8f55425ffc23a3e901256cc22bad724 Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Mon, 4 May 2026 18:28:21 -0700 Subject: [PATCH 1/2] fix(spec): mark DeviceStats.index and NodeInfo.essentials_category as nullable (#13706) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(spec): mark DeviceStats.index and NodeInfo.essentials_category as nullable Two fields in openapi.yaml are declared as required/non-nullable but the Python implementation legitimately returns `null` for them, so any client that response-validates against the spec will fail. `DeviceStats.index` (used by GET /api/system_stats): - server.py emits `"index": device.index` unconditionally - For the CPU device (--cpu mode), `torch.device("cpu").index` is `None` - → JSON response includes `"index": null` for CPU devices `NodeInfo.essentials_category` (used by GET /api/object_info): - The V3 schema-based path (comfy_api/latest/_io.py:1654) unconditionally passes `essentials_category=self.essentials_category` into NodeInfoV1 and serializes via dataclasses.asdict(), so the key is always present - Schema's `essentials_category` defaults to `None` for nodes that don't set it in `define_schema` (e.g. the APG node) - → JSON response includes `"essentials_category": null` for those nodes - (The V1 path in server.py uses `hasattr` and so omits the key entirely when not set, but the V3 path is the one that produces nulls) Both fields keep their existing `required` status — they're always present in the response, the value is just nullable. Descriptions expanded to spell out when `null` is expected. * docs(spec): clarify essentials_category presence rules The previous description said "null for nodes that don't set ESSENTIALS_CATEGORY (V1)" — that's wrong. server.py:739-740 uses `hasattr` and OMITS the key when the V1 attribute isn't defined; null only happens if the attribute is explicitly set to None. Spell out all three legal shapes (string / null / absent) and which path produces which. --- openapi.yaml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 77d0e2318..3b602e0f6 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2347,7 +2347,12 @@ components: description: Device type (cuda, mps, cpu, etc.) index: type: number - description: Device index + nullable: true + description: | + Device index within its type (e.g. CUDA ordinal for `cuda:0`, + `cuda:1`). `null` for devices with no index, including the CPU + device returned in `--cpu` mode (PyTorch's `torch.device('cpu').index` + is `None`). vram_total: type: number description: Total VRAM in bytes @@ -2503,7 +2508,18 @@ components: description: Alternative search terms for finding this node essentials_category: type: string - description: Category override used by the essentials pack + nullable: true + description: | + Category override used by the essentials pack. The + `essentials_category` key may be present with a string value, + present and `null`, or absent entirely: + + - V1 nodes: `essentials_category` is **omitted** when the node + class doesn't define an `ESSENTIALS_CATEGORY` attribute, and + **`null`** if the attribute is explicitly set to `None`. + - V3 nodes (`comfy_api.latest.io`): `essentials_category` is + **always present**, and **`null`** for nodes whose `Schema` + doesn't populate it. # ------------------------------------------------------------------- # Models From 413e250ccd04d830c3fa27f8b1957885ea0b8e1b Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Mon, 4 May 2026 18:59:48 -0700 Subject: [PATCH 2/2] spec: add workflow_id / workflow_version_id to PromptRequest with x-runtime tag (#13709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds two optional, nullable UUID fields to PromptRequest for runtimes that wrap workflow execution in a workflow-version entity (the hosted-cloud runtime does this; local ComfyUI does not). Both fields are tagged `x-runtime: [cloud]` to mark them as runtime-specific — local ComfyUI returns `null` (or omits them entirely) and that's correct behavior, not drift. ## Why these fields belong in the OSS spec Hosted-cloud's frontend and backend share `openapi.yaml` as their single source of truth via auto-generated client types. Without the fields declared in the spec, the cloud runtime has to either: 1. Hand-edit a vendored copy of openapi.yaml (drift between vendor and upstream — unsustainable). 2. Maintain a separate cloud-only spec file (forks the contract, defeats the point of a shared OSS spec). Both options have been tried and both produce maintenance pain. The shape that scales is: cloud-only fields live in OSS spec under their intended path, declared nullable, with an explicit `x-runtime` tag so local-only readers can ignore them programmatically and human readers can see what each runtime populates. ## About the `x-runtime` extension This is the first use of `x-runtime` in this spec. Convention: - `x-runtime: [cloud]` — only the hosted-cloud runtime populates the field; local returns null or omits. - `x-runtime: [local]` — only local populates; cloud returns null. - Tag absent — both runtimes populate the field (the default). This is a vendor extension (`x-` prefix) and is ignored by spec validators that don't recognize it, including `kin-openapi`. Local clients reading the spec see two extra optional nullable fields, which is forward-compatible with all existing readers. ## What this does not change - No Python code changes. `PromptRequest` already accepts arbitrary optional fields (`extra_data: additionalProperties: true` on the same schema is a stronger guarantee). The Python server already silently accepts and ignores both fields today. - No required-fields change. Both fields stay outside `required`, so older clients that don't know about them keep validating. - No nullability widening on existing fields. ## Verification - YAML parses (`yaml.safe_load`). - `kin-openapi` `loader.LoadFromFile` accepts the modified spec. - `openapi3filter.ValidateRequest` on a PromptRequest with both fields set to `null`, set to a valid UUID, or omitted — all pass. --- openapi.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 3b602e0f6..30f85b6ad 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1999,6 +1999,26 @@ components: items: type: string description: List of node IDs to execute (partial graph execution) + workflow_id: + type: string + format: uuid + nullable: true + x-runtime: [cloud] + description: | + UUID identifying a hosted-cloud workflow entity to associate with this + job. Local ComfyUI doesn't track workflow entities and returns `null` + (or omits the field). The `x-runtime: [cloud]` extension marks this + as populated only by the hosted-cloud runtime; absence of the tag + means a field is populated by all runtimes. + workflow_version_id: + type: string + format: uuid + nullable: true + x-runtime: [cloud] + description: | + UUID identifying a hosted-cloud workflow version to associate with + this job. Local ComfyUI returns `null` (or omits the field). See + `workflow_id` above for `x-runtime` semantics. PromptResponse: type: object