Commit Graph
6 Commits
Author SHA1 Message Date
alisson-anjosandClaude Opus 5 5c8c41abbd LoRA Surgery: carry a recipe to the save node without copying JSON (1.45.0)
Getting a recipe from the interactive node into the save node meant copying the rules JSON
between two text widgets, which is a bad way to move state and easy to get wrong.

Two paths now. BFS LoRA Surgery gained a `rules` output that can be wired straight into the
save node's `rules` input, so the file is produced as part of the run. And the panel has a
"save as file" button with an optional name, which posts to a new /bfs/lora/save route and
reports the result inline, for when you are still exploring and do not want a second node in
the graph.

Both go through one write_surgery function, so the two paths cannot drift apart. That
function is the old node body lifted out, not a copy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 12:33:29 +00:00
alisson-anjosandClaude Opus 5 5073cf00ae LoRA Surgery: keep the panel's configuration across reloads, and stop implying Qwen names (1.43.2)
Two fixes.

The panel lost its configuration when a workflow was reopened. The Vue app mounts in
nodeCreated, which runs before ComfyUI restores widget values in configure, so it read an
empty widget and the first edit would then overwrite the stored recipe. The node now wraps
onConfigure and tells the panel to re-read once values have landed, and the rules widget is
explicitly marked serializable with a serializeValue, so the configuration travels with a
shared workflow rather than living only in the session.

The widget now stores {rules, ui} instead of a bare array, so the selected family, type,
block range and scale come back too, not just the rules. A bare array is still accepted, for
workflows saved by the previous version and because the Python side takes either shape;
verified both produce identical results.

The inline guide named gate_up as if it were universal. It now says up front that names
depend on the base model, gives the three architectures verified so far with their actual
family and module names and block counts, and frames the finding as the MLP input projection
whatever the model calls it, explicitly a starting point rather than a rule.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 12:24:49 +00:00
alisson-anjosandClaude Opus 5 ee4d2eecb8 LoRA Surgery save: bounded filenames and metadata that explains the file (1.43.1)
Filenames could exceed the OS limit: the slug was capped at 110 characters but the final
name is stem + slug, so a long source name pushed it past NAME_MAX (255 bytes on Linux, and
Windows caps the whole path near 260 without long paths). Names are now fitted to 160 bytes,
trimming both halves and appending a short hash of the full recipe when needed, so two
different recipes still never produce the same name. A path over 240 characters logs a
warning, since the folder above us is not ours to control.

Metadata now records what was applied rather than just that something was. The original
metadata is preserved untouched, and next to it:

  bfs_surgery_summary  one readable line, for viewers that know nothing about this tool
  bfs_surgery          tool, UTC timestamp, source filename and its sha256, the readable
                       recipe, the exact rules, and module counts (total/kept/dropped/scaled)
  ss_output_name       updated to the new filename

The sha256 matters more than the filename: it ties the result to the checkpoint it came from
even after either one is renamed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 12:15:30 +00:00
alisson-anjosandClaude Opus 5 ce11d082fd LoRA Surgery: a save node that names the file after the recipe (1.43.0)
BFS LoRA Surgery (save) applies the same rules and writes a .safetensors into models/loras,
for when a recipe is settled and you want it usable outside the workflow that produced it.

With no filename given, the name is derived from the rules themselves:
mylora__attn-x1.15__gate_up-b8_15-off__all-b16_23-off.safetensors. Names get sanitized, so a
type like *mlp* or a regex match still yields a valid file. The recipe also goes into the
safetensors metadata under bfs_surgery, next to the original metadata, so a shared file can
explain itself later.

Verified against the study output: saving the body-swap recipe produces the same 136 of 192
modules, and the effective dW matches the file produced by the standalone script to 3e-3
relative. The factors differ because the node scales only the up/B side while the script
split the scale across both, but the product is what the model sees.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 12:09:13 +00:00
alisson-anjosandClaude Opus 5 be0bf3e7ca Drop em dashes from the node's prose (1.42.1)
Plain punctuation reads better and does not carry the stylistic tell. No behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 11:49:10 +00:00
alisson-anjosandClaude Opus 5 e9a27c765c BFS LoRA Surgery: read any LoRA's layers and blocks, scale or drop them live
A defect a LoRA learned — smoothed skin, identity drifting at distance, a pose it
refuses to copy — usually lives in one module family and a range of blocks, not in the
whole adapter. This node makes that testable without retraining: pick a family, pick
blocks, set a scale, queue. Nothing is written to disk, so iterating is a slider away.

Model-agnostic by construction. The structure is discovered from key names rather than
hardcoded, covering the diffusers (lora_A/lora_B) and kohya (lora_down/lora_up + alpha)
conventions. Verified against three architectures with different naming: Qwen-Image-2.1
(transformer_blocks, 32), Krea 2 (blocks 28 + txtfusion) and MiniMax-H3 (blocks 50 +
token_refiner).

Scaling multiplies only the up/B factor, since (sB)A = s(BA) — exact under either alpha
convention, and negative scales stay usable.

The panel is a Vue app in a DOM widget, with Vue vendored so it works offline. It lists
each family's module types sorted by ||dW||, which reads as a map of where training
invested. Selections convert to a regex on demand for cases the tree cannot express.
Rules are ordered and later ones win, so the UI says so and lets you reorder.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 11:26:37 +00:00