Commit Graph

4 Commits

Author SHA1 Message Date
Jedrzej Kosinski
8cac12afa8 DynamicSlot: support required slots and always forceInput
- Add `optional` kwarg to DynamicSlot.Input (default True). When False,
  declaring a when=None Option is rejected because the unconnected branch
  is unreachable.
- Always publish `forceInput=True` on the slot itself. slotType may
  include widget-capable types (INT/STRING/etc.) but a DynamicSlot is
  meant to look like a connection point, never a widget.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8568-f382-743d-a97f-0de3ff29d501
Co-authored-by: Amp <amp@ampcode.com>
2026-06-01 19:28:15 -07:00
Jedrzej Kosinski
346ee898cb DynamicSlot: forbid AnyType inside list/MultiType when
Grouping AnyType with concrete types conflates the known-type case with
the unresolvable-wildcard case under one branch and muddies slotType.
AnyType must stand alone as when=io.AnyType so the two states stay
distinct in both dispatch and the serialized schema.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8568-f382-743d-a97f-0de3ff29d501
Co-authored-by: Amp <amp@ampcode.com>
2026-06-01 19:18:10 -07:00
Jedrzej Kosinski
16dd7d115c DynamicSlot: address code review
Bug fixes:
- execution.py validate_inputs() now calls _select_option for DynamicSlot
  links instead of validating against slotType. Old code accepted any
  concrete upstream type whenever AnyType was enumerated (slotType
  contained '*', which validate_node_input treats as accept-anything).
  Verified end-to-end: LATENT into an IMAGE+AnyType slot is now rejected.
- Thread live_input_types through get_input_data so custom V3
  validate_inputs() sees the same DynamicSlot branch that finalization
  picked, instead of re-finalizing without resolver context.
- DynamicSlot.Option._when_types is now an ordered tuple (preserves
  author declaration order); _slot_io_type/slotType ordering was
  previously nondeterministic via frozenset iteration.

Design:
- DynamicSlot.Input.get_all() now returns [self] + children, matching
  Autogrow / DynamicCombo so consumers like PriceBadge work uniformly.
- Enforce per-option type uniqueness in DynamicSlot.Input: each io_type
  may appear in at most one option's 'when', and at most one option may
  declare when=None. Removes the ambiguous first-match-on-overlap case
  for single concrete types; ordering still matters when upstream is a
  multi-type union.
- Reject non-Option entries in options=[...] explicitly.

Polish:
- Trim verbose DynamicSlot docstrings and inline comments.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8568-f382-743d-a97f-0de3ff29d501
Co-authored-by: Amp <amp@ampcode.com>
2026-06-01 18:34:30 -07:00
Jedrzej Kosinski
d91c1d8d48 DynamicSlot: typed option dispatch driven by TypeResolver
Replaces the old connected/unconnected fixed-child DynamicSlot with a
type-keyed option list. Each Option declares a 'when' condition (None,
io.AnyType, a single ComfyType, a list, or a MultiType.Input) and the
child inputs revealed when that condition matches the slot's resolved
upstream type.

Selection happens at schema-finalization time using live_input_types
computed by TypeResolver, so API-only workflows (no frontend) get the
same expansion the UI would.

- _io.py: redesign DynamicSlot.Input / Option; auto-derive slotType as
  the union of all non-None when sets; expose it via as_dict so the
  frontend knows what types are accepted; the class io_type stays
  COMFY_DYNAMICSLOT_V3 as the parse-time dispatch tag.
- type_resolver.py: return the auto-derived _slot_io_type for
  DynamicSlot.Input; document the AnyType (*) limitation.
- execution.py: validate links into a DynamicSlot against slotType,
  not the dispatch tag COMFY_DYNAMICSLOT_V3.
- tests: new test_dynamic_slot.py + regression coverage in
  test_type_resolver.py.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8568-f382-743d-a97f-0de3ff29d501
Co-authored-by: Amp <amp@ampcode.com>
2026-06-01 17:56:32 -07:00