Studio: preserve foreign gallery files, force safetensors on remote ControlNets, and close dataset/seed/GPU gaps

Gallery clear/delete now scope to Studio-owned files: image_gallery and
video_gallery skip PNGs / MP4s without a readable recipe (a hand-dropped or
orphan file the listing already hides), so clear() and a guessed-id delete no
longer destroy files the gallery never surfaced.

Remote ControlNets now force use_safetensors: a bare owner/name reaches
from_pretrained without the base trust gate, and the Hub scan fails open when
unavailable, so requiring safetensors closes the pickle deserialization vector.

POSIX uninstall now stops resident sd-server / sd-cli under an owned sd.cpp root
before removing the tree (marker-gated), mirroring the Windows stop-before-delete
scan; a live native server no longer survives unlinking its binary.

Diffusion dataset containment: the training-start read path and the discovery
picker route bare names through the protected resolver, so a symlinked dataset
is rejected / not advertised like the caption/delete routes already do. Uploads
gain the inference decode guard (oversized real images 400 before OOMing the
trainer) and dataset upload/caption/delete/import are blocked with 409 while a
diffusion run is active.

JSONL readers (trainer + routes) tolerate non-object JSON and invalid UTF-8
instead of raising AttributeError / 500.

LoRA family compatibility is enforced in the shared resolver, not only the
picker, so a direct API client cannot apply a mismatched-family adapter.

GPU arbiter gains release_if so the image/video unload idle-check and release
are atomic against a concurrent same-owner load's registration. Native batch
recipes persist the base batch_seed and restore replays from it, so a native
batch_index>0 image no longer advances its seed twice.

FLUX.2-klein selects its sd.cpp text encoder by variant (4B -> Qwen3-4B,
9B -> Qwen3-8B) instead of the single family default.
This commit is contained in:
Daniel Han 2026-07-13 10:02:42 +00:00
commit 5eef2f4003
23 changed files with 548 additions and 33 deletions

View file

@ -183,6 +183,26 @@ def test_asset_specs_cover_required_files(fam_name, expect_kinds):
assert tr[0] == "unsloth/x-GGUF" and tr[1] == "x-Q4_K_M.gguf"
def test_asset_specs_flux2_klein_selects_encoder_by_variant():
# FLUX.2-klein 4B pairs with Qwen3-4B, 9B with Qwen3-8B; the encoder must be chosen from the
# load identity, not the family's single default (a mismatched encoder fails deep in sd-cli).
b = SdCppDiffusionBackend(engine = _FakeEngine())
fam = detect_family("flux.2-klein")
specs_4b = b._asset_specs("unsloth/FLUX.2-klein-4B-GGUF", "FLUX.2-klein-4B-Q4_K_M.gguf", fam)
te_4b = [(r, f) for r, f, k in specs_4b if k == "llm"]
assert te_4b == [("Comfy-Org/z_image_turbo", "split_files/text_encoders/qwen_3_4b.safetensors")]
specs_9b = b._asset_specs("unsloth/FLUX.2-klein-9B-GGUF", "FLUX.2-klein-9B-Q4_K_M.gguf", fam)
te_9b = [(r, f) for r, f, k in specs_9b if k == "llm"]
assert te_9b == [
(
"Comfy-Org/vae-text-encorder-for-flux-klein-9b",
"split_files/text_encoders/qwen_3_8b.safetensors",
)
]
# ── guidance mapping ──────────────────────────────────────────────────────────
@ -295,6 +315,7 @@ def test_generate_publishes_progress_before_lora_resolution(monkeypatch):
def _resolve(
active,
*,
family = None,
hf_token = None,
cancel_event = None,
):