A seed of -1 means random, as it does everywhere else

Omitting the seed was already random. Passing -1 was not: it went through the
uint64 wrap and arrived as 18446744073709551615, which is a perfectly valid
*fixed* seed -- so "give me something new" returned the identical picture every
time, silently, and the retry loop would have redrawn the same rejected image
until it ran out of attempts.

-1 is what ComfyUI's own interface uses for random, and A1111, and everything
else that has ever asked somebody for a seed. A model that has read any of them
will write it, so the one reading that had to work was the one that did not.

Any negative value, not only -1, because the sentinel is the *idea* rather than
the number and a model that writes -2 means the same thing. Zero stays a real
seed: it is the boundary this change could easily have swallowed, and it is one
somebody deliberately picks.

Confirmed against the real ComfyUI: -1 now sends a random uint64 that it accepts
and draws from.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaroslav Beneš
2026-08-05 14:23:38 +02:00
parent 5e75948069
commit ca7eb6cedb
5 changed files with 41 additions and 4 deletions
+21
View File
@@ -96,6 +96,27 @@ def test_a_named_seed_is_kept():
assert wf.resolve({"prompt": "x", "seed": 1234})["seed"] == 1234
@pytest.mark.parametrize("sentinel", [-1, -5, "-1"])
def test_a_negative_seed_means_random(sentinel):
"""`-1` is what ComfyUI's own interface, A1111 and everything else that has
ever asked for a seed use for "surprise me", so a model that has read any of
them will write it.
Without this it went through the uint64 wrap and came out as
18446744073709551615 -- a perfectly valid *fixed* seed, so asking for
something new produced the same picture every time.
"""
seeds = {wf.resolve({"prompt": "x", "seed": sentinel})["seed"] for _ in range(8)}
assert len(seeds) == 8
assert all(0 <= seed <= wf.MAX_SEED for seed in seeds)
def test_seed_zero_is_a_real_seed():
"""It is the boundary the negative test could easily have swallowed, and
zero is a seed somebody deliberately picks."""
assert wf.resolve({"prompt": "x", "seed": 0})["seed"] == 0
@pytest.mark.parametrize("empty", [None, ""])
def test_null_and_empty_mean_no_opinion(empty):
"""A model that emits `"steps": null` rather than omitting the key is common