Update ClinePass model ordering

This commit is contained in:
Arafatkatze
2026-07-08 12:12:44 -07:00
parent 7eb7897ff2
commit 11c65023fd
2 changed files with 78 additions and 1 deletions
@@ -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,
@@ -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<string, number>(
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),
),
};
}