From 8fabfe3b3f1bd679a22a85b94c271815ce4ee17c Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Sat, 10 Oct 2026 01:40:01 +0300 Subject: [PATCH] feat: the model loader's fields read in order: file, storage, attention, then SLA as its choices narrow it Co-Authored-By: Claude Opus 5.5 --- core/widgets.py | 5 +++++ modules/loaders/diffusion_model/nodes.py | 7 +++++++ modules/loaders/tests/test_sla_attention.py | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/core/widgets.py b/core/widgets.py index 466dc8d6..084df031 100644 --- a/core/widgets.py +++ b/core/widgets.py @@ -102,6 +102,11 @@ def describe(class_type: str) -> Optional[dict]: sub = dict(_one(dotted, decl, req), shows=[{"input": parent, "when": keys}]) (widgets if sub["type"] in PRIMITIVE and not sub.get("forceInput") else sockets).append(sub) + # A node may say how its fields read best (WIDGET_ORDER); unnamed ones keep their place after those. + order = list(getattr(node, "WIDGET_ORDER", ()) or ()) + if order: + widgets.sort(key=lambda w: order.index(w["name"]) if w["name"] in order else len(order)) + outputs = list(getattr(node, "RETURN_TYPES", ()) or ()) # RETURN_NAMES is optional even on a well-formed node -- absent means # "named after its type", which is what ComfyUI's own frontend falls back diff --git a/modules/loaders/diffusion_model/nodes.py b/modules/loaders/diffusion_model/nodes.py index 63428334..ca297af5 100644 --- a/modules/loaders/diffusion_model/nodes.py +++ b/modules/loaders/diffusion_model/nodes.py @@ -38,6 +38,13 @@ def shows(*conditions): return {"funpack_shows": [{"input": name, "when": list(values)} for name, values in conditions]} class FunPackDiffusionModelLoader(io.ComfyNode): + # How the form lists them (core/widgets): the file, how it is stored and computed, attention, then SLA in the + # order its choices narrow it. Not the schema's order, which saved canvas workflows read by position. + WIDGET_ORDER = ("model_name", "weight_dtype", "int8_convrot", "compute_dtype", "fp16_accumulation", "attention", + "sla", "sla_method", "sla_engine", "sla_sparsity", "sla_tau", "sla_block_size", + "sla_dense_steps", "sla_dense_last_steps", "sla_min_seq_len", "sla_protect_audio", + "sla_references", "sla_tail", "sla_stabilize_motion") + @classmethod def define_schema(cls) -> io.Schema: return io.Schema( diff --git a/modules/loaders/tests/test_sla_attention.py b/modules/loaders/tests/test_sla_attention.py index bc5d70bd..c4d0a6b6 100644 --- a/modules/loaders/tests/test_sla_attention.py +++ b/modules/loaders/tests/test_sla_attention.py @@ -502,3 +502,9 @@ def test_the_loader_draws_each_sla_field_only_in_its_mode(): assert rules["sla_block_size"]["sla_engine"] == ["triton"] and rules["sla_tail"]["sla_engine"] == ["comfy_kitchen"] assert all(r.get("sla") == [True] for name, r in rules.items() if name.startswith("sla_")) assert rules["sla"] == {} and rules["int8_convrot"] == {} + + +def test_the_loaders_fields_are_listed_in_reading_order(): + from modules.loaders.diffusion_model.nodes import FunPackDiffusionModelLoader as L + named = [i.id for i in L.define_schema().inputs] + assert sorted(L.WIDGET_ORDER) == sorted(named) # every field placed, none invented