Remove the autocomplete JS class (was ~155 lines). Instead, resolve
short LoRA names server-side: typing "Milena_20260216180133" matches
against installed LoRAs by filename stem, so it resolves to e.g.
"ZImageTurbo/character/Milena_20260216180133.safetensors". No Lora
Manager dependency needed — just plain text input with smart matching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a multiline text widget where users can type LoRA paths directly
(one per line) with optional strength values. Supports three formats:
path.safetensors (strength 1.0), path:0.8 (both), path:0.8:0.5
(model:clip). When ComfyUI-Lora-Manager is installed, a lightweight
autocomplete dropdown suggests matches via its API. Works without
Lora Manager too (no autocomplete, user types exact paths).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix absolute→relative path matching (endsWith against fullLoraList)
- Fix page_size cap (paginate through all pages, build local map)
- Add explicit base_model_filter param to build_stack (no kwargs leak)
- Add retry when widget options not yet populated
- Preserve selected LoRA value when filter changes (no silent reset)
- Handle workflow restore (apply filter after interceptor setup)
- Extract interceptWidgetValue helper, add configurable:true
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a dropdown that filters LoRA dropdowns by base model type (SDXL,
Flux, Wan, etc.) using ComfyUI-Lora-Manager's API. If Lora Manager is
not installed, the filter widget is automatically hidden and dropdowns
show the full unfiltered list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Thin subclass of LoRAOptimizer that accepts WANVIDEOMODEL input/output,
enabling LoRA merging for kijai's WanVideoWrapper pipeline. All merging
algorithms (TIES, DARE/DELLA, SVD, auto-strength) are inherited. Wan key
normalization (LyCORIS, diffusers, Fun LoRA, finetrainer, RS-LoRA) was
already supported by the parent class.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a new node that wraps merged LoRA patches as conditioning hooks (HOOKS)
for per-conditioning application instead of global model patching. Also
reorganize README with collapsible detail sections, reduce SVG margins,
and document the new node.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- LoRAConflictEditor: clear loaded_loras after analysis to prevent
unbounded memory accumulation across runs (100s of MB per large LoRA).
- SaveMergedLoRA: iterate model/clip patches separately with explicit
is_clip flag instead of checking membership in clip_patches dict.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The mask comparison now uses effective_diff (sign-corrected for negative
weight) instead of raw diff, consistent with the sign voting fix. Without
this, low_conflict and high_conflict were inverted for negative-strength
LoRAs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- LoRAConflictEditor single-LoRA path now finds the original stack
position instead of hardcoding conflict_mode_1, consistent with
the multi-LoRA path fix from the previous commit.
- LoRAOptimizer.__init__ now calls super().__init__() for forward
compatibility with _LoRAMergeBase changes.
- Fix stale _merge_cache comment (4-tuple → 5-tuple).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move _normalize_stack from LoRAOptimizer to _LoRAMergeBase so both
LoRAOptimizer and LoRAConflictEditor can use it. Previously the editor
crashed with AttributeError on every execution.
- Fix conflict-mode sign voting to account for negative eff_strength
(negate sign vote when weight < 0), consistent with _compute_conflict_mask.
- Fix widget-to-LoRA mapping to use original stack position instead of
active-only index, preventing misalignment when zero-strength LoRAs
exist in the stack.
- Add torch.cuda.empty_cache() after conflict editor GPU analysis loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- _compute_cache_key and LoRAConflictEditor.IS_CHANGED: float(None)
crash when tuples carry clip_strength=None (meaning "use global
multiplier"). Use sentinel -1.0 for hashing.
- SaveMergedLoRA.save_lora: early return when lora_data is None,
which can happen from optimizer early-exit paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- All optimize_merge early returns now include lora_data=None as 4th
element (prevents IndexError when SaveMergedLoRA is connected)
- merge_strategy_override now skips when optimization_mode is
weighted_sum_only (user's explicit choice to protect DPO/edit LoRAs
should not be overridden by upstream Conflict Editor)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Single-LoRA path now preserves clip_strength=None instead of
substituting model strength (preserves global multiplier semantics)
- Remove unnecessary GPU->CPU->GPU round-trip in conflict analysis
(keep diffs on GPU during pairwise comparisons)
- Include conflict_mode from stack entries in IS_CHANGED hash
(prevents stale cache when editor-chaining)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow the LoRAConflictEditor's merge_strategy output to connect to the
optimizer and override its auto-detected merge strategy. Applies to both
global and per-prefix decision paths. Includes cache key and IS_CHANGED
updates so ComfyUI properly detects when the override changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix prefix pre-filter to match all LoRA key formats (including
diffusers3 lora.up/lora.down patterns)
- Add explicit del mat_up/mat_down after diff computation for GPU memory
- Add early return for single-LoRA case (no pairwise analysis needed)
- Remove redundant import os (already at file level)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow users to control how each LoRA behaves in contested weight regions.
'low_conflict' applies only where the LoRA agrees with the majority sign,
'high_conflict' applies only where it disagrees. Defaults to 'all' (no
filtering) with zero overhead when unused.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Auto-strength now uses pairwise cosine similarity for exact vector-sum
energy normalization instead of assuming orthogonal LoRAs
- Save Merged LoRA defaults to ComfyUI loras folder; supports absolute paths
- Add JS extension for LoRA Stack (Dynamic) widget show/hide
- Fix LTX architecture detection for middle_block/mid_block keys
- Update banner SVG with new feature tags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add LoRA Stack (Dynamic) and Save Merged LoRA node sections, update
auto-strength from L2-aware to interference-aware energy normalization
with cosine similarity, add LORA_DATA output, and reorder sub-features
for logical pipeline flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite sparsification section to explain standard vs conflict-aware
modes. Redesign SVG diagram with side-by-side comparison showing how
standard drops weights blindly while conflict-aware only targets
positions where LoRAs push in opposite directions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only sparsify positions where LoRAs push in opposite directions (sign
conflict), leaving same-sign reinforcing positions untouched. Preserves
unique contributions while still reducing interference.
Adds dare_conflict and della_conflict to the sparsification dropdown.
Also includes tooltip improvements and SaveMergedLoRA auto-rank.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move torch.Generator to compute_device so bernoulli mask generation
stays on GPU, eliminating a full-tensor CPU round-trip per prefix
(~64MB for 4096x4096 layers).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add SaveMergedLoRA node that serializes merged patches to standard
.safetensors LoRA format (lora_up/lora_down/alpha). Full-rank diffs
are SVD-compressed automatically. Includes bake_strength option to
embed output/clip strength into saved weights.
Also adds LoRAStackDynamic node, DARE/DELLA sparsification support,
and related infrastructure (cache key updates, report formatting).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ComfyUI's LoRAAdapter stores data in .weights, not .lora_data.
The wrong attribute name would cause AttributeError at runtime
when re-fusing Z-Image QKV patches in the LoRAAdapter path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When patches are SVD-compressed, each to_q/to_k/to_v gets an
independent decomposition with its own down matrix. The re-fusion
code assumed shared down matrices (correct for uncompressed LoRA,
wrong after SVD). K and V would use Q's down matrix, producing
incorrect attention weights.
Now checks if down matrices are actually shared (identity check).
If not, expands to full-rank diffs before fusing into a single
diff patch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- LTX detection: exclude keys containing input_blocks/output_blocks/
down_blocks/up_blocks (SDXL patterns) to prevent Kohya SDXL LoRAs
from being misclassified as LTX and having keys mangled
- Wan RS-LoRA: replace unreliable marker key detection with heuristic
that checks for zero alpha keys in the file (RS-LoRA convention).
The old marker key existed in ALL Wan LoRAs, causing standard LoRAs
without explicit alphas to get sqrt(rank) amplification (8-11x)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>