Commit Graph
112 Commits
Author SHA1 Message Date
benjcooley 97ff14ef4f feat: enforce API V2 runtime profiles 2026-08-31 13:26:00 -07:00
benjcooley 4c665f3263 Expand secure V2 SDK surface 2026-08-31 12:50:58 -07:00
benjcooley ed6abc963d Make comfy_api importable without ComfyUI core 2026-08-31 12:49:46 -07:00
benjcooley 58f175c470 feat(sdk): transport unchanged V2 node values 2026-08-31 12:49:46 -07:00
benjcooley 19ae4ffaf9 feat(io): publish MAX_RESOLUTION on the io surface
Pack schemas use it for input bounds, and the module that has always
defined it (nodes.py) is a host module a sandboxed pack cannot import.
Same value by definition: 16384 is frozen into every workflow that
ever serialized a bound.
2026-08-31 12:49:46 -07:00
benjcooley dc2e9ac1ec feat(sdk): model transforms, preview/profiling surfaces, structured-vs-live ref boundary
The V2 additions the KJNodes completion needed on the core side:

- _model_transforms: the closed, core-owned transform vocabulary
  behind ModelRef.patch — 29 named transforms, declaratively
  parameterized, validated host-side, immutable and stacking. No
  function ever crosses the boundary; a pack cannot register one.
- structured-vs-live split: value()/from_value() only on structured
  data refs (LATENT, AUDIO, TRACKS...). MODEL/CLIP/VAE/asset refs are
  handles in every execution mode — in-process identity resolution no
  longer hands a live model to node code.
- preview overrides (tiny-VAE, LTX factors), triton VAE seam, memory
  attention, and profiling surfaces backing the corresponding closed
  brokers in the overlay.
- torch_compile/model_patcher/model_management: compiled-view
  aliasing recognized by the model manager (no double-counted
  weights); shared state-dict loading path so the native loader and
  the V2 broker cannot drift.
2026-08-31 12:49:46 -07:00
benjcooley 98cfc5fd73 feat(sdk): handle ops for live engine objects; host-authoritative refs
VaeRef.decode/encode, ClipRef.tokenize/encode_from_tokens_scheduled/encode,
CondRef.combine/concat, with in-process implementations behind the existing
named-op registry so an overlay extends the vocabulary without touching the
contract.

These keep the old API's shape on purpose — you still write vae.decode(latent)
— and change only what the call means: the node holds a handle, awaits, and the
decode runs on the trusted plane against weights it never sees. That is what
lets a node DECLARE a VAE input and still be sandboxable. Compatible in shape so
conversion is mechanical across a corpus nobody here maintains; different in
substance so a converted node is sandboxable by construction.

