v1.2.1 - Removed the maximum number of inputs and outputs on the Subworkflow

This commit is contained in:
Edward Niewold
2026-04-25 16:28:22 +02:00
parent 33d3bb4f49
commit b711fa8f07
5 changed files with 11 additions and 27 deletions
+2
View File
@@ -178,9 +178,11 @@ ComfyUI workflow JSON appears in a few different shapes depending on how it was
- [ ] Used paths with macro elements are not formatted currectly when used in inner workflow? (use Video Combine node with %date:yyyy-MM-dd%/WAN/Video)
- [ ] Green progress borders appear on more than one node when executing a inner workflow as part of a larger workflow. These borders should be limited to the currently executing node(s) outer workflow.
- [ ] The order if inputs/outputs on the `Subworkflow` node is undetermined (probably based on the order of nodes in the inner workflow JSON). Consider adding an option to control this order.
- [ ] When a node `Subworkflow Input` is used inside a subgraph, it will not be detected as a boundary node and will not be exposed on the `Subworkflow` node.
### Version History
- v1.2.1 - Removed the maximum number of inputs and outputs on the `Subworkflow` node (was previously set to 8).
- v1.2.0 - Added manual value entry for primitive `Subworkflow Input` input nodes on the `Subworkflow` node. Check README features section for details.
- v1.1.0 - Added `Subworkflow Modifier`, `Subworkflow Modifier Source` (+ from URL) nodes. Combining these nodes in inner and outer workflows allows for circular links between an inner workflow input and output, without circular reference problems.
- v1.0.1 - UI only nodes are now supported in inner workflows, no longer raising and error when loading.
+3 -4
View File
@@ -56,7 +56,6 @@ const NODE_CONFIGS = {
},
},
};
const MAX_SLOTS = 8;
const LOG = "[SWF]";
const DEBUG = window.localStorage?.getItem("swf_debug") === "1";
let workflowErrorDialog = null;
@@ -225,7 +224,7 @@ function updateInputSlots(node, inputs) {
if (node.inputs[i].name?.startsWith("swf_in_")) node.removeInput(i);
}
}
inputs.slice(0, MAX_SLOTS).forEach((inp, i) => {
inputs.forEach((inp, i) => {
debugLog(`updateInputSlots: adding swf_in_${i}`, inp);
node.addInput(`swf_in_${i}`, swfSlotType(inp), { label: inp.slot_name });
});
@@ -233,7 +232,7 @@ function updateInputSlots(node, inputs) {
}
function updateOutputSlots(node, outputs) {
const needCount = Math.min(outputs.length, MAX_SLOTS);
const needCount = outputs.length;
debugLog("updateOutputSlots: before", slotSummary(node.outputs));
for (let i = (node.outputs || []).length - 1; i >= 0; i--) {
@@ -443,7 +442,7 @@ function _syncOverrideWidgets(node, inputs, config, pendingOverrideValues) {
let pendingOffset = 0;
inputs.slice(0, MAX_SLOTS).forEach((inp, i) => {
inputs.forEach((inp, i) => {
if (inp.type !== "INT" && inp.type !== "FLOAT") return;
const defaultVal = (inp.default != null) ? inp.default : (inp.type === "INT" ? 0 : 0.0);
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "comfyui-subworkflow"
version = "1.2.0"
version = "1.2.1"
description = "Use ComfyUI workflows as reusable subworkflows via Subworkflow Input, Subworkflow Output, and Subworkflow nodes"
license = { file = "LICENSE" }
requires-python = ">=3.10"
+5 -21
View File
@@ -16,7 +16,6 @@ from .workflow_utils import (
apply_control_after_generate,
validate_workflow_nodes_installed,
get_workflow_interface,
MAX_SLOTS,
)
log = configure_logger("ComfyUI-Subworkflow")
@@ -112,32 +111,17 @@ class BaseSubworkflow(io.ComfyNode):
effective_inputs = _apply_primitive_overrides(data, kwargs)
output_refs, graph = build_expansion(data, effective_inputs)
return cls._finalize_execution(output_refs, graph, data, reload_each_execution, pad_outputs=MAX_SLOTS)
return cls._finalize_execution(output_refs, graph, data, reload_each_execution)
@classmethod
def _finalize_execution(
cls,
output_refs,
graph,
data: dict,
reload_each_execution: bool,
pad_outputs: int | None = None,
):
def _finalize_execution(cls, output_refs, graph, data: dict, reload_each_execution: bool):
if not reload_each_execution:
apply_control_after_generate(data)
if pad_outputs is not None:
while len(output_refs) < pad_outputs:
output_refs.append(None)
return io.NodeOutput(*output_refs, expand=graph.finalize())
def _subworkflow_outputs():
return [
io.AnyType.Output(id=f"out_{i}", display_name=f"out_{i}")
for i in range(MAX_SLOTS)
]
return []
def _reload_input():
@@ -330,7 +314,7 @@ class SubworkflowModifierSource(BaseSubworkflow):
data = cls._get_workflow_data(reload_each_execution, workflow=workflow, **kwargs)
validate_workflow_nodes_installed(data)
output_refs, graph = build_modifier_source_expansion(data, kwargs)
return cls._finalize_execution(output_refs, graph, data, reload_each_execution, pad_outputs=MAX_SLOTS)
return cls._finalize_execution(output_refs, graph, data, reload_each_execution)
class SubworkflowModifierSourceFromURL(BaseSubworkflow):
@@ -384,4 +368,4 @@ class SubworkflowModifierSourceFromURL(BaseSubworkflow):
)
validate_workflow_nodes_installed(data)
output_refs, graph = build_modifier_source_expansion(data, kwargs)
return cls._finalize_execution(output_refs, graph, data, reload_each_execution, pad_outputs=MAX_SLOTS)
return cls._finalize_execution(output_refs, graph, data, reload_each_execution)
-1
View File
@@ -23,7 +23,6 @@ _UUID_RE = re.compile(
SWF_SUBWORKFLOW_INPUT = "SWF_SubworkflowInput"
SWF_SUBWORKFLOW_OUTPUT = "SWF_SubworkflowOutput"
SWF_SUBWORKFLOW_MODIFIER = "SWF_SubworkflowModifier"
MAX_SLOTS = 8
PLACEHOLDER = ""
MAX_URL_WORKFLOW_BYTES = 50 * 1024 * 1024
URL_WORKFLOW_TIMEOUT = 20