diff --git a/src/cli/doctor/checks/model-resolution.test.ts b/src/cli/doctor/checks/model-resolution.test.ts index 2d1c09919..49d308f3c 100644 --- a/src/cli/doctor/checks/model-resolution.test.ts +++ b/src/cli/doctor/checks/model-resolution.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeEach, afterEach, spyOn, mock } from "bun:test" +import { describe, it, expect } from "bun:test" describe("model-resolution check", () => { describe("getModelResolutionInfo", () => { @@ -235,6 +235,28 @@ describe("model-resolution check", () => { expect(issues[0]?.title).toContain("compatibility fallback") expect(issues[0]?.description).toContain("oracle=custom/unknown-llm") }) + + it("does not warn for known provider aliases used by current recommended models", async () => { + const { collectCapabilityResolutionIssues, getModelResolutionInfoWithOverrides } = await import("./model-resolution") + + // #given current recommended provider aliases from user configuration + const info = getModelResolutionInfoWithOverrides({ + agents: { + sisyphus: { model: "kimi-for-coding/k2pb" }, + metis: { model: "github-copilot/claude-opus-4.7" }, + }, + categories: { + "visual-engineering": { model: "github-copilot/claude-opus-4.7" }, + artistry: { model: "github-copilot/claude-opus-4.7" }, + }, + }) + + // #when collecting doctor capability issues + const issues = collectCapabilityResolutionIssues(info) + + // #then these known aliases do not create compatibility fallback warnings + expect(issues).toHaveLength(0) + }) }) }) diff --git a/src/cli/doctor/checks/model-resolution.ts b/src/cli/doctor/checks/model-resolution.ts index ea7d538e6..ccc697845 100644 --- a/src/cli/doctor/checks/model-resolution.ts +++ b/src/cli/doctor/checks/model-resolution.ts @@ -95,7 +95,7 @@ export function collectCapabilityResolutionIssues(info: ModelResolutionInfo): Do const allEntries = [...info.agents, ...info.categories] const fallbackEntries = allEntries.filter((entry) => { const mode = entry.capabilityDiagnostics?.resolutionMode - return mode === "alias-backed" || mode === "heuristic-backed" || mode === "unknown" + return mode === "unknown" }) if (fallbackEntries.length === 0) { diff --git a/src/shared/model-capability-aliases.test.ts b/src/shared/model-capability-aliases.test.ts index b6f5b6641..83936169b 100644 --- a/src/shared/model-capability-aliases.test.ts +++ b/src/shared/model-capability-aliases.test.ts @@ -56,6 +56,28 @@ describe("model-capability-aliases", () => { }) }) + test("normalizes Kimi for Coding k2pb aliases to the snapshot ID", () => { + const result = resolveModelIDAlias("kimi-for-coding/k2pb") + + expect(result).toEqual({ + requestedModelID: "kimi-for-coding/k2pb", + canonicalModelID: "k2p5", + source: "exact-alias", + ruleID: "kimi-k2pb-alias", + }) + }) + + test("normalizes GitHub Copilot dotted Claude Opus aliases to the snapshot ID", () => { + const result = resolveModelIDAlias("github-copilot/claude-opus-4.7") + + expect(result).toEqual({ + requestedModelID: "github-copilot/claude-opus-4.7", + canonicalModelID: "claude-opus-4-7", + source: "exact-alias", + ruleID: "claude-opus-dotted-version-alias", + }) + }) + test("does not resolve prototype keys as aliases", () => { const result = resolveModelIDAlias("constructor") diff --git a/src/shared/model-capability-aliases.ts b/src/shared/model-capability-aliases.ts index fe7ef6b3b..7691c4683 100644 --- a/src/shared/model-capability-aliases.ts +++ b/src/shared/model-capability-aliases.ts @@ -32,6 +32,18 @@ const EXACT_ALIAS_RULES: ReadonlyArray = [ canonicalModelID: "gemini-3-pro-preview", rationale: "Legacy Gemini 3 tier suffixes still need to land on the canonical preview model.", }, + { + aliasModelID: "k2pb", + ruleID: "kimi-k2pb-alias", + canonicalModelID: "k2p5", + rationale: "Kimi for Coding exposes k2pb while the bundled capabilities snapshot uses the canonical k2p5 ID.", + }, + { + aliasModelID: "claude-opus-4.7", + ruleID: "claude-opus-dotted-version-alias", + canonicalModelID: "claude-opus-4-7", + rationale: "GitHub Copilot exposes Claude Opus 4.7 with dotted version syntax while the snapshot uses dashed syntax.", + }, ] const EXACT_ALIAS_RULES_BY_MODEL: ReadonlyMap = new Map(