From 38afb10c84fec9bb96276a83a507336abd698aab Mon Sep 17 00:00:00 2001 From: killersteps <34531389+killersteps@users.noreply.github.com> Date: Tue, 8 Sep 2026 11:17:41 +0800 Subject: [PATCH] fix: hide leftover enabledModels warnings when other models still match A deleted or retired model can leave a glob in enabledModels. The composer then showed a model-scope warning on every session, including ones that never used that model. Keep no-match diagnostics only when the entire scope is empty and the UI falls back to every available model. Sibling leftovers are ignored while the remaining patterns still produce a usable list. --- lib/model-scope.test.mjs | 11 +++++++---- lib/model-scope.ts | 8 +++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/model-scope.test.mjs b/lib/model-scope.test.mjs index a6e7c1443..dc377e66f 100644 --- a/lib/model-scope.test.mjs +++ b/lib/model-scope.test.mjs @@ -108,12 +108,15 @@ test("leaves models without a pinned thinking level unpinned", async () => { assert.deepEqual(result.thinkingLevelPins, { "anthropic/claude-opus-5": "high" }); }); -test("reports patterns that match nothing but keeps the models that matched", async () => { - const result = await resolveVisibleModels(runtime, ["anthropic/claude-opus-5", "ghost-gateway/*"]); +test("keeps models that matched and stays quiet about leftover unmatched globs", async () => { + const result = await resolveVisibleModels(runtime, [ + "anthropic/claude-opus-5", + "retired-provider/old-model-*", + "ghost-gateway/*", + ]); assert.deepEqual(refs(result), ["anthropic/claude-opus-5"]); - assert.equal(result.warnings.length, 1); - assert.match(result.warnings[0], /ghost-gateway\/\*/); + assert.deepEqual(result.warnings, []); }); test("falls back to all available models when nothing matches at all", async () => { diff --git a/lib/model-scope.ts b/lib/model-scope.ts index ce399055b..429b5167b 100644 --- a/lib/model-scope.ts +++ b/lib/model-scope.ts @@ -125,7 +125,13 @@ export async function resolveVisibleModels( getAvailable: async () => available, } as ModelRuntime; const { scopedModels, diagnostics } = await resolveModelScopeWithDiagnostics(cleaned, snapshotRuntime); - const warnings = diagnostics.map((diagnostic) => diagnostic.message); + // A leftover glob after a model was removed is not a chat-level problem when + // other enabledModels entries still matched. Keep no-match warnings only for + // a total miss, where the UI falls back to every available model and the user + // needs to know the scope did not apply. + const warnings = diagnostics + .filter((diagnostic) => diagnostic.code !== "no-match" || scopedModels.length === 0) + .map((diagnostic) => diagnostic.message); if (scopedModels.length === 0) { return { visible: available,