These two fields were added recently to the Asset schema as nullable
integers, with the intent of exposing original image dimensions for FE
consumers (cloud-side thumbnailing makes naturalWidth/Height return
the wrong size for an image card's dimension label).
The implementation effort that consumes them subsequently converged on
a different shape — dimensions nested under the existing free-form
`metadata` JSON field as `{kind: "image", width, height}` — to avoid
introducing type-specific flat fields on the canonical Asset shape,
and to leave room for forward-compatible additions (video duration,
fps, etc.) without further schema churn.
This removes the now-unused top-level fields so the spec reflects the
agreed direction. No other schema definitions reference these fields
directly: AssetCreated, AssetUpdated, etc. inherit Asset via allOf and
do not redefine them.
The runtime ingest implementation that would have populated these
fields was not yet shipped, so no clients are relying on the
top-level shape.
Co-authored-by: Alexis Rolland <alexisrolland@hotmail.com>
Mark the uploadMask operation as deprecated and point clients at
/api/upload/image. The mask-compositing behavior the endpoint provides
(alpha-compositing the supplied mask onto an original_ref image) is now
expected to happen client-side, with the composited result uploaded
through the unified /api/upload/image path.
The endpoint continues to function for older clients; no runtime
behavior changes ship with this commit. Only the OpenAPI annotation
and the human-facing description are updated.
* Move detection category under image category
* Add missing categories
* Move detection nodes to detection category
* Move save nodes to image root catefory
* Rename postprocessors
* Move mask category under image
* Move guiders category to parent level at root of sampling category
* Move custom_sampling category to parent level at the root of sampling category
* Modify description of LoRA loaders
* Fix node id SolidMask
* Move VOID Quadmask under image/mask
* Group compositing nodes under image/compositing
* Move load image as mask to image category for consistency with other load image nodes
* Align display name with Load Checkpoint
* Move dataset category under training category
* Rename Number Convert to Conver Number (verb first)
* Rename Canny node
* Revert wanBlockSwap + description
* Add description to RemoveBackground node
* Revert category update of dataset
Addresses comfyanonymous's review nit on PR #13905. The store is touched
from three threads — the aiohttp event loop (``register`` via
``post_prompt``), the worker thread (``unregister`` via the
``prompt_worker`` try/finally and ``execution_error`` paths), and any
thread that fires ``send_sync`` (``inject``). Individual ``dict``
operations are GIL-atomic but ``register``'s ``len -> pop -> setitem``
and ``inject``'s ``get -> {**a, **b}`` are multi-step compounds whose
interleaving without a lock is racy. A single ``threading.Lock`` keeps
the FIFO cap honest and snapshots the envelope under the lock before
the spread runs.
Adds a stress-test that runs concurrent register/unregister/inject for
100 ms across five threads and asserts no exception escapes and the
capacity bound is held.
Switch the wire shape from nested ``metadata: {workflow_id: ...}`` to
spreading the envelope's keys directly onto each event payload. The
contract on the websocket is now identical to the prior workflow-id-on-
events work — consumers read ``event.workflow_id`` directly — but the
core executor still has no concept of workflow scope; the envelope is
captured at submission and decorated at the server transport layer.
Server-emitted fields always win on collision (``{**envelope, **d}``):
a misbehaving client cannot shadow ``prompt_id``, ``node``, etc. by
stamping the same key in their submission envelope.
Addresses review feedback on the per-prompt metadata envelope:
- Sanitize at the boundary: reject envelopes larger than 16 keys, keys
over 64 chars, values over 256 chars, or anything that isn't a flat
``dict[str, str]``. Logs a warning so abuse is observable. Stops a
malicious client from inflating broadcast volume by stamping a 10 MB
metadata blob onto every WS event.
- Cap the in-memory store at 4096 concurrent envelopes with FIFO
eviction. Acts as a backstop if any cleanup hook is skipped.
- Drop envelopes when prompts are cancelled before reaching the worker:
``PromptQueue.wipe_queue`` and ``delete_queue_item`` now call
``server.unregister_prompt_metadata`` for every removed item.
- Drop envelopes on hard execution failures: the worker now wraps
``e.execute()`` in ``try/finally``, so an uncaught exception in
execution no longer leaks the envelope.
- Guard the WS reconnect handler: only include ``prompt_id`` in the
``executing`` payload when ``last_prompt_id`` is set, so clients
with strict schemas (zod ``prompt_id: zJobId``) don't reject the
message with a null id.
- Extract a ``PromptMetadataStore`` class that owns the dict and the
bounds, so ``PromptServer`` becomes a thin delegating layer and the
full register/inject/unregister cycle (plus FIFO eviction and
sanitization) is unit-tested without torch.
44 tests passing; ruff clean on all touched files.
Replaces the workflow_id-on-every-event approach (#13684, reverted in
#13901) with a generic metadata envelope captured at submission and
injected at the server-side send chokepoint.
- POST /prompt accepts an opaque ``extra_data.metadata`` dict (falls
back to synthesizing ``{"workflow_id": <id>}`` from
``extra_pnginfo.workflow.id`` so existing frontends keep working).
- ``PromptServer`` owns a ``prompt_id -> metadata`` map populated at
submission, drained when the prompt finishes. ``send_sync`` injects
the envelope into any outbound payload that carries a ``prompt_id``,
including the ``(preview_image, metadata_dict)`` tuple used by
``PREVIEW_IMAGE_WITH_METADATA``. WS reconnect path carries it too.
- Pure helpers live in ``app/prompt_metadata.py`` so the execution
layer never depends on workflow concepts and the helpers can be
unit-tested without torch.
Execution layer (``execution.py``, ``comfy_execution/*``) and the jobs
API are unchanged. Backward compatible: existing fields and shapes are
preserved, only an additional ``metadata`` field is attached when
present.
Split GLB save logic out of nodes_hunyuan3d.py into a new nodes_save_3d.py, and extend the writer to support UVs, per-vertex colors, and embedded baseColor textures.
Extend the MESH type with optional uvs, vertex_colors, and texture fields so meshes can carry texture data through the graph.
Add pack_variable_mesh_batch / get_mesh_batch_item helpers and switch VoxelToMesh / VoxelToMeshBasic to use them so batches with differing vertex/face counts no longer fail at torch.stack.
The /ws path uses HTTP 101 (Switching Protocols), which is the correct
response for a WebSocket upgrade but not a 2xx. The built-in
operation-success-response rule fires as a false positive because
OpenAPI 3.x has no native WebSocket support.
Add a path-scoped override in .spectral.yaml to disable the rule for
/ws only, leaving it active for all other operations.
* Mark deprecated cloud-runtime endpoints in openapi.yaml
Add five cloud-runtime FE-facing endpoints to the OSS spec with
deprecated: true and standardized description prefixes:
- GET /api/history_v2 — superseded by GET /api/jobs
- GET /api/history_v2/{prompt_id} — superseded by GET /api/jobs/{prompt_id}
- GET /api/logs — returns static placeholder; no real log data
- GET /api/viewvideo — alias of GET /api/view for legacy video playback
- GET /api/job/{job_id}/status — superseded by GET /api/jobs/{job_id}
Each endpoint is tagged x-runtime: [cloud] and follows the same
deprecation convention established for /api/history endpoints.
Co-authored-by: Matt Miller <MillerMedia@users.noreply.github.com>
* fix(spec): consolidate duplicate path entries on deprecated cloud-runtime endpoints
Previous commit added new path entries with `deprecated: true` for
`/api/job/{job_id}/status`, `/api/history_v2`, `/api/history_v2/{prompt_id}`,
`/api/logs`, and `/api/viewvideo`, but the canonical entries already existed
elsewhere in the file. Result: 5 duplicate path keys (Spectral parser errors),
and the deprecation flag did not land on the operations that FE clients
consume by operationId.
This commit moves `deprecated: true` plus the standardized "Deprecated."
description onto the canonical operations (`getCloudJobStatus`, `getHistoryV2`,
`getHistoryV2ByPromptId`, `getCloudLogs`, `viewVideo`) and removes the
duplicate entries. Operation IDs and response schemas are unchanged.
Spectral lint passes with zero new warnings.