From e1c792f4912a1bcb2830ef56d5d65e28f28149f1 Mon Sep 17 00:00:00 2001 From: Devvyn <22340871+opticon454@users.noreply.github.com> Date: Mon, 2 Nov 2026 16:53:09 +0800 Subject: [PATCH] fix(custom-model): ignore a remembered model id the endpoint no longer lists Round-four review, split fix 1: a stale 'last used' id kept the promotion truthy, so no row was tagged and the 'Nothing is marked' line stayed hidden. Derive it from promoted && models.includes(promoted). --- src/web/public/session-ui.js | 5 ++++- test/custom-model-run-menu-ui.test.ts | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/web/public/session-ui.js b/src/web/public/session-ui.js index e965485e..f87da923 100644 --- a/src/web/public/session-ui.js +++ b/src/web/public/session-ui.js @@ -1133,7 +1133,10 @@ Object.assign(CodemanApp.prototype, { // `isLlamaSwap: false` is a real "I cannot tell you", where a probe that timed out or // failed (`runningStatus === null`) is not, the box may merely be asleep, so an // unreachable endpoint stays silent instead of explaining something it does not know. - const nothingKnown = !promoted && runningStatus?.isLlamaSwap === false; + // A remembered id that has since vanished from host.models is no promotion: count + // only a promoted id that is actually a row, or a stale "last used" would both skip + // tagging any row and hide this line, leaving 40 unmarked rows with no explanation. + const nothingKnown = !(promoted && models.includes(promoted)) && runningStatus?.isLlamaSwap === false; const unknownLine = document.getElementById('customModelPickUnknown'); if (unknownLine) unknownLine.hidden = !nothingKnown; list.innerHTML = models diff --git a/test/custom-model-run-menu-ui.test.ts b/test/custom-model-run-menu-ui.test.ts index 8fe11364..579ce8ea 100644 --- a/test/custom-model-run-menu-ui.test.ts +++ b/test/custom-model-run-menu-ui.test.ts @@ -329,6 +329,27 @@ describe('Custom Model Endpoint Profiles: the "which model" picker', () => { expect(buttons[0].textContent).not.toContain('Currently loaded'); }); + it('treats a remembered "last used" id the host no longer lists as nothing promoted: no tag, the line shows', async () => { + const { win, app } = bootApp({ + hosts: [{ id: 'llama-box', label: 'llama.cpp', baseUrl: 'http://x', models: ['qwen3', 'llama3'] }], + }); + const origApiJson = app._apiJson; + app._apiJson = async (path: string) => { + if (path === '/api/model-endpoints/llama-box/running-status') return { isLlamaSwap: false, running: [] }; + return origApiJson(path); + }; + // The remembered model was deleted from this endpoint since the last launch. + win.localStorage.setItem('codeman:customModelLastUsed:claude:llama-box', 'gone-model'); + + await app.selectCustomModelEntry('claude', 'llama-box'); + + const list = win.document.getElementById('customModelPickList')!; + expect(list.textContent).not.toContain('Last used'); + // Without a promoted row the probe really did answer "nothing is known", so the + // explanation line must show rather than leave two unmarked rows unexplained. + expect(win.document.getElementById('customModelPickUnknown')!.hidden).toBe(false); + }); + it('prefers the currently-loaded model over a stale "last used" entry when both are present', async () => { const { win, app } = bootApp({ hosts: [{ id: 'llama-box', label: 'llama.cpp', baseUrl: 'http://x', models: ['qwen3', 'llama3', 'phi4'] }],