A combo can now hold its own node structure: pick nodes on the canvas and
New -> From the nodes picked on the canvas keeps the model nodes (a
drop-down of model files) and the text nodes (a multiline text box by the
node's definition) with the links between them; other picked nodes and
links to them are left out, their ports stay open on the canvas.
Slots are per box, so a node with several model drop-downs has several; a
box fed by a link is no slot. Each model slot's folder is the one whose
files hold all its drop-down's model-file options (ComfyUI's /models
lists), never guessed from names. Every other box is stored by name and
put back untouched, in order (a count box adds its rows first).
The save dialog shows what is kept and dropped and lets slots be renamed
or unticked. The editor lists the slots: a picker of that folder's models
with covers, filtered by base model, and text boxes. Put on canvas makes
the nodes (missing node types and their packs are named before anything
is placed), fills the slots by name, links by port name and type, as one
Ctrl+Z step; a box or link that cannot be restored is reported, never
guessed. New -> Same structure as ... starts another combo from a saved
structure. The default combo is unchanged. MCP list_combos lists node
combos by slot and place_combo places them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three MCP tools: download_missing_models (Model Check's Download all for
the open workflow, through the page so the placement rules and the put-in
afterwards are the UI's own), download_model (one model from a Civitai
version link, a Hugging Face / GitHub file link or a Civitai hash, into a
folder of its type) and download_status. The default models folder of a
type is shared by the dialog and the tools.
A Civitai version link without a matching file name now takes the
version's primary model file (people rename their files); a hash, when
there is one, still decides.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Current node's "Insert LoRA before / after" refused the most common workflows: a
checkpoint whose CLIP feeds both prompts (one link per output only) and UNet workflows
with their own CLIP loader (MODEL and CLIP had to come from one node).
- graph_splice.js: planLoraInsertion decides the links (after a node: every link of its
MODEL output; before one: only its own MODEL input) and, for LoRAs that train the text
encoder, the CLIP line (same node, a UNet workflow's one CLIP source, or before a
sampler the source its prompts share); spliceLora wires it, all or nothing. The old
analyzeModelChainInsertion / spliceModelChainNode / spliceAfterOutputs are gone.
- api/lora_info.py: GET /anomalous/lora_info reads the LoRA's safetensors header; the
picker asks it on confirm and inserts a model-only loader when there are no
text-encoder weights. The MCP add_lora uses the same helper.
- Insertion messages speak of the MODEL line; the fan-out ones are removed.
- tests/graph_splice.mjs (local) covers checkpoint, UNet + CLIP loader, before a
sampler, and the rollback.
Verified on 8199 through the Current node picker: after a checkpoint feeding two prompts
(full LoRA, both prompts moved) and before a sampler (model-only Flux LoRA).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A model-only LoRA loader was used for every UNet workflow, so a LoRA with text-encoder
weights lost them; and inserting after a checkpoint whose CLIP feeds both prompts was
refused (one link per output only).
- api/mcp_actions.py reads the LoRA's safetensors header: lora_te / te1 / te2 /
text_encoder keys mean it trains the text encoder.
- Such a LoRA becomes a LoraLoader taking MODEL from the model line's end and CLIP from
the same node (checkpoint, full LoRA loader) or a UNet workflow's one CLIP source;
others stay model-only.
- graph_splice.js: spliceAfterOutputs puts a node after outputs on different nodes and
moves every link each output had. The picker's spliceModelChainNode is back to its
committed behavior (the `types` option is gone).
Verified on 8199: UNet + CLIP loader with a text-encoder LoRA, a model-only one after it
and another text-encoder one; a checkpoint feeding two prompts; Ctrl+Z after each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The second batch of MCP tools: they change things, through the same code the UI uses.
- Canvas, done by the open ComfyUI page: describe_canvas, set_prompt, set_model,
add_lora, place_combo, check_workflow_models, fix_workflow_models, run_workflow,
open_in_anomalous. api/mcp_bridge.py sends the action over ComfyUI's websocket and
waits; web/modules/mcp_bridge.js claims it (visible tab first), does it with
Anomalous's canvas code and answers. Each change is one Ctrl+Z step, shows a toast and
is logged as the AI's (activity entries carry via: "mcp", with their undo).
- This server: scan_models (new / look up again / picked models, via /anomalous/scan_all),
list_voices and speak (Anomalous TTS through /prompt and /history).
- graph_splice.js takes the chain's slot types, so a LoRA can go into a model-only (UNet,
Flux) chain as LoraLoaderModelOnly; the default (MODEL and CLIP) is unchanged.
- Nothing deletes or renames files; acting tools are not marked read-only, so AI apps
ask before calling them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>