Two issues raised against the per-prompt metadata registry:
1. Client-supplied prompt_id can collide (post_prompt accepts the id
verbatim). With a flat dict-keyed registry, the second submission
clobbered the first and a single unregister could erase metadata still
needed by the other prompt. Now stored as a LIFO stack per prompt_id —
most recent registration wins on merge, unregister pops one entry, the
key is dropped only when the stack drains.
2. BinaryEventTypes.TEXT (send_progress_text) bypasses the metadata merge
because the payload is bytes, and the wire format has no prompt_id /
workflow_id field. The merge can't fix this without a wire-format
change + frontend feature flag, which is out of scope for FE-745. Inside
scope: default the sid to PromptServer.client_id so other clients no
longer silently receive untagged text frames. Cross-tab isolation
inside a single client still depends on the wire-format follow-up.
- comfy_execution/metadata.py: registry is dict[str, list[PromptMetadata]];
merge_prompt_metadata reads stack[-1]; new resolve_progress_text_sid
helper extracted so the routing default is unit-testable without the
full server import chain.
- server.py: register_prompt_metadata appends to the stack;
unregister_prompt_metadata pops; get_prompt_metadata returns a copy of
the top entry; send_progress_text routes through resolve_progress_text_sid.
- tests: collision LIFO behavior, sid resolution default, and the existing
merge tests updated to the stack shape. 16 new assertions in this file,
104/104 pass overall.
PR #13684 added workflow_id directly to ~9 dict literals across execution.py,
progress.py and main.py, along with executor.workflow_id and
server.last_workflow_id state. It was reverted because the execution layer
should not know about workflow concepts and because a finally-clear race
emitted workflow_id=None on the terminal "executing" frame.
Instead, register per-prompt metadata on PromptServer at submission time
and merge it onto outbound WebSocket payloads inside send_sync. The merge
keys off prompt_id (already present on every execution event), so
execution.py stays workflow-agnostic. Metadata is unregistered in main.py's
queue loop AFTER the terminal executing send, which structurally removes
the race.
- New comfy_execution/metadata.py: PromptMetadata TypedDict +
build_prompt_metadata + merge_prompt_metadata helpers.
- PromptServer: prompt_metadata registry (lock-protected), register on
post_prompt, merge in send_sync, expose get_prompt_metadata.
- jobs.py: extracted extract_workflow_id with strict isinstance guards;
_extract_job_metadata delegates.
- main.py: try/finally around the queue iteration; unregister after the
terminal "executing: {node: None}" send.
- execution.py PromptQueue: drop registry entries on wipe_queue /
delete_queue_item so cancellations don't leak.
- progress.py: look up workflow_id from the server registry for the
per-node nested copies and the binary preview metadata, matching #13684's
wire shape so the frontend needs no changes.
- Tests: tests-unit/server_test/test_prompt_metadata.py covers the merge,
the passthrough cases (no prompt_id, unknown prompt_id, binary payloads),
and the terminal-frame race regression.
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
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.
* Initial HiDream01-image support
* Cleanup nodes
* Cleaner handling of empty placeholder models
* Remove snap_to_predefined, prefer tooltip for the trained resolutions
* Add model and block wrappers
* Fix shift tooltip
* Add node to work around the patch tile issue
Experimental, runs multiple passes with the patch grid offset and blends with various different methods.
* Qwen35 vision rotary_pos_emb cast fix
* Fix embedding layout type
* Some small optimizations
* Cleanup, don't need this fallback
* Prefix KV cache, cleanup
Bit of speed, reduce redundant code
* Get rid of redundant custom sampler, refactor noise scaling
Our existing lcm sampler is mathematically same, just added the missing options to it instead and a node to control them. Refactored the noise scaling and fix it for the stochastic samplers, add a generic node to control the initial noise scale.
* Update nodes_hidream_o1.py
* Fix some cache validation cases
* Keep existing sampling params
* Remove redundant video vision path
* Replace some numpy ops with torch
* Fx RoPE index for batch size > 1
* Prefer torch preprocessing
* Rename block_type to be compatible with existing patch nodes
* Fixes and tweaks