Match both spellings when the monitor unloads a model
My earlier fix compared the store checkpoint only against the identifier /status reports, which is the concrete load path. For a GGUF loaded through auto-switch or from a non-active cache the store can hold the advertised repo id instead, so the comparison failed and the store stayed pinned to a model that had just been freed. Match the load path and the public alias, and keep the external guard that prompted the narrower comparison.
This commit is contained in:
parent
79ddfa2ef4
commit
dc2d160c64
2 changed files with 28 additions and 1 deletions
|
|
@ -21,6 +21,7 @@ import { getInferenceStatus, unloadModel } from "@/features/chat/api/chat-api";
|
|||
import { resolveInferenceCheckpointId } from "@/features/chat/lib/apply-inference-status-to-store";
|
||||
import { useChatRuntimeStore } from "@/features/chat/stores/chat-runtime-store";
|
||||
import type { ApiMonitorEntry } from "@/features/chat/types/api";
|
||||
import { isExternalModelId } from "@/features/chat/external-providers";
|
||||
import { modelIdsMatch } from "@/features/hub/lib/model-identity";
|
||||
import { useSettingsDialogStore } from "@/features/settings";
|
||||
import { getApiBase, isTauri } from "@/lib/api-base";
|
||||
|
|
@ -520,9 +521,17 @@ export function ApiMonitorPage(): ReactElement {
|
|||
// external provider selected while a local model stays resident, and
|
||||
// clearCheckpoint calls saveLastExternalCheckpoint(null), so clearing
|
||||
// unconditionally would delete a selection this button never touched.
|
||||
// Both spellings: status reports the concrete load path as the identifier
|
||||
// while the store may hold the advertised repo id, so matching only the
|
||||
// path leaves the store pinned to a model this button just freed.
|
||||
const store = useChatRuntimeStore.getState();
|
||||
const selected = store.params.checkpoint;
|
||||
if (selected && modelIdsMatch(selected, checkpoint)) {
|
||||
const unloadedAliases = [checkpoint, status.active_model];
|
||||
if (
|
||||
selected &&
|
||||
!isExternalModelId(selected) &&
|
||||
unloadedAliases.some((alias) => modelIdsMatch(selected, alias))
|
||||
) {
|
||||
store.clearCheckpoint();
|
||||
}
|
||||
setUnloadError(null);
|
||||
|
|
|
|||
|
|
@ -1527,3 +1527,21 @@ def test_a_standalone_gguf_has_one_settings_identity_everywhere():
|
|||
bare = route.index("\n target_id,\n")
|
||||
labelled = route.index('f"{target_id}:{file_variant}"')
|
||||
assert bare < labelled, "the bare path must be read before the filename label"
|
||||
|
||||
|
||||
def test_monitor_unload_clears_only_the_model_it_freed():
|
||||
"""Unload targets the resident local model from /status, but the store may
|
||||
hold either spelling: status reports the concrete load path while the store
|
||||
can hold the advertised repo id. Matching one spelling leaves the store
|
||||
pinned to a model just freed; matching none of them, or matching an external
|
||||
pick, deletes a selection this button never touched, because clearCheckpoint
|
||||
also drops the persisted external checkpoint."""
|
||||
page = " ".join(
|
||||
_read("features/api-monitor/api-monitor-page.tsx").split()
|
||||
)
|
||||
assert "const unloadedAliases = [checkpoint, status.active_model];" in page
|
||||
assert "!isExternalModelId(selected)" in page
|
||||
assert (
|
||||
"unloadedAliases.some((alias) => modelIdsMatch(selected, alias))" in page
|
||||
)
|
||||
assert "store.clearCheckpoint();" in page
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue