Commit Graph
125 Commits
Author SHA1 Message Date
EthanfelandClaude Opus 4.6 6a60059cf0 refactor: simplify lora_text to plain text input with name resolution
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>
2026-03-04 19:34:42 +01:00
EthanfelandClaude Opus 4.6 3e1eb45065 feat: add lora_text input with autocomplete to LoRAStackDynamic
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>
2026-03-04 19:17:44 +01:00
EthanfelandClaude Opus 4.6 0363d23732 fix: cap retry attempts in base model filter init
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:52:36 +01:00
EthanfelandClaude Opus 4.6 20c72fab5c fix: base model filter — path matching, pagination, data safety
- 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>
2026-03-04 18:48:53 +01:00
EthanfelandClaude Opus 4.6 58a2ec07db feat: add base model filter to LoRAStackDynamic
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>
2026-03-04 18:43:40 +01:00
EthanfelandClaude Opus 4.6 7d2f1ad623 chore: remove remaining plan docs from tracking (gitignored)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:26:21 +01:00
EthanfelandClaude Opus 4.6 b5c43f6621 chore: remove plan doc from tracking (gitignored)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:26:08 +01:00
EthanfelandClaude Opus 4.6 0b5408813f refactor: use named unpacking in WanVideoLoRAOptimizer return
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:25:02 +01:00
EthanfelandClaude Opus 4.6 71d253fdc6 feat: add WanVideoLoRAOptimizer node for WanVideo model LoRA merging
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>
2026-03-04 18:21:12 +01:00
EthanfelandClaude Opus 4.6 043c8200a4 docs: add WanVideoLoRAOptimizer design document
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:17:16 +01:00
EthanfelandClaude Opus 4.6 3cf484fd34 fix: restore <p> wrappers on images for full-width GitHub rendering
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:43:20 +01:00
EthanfelandClaude Opus 4.6 33d039df9a feat: add MergedLoRAToHook converter node + README update
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>
2026-03-04 17:40:27 +01:00
EthanfelandClaude Opus 4.6 8341e8b84c bump version to 1.1.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:01:56 +01:00
EthanfelandClaude Opus 4.6 fbf7a7b15a fix: conflict editor memory leak and SaveMergedLoRA is_clip detection
- 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>
2026-03-04 16:58:57 +01:00
EthanfelandClaude Opus 4.6 65db42c217 fix: conflict-mode masking accounts for negative eff_strength
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>
2026-03-04 16:51:41 +01:00
EthanfelandClaude Opus 4.6 8cf4b7e8ff fix: single-LoRA widget mapping in conflict editor, add super().__init__()
- 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>
2026-03-04 16:43:27 +01:00
EthanfelandClaude Opus 4.6 1475c4a453 fix: critical LoRAConflictEditor bugs — _normalize_stack, sign voting, widget mapping
- 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>
2026-03-04 16:36:59 +01:00
EthanfelandClaude Opus 4.6 0991364d48 fix: handle None clip_strength in cache key and guard SaveMergedLoRA
- _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>
2026-03-04 16:28:27 +01:00
EthanfelandClaude Opus 4.6 ddc596f1d7 fix: add missing 4th return value on early-exit paths; respect weighted_sum_only
- 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>
2026-03-04 16:18:00 +01:00
EthanfelandClaude Opus 4.6 22507bf136 fix: preserve clip_strength=None, fix GPU round-trip, improve IS_CHANGED hash
- 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>
2026-03-04 16:06:18 +01:00
EthanfelandClaude Opus 4.6 ab923303a6 fix: add IS_CHANGED, DESCRIPTION to LoRAConflictEditor; clean up empty-stack return
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:50:39 +01:00
EthanfelandClaude Opus 4.6 2cad48fda6 feat: add JS extension stub for LoRAConflictEditor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:09:22 +01:00
EthanfelandClaude Opus 4.6 3a833cf192 fix: add warning for invalid merge_strategy_override values
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:05:55 +01:00
EthanfelandClaude Opus 4.6 0a1a72c665 feat: add merge_strategy_override input to LoRAOptimizer
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>
2026-03-04 15:03:25 +01:00
EthanfelandClaude Opus 4.6 74cca3f2ef fix: LoRAConflictEditor prefix detection, GPU memory, single-LoRA path
- 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>
2026-03-04 15:00:21 +01:00
EthanfelandClaude Opus 4.6 9a4531ee3b feat: add LoRAConflictEditor node with conflict analysis and auto-suggest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:55:17 +01:00
EthanfelandClaude Opus 4.6 7a6c710c57 add .gitignore for pycache and plan docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:04:24 +01:00
EthanfelandClaude Opus 4.6 d3a1efb496 bump version to 1.1.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:18:52 +01:00
EthanfelandClaude Opus 4.6 f48898f6ca feat: add per-LoRA conflict_mode masking (all/low_conflict/high_conflict)
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>
2026-03-04 09:17:52 +01:00
EthanfelandClaude Opus 4.6 39664f368f docs: fix style bleeding annotation clipping in problem diagram
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:38:03 +01:00
EthanfelandClaude Opus 4.6 37dcfb44b2 docs: fix clipping on Clean Separation card in problem diagram
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:34:26 +01:00
EthanfelandClaude Opus 4.6 6e0e3526e5 docs: narrow problem diagram for GitHub column width
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:31:47 +01:00
EthanfelandClaude Opus 4.6 0447a57bfc docs: replace problem text with visual diagram
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:27:12 +01:00
EthanfelandClaude Opus 4.6 bf8686926b bump version to 1.1.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:22:08 +01:00
EthanfelandClaude Opus 4.6 226fde58b5 docs: add example workflow and preview image
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:16:54 +01:00
EthanfelandClaude Opus 4.6 399ada6d93 docs: add title and separator for merge use-cases diagram
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:49:53 +01:00
EthanfelandClaude Opus 4.6 6190e68aff docs: add separator before Nodes section
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:48:57 +01:00
EthanfelandClaude Opus 4.6 9bbf061cdf docs: move merge use-cases diagram above Nodes section
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:48:20 +01:00
EthanfelandClaude Opus 4.6 43c8ece9d8 docs: add edit/structural LoRA warnings and merge use-cases diagram
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:45:09 +01:00
EthanfelandClaude Opus 4.6 a38dc9a5f1 docs: add development timeline SVG and PNG
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:24:14 +01:00
EthanfelandClaude Opus 4.6 77fcabb1f7 fix: dynamic stacker widget hiding (add widget.hidden, canvas dirty, timing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:20:22 +01:00
EthanfelandClaude Opus 4.6 e9304617f4 feat: interference-aware auto-strength, save to loras folder, dynamic stacker JS
- 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>
2026-03-03 23:07:41 +01:00
EthanfelandClaude Opus 4.6 7d77079acb docs: update README for dynamic stacker, save node, and interference-aware auto-strength
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>
2026-03-03 22:51:09 +01:00
EthanfelandClaude Opus 4.6 043c510367 docs: update README and SVG for conflict-aware sparsification
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>
2026-03-03 21:56:15 +01:00
EthanfelandClaude Opus 4.6 823811520a feat: add conflict-aware DARE/DELLA sparsification variants
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>
2026-03-03 21:47:47 +01:00
EthanfelandClaude Opus 4.6 c708d9405e perf: run DARE/DELLA sparsification mask generation on GPU
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>
2026-03-03 20:56:53 +01:00
EthanfelandClaude Opus 4.6 6b0730cc31 feat: add Save Merged LoRA node and LORA_DATA output
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>
2026-03-03 20:48:47 +01:00
EthanfelandClaude Opus 4.6 5b25ba28d5 fix: use correct LoRAAdapter attribute name (.weights not .lora_data)
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>
2026-03-03 15:50:16 +01:00
EthanfelandClaude Opus 4.6 400ad0c98e fix: Z-Image re-fusion with SVD-compressed patches
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>
2026-03-03 15:44:57 +01:00
EthanfelandClaude Opus 4.6 b36aa9ce75 fix: SDXL/LTX detection overlap and Wan RS-LoRA false positive
- 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>
2026-03-03 15:39:36 +01:00