From 3861b6c84dc7c7eecfee00bf936491ec94bb776e Mon Sep 17 00:00:00 2001 From: Darksidewalker <> Date: Sun, 23 Aug 2026 11:16:15 +0200 Subject: [PATCH] fix(director v2): render tiny-VAE selector as true combo (bare-list spec) Frontend v1.49.x maps a legacy ("STRING", {"combo": [...]}) tuple to a free-text widget, not a dropdown. Use the bare-list combo spec shape (same form as core VAELoader.vae_name) so preview_tiny_vae renders as a clean model-selector combo; socketless=True in the options dict keeps the optional input dot hidden. --- .tests/test_minimax_h3_director_v2.py | 17 ++++++++++------- docs/minimax_h3_director.md | 2 +- nodes/nodes_minimax_h3_director_v2.py | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.tests/test_minimax_h3_director_v2.py b/.tests/test_minimax_h3_director_v2.py index ab8d20f..c757f46 100644 --- a/.tests/test_minimax_h3_director_v2.py +++ b/.tests/test_minimax_h3_director_v2.py @@ -86,18 +86,21 @@ def test_optional_sampling_sockets_present(): def test_preview_sockets_present(): opt = MiniMaxH3DirectorV2.INPUT_TYPES()["optional"] - # The tiny-VAE selector is a socketless combo widget — rendered like a + # The tiny-VAE selector is a bare-list COMBO spec (the same shape as + # core VAELoader.vae_name) with socketless=True — rendered like a # model selector (e.g. the VAE loader's dropdown), no linkable input - # dot on the node edge. - assert opt["preview_tiny_vae"][0] == "STRING" + # dot on the node edge. In frontend v1.49.x the bare-list form is + # what maps to a combo widget; a legacy ("STRING", {"combo": ...}) + # tuple degrades to a free-text field instead. + assert isinstance(opt["preview_tiny_vae"][0], list) assert opt["preview_tiny_vae"][1].get("forceInput") is not True assert opt["preview_tiny_vae"][1].get("socketless") is True + assert opt["preview_tiny_vae"][1].get("default") == "none" # The full-quality VAE path remains an optional input socket. assert opt["preview_vae"][0] == "VAE" - # INPUT_TYPES() is evaluated once at node load: the combo value is the - # option list itself, not a callable (callables only appear in specs). - combo = opt["preview_tiny_vae"][1].get("combo") - names = combo() if callable(combo) else list(combo) + # INPUT_TYPES() is evaluated once at node load: the options are the + # list itself (element 0 of the tuple), not a callable or a dict key. + names = list(opt["preview_tiny_vae"][0]) assert "none" in names if HAS_FOLDER_PATHS: # Options come from the models/vae_approx folder listing. diff --git a/docs/minimax_h3_director.md b/docs/minimax_h3_director.md index b68dc89..675f1b6 100644 --- a/docs/minimax_h3_director.md +++ b/docs/minimax_h3_director.md @@ -383,7 +383,7 @@ The Director decodes per-step denoising frames itself and streams them into its - **Toggle:** **live step preview** in the ☰ *Preview & Output options* menu (default on). When off the backend skips the whole decode path (no tiny-VAE decode, no `send_sync`) — a true bypass, not just a hidden pane. - **Limits:** `preview_max_resolution` (default 1024 px, 0 = full), `preview_frames` (1 = still JPEG; >1 = animated WebP, or NVENC H.264 MP4 when PyAV probes NVENC), `preview_fps` (default 12). -- **Decoder precedence:** `preview_tiny_vae` socketless combo widget (a `models/vae_approx` filename selector, e.g. `taeh3.safetensors` — the special H3 tiny decoder that core's `VAELoader` cannot build; rendered like a model selector, no input socket) > `preview_vae` input socket (full-quality `vae.decode()`) > core latent previewer > latent-to-RGB fallback. The tiny-VAE path clamps output before uint8 because taeh3 output is not [0,1]-guaranteed. +- **Decoder precedence:** `preview_tiny_vae` socketless combo widget (a `models/vae_approx` filename selector, e.g. `taeh3.safetensors` — the special H3 tiny decoder that core's `VAELoader` cannot build; rendered like a model selector, no input socket) > `preview_vae` input socket (full-quality `vae.decode()`) > core latent previewer > latent-to-RGB fallback. The tiny-VAE path clamps output before uint8 because taeh3 output is not [0,1]-guaranteed. Implementation note: the widget must stay a **bare-list combo spec** — `(_vae_approx_options(), {"default": "none", "socketless": True, ...})`, the same shape as core `VAELoader.vae_name`. The legacy `("STRING", {"combo": [...]})` tuple renders as a free-text field (no dropdown) in frontend v1.49.x; `socketless: True` in the options dict is what hides the optional input dot. - **KJ alternative:** a KJ `ModelPreviewOverrideKJ` in the chain remains a valid external preview. Because KJ's preview is a native `OUTER_SAMPLE` model wrapper — not a DOM hook on the graph sampler — its own widget also animates during the Director's internal-execution runs. Canonical wiring is unchanged: `Settings.MODEL → KJ.model → KJ.MODEL → Director.ref2va_model`. ## Dense prompting guide diff --git a/nodes/nodes_minimax_h3_director_v2.py b/nodes/nodes_minimax_h3_director_v2.py index 1c05c43..543a80e 100644 --- a/nodes/nodes_minimax_h3_director_v2.py +++ b/nodes/nodes_minimax_h3_director_v2.py @@ -95,7 +95,7 @@ class MiniMaxH3DirectorV2: "external_steps": ("INT", {"default": 0, "min": 0, "forceInput": True}), "external_shift_video": ("FLOAT", {"default": 0.0, "min": 0.0, "forceInput": True}), "external_shift_audio": ("FLOAT", {"default": 0.0, "min": 0.0, "forceInput": True}), - "preview_tiny_vae": ("STRING", {"default": "none", "combo": _vae_approx_options(), "socketless": True, "tooltip": "Optional tiny VAE decoder (models/vae_approx) for fast step previews. Overrides preview_vae and the built-in previewer."}), + "preview_tiny_vae": (_vae_approx_options(), {"default": "none", "socketless": True, "tooltip": "Optional tiny VAE decoder (models/vae_approx) for fast step previews. Overrides preview_vae and the built-in previewer."}), "preview_vae": ("VAE", {"lazy": True}), }, "hidden": {"prompt_context": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "unique_id": "UNIQUE_ID"},