From 11c65023fd339d346220fd1052b34b1908b22699 Mon Sep 17 00:00:00 2001 From: Arafatkatze Date: Wed, 8 Jul 2026 12:08:31 -0700 Subject: [PATCH] Update ClinePass model ordering --- .../refreshClineRecommendedModels.test.ts | 48 +++++++++++++++++++ .../models/refreshClineRecommendedModels.ts | 31 +++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/apps/vscode/src/core/controller/models/__tests__/refreshClineRecommendedModels.test.ts b/apps/vscode/src/core/controller/models/__tests__/refreshClineRecommendedModels.test.ts index ede91bd7f7..bf89aed185 100644 --- a/apps/vscode/src/core/controller/models/__tests__/refreshClineRecommendedModels.test.ts +++ b/apps/vscode/src/core/controller/models/__tests__/refreshClineRecommendedModels.test.ts @@ -11,6 +11,19 @@ import { resetClineRecommendedModelsCacheForTests, } from "../refreshClineRecommendedModels"; +const expectedClinePassModelOrder = [ + "cline-pass/glm-5.2", + "cline-pass/deepseek-v4-pro", + "cline-pass/deepseek-v4-flash", + "cline-pass/kimi-k2.7-code", + "cline-pass/kimi-k2.6", + "cline-pass/mimo-v2.5-pro", + "cline-pass/mimo-v2.5", + "cline-pass/minimax-m3", + "cline-pass/qwen3.7-max", + "cline-pass/qwen3.7-plus", +] as const; + describe("refreshClineRecommendedModels", () => { let sandbox: sinon.SinonSandbox; @@ -128,6 +141,41 @@ describe("refreshClineRecommendedModels", () => { expect(secondResult).to.deep.equal(firstResult); }); + it("orders ClinePass models using the curated display order", async () => { + sandbox.stub(ClineEnv, "config").returns({ + environment: Environment.production, + appBaseUrl: "https://app.cline-mock.bot", + apiBaseUrl: "https://api.cline-mock.bot", + mcpBaseUrl: "https://api.cline-mock.bot/v1/mcp", + }); + sandbox.stub(disk, "ensureCacheDirectoryExists").resolves("/tmp"); + sandbox.stub(fs, "writeFile").resolves(); + sandbox.stub(axios, "get").resolves({ + data: { + clinePass: [ + { id: "cline-pass/qwen3.7-plus" }, + { id: "cline-pass/new-model" }, + { id: "cline-pass/deepseek-v4-flash" }, + { id: "cline-pass/glm-5.2" }, + { id: "cline-pass/qwen3.7-max" }, + { id: "cline-pass/deepseek-v4-pro" }, + { id: "cline-pass/minimax-m3" }, + { id: "cline-pass/kimi-k2.6" }, + { id: "cline-pass/mimo-v2.5" }, + { id: "cline-pass/mimo-v2.5-pro" }, + { id: "cline-pass/kimi-k2.7-code" }, + ], + }, + }); + + const result = await refreshClineRecommendedModels(); + + expect(result.clinePass.map((model) => model.id)).to.deep.equal([ + ...expectedClinePassModelOrder, + "cline-pass/new-model", + ]); + }); + it("normalizes Cline provider Z.ai recommended IDs to the Cline API alias", async () => { sandbox.stub(ClineEnv, "config").returns({ environment: Environment.production, diff --git a/apps/vscode/src/core/controller/models/refreshClineRecommendedModels.ts b/apps/vscode/src/core/controller/models/refreshClineRecommendedModels.ts index 00a38e7bc4..dbb181ba10 100644 --- a/apps/vscode/src/core/controller/models/refreshClineRecommendedModels.ts +++ b/apps/vscode/src/core/controller/models/refreshClineRecommendedModels.ts @@ -26,6 +26,21 @@ const RECOMMENDED_MODELS_CACHE_TTL_MS = 60 * 60 * 1000; const CLINE_PASS_MODEL_ID_ALIAS_RULES = [ { canonicalPrefix: "cline-pass/zai/", aliasPrefix: "cline-pass/z-ai/" }, ] as const; +const CLINE_PASS_MODEL_ORDER = [ + "cline-pass/glm-5.2", + "cline-pass/deepseek-v4-pro", + "cline-pass/deepseek-v4-flash", + "cline-pass/kimi-k2.7-code", + "cline-pass/kimi-k2.6", + "cline-pass/mimo-v2.5-pro", + "cline-pass/mimo-v2.5", + "cline-pass/minimax-m3", + "cline-pass/qwen3.7-max", + "cline-pass/qwen3.7-plus", +] as const; +const CLINE_PASS_MODEL_ORDER_INDEX = new Map( + CLINE_PASS_MODEL_ORDER.map((modelId, index) => [modelId, index]), +); function normalizeClineProviderRecommendedModelId(modelId: string): string { const zaiPrefix = "zai/"; @@ -75,6 +90,18 @@ function preferCanonicalRecommendedModels( }); } +function orderClinePassRecommendedModels( + models: ClineRecommendedModelData[], +): ClineRecommendedModelData[] { + return [...models].sort((a, b) => { + const aIndex = + CLINE_PASS_MODEL_ORDER_INDEX.get(a.id) ?? Number.MAX_SAFE_INTEGER; + const bIndex = + CLINE_PASS_MODEL_ORDER_INDEX.get(b.id) ?? Number.MAX_SAFE_INTEGER; + return aIndex - bIndex; + }); +} + function normalizeRecommendedModel( raw: unknown, ): ClineRecommendedModelData | null { @@ -137,7 +164,9 @@ function normalizeRecommendedModelsResponse( return { recommended: normalizeClineProviderRecommendedModels(recommended), free: normalizeClineProviderRecommendedModels(free), - clinePass: preferCanonicalRecommendedModels(clinePass), + clinePass: orderClinePassRecommendedModels( + preferCanonicalRecommendedModels(clinePass), + ), }; }