Local mode runs rewritten components inside the local ComfyUI process and
exists only for developing the extension, yet it was the default, so users
who did not set the variable silently ran in it. settings now owns the
default (remote) through configured_execution_mode(), and every host-side
reader uses it. The Modal image environment pins local explicitly, as SSH
and Vast workers already do, so container code keeps its in-process
behaviour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Worker slots live in separate namespaces (mapped lanes use
worker-pool:slot:N, ordinary components worker-pool:comfy|llm:slot:N),
each its own Modal container. Matching only the trailing slot:N gave the
reserve cooldown to both the static comfy:slot:0 worker and mapped lane
slot:0 in hybrid prompts, so reserve_cooldown_count=1 kept two idle GPUs.
The planner now stamps one modal_reserve_cooldown_pool per Modal
environment (mapped lanes when the prompt has mapped work, else comfy,
else llm), and the lookup grants the reserve cooldown only to leading
slots of that pool; every other worker uses the global cooldown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Modal Configuration node gains three advanced widgets:
- global_cooldown (default 60s): idle scaledown for every Modal worker.
- reserve_cooldown_count (default 0): how many worker slots use the reserve
cooldown; must not exceed instance_count.
- reserve_cooldown (default 300s): idle scaledown for the reserved slots.
The policy travels on remote payloads and is applied per call with
Cls.with_options(scaledown_window=...), keyed by the worker-pool slot parsed
from the affinity key. Slots below reserve_cooldown_count stay warm longer;
other slots and unslotted keys use the global cooldown. Local-gap pools still
keep at least the local keepalive window. The fields do not shape the runtime
fingerprint, but derived payloads (warmups, prewarm targets, mapped phases)
inherit them so they land in the same container pool.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hybrid mapped execution rebuilt its static, mapped, and cleanup phase payloads
from a fixed field list that dropped modal_gpu and modal_max_containers. Those
payloads resolved default settings and expected a different runtime fingerprint
for the same Modal app, so the sibling-validation guard refused them with
ModalRemoteAppOutOfDateError.
Define the fingerprint-shaping payload fields once in settings and copy them at
every derived-payload site (mapped phases, warmup requests, speculative
prewarm targets).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>