fix(cql): expand dynamic-combo sub-inputs in slot extraction and set-slot/vary write path (BE-3371)#574
Open
mattmillerai wants to merge 1 commit into
Open
fix(cql): expand dynamic-combo sub-inputs in slot extraction and set-slot/vary write path (BE-3371)#574mattmillerai wants to merge 1 commit into
mattmillerai wants to merge 1 commit into
Conversation
…slot/vary write path (BE-3371) COMFY_DYNAMICCOMBO_V3 ports were treated as connections and dropped from widget_order, so on a pristine Seedream template every slot after the selector was mislabeled (1.seed showed the model name) and set-slot/vary wrote into the wrong widgets_values positions (1.seed=42 silently overwrote the model selector). - parse dynamic combos as widget ports: enum = option keys, raw option dicts retained for expansion - add value-aware Graph.widget_order_for_node that expands the selected option's widget sub-inputs in place (model.size_preset, model.width, …), recursing for nested combos and skipping connection subs (AUTOGROW) - migrate _node_widget_slots, _resolve_proxy_value, and _write_widget to the value-aware order; slots now surface N.model + N.model.<sub> with types/enums/current values - set-slot N.model=<other key> rebuilds the sub-widget roster from schema defaults, preserving values before/after the combo, with a warning - an N.model.<sub> address not under the current selector warns (no write) and lists the valid addresses Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughWalkthroughThe engine now parses V3 dynamic-combo metadata, expands widget slots based on selected values, resolves proxy indices accordingly, and supports validated sub-input writes and selector-driven roster rebuilding. Tests cover dynamic-combo workflows, nested options, warnings, and Seedream fixtures. ChangesDynamic combo workflow editing
Sequence Diagram(s)sequenceDiagram
participant CLI
participant Graph
participant Workflow
CLI->>Graph: resolve dynamic-combo widget slots
Graph->>Workflow: read selected widget values
Workflow-->>Graph: return current selector values
Graph-->>CLI: return expanded slot addresses
CLI->>Workflow: write selector or sub-input
Workflow-->>CLI: return updated values and warnings
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
mattmillerai
marked this pull request as ready for review
July 22, 2026 19:13
There was a problem hiding this comment.
🔍 Cursor Review — Consolidated panel
Triggered by @mattmillerai.
Judge call failed (status=parse_error): Could not parse JSON findings from output. First 500 chars:
I've verified the findings against the actual code. Key confirmations: `_dynamic_combo_sub_ports` returns `[]` on unknown selectors (line 1421); the repo's own `workflow_to_api._has_control_after_generate_companion` handles implicit `seed`/`noise_seed` markers that `engine.py`'s expansion ignores; the `extend` flag is not checked before padding on selector change; and the fixtures use explicit `control_after_generate`.
[
{
"file": "comfy_cli/cql/engine.py",
"line": 1421,
"side": "
Re-trigger by removing and re-adding the cursor-review label.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ELI-5
ComfyUI has "shape-shifter" dropdowns: pick a model in the dropdown and the node grows extra knobs (size, width, height…) that belong to that model. The CLI didn't know these dropdowns existed, so when it counted a node's knobs it skipped the dropdown and its extra knobs — every knob after it got the wrong label, and
set-slotturned the wrong knob (setting the seed actually overwrote the model choice, silently). Now the CLI reads which model is picked, counts that model's knobs in their real positions, and when you switch models it swaps the knob set for the new model's defaults and tells you it did.Problem
On the pristine
api_bytedance_seedream_5_0_pro_t2itemplate (reproduced onorigin/main):comfy workflow slotsshowed1.seed='seedream 5.0 pro',1.watermark/1.thinking=2048, and no1.model/1.model.*slots at allapply_slots({"1.seed": 42})wrote index 1 — silently clobbering the model selector — with zero warningsRoot cause:
_is_linktreatedCOMFY_DYNAMICCOMBO_V3as a connection (dropped fromwidget_order), andwidget_orderwas value-independent while the frontend inlines the selected option's widget sub-values into the flat positionalwidgets_valuesright after the selector.Fix
COMFY_*COMBO*type is a widget port. Its enum = the optionkeystrings; the raw option dicts are retained onPort.dynamic_optionsfor expansion._is_scalar_choicestill rejects dict options for ordinary combos.Graph.widget_order_for_node(class_name, widgets_values): value-aware order — at a dynamic combo it reads the selector from its own positional slot and expands the matching option's widget-like sub-inputs as<name>.<sub>(same widget-vs-link test as top level; nested dynamic combos recurse with a depth cap; connection subs likeCOMFY_AUTOGROW_V3contribute no slot;control_after_generatemarkers follow control-flagged inputs, sub-inputs included).widget_order(class_name)is kept for callers without node context._node_widget_slotsemitsN.model(typeCOMFY_DYNAMICCOMBO_V3,enum= option keys, current = selector) plusN.model.<sub>slots with correct types/enums/current values. Slots with enum choices now carry an additiveenumkey.set-slot/vary):N.model.<sub>=vwrites the correct position, validated against the sub-spec.N.model=<other key>rebuildswidgets_valuesfor that node: values before the combo kept, new selector written, the new option's widget sub-inputs filled from schema defaults (sub-specdefault, first enum option for combos), trailing values (seed/marker/watermark/thinking) re-aligned — and emits adynamic_combo_roster_rebuiltwarning describing the rebuild.N.model.<sub>that doesn't exist under the current selector →unknown_dynamic_sub_inputwarning, no write, listing the valid addresses and how to switch rosters. This denial is schema-grounded, not assumed: under theproselector the frontend serializes nomax_imagesslot (the vendored pristine template's 8-value layout confirms it), so the write has no position to land in — the warning redirects to the valid addresses instead of dead-ending.N.model=<unknown key>→ hard error listing valid options (an unknown selector has no roster to build; writing it would corrupt the positional alignment of everything after — deliberate deviation from ordinary combos, which warn-and-write)._resolve_proxy_value(curated subgraph proxy reads) migrated to the value-aware order as well.Judgment calls
workflow_to_api). I kept them separate — the converter operates on rawINPUT_TYPESspecs, the engine on parsedPorts, and a cross-module import would couple the CQL engine to the converter's internals. The rules are aligned (_is_dynamic_combo_typemirrors_is_widget_input'sCOMFY_*COMBO*test) and both sides are pinned by tests on the same fixtures.size_presetlist ≠ pro's), so defaults are the safe deterministic choice; the warning tells the agent what was reset.test_slot_address_with_dotted_input_name) to monkeypatchwidget_order_for_nodeinstead ofwidget_order— its intent (first-dot address split) is unchanged.Tests
tests/comfy_cli/command/test_workflow_slots.py: pristine-template slots (addresses/types/enums/currents,1.seedcurrent is0not the model name), seed write doesn't clobber the selector, sub-input write hits index 2, selector change to lite rebuilds the roster (+2 slots,max_images/fail_on_partialappear, prompt/seed/watermark preserved, warning emitted, new roster addressable), unknown sub-address warns without mutating, unknown selector rejected,varyover a sub-input, autogrow subs not exposed.tests/comfy_cli/cql/test_engine.py: dynamic combo parses as widget with option-key enum; value-independent vs value-aware order; nested-combo recursion; unknown selector expands nothing; nested + outer selector-change rebuilds.Verification
uv run pytest tests/comfy_cli/command/test_workflow_slots.py tests/comfy_cli/cql/ tests/comfy_cli/test_workflow_to_api.py— 285 passeduv run pytest tests/— 2653 passed, 2 failed:test_validate_command.py::test_api_format_unchanged+::test_empty_dict_payload_unchangedfail identically on cleanorigin/main(pre-existing: the BE-3357prompt_no_outputshard error now rejects those tests' output-node-less fixtures) — unrelated to this diffruff checkclean on all touched files;ruff formatapplied (the 15 repo-wide UP038 findings also pre-exist onorigin/mainunder the local ruff)