Skip to content

Commit b64738c

Browse files
committed
Recover compare layout after transient refresh errors
1 parent 1329ed7 commit b64738c

2 files changed

Lines changed: 23 additions & 13 deletions

File tree

studio/frontend/src/features/chat/chat-page.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -478,20 +478,28 @@ const CompareContent = memo(function CompareContent({
478478
);
479479
const modelsError = useChatRuntimeStore((state) => state.modelsError);
480480
const [isLoraCompare, setIsLoraCompare] = useState<boolean | null>(null);
481+
const usedInventoryFallbackRef = useRef(false);
481482

482483
// Wait for the full LoRA inventory before choosing the layout, then freeze
483484
// that choice. Generalized compare temporarily changes the global checkpoint
484485
// as it visits each pane; those later changes must never remount the layout.
485486
useEffect(() => {
486-
if (!modelRuntimeHydrated && !modelsError) return;
487-
setIsLoraCompare(
488-
(current) =>
489-
current ??
490-
(modelRuntimeHydrated
491-
? getIsLoraCompareFromState(useChatRuntimeStore.getState())
492-
: false),
493-
);
494-
}, [modelRuntimeHydrated, modelsError]);
487+
if (modelRuntimeHydrated) {
488+
const detected = getIsLoraCompareFromState(
489+
useChatRuntimeStore.getState(),
490+
);
491+
if (usedInventoryFallbackRef.current) {
492+
usedInventoryFallbackRef.current = false;
493+
setIsLoraCompare(detected);
494+
} else {
495+
setIsLoraCompare((current) => current ?? detected);
496+
}
497+
return;
498+
}
499+
if (!modelsError || isLoraCompare !== null) return;
500+
usedInventoryFallbackRef.current = true;
501+
setIsLoraCompare(false);
502+
}, [modelRuntimeHydrated, modelsError, isLoraCompare]);
495503

496504
if (isLoraCompare === null) {
497505
return <div className="min-h-0 flex-1" aria-busy="true" />;

tests/studio/test_compare_cancellation_contract.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ def test_compare_layout_waits_for_inventory_then_freezes():
3232
compare = compare.split("return isLoraCompare ?", 1)[0]
3333
assert "state.modelRuntimeHydrated" in compare
3434
assert "state.modelsError" in compare
35-
assert "if (!modelRuntimeHydrated && !modelsError) return;" in compare
36-
assert ": false)" in compare
35+
assert "usedInventoryFallbackRef" in compare
36+
assert "if (!modelsError || isLoraCompare !== null) return;" in compare
37+
assert "setIsLoraCompare(false);" in compare
38+
assert "setIsLoraCompare(detected);" in compare
3739
assert "const [isLoraCompare, setIsLoraCompare]" in compare
38-
assert "getIsLoraCompareFromState(useChatRuntimeStore.getState())" in compare
40+
assert "getIsLoraCompareFromState(" in compare
41+
assert "useChatRuntimeStore.getState()" in compare
3942
assert "current ??" in compare
40-
assert "? getIsLoraCompareFromState" in compare
4143
assert 'aria-busy="true"' in compare
4244

4345

0 commit comments

Comments
 (0)