Two mirroring defects fixed before shipping: encode() sliced its input to three
channels (core's VAEEncode does not, so it silently dropped alpha), and ClipRef
offered only a combined encode(text) (CLIPTextEncodeSDXL builds one token dict
from two prompts, and the ACE nodes pass a dozen tokenizer kwargs, so the
collapse made both inexpressible).

InProcessRefResolver now records a ref's kind at creation and checks it at
resolve. Ref tokens cross as {kind, id, cls} and the host rebuilt from what
arrived, so the holder chose its own ref's type: an ImageRef id could be
presented as a VaeRef. Unguessable ids already stopped a guest reaching a handle
it was never given; possessing a handle is not the same as labelling it.

Release is explicit, not collected. InProcessRefResolver.clear() drops the
table's strong references at a known point, called from execution.py in a
finally so it also covers the path where the node raised or its guest died —
which is exactly when nothing else will run. A ref table can hold multi-gigabyte
tensors, and refcount timing neither crosses a process boundary nor is bounded
under reference cycles.

OpsProvider.apply is annotated (op, subject: Ref, params) -> Any; it claimed
ImageRef in and out while handle ops take a VaeRef and may return a LatentRef,
a CondRef, or a plain token dict.
2026-08-31 12:49:46 -07:00
benjcooley c4e665118e feat(sdk): live engine objects cross the seam as refs; nodes declare permissions
Two generic gaps that blocked an out-of-process node from being a sampler.

1. wrap_inputs only wrapped tensors and latents. A MODEL or CONDITIONING is a
   live engine object, so it passed straight through — and an out-of-process
   backend cannot serialize a ModelPatcher, so any node taking one simply could
   not run in a guest. The rule is now by capability rather than an enumerated
   type list: a value that can cross as data does, and anything else becomes a
   handle. That is the correct boundary rule anyway — objects do not cross,
   handles do — and it is what lets a node take a MODEL and still run isolated.

2. ExecutionPlan.permissions was never populated, so the seam could not tell a
   backend what a node needs. A node now declares SDK_PERMISSIONS and the seam
   copies it onto the plan. Declaring is not granting: the backend decides, and
   an out-of-process one still gates every call at the wire. Nodes that declare
   nothing — the overwhelming majority — get nothing.

Behaviour-preserving in-process: 54 core seam tests and 26 overlay tests pass.
2026-08-31 12:49:46 -07:00
benjcooley 6f4b46a204 fix(sdk): unwrap_outputs must preserve ui/expand/block_execution
`unwrap_outputs` rebuilds a node's NodeOutput in order to swap output refs back
for real objects. It rebuilt it from the results alone — `NodeOutput(*resolved)`
— silently discarding `ui`, `expand` and `block_execution`.

The practical effect: no SDK_REFS node could be an output node. ComfyUI only
emits the `executed` websocket event, the one that delivers a node's results to
the frontend, for nodes that return ui data (`if len(output_ui) > 0`). So a
converted PreviewImage-style node executed perfectly and then displayed
nothing, with no error anywhere to explain it. `expand` (subgraph expansion)
and `block_execution` were lost the same way.

Resolving refs is a transport concern and has no business changing what the
node said. Generic fix, not specific to any backend: it applies equally to the
in-process path.
2026-08-31 12:49:46 -07:00
benjcooley 1684d15089 feat(sdk): generic image.op(name, **params) transport — op vocabulary is data, not API surface
Replaces enumerated invert/scale methods on OpsProvider with generic dispatch:
apply(op, image, params) + supports(op) + a built-in registry {invert, scale}
+ register_op. ImageRef.op(name, **params) is the untyped transport seam;
invert()/scale() remain as built-in convenience. Adds OpNotSupported (carries
the capability name) so a node can fall back to the raw tier. An overlay now
extends the op vocabulary without touching OSS core.

Statically-typed op methods live on the secure-lib side (per guidance), not
here — core stays a generic seam.
2026-08-31 12:49:46 -07:00
benjcooley 342b12ab6d feat(sdk): execution seam carries the work unit — plan.inputs/node_module, dispatch(plan, local_call, runtime)
Generic out-of-process enablement: the ExecutionPlan now ships the node's
module spec and ref-wrapped inputs, and dispatch receives the per-node host
runtime (refs/ctx/ops) so an external backend can execute the node elsewhere
and broker guest calls against the same ref table. In-process default ignores
all of it; legacy nodes unaffected (seam tests green).
2026-08-31 12:49:46 -07:00
benjcooley cf167e2b4f feat(sdk): ops-first asset interface — OpsProvider seam, SDK_REFS marshaling, raw() escape hatch
Nodes operate on assets (image.invert()) and never receive buffers; compute
runs on the trusted plane via the OpsProvider seam. Raw buffer access becomes
a permissioned, discouraged escape hatch (raw(); forces dedicated tier under
the overlay). The execution seam wraps heavy inputs as refs for SDK_REFS
nodes and resolves output refs for downstream legacy nodes. The .pyi contract
no longer imports torch.

POC stand-ins (interface debt, ledgered in the overlay repo DEBT.md):
invert/scale enumerated on OpsProvider; duck-typed wrap_inputs; SDK_REFS
class-attr opt-in.
2026-08-31 12:49:46 -07:00
benjcooley 1f07da19ac feat(sdk): wire execution seam + .pyi contract + POC node & test
- execution.py: route V3 node dispatch through providers.execution_backend
  with a behavior-preserving local_call closure (exact sync/async-task
  semantics retained); bind per-node ctx+refs inside the invocation scope so
  the concurrent-async path is correct. V1 nodes untouched. Default backend =
  in-process => byte-identical to today.
- comfy_api/latest/_sdk_public.pyi: authoritative type contract for the secure
  SDK (backend analog of the frontend comfy-api.d.ts): refs, ctx + domains,
  ctx() accessor; host/overlay seam separated.
- custom_nodes/comfy_sdk_poc: SandboxInvert POC node authored to the SDK.
- tests-unit: seam regression (sync+async SDK nodes through the real engine;
  provider-swap intercept). Verified PASS.
2026-08-31 12:49:46 -07:00
benjcooley ccf67659b1 feat(sdk): custom-node SDK seam — refs, ctx, provider registry, overlay loader
Establishes the open-source 'key Python API' for secure custom nodes:
- comfy_api/latest/_sdk.py: opaque typed refs (ImageRef/ModelRef/AssetRef...),
  a brokered ctx surface (assets/progress/scratch/events/storage + stubs),
  and a Providers registry (ExecutionBackend/CtxProvider/RefResolver) with
  in-process DEFAULTS so OSS behaves exactly as today (a ref wraps the real
  object; ctx is a passthrough; zero-copy, zero-overhead).
- load_overlay(): env-var (COMFY_OVERLAY_MODULE) path loader that lets a
  separable, proprietary cloud overlay register isolated implementations at
  the seam. Unset => pure OSS. Wired guarded into main.startup.
- comfy_api/v0_0_3: new API version exposing sdk; registered in version_list.

Nothing isolation-specific lives in OSS: this is the seam, not the engine.
2026-08-31 12:49:36 -07:00
Terry Jia f938505952 feat: add VideoTrim and VideoCrop nodes with VIDEO_EDIT widget inputs (#15637) 2026-08-30 15:54:48 -07:00
Alexander Piskun d8e7bbc9d5 fix(video): remux HEVC to mp4/mov as hvc1 via hevc_mp4toannexb (#15809) 2026-08-26 20:28:50 -04:00
comfyanonymous 9db05e0e1f Add colorspace option and change bit_depth to a combo on CreateVideo. (#15810) 2026-08-22 21:07:29 -04:00
Jukka Seppänen 0e65cb9071 feat: Support Pixal3d and TRELLIS2 (CORE-278) (CORE-199) (CORE-236) (CORE-312) (#14718) 2026-08-21 20:32:25 -04:00
comfyanonymous dcbcf8c2e1 Support HDR video saving, AV1 codec, mkv and webm. (#15741) 2026-08-20 19:29:20 -04:00
Terry Jia 8fadc7b5be [Partner Nodes] feat: ImageCompositor node with layer-state compositing, layer from bbox and Seedream Layer Separation node (#15317) 2026-08-07 13:25:37 -07:00
comfyanonymous 9a9fdb10ed Harden some nodes against potential issues related to combos. (#15277) 2026-08-03 23:55:13 -04:00
comfyanonymous 2881e61610 Store mp4 metadata at the beginning of the file when possible. (#15195) 2026-08-01 03:21:28 -04:00
comfyanonymous 235b466a0c Add crf option to save video node. (#15191) 2026-08-01 00:27:48 -04:00
Alexander Piskun cc6b352511 fix(Video): stream the video transcode instead of buffering every frame in RAM (CORE-353) (CORE-351) (#14813) 2026-07-15 15:23:43 +08:00
Alexander PiskunandAlexis Rolland a3020f107e fix(Video): don't crash on videos with undecodable audio streams (#14746)
* fix(Video): don't crash on videos with undecodable audio streams

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* Update comfy_api_nodes/util/upload_helpers.py

---------

Signed-off-by: bigcat88 <bigcat88@icloud.com>
Co-authored-by: Alexis Rolland <alexisrolland@hotmail.com>
2026-07-07 15:59:49 +03:00
Terry Jia dac4ea3a80 feat: Bounding boxes canvas and Ideogram JSON prompt (#14537) 2026-06-25 22:34:09 +08:00
John Pollock 5db51b76b4 Fix odd-height crash and edge bleed in unaligned-width image/video decode (#14491)
a1d95f3f padded the decode width to the next multiple of 32 with the pad filter to fix libswscale's float YUV->GBR edge corruption, but kept the pad target height equal to the source height. The pad filter requires the target height to be a multiple of the input's vertical chroma subsampling factor, so a chroma-subsampled input such as yuv420p (the format the gbrpf32le float branch decodes) with an odd height makes the filter round the target below the input height and fail to configure: 'Padded dimensions cannot be smaller than input dimensions' (Errno 22). This is reachable from LoadImage, which routes static images through VideoFromFile, on a lossy WebP whose width is not a multiple of 32 and whose height is odd.

The pad filter also fills the added border with black, and chroma upsampling bleeds that black into the cropped edge of every unaligned-width subsampled decode.

Pad both axes to the next multiple of 32 (32 is a multiple of every vertical subsampling factor, including yuv410p's 4 that a plain even rounding misses) and run fillborders mode=smear to replicate the real edge into the padding so it never bleeds into the cropped output, then crop both axes back to the source size. Aligned-width and uint8 paths run the identical to_ndarray call as before and are byte-identical to master; only unaligned-width subsampled inputs change, from a crash or edge artifact to a clean, deterministic decode.
2026-06-15 20:23:09 -07:00
John Pollock a1d95f3f82 Fix nondeterministic video decode at unaligned widths (CORE-299) (#14438) 2026-06-14 08:58:48 +08:00
Alexander Piskun fe54b5e955 Add 10-bit video support (#14452)
Create Video gets a bit_depth option (8-bit/10-bit); the selected depth is carried by the video and applied when it gets encoded. Save Video and Video Slice now keep the source bit depth instead of always quantizing to 8-bit, so 10-bit videos stay 10-bit. 10-bit uses h264 with the yuv420p10le pixel format,so there's no new codec or container.

Signed-off-by: bigcat88 <bigcat88@icloud.com>
2026-06-13 16:05:25 +03:00
Robin Huang bc5f8eca3b Add Comfy-Usage-Source pass-through for API node requests (#14404) 2026-06-12 09:20:44 +08:00
Terry Jia 2ef2cf1a7c feat: add PreviewGaussianSplat + PreviewPointCloud nodes (#14194) 2026-06-05 12:30:58 -07:00
Alexis Rolland ab0d8a9203 Consolidate audio nodes into SaveAudioAdvanced node (CORE-202) (#13871) 2026-06-04 19:29:41 -07:00
Alexander Piskun 0b610bd63a [Partner Nodes] fix: respect VideoSlice trim when resizing videos (#14213) 2026-06-01 09:09:57 -07:00
Jukka Seppänen c37d2a0dac feat: Add gaussian splat nodes (#14190) 2026-05-31 11:47:29 -07:00
Terry JiaandAlexis Rolland 08e93a31a3 feat: add Preview3DAdvanced node (#14175)
Co-authored-by: Alexis Rolland <alexisrolland@hotmail.com>
2026-05-30 17:57:36 -04:00
Terry Jia bb560036b9 feat(io): add File3DPLY / File3DSPLAT / File3DSPZ / File3DKSPLAT types (#14185) 2026-05-30 09:39:26 -04:00
Terry Jia e7214d78ee feat: add model_info output to Load3D node (#14144) 2026-05-29 00:06:00 -07:00
Terry Jia 26aad73cd7 refactor: drop rotation from Load3DCamera (#14159) 2026-05-28 17:42:47 -07:00
Terry Jia 8ed308bcde feat: add camera intrinsics fields to Load3DCamera info (#14143) 2026-05-27 22:34:43 -07:00
comfyanonymous da49b7d0b6 Remove useless annotations imports. (#14105) 2026-05-25 19:23:29 -07:00
Jukka Seppänen 8505abf52e feat: Extend Save3D to save vertex colors and textures (CORE-189) (#13824)
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.
2026-05-13 18:33:53 +03:00
Yousef R. Gamaleldin d3c18c1636 Add support for BiRefNet background remove model (CORE-46) (#12747) 2026-05-08 17:59:24 +08:00
431fadb520 fix(api-io): serialize MultiCombo multi_select as object config (#13484)
* fix(api-io): serialize MultiCombo multi_select as object config
* fix: remove dead code and redundant top-level keys from MultiCombo serialization
* fix: correct skip warning to mention comfy_entrypoint, remove nonexistent NODES_LIST
* fix: validate MultiCombo list values against options individually
* fix: gate multiselect validation on schema config, improve error message, add tests

---------

Co-authored-by: Ni-zav <ni-zav@users.noreply.github.com>
Co-authored-by: guill <jacob.e.segal@gmail.com>
2026-05-05 13:58:32 -07:00
comfyanonymous e6e0936128 Load other jpeg formats without taking so much memory. (#13642) 2026-04-30 19:33:09 -04:00
comfyanonymous d10fc2d652 Lower peak mem usage for 8 bit formats with pyav. (#13626) 2026-04-29 23:05:31 -04:00
comfyanonymous c7a517c2f9 Make pyav loading code handle tRNS PNG. (#13607) 2026-04-28 17:59:55 -04:00
comfyanonymous 13519934ba Handle metadata rotation in pyav code. (#13605) 2026-04-28 16:27:42 -04:00
comfyanonymous 3cbf015578 Read audio and video at the same time in video loader node. (#13591) 2026-04-27 16:44:12 -07:00
comfyanonymous df22bcd5e1 Support loading the alpha channel of videos. (#13564)
Not exposed in nodes yet.
2026-04-25 21:02:58 -04:00
comfyanonymous 4304c15e9b Properly load higher bit depth videos. (#13542) 2026-04-24 16:46:10 -04:00