From 3be31947dd434be340eb66caefd219230927038f Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Wed, 15 Jul 2026 14:49:43 +0000 Subject: [PATCH] Export page: defer format pruning until hardware info is authoritative The availableFormats prune effect ran on the initial render before /api/system/hardware resolves, when hasNvidia is false and the NVIDIA-only compressed-tensors formats are transiently absent. On a fresh Export mount with the module cache empty (cold start, or a remount during refreshHardwareInfo), a running FP8/NVFP4 selection was pruned permanently, since the later hardware response only adds formats back to availableFormats and never restores selectedFormats. Gate the effect on hardware.loaded so it prunes only against the authoritative capability set, matching the effect's stated intent. --- studio/frontend/src/features/export/export-page.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/studio/frontend/src/features/export/export-page.tsx b/studio/frontend/src/features/export/export-page.tsx index 8edc8dcb73..42cbff5a32 100644 --- a/studio/frontend/src/features/export/export-page.tsx +++ b/studio/frontend/src/features/export/export-page.tsx @@ -260,13 +260,17 @@ export function ExportPage() { }, []); // Drop any already-selected format that the gate just removed (e.g. torchao once win32Rocm // resolves after /api/system/hardware lands), so a stale pick isn't summarized or exported. + // Gate on hardware.loaded: before the authoritative response hasNvidia is false, so the + // NVIDIA-only compressed formats are transiently absent and pruning here would permanently + // drop a running FP8/NVFP4 selection that the later response cannot restore. useEffect(() => { + if (!hardware.loaded) return; const allowed = new Set(availableFormats.map((f) => f.value)); setSelectedFormats((prev) => { const next = prev.filter((v) => allowed.has(v)); return next.length === prev.length ? prev : next; }); - }, [availableFormats]); + }, [availableFormats, hardware.loaded]); // IQ quants are imatrix-only: force imatrix on when one is selected, else llama.cpp rejects it. const requiresImatrix = quantLevels.some( (q) => QUANT_OPTIONS.find((o) => o.value === q)?.imatrix,