feat/model3d-input-multitype-mapping
Follow-up to PR #20: the `MODEL_3D` input wire type now resolves to an `IO.MultiType.Input(types=[IO.File3DGLB, IO.File3DOBJ, IO.File3DFBX, IO.File3DAny])` socket — symmetric counterpart of the existing `"MODEL_3D"` entry in `_OUTPUT_CLASSES` that maps to `IO.File3DGLB.Output`. Previously the descriptor wire type `"MODEL_3D"` fell through to the opaque `IO.Custom("MODEL_3D").Input(...)` socket, which is a single-comfytype socket the frontend only allows connections from identically-tagged outputs. Real upstream 3D sources expose different comfytypes: - `Load3D` outputs `IO.File3DAny` (comfytype `FILE_3D`). - Meshy / Hunyuan3D / Tripo / Rodin partner nodes output `IO.File3DGLB` (comfytype `FILE_3D_GLB`) via the existing `_OUTPUT_CLASSES["MODEL_3D"]` mapping. - Meshy's dual `FILE_3D_FBX` output socket emits `FILE_3D_FBX`. None of these connect to `IO.Custom("MODEL_3D")`. The upstream Tencent Hunyuan3D MODEL_3D-input nodes (`TencentModelTo3DUVNode` / `Tencent3DTextureEditNode` / `Tencent3DPartNode` / `TencentSmartTopologyNode`) all use `IO.MultiType.Input(types=[...])` to accept the union; mirroring that union here keeps the proxy socket compatible with every existing 3D-emitting node. `get_io_type()` on `IO.MultiType.Input` returns the comma-joined inner type IDs (e.g. `"FILE_3D_GLB,FILE_3D_OBJ,FILE_3D_FBX,FILE_3D"`) — matches the convention SxS workflows already use for their `SaveGLB` connector inputs. Per-node format validation (e.g. 3DTextureEdit's FBX-only enforcement, 3DPart's FBX-only enforcement) is done server-side in each provider's `execute()` against the inline envelope's `format` extra; this socket-level filter is purely about frontend connection validity. Unblocks the paired comfy-rnp-server PR (`TencentModelTo3DUVNode_RNP` + `Tencent3DPartNode_RNP`) which uses the `["MODEL_3D", {}]` wire shape. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019e362f-db40-7338-8ca4-99f617d89812
comfy-remote-nodes
ComfyUI custom-node package that fetches node descriptors from an RNP/1 (Remote Node Protocol v1) server and exposes them as native V3 nodes inside ComfyUI.
The reference server lives at
Comfy-Org/comfy-rnp-server
(private). This client is intentionally provider-agnostic: any server
that speaks RNP/1 can publish nodes through it.
Install
Clone into your ComfyUI custom_nodes/ directory:
cd ComfyUI/custom_nodes
git clone https://github.com/Comfy-Org/comfy-remote-nodes.git
(The directory name on disk doesn't matter — ComfyUI loads the package
via spec_from_file_location, so comfy-remote-nodes/ is fine.)
Configure
Point the extension at one RNP server URL via env var before starting ComfyUI:
export RNP_SERVER_URL=http://127.0.0.1:9190
python main.py
If RNP_SERVER_URL is unset, the extension registers zero nodes and
logs a single line — ComfyUI starts normally with no remote nodes.
What works today
- Manifest + capability handshake
object_infofetch and dynamic V3 class generation (with ETag conditional GETs)- Sync
executeand asyncexecute_async+ poll/cancel - Image / mask / audio / video envelope encode + decode
- Presigned upload helper for >8 MiB inputs
- Tier 3 (recent):
TASK_LOSTdetection with idempotent resubmission — survives an RNP server restart mid-task without losing the workflowSERVER_BUSY/MAINTENANCE503 envelopes treated as rate limits withRetry-Afterhonoring and friendly per-second progress text ("Server busy, retrying in 30s...")- Out-of-band
url_fetchfor URI-only output envelopes, driven by the descriptor'sremote.url_fetchpolicy - Per-poll auth refresh so long-running tasks can rotate tokens
What does not (yet)
validate_inputs/fingerprint_inputs/check_lazy_status— the server returns501 NOT_IMPLEMENTED; the client falls through to ComfyUI's defaults- Multi-server config file (
comfy_remote_nodes.yamlor similar) — today's setup is one server per ComfyUI process via env var - Streaming execute (server-sent events for incremental previews)
Languages
Python
100%