metrics_runner computes metrics for an existing session straight to disk; a
generation run's in-memory copy of those items had no metrics and would have
wiped them on its next save. Disk wins for an item's metrics when the memory
item has none (merge_manifest_user_changes, flush_batch_with_vae's disk sync,
the remote VAE worker's disk sync). Fresh in-memory metrics are kept.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Hooks: decode_latent_with_vae metrics_sink, flush_batch_with_vae, remote VAE
worker, orchestrator upscale/Florence2/SeedVR2 inserts, dashboard upscale
thread (explicit spec, never inherits), florence2 builders drop metrics.
sampler_node wraps the run in a token-based begin_run/end_run context.
Adapters mechanism is tested with fake nodes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pairwise-review votes live in manifest["comparisons"]. Locked read-modify-write
helper, disk-wins preservation in every manifest writer, two new routes, tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
MOSS-Image (Flux.2 latent: 128ch, 16 px per cell) jobs were built with the
SD-era `h // 8`, so every image sampled a latent with 4x the cells and decoded
at 2x the requested size (832x1216 -> 1664x2432): ~10x slower than the official
ComfyUI template (~120 s vs ~10 s per image on the 5060 Ti).
- model_loader: get_latent_downscale_ratio() reads latent_format.spacial_downscale_ratio
(8 for SD/SDXL/Flux.1, 16 for the Flux.2 family); make_empty_latent() builds the
job latent and warns when WxH is not a multiple of the ratio. Both orchestrator
latent sites (main loop + distributed worker) use it; hires-fix latent upscale,
tiled hires sampling and VAE tiling divisors no longer assume 8.
- CLIP type: resolve_clip_type() warns on unknown types instead of silently using
stable_diffusion, and when clip_type is left at the default it follows the
detected model family (MOSSImage -> moss_image, Flux2 -> flux2, ...). MOSS loaded
as a generic Qwen3.5 TE before (wrong chat template). The Builder's CLIP Type
list is now read from ComfyUI's CLIPLoader/DualCLIPLoader (static list = fallback,
now including moss_image); LS_CACHE_VERSION 3 refreshes cached lists.
- Skip Layer Guidance: new Extra Model & Sampling sub-group wrapping
SkipLayerGuidanceDiTSimple (double/single layers, start/end %), plumbed like Deep
Shrink (builder emission, expand_configs, orchestrator, generate_image). Defaults
match the official MOSS-Image workflow (single block 22, 0-50%).
- tests: latent geometry + clip type resolution, dynamic clip type lists, SLG
config emission/expansion (24 new; the 15 pre-existing torch-stub failures unchanged).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Extends the May 2026 Florence2 fix (29GB -> <5GB) to every other out-of-graph
inference entry point in the project. Same root cause everywhere: we call
ComfyUI models from background threads / our orchestrator, bypassing
ComfyUI/execution.py:732 which wraps every node in torch.inference_mode().
Decorated with @torch.inference_mode() in image_generation.py:
- generate_image() — SDXL/diffusion sampling (nodes.common_ksampler)
- upscale_image() — KSampler hires fix + ImageUpscaleWithModel
(ESRGAN-style) + VAE encode/decode
- decode_latent_with_vae() — VAE decode (with NaN float32 retry)
- seedvr2_upscale() — SeedVR2 diffusion-based video upscaler
(DiT + VAE + sampling loop)
Plus prominent module-docstring warning blocks in:
- image_generation.py: full "why this matters / where / what to do if
you add a new entry point" explanation
- ltx_video_generation.py: warning that _call_node()'s inference_mode wrap
is load-bearing and must not be removed
Inline comment above each decorated function points back to the module
docstring so anyone editing one function still sees the rationale.
Updated the stale comment in decode_latent_with_vae explaining .detach()
(was 'tensor may have requires_grad=True' — under inference_mode it can't,
so .detach() is now a defensive no-op; kept for double-safety).
Tests: 118/118 pass.
Runtime error: "'PatchModelAddDownscale' object has no attribute 'patch'".
Current ComfyUI (verified in this install's comfy_extras/nodes_model_
downscale.py) ships PatchModelAddDownscale as a V3 io.ComfyNode subclass
with a classmethod execute() returning io.NodeOutput. The agent's
original .patch() instance call only works on the legacy V1 class.
Now dispatches V3-first (subclass check + cls.execute()) with a V1
fallback (FUNCTION attribute, default "patch") for older builds. Unwraps
NodeOutput.args[0] for V3, tuple[0] for V1, bare value otherwise. Same
pattern as ltx_video_generation._call_node / _unwrap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a new SUB-GROUP 4 in the Builder UI's "Extra Model & Sampling
Options" section with all 7 params from ComfyUI's built-in
PatchModelAddDownscale node:
- block_number (int, default 3)
- downscale_factor (float, default 2.0)
- start_percent / end_percent (float 0-1, default 0.0 / 0.35)
- downscale_after_skip (bool, default true)
- downscale_method / upscale_method (combo: bicubic/nearest-exact/
bilinear/area/bislerp, default bicubic)
Toggle checkbox controls whether the patch is applied. State plumbs:
config_array.use_deep_shrink/* (JS) -> state_to_configs_json -> per-
config entries -> expand_configs base_combos -> generate_image -> looks
up PatchModelAddDownscale via NODE_CLASS_MAPPINGS and calls .patch() to
patch the model before sampling. Logs an "Applied
PatchModelAddDownscale" line on each gen for visibility.
Mirrors the existing model_sampling_override / use_advanced_sampling
patterns for consistency. Hidden on LTX video config arrays since the
patch targets the SDXL/SD UNet.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a dropdown to the Builder UI's Run Settings section letting users
pick the saved image file format. Default remains webp (current
behavior). State plumbed through state_to_configs_json ->
_session_settings -> orchestrator -> save_image_to_disk.
PNG users will see lossless saves; JPG users smaller files at quality 95.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SeedVR2 nodes use ComfyUI's V3 API which calls get_executing_context()
internally to get the current node_id. When calling execute() directly
from our code (outside ComfyUI's execution pipeline), the context is
None, causing AttributeError.
Fix: wrap all SeedVR2 execute() calls inside a CurrentNodeContext
context manager with a dummy prompt_id and node_id. This provides the
required execution context that V3 API nodes expect.
Also fixed indentation — all three execute() calls (DiT, VAE, Upscaler)
are now properly inside the with block.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous approach tried 'from custom_nodes import ComfyUI_SeedVR2...'
which fails because ComfyUI doesn't expose custom nodes as importable
packages. Now scans nodes.NODE_CLASS_MAPPINGS directly for the three
SeedVR2 node classes (LoadDiTModel, LoadVAEModel, VideoUpscaler).
This works for both V2 and V3 API nodes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds SeedVR2 as a new upscale mode alongside HiRes Fix, Model Upscale,
and Model+HiRes. Requires ComfyUI-SeedVR2_VideoUpscaler to be installed
as a dependency — the plugin calls its nodes programmatically.
Data Model:
- New seedvr2 options object on each upscale step with all SeedVR2
parameters: dit_model, resolution, max_resolution, seed,
color_correction, batch_size, noise scales, blocks_to_swap,
attention_mode, offload_device, cache_model, VAE tiling options
- _defaultSeedVR2Options() / createDefaultSeedVR2Options() helpers
- Migration: ensureStepFields adds seedvr2 defaults to existing configs
Builder UI (conf-builder-config-management.js):
- "SeedVR2 Upscale" added to mode dropdown
- When selected, shows full SeedVR2 settings: DiT model selection
(10 variants: 3B/7B x fp16/fp8/GGUF/sharp), resolution, seed,
color correction, noise scales, batch size, VRAM optimization
(blocks_to_swap, attention_mode, offload), VAE tiling with
conditional encode/decode tile size and overlap fields
Dashboard (logic_upscale_modal.js):
- Same SeedVR2 mode and fields in renderPipelineEditor via _renderStep
- All fields use existing _makeSelect/_makeNumber/_makeCheckbox helpers
Python Execution (image_generation.py):
- New seedvr2_upscale(pil_image, seedvr2_config) function
- Imports SeedVR2 nodes from NODE_CLASS_MAPPINGS at runtime
- Calls SeedVR2LoadDiTModel → SeedVR2LoadVAEModel → SeedVR2VideoUpscaler
- Converts PIL→tensor→SeedVR2→tensor→PIL
- Clear error if SeedVR2 not installed
Pipeline Integration (generation_orchestrator.py):
- Inline upscale path: mode=="seedvr2" branch decodes current latent
to PIL, calls seedvr2_upscale, saves result, updates manifest
- Supports chained steps: non-final SeedVR2 steps re-encode to latent
for the next step in the pipeline
Preset compatible: seedvr2 config serializes naturally as JSON, saved
and loaded with upscale presets without any special handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add "flux2" to clip_types and dual_clip_types lists so CLIPType.FLUX2
is correctly passed to ComfyUI's text encoder loader
- Add "flux2" model_sampling_override option in Builder UI dropdown
- Implement ModelSamplingFlux2 handler using fixed shift (default 2.02,
matching ComfyUI's Flux2 supported_models.py)
- Handle "flux2" in config_builder_node.py config generation with
default shift value
Users with Flux2 models (Klein, etc.) should set:
- CLIP Type: flux2
- Model Sampling Override: Flux2
- For best results: enable Advanced Sampling with Flux2 Scheduler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ETA calculation now uses the last 10 job durations instead of the
overall average. This adapts faster when upscale patterns change
(e.g., some configs have upscale, some don't) and prevents early
slow jobs from permanently skewing the estimate.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace flat upscale configs with pipeline/steps/repeat architecture:
- Pipelines run independently from base image
- Steps chain sequentially within a pipeline
- Steps support repeat count for iterative refinement
Add "Save Pre-Upscaled Output" option to also keep the base image.
Add "Adjust Prompt During HiRes Fix" with prepend/append/replace
behaviors. HiRes-adjusted prompts are batch pre-encoded for efficiency.
Results written to manifest metadata and exposed as label overlays.
Fix fmtVal scoping error in buildLabelOverlay (was referenced outside
the upscale block where it was defined).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Seed: expanded per-gen behavior + new full run seed behavior (random/increment/decrement before/after entire run)
- Canvas: fix flicker during simultaneous pan+zoom via requestAnimationFrame batching
- Upscaling: 3 session-level modes (HiRes fix, model upscale, model+HiRes) with tiled VAE support
- Cooldown: configurable GPU breaks between generations with optional VRAM clearing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Worker now clones latent and frees UNet tensors + CUDA cache before
VAE decode, giving Dynamic VRAM clean memory for VAE loading.
decode_latent_with_vae now detects NaN in input/output, logs diagnostic
info, retries with float32, and handles bfloat16->numpy conversion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>