From bd1c35e0bafae2e7c2db1469de698a5b5adf7e20 Mon Sep 17 00:00:00 2001 From: "uihyeon.cha" Date: Sun, 12 Apr 2026 03:35:42 +0900 Subject: [PATCH 1/5] fix(models): align github-copilot fallback variants --- src/shared/model-capabilities.test.ts | 47 ++++++++ src/shared/model-requirements.test.ts | 105 ++++++++++++------ src/shared/model-requirements.ts | 52 ++++++--- .../model-settings-compatibility.test.ts | 36 ++++++ 4 files changed, 190 insertions(+), 50 deletions(-) diff --git a/src/shared/model-capabilities.test.ts b/src/shared/model-capabilities.test.ts index d221633effe..933622550ad 100644 --- a/src/shared/model-capabilities.test.ts +++ b/src/shared/model-capabilities.test.ts @@ -346,6 +346,53 @@ describe("getModelCapabilities", () => { }) }) + describe("Copilot runtime metadata edge cases", () => { + test("resolves claude-opus-4-6 object-form variants to exactly ['low','medium','high'] via Copilot provider", () => { + findProviderModelMetadataSpy = spyOn(connectedProvidersCache, "findProviderModelMetadata").mockReturnValue(undefined) + const result = getModelCapabilities({ + providerID: "github-copilot", + modelID: "claude-opus-4-6", + runtimeModel: { + variants: { + low: {}, + medium: {}, + high: {}, + }, + }, + bundledSnapshot, + }) + + expect(result.variants).toEqual(["low", "medium", "high"]) + expect(result.diagnostics).toMatchObject({ + variants: { source: "runtime" }, + }) + }) + + test("does not treat empty variants object as runtime variants for gemini-3.1-pro via Copilot provider", () => { + findProviderModelMetadataSpy = spyOn(connectedProvidersCache, "findProviderModelMetadata").mockReturnValue(undefined) + const result = getModelCapabilities({ + providerID: "github-copilot", + modelID: "gemini-3.1-pro", + runtimeModel: { + variants: {}, + }, + bundledSnapshot, + }) + + // An empty variant object must not produce numeric keys or phantom runtime variants. + // The runtime reader returns undefined for {}, so no runtime-sourced variants exist. + expect(result.diagnostics.variants.source).not.toBe("runtime") + // Variants may still be populated by heuristic family rules, but never from the empty object. + if (result.variants !== undefined) { + expect(result.variants).toEqual(expect.arrayContaining([expect.any(String)])) + for (const v of result.variants) { + expect(typeof v).toBe("string") + expect(Number.isInteger(Number(v))).toBe(false) + } + } + }) + }) + test("keeps every built-in OmO requirement model snapshot-backed", () => { const bundledSnapshot = getBundledModelCapabilitiesSnapshot() const requirementModels = new Set() diff --git a/src/shared/model-requirements.test.ts b/src/shared/model-requirements.test.ts index bb110f554b9..a34c31e3311 100644 --- a/src/shared/model-requirements.test.ts +++ b/src/shared/model-requirements.test.ts @@ -23,43 +23,56 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(primary.variant).toBe("high") }) - test("sisyphus has claude-opus-4-6 as primary with k2p5, kimi-k2.5, gpt-5.4 medium fallbacks", () => { + test("sisyphus keeps split claude-opus-4-6 entries and non-Copilot siblings", () => { // #given - sisyphus agent requirement const sisyphus = AGENT_MODEL_REQUIREMENTS["sisyphus"] // #when - accessing Sisyphus requirement - // #then - fallbackChain has 7 entries with correct ordering + // #then - fallbackChain has 8 entries with correct ordering expect(sisyphus).toBeDefined() expect(sisyphus.fallbackChain).toBeArray() - expect(sisyphus.fallbackChain).toHaveLength(7) + expect(sisyphus.fallbackChain).toHaveLength(8) expect(sisyphus.requiresAnyModel).toBe(true) const primary = sisyphus.fallbackChain[0] - expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode"]) + expect(primary.providers).toEqual(["anthropic", "opencode"]) expect(primary.model).toBe("claude-opus-4-6") expect(primary.variant).toBe("max") const second = sisyphus.fallbackChain[1] - expect(second.providers).toEqual(["opencode-go"]) - expect(second.model).toBe("kimi-k2.5") + expect(second.providers).toEqual(["github-copilot"]) + expect(second.model).toBe("claude-opus-4-6") + expect(second.variant).toBe("high") const third = sisyphus.fallbackChain[2] - expect(third.providers).toEqual(["kimi-for-coding"]) - expect(third.model).toBe("k2p5") + expect(third.providers).toEqual(["opencode-go"]) + expect(third.model).toBe("kimi-k2.5") const fourth = sisyphus.fallbackChain[3] - expect(fourth.model).toBe("kimi-k2.5") + expect(fourth.providers).toEqual(["kimi-for-coding"]) + expect(fourth.model).toBe("k2p5") const fifth = sisyphus.fallbackChain[4] - expect(fifth.providers).toContain("openai") - expect(fifth.model).toBe("gpt-5.4") - expect(fifth.variant).toBe("medium") + expect(fifth.model).toBe("kimi-k2.5") + expect(fifth.providers).toEqual([ + "opencode", + "moonshotai", + "moonshotai-cn", + "firmware", + "ollama-cloud", + "aihubmix", + ]) const sixth = sisyphus.fallbackChain[5] - expect(sixth.providers[0]).toBe("zai-coding-plan") - expect(sixth.model).toBe("glm-5") + expect(sixth.providers).toEqual(["openai", "github-copilot", "opencode"]) + expect(sixth.model).toBe("gpt-5.4") + expect(sixth.variant).toBe("medium") + + const seventh = sisyphus.fallbackChain[6] + expect(seventh.providers[0]).toBe("zai-coding-plan") + expect(seventh.model).toBe("glm-5") - const last = sisyphus.fallbackChain[6] + const last = sisyphus.fallbackChain[7] expect(last.providers[0]).toBe("opencode") expect(last.model).toBe("big-pickle") }) @@ -148,7 +161,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(last.model).toBe("gpt-5-nano") }) - test("prometheus has claude-opus-4-6 as primary", () => { + test("prometheus keeps split claude-opus-4-6 entries with Copilot high variant", () => { // #given - prometheus agent requirement const prometheus = AGENT_MODEL_REQUIREMENTS["prometheus"] @@ -160,11 +173,16 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { const primary = prometheus.fallbackChain[0] expect(primary.model).toBe("claude-opus-4-6") - expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode"]) + expect(primary.providers).toEqual(["anthropic", "opencode"]) expect(primary.variant).toBe("max") + + const sibling = prometheus.fallbackChain[1] + expect(sibling.providers).toEqual(["github-copilot"]) + expect(sibling.model).toBe("claude-opus-4-6") + expect(sibling.variant).toBe("high") }) - test("metis has claude-opus-4-6 as primary", () => { + test("metis keeps split claude-opus-4-6 entries with Copilot high variant", () => { // #given - metis agent requirement const metis = AGENT_MODEL_REQUIREMENTS["metis"] @@ -176,9 +194,14 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { const primary = metis.fallbackChain[0] expect(primary.model).toBe("claude-opus-4-6") - expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode"]) + expect(primary.providers).toEqual(["anthropic", "opencode"]) expect(primary.variant).toBe("max") + const sibling = metis.fallbackChain[1] + expect(sibling.providers).toEqual(["github-copilot"]) + expect(sibling.model).toBe("claude-opus-4-6") + expect(sibling.variant).toBe("high") + const openAiFallback = metis.fallbackChain.find((entry) => entry.providers.includes("openai")) expect(openAiFallback).toEqual({ providers: ["openai", "github-copilot", "opencode"], @@ -336,15 +359,15 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { expect(primary.providers).toContain("github-copilot") }) - test("visual-engineering has valid fallbackChain with gemini-3.1-pro high as primary", () => { + test("visual-engineering keeps split gemini and opus entries", () => { // given - visual-engineering category requirement const visualEngineering = CATEGORY_MODEL_REQUIREMENTS["visual-engineering"] // when - accessing visual-engineering requirement - // then - fallbackChain: gemini-3.1-pro(high) → glm-5 → opus-4-6(max) → opencode-go/glm-5 → k2p5 + // then - fallbackChain: gemini-3.1-pro(high) → github-copilot gemini → glm-5 → opus-4-6(max) → github-copilot opus → glm-5 → k2p5 expect(visualEngineering).toBeDefined() expect(visualEngineering.fallbackChain).toBeArray() - expect(visualEngineering.fallbackChain).toHaveLength(5) + expect(visualEngineering.fallbackChain).toHaveLength(7) const primary = visualEngineering.fallbackChain[0] expect(primary.providers[0]).toBe("google") @@ -352,20 +375,31 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { expect(primary.variant).toBe("high") const second = visualEngineering.fallbackChain[1] - expect(second.providers[0]).toBe("zai-coding-plan") - expect(second.model).toBe("glm-5") + expect(second.providers).toEqual(["github-copilot"]) + expect(second.model).toBe("gemini-3.1-pro") + expect(second.variant).toBeUndefined() const third = visualEngineering.fallbackChain[2] - expect(third.model).toBe("claude-opus-4-6") - expect(third.variant).toBe("max") + expect(third.providers[0]).toBe("zai-coding-plan") + expect(third.model).toBe("glm-5") const fourth = visualEngineering.fallbackChain[3] - expect(fourth.providers[0]).toBe("opencode-go") - expect(fourth.model).toBe("glm-5") + expect(fourth.providers).toEqual(["anthropic", "opencode"]) + expect(fourth.model).toBe("claude-opus-4-6") + expect(fourth.variant).toBe("max") const fifth = visualEngineering.fallbackChain[4] - expect(fifth.providers[0]).toBe("kimi-for-coding") - expect(fifth.model).toBe("k2p5") + expect(fifth.providers).toEqual(["github-copilot"]) + expect(fifth.model).toBe("claude-opus-4-6") + expect(fifth.variant).toBe("high") + + const sixth = visualEngineering.fallbackChain[5] + expect(sixth.providers[0]).toBe("opencode-go") + expect(sixth.model).toBe("glm-5") + + const seventh = visualEngineering.fallbackChain[6] + expect(seventh.providers[0]).toBe("kimi-for-coding") + expect(seventh.model).toBe("k2p5") }) test("quick has valid fallbackChain with gpt-5.4-mini as primary and claude-haiku-4-5 as secondary", () => { @@ -402,7 +436,7 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { expect(primary.providers[0]).toBe("anthropic") }) - test("unspecified-high has claude-opus-4-6 as primary and gpt-5.4 as secondary", () => { + test("unspecified-high keeps split claude-opus-4-6 entries and preserves gpt-5.4", () => { // #given - unspecified-high category requirement const unspecifiedHigh = CATEGORY_MODEL_REQUIREMENTS["unspecified-high"] @@ -415,9 +449,14 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { const primary = unspecifiedHigh.fallbackChain[0] expect(primary.model).toBe("claude-opus-4-6") expect(primary.variant).toBe("max") - expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode"]) + expect(primary.providers).toEqual(["anthropic", "opencode"]) + + const sibling = unspecifiedHigh.fallbackChain[1] + expect(sibling.providers).toEqual(["github-copilot"]) + expect(sibling.model).toBe("claude-opus-4-6") + expect(sibling.variant).toBe("high") - const secondary = unspecifiedHigh.fallbackChain[1] + const secondary = unspecifiedHigh.fallbackChain[2] expect(secondary.model).toBe("gpt-5.4") expect(secondary.variant).toBe("high") expect(secondary.providers).toEqual(["openai", "github-copilot", "opencode"]) diff --git a/src/shared/model-requirements.ts b/src/shared/model-requirements.ts index 5a1889eae3e..1f16609a228 100644 --- a/src/shared/model-requirements.ts +++ b/src/shared/model-requirements.ts @@ -21,10 +21,11 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { sisyphus: { fallbackChain: [ { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { providers: ["opencode-go"], model: "kimi-k2.5" }, { providers: ["kimi-for-coding"], model: "k2p5" }, { @@ -62,15 +63,17 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { variant: "high", }, { - providers: ["google", "github-copilot", "opencode"], + providers: ["google", "opencode"], model: "gemini-3.1-pro", variant: "high", }, + { providers: ["github-copilot"], model: "gemini-3.1-pro" }, { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { providers: ["opencode-go"], model: "glm-5" }, ], }, @@ -102,10 +105,11 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { prometheus: { fallbackChain: [ { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", @@ -113,18 +117,21 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { }, { providers: ["opencode-go"], model: "glm-5" }, { - providers: ["google", "github-copilot", "opencode"], + providers: ["google", "opencode"], model: "gemini-3.1-pro", + variant: "high", }, + { providers: ["github-copilot"], model: "gemini-3.1-pro" }, ], }, metis: { fallbackChain: [ { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", @@ -142,15 +149,17 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { variant: "xhigh", }, { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { - providers: ["google", "github-copilot", "opencode"], + providers: ["google", "opencode"], model: "gemini-3.1-pro", variant: "high", }, + { providers: ["github-copilot"], model: "gemini-3.1-pro" }, { providers: ["opencode-go"], model: "glm-5" }, ], }, @@ -185,16 +194,18 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { "visual-engineering": { fallbackChain: [ { - providers: ["google", "github-copilot", "opencode"], + providers: ["google", "opencode"], model: "gemini-3.1-pro", variant: "high", }, + { providers: ["github-copilot"], model: "gemini-3.1-pro" }, { providers: ["zai-coding-plan", "opencode"], model: "glm-5" }, { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { providers: ["opencode-go"], model: "glm-5" }, { providers: ["kimi-for-coding"], model: "k2p5" }, ], @@ -207,15 +218,17 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { variant: "xhigh", }, { - providers: ["google", "github-copilot", "opencode"], + providers: ["google", "opencode"], model: "gemini-3.1-pro", variant: "high", }, + { providers: ["github-copilot"], model: "gemini-3.1-pro" }, { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { providers: ["opencode-go"], model: "glm-5" }, ], }, @@ -227,29 +240,33 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { variant: "medium", }, { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { - providers: ["google", "github-copilot", "opencode"], + providers: ["google", "opencode"], model: "gemini-3.1-pro", variant: "high", }, + { providers: ["github-copilot"], model: "gemini-3.1-pro" }, ], }, artistry: { fallbackChain: [ { - providers: ["google", "github-copilot", "opencode"], + providers: ["google", "opencode"], model: "gemini-3.1-pro", variant: "high", }, + { providers: ["github-copilot"], model: "gemini-3.1-pro" }, { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4" }, ], requiresModel: "gemini-3.1-pro", @@ -294,10 +311,11 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { "unspecified-high": { fallbackChain: [ { - providers: ["anthropic", "github-copilot", "opencode"], + providers: ["anthropic", "opencode"], model: "claude-opus-4-6", variant: "max", }, + { providers: ["github-copilot"], model: "claude-opus-4-6", variant: "high" }, { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", diff --git a/src/shared/model-settings-compatibility.test.ts b/src/shared/model-settings-compatibility.test.ts index d9b8a455d59..37d2534125c 100644 --- a/src/shared/model-settings-compatibility.test.ts +++ b/src/shared/model-settings-compatibility.test.ts @@ -58,6 +58,42 @@ describe("resolveCompatibleModelSettings", () => { ]) }) + test("downgrades github-copilot claude opus max variant to high when metadata variants are limited", () => { + const result = resolveCompatibleModelSettings({ + providerID: "github-copilot", + modelID: "claude-opus-4-6", + desired: { variant: "max" }, + capabilities: { variants: ["low", "medium", "high"] }, + }) + + expect(result).toEqual({ + variant: "high", + reasoningEffort: undefined, + changes: [ + { + field: "variant", + from: "max", + to: "high", + reason: "unsupported-by-model-metadata", + }, + ], + }) + }) + + test("keeps github-copilot gemini unchanged when desired settings omit variant", () => { + const result = resolveCompatibleModelSettings({ + providerID: "github-copilot", + modelID: "gemini-3.1-pro", + desired: {}, + }) + + expect(result).toEqual({ + variant: undefined, + reasoningEffort: undefined, + changes: [], + }) + }) + test("downgrades unsupported Claude Sonnet max variant to high when metadata is absent", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", From 2fd531a9c138c7b8a0ea160b1ac6c8f157a157f9 Mon Sep 17 00:00:00 2001 From: "uihyeon.cha" Date: Sun, 12 Apr 2026 03:35:50 +0900 Subject: [PATCH 2/5] test(model-fallback): refresh copilot fallback expectations --- .../__snapshots__/model-fallback.test.ts.snap | 386 ++++++++---------- src/hooks/model-fallback/hook.test.ts | 6 +- src/plugin/event.model-fallback.test.ts | 20 +- 3 files changed, 175 insertions(+), 237 deletions(-) diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index e6dee4dc836..8bf152a6fd2 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -403,6 +403,7 @@ exports[`generateModelConfig single native provider uses Gemini models when only }, "prometheus": { "model": "google/gemini-3.1-pro-preview", + "variant": "high", }, "sisyphus-junior": { "model": "opencode/gpt-5-nano", @@ -467,6 +468,7 @@ exports[`generateModelConfig single native provider uses Gemini models with isMa }, "prometheus": { "model": "google/gemini-3.1-pro-preview", + "variant": "high", }, "sisyphus-junior": { "model": "opencode/gpt-5-nano", @@ -580,6 +582,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal }, { "model": "google/gemini-3.1-pro-preview", + "variant": "high", }, ], "model": "anthropic/claude-opus-4-6", @@ -779,6 +782,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM }, { "model": "google/gemini-3.1-pro-preview", + "variant": "high", }, ], "model": "anthropic/claude-opus-4-6", @@ -984,6 +988,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on }, { "model": "opencode/gemini-3.1-pro", + "variant": "high", }, ], "model": "opencode/claude-opus-4-6", @@ -1209,6 +1214,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is }, { "model": "opencode/gemini-3.1-pro", + "variant": "high", }, ], "model": "opencode/claude-opus-4-6", @@ -1388,17 +1394,16 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "momus": { "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, ], "model": "github-copilot/gpt-5.4", @@ -1411,11 +1416,10 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "fallback_models": [ { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "github-copilot/gpt-5.4", @@ -1432,7 +1436,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "sisyphus": { "fallback_models": [ @@ -1442,7 +1446,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "sisyphus-junior": { "fallback_models": [ @@ -1455,28 +1459,14 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when }, }, "categories": { - "artistry": { - "fallback_models": [ - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, - { - "model": "github-copilot/gpt-5.4", - }, - ], - "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", - }, "deep": { "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, ], "model": "github-copilot/gpt-5.4", @@ -1497,11 +1487,10 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, "unspecified-high": { "fallback_models": [ @@ -1523,11 +1512,10 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, "writing": { "fallback_models": [ @@ -1574,17 +1562,16 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "momus": { "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, ], "model": "github-copilot/gpt-5.4", @@ -1597,11 +1584,10 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "fallback_models": [ { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "github-copilot/gpt-5.4", @@ -1618,7 +1604,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "sisyphus": { "fallback_models": [ @@ -1628,7 +1614,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "sisyphus-junior": { "fallback_models": [ @@ -1641,28 +1627,14 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, }, "categories": { - "artistry": { - "fallback_models": [ - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, - { - "model": "github-copilot/gpt-5.4", - }, - ], - "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", - }, "deep": { "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, ], "model": "github-copilot/gpt-5.4", @@ -1683,11 +1655,10 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, "unspecified-high": { "fallback_models": [ @@ -1697,7 +1668,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "unspecified-low": { "fallback_models": [ @@ -1711,11 +1682,10 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, "writing": { "fallback_models": [ @@ -1956,6 +1926,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen }, { "model": "opencode/gemini-3.1-pro", + "variant": "high", }, ], "model": "anthropic/claude-opus-4-6", @@ -2180,7 +2151,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "momus": { "fallback_models": [ @@ -2190,11 +2161,10 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, ], "model": "openai/gpt-5.4", @@ -2220,11 +2190,10 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "openai/gpt-5.4", @@ -2245,7 +2214,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "sisyphus": { "fallback_models": [ @@ -2259,7 +2228,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, ], "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, "sisyphus-junior": { "fallback_models": [ @@ -2276,22 +2245,6 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, }, "categories": { - "artistry": { - "fallback_models": [ - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, - { - "model": "openai/gpt-5.4", - }, - { - "model": "github-copilot/gpt-5.4", - }, - ], - "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", - }, "deep": { "fallback_models": [ { @@ -2300,11 +2253,10 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, ], "model": "openai/gpt-5.4", @@ -2328,11 +2280,10 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "fallback_models": [ { "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "openai/gpt-5.4", @@ -2366,11 +2317,10 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "fallback_models": [ { "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "variant": "high", }, ], "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", }, "writing": { "fallback_models": [ @@ -2509,6 +2459,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "fallback_models": [ { "model": "google/gemini-3.1-pro-preview", + "variant": "high", }, ], "model": "anthropic/claude-opus-4-6", @@ -2660,8 +2611,8 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "metis": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "github-copilot/gpt-5.4", @@ -2672,7 +2623,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, "momus": { @@ -2681,22 +2632,21 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/gpt-5.4", "variant": "xhigh", }, - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, { "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "github-copilot/claude-opus-4.6", "variant": "high", }, { "model": "opencode/gemini-3.1-pro", "variant": "high", }, + { + "model": "github-copilot/gemini-3.1-pro-preview", + }, ], "model": "github-copilot/gpt-5.4", "variant": "xhigh", @@ -2722,22 +2672,21 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/gpt-5.4", "variant": "high", }, - { - "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", - }, { "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "opencode/claude-opus-4-6", "variant": "max", }, + { + "model": "github-copilot/claude-opus-4.6", + "variant": "high", + }, ], "model": "github-copilot/gpt-5.4", "variant": "high", @@ -2745,8 +2694,8 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "prometheus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "github-copilot/gpt-5.4", @@ -2757,20 +2706,21 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", + "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", + "model": "github-copilot/gemini-3.1-pro-preview", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "opencode/kimi-k2.5", @@ -2793,7 +2743,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/big-pickle", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { @@ -2820,16 +2770,15 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "artistry": { "fallback_models": [ { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "github-copilot/gpt-5.4", @@ -2838,7 +2787,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/gpt-5.4", }, ], - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, "deep": { @@ -2847,22 +2796,21 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/gpt-5.4", "variant": "medium", }, - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, { "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "github-copilot/claude-opus-4.6", "variant": "high", }, { "model": "opencode/gemini-3.1-pro", "variant": "high", }, + { + "model": "github-copilot/gemini-3.1-pro-preview", + }, ], "model": "github-copilot/gpt-5.4", "variant": "medium", @@ -2892,22 +2840,21 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, "ultrabrain": { "fallback_models": [ - { - "model": "github-copilot/gemini-3.1-pro-preview", - "variant": "high", - }, { "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "opencode/claude-opus-4-6", "variant": "max", }, + { + "model": "github-copilot/claude-opus-4.6", + "variant": "high", + }, ], "model": "opencode/gpt-5.4", "variant": "xhigh", @@ -2951,8 +2898,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "visual-engineering": { "fallback_models": [ { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "zai-coding-plan/glm-5", @@ -2961,15 +2907,15 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/glm-5", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, ], - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, "writing": { @@ -3068,12 +3014,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "metis": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "openai/gpt-5.4", @@ -3105,26 +3051,25 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "anthropic/claude-opus-4-6", "variant": "max", }, - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, { "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "google/gemini-3.1-pro-preview", + "model": "github-copilot/claude-opus-4.6", "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "google/gemini-3.1-pro-preview", "variant": "high", }, { "model": "opencode/gemini-3.1-pro", "variant": "high", }, + { + "model": "github-copilot/gemini-3.1-pro-preview", + }, ], "model": "openai/gpt-5.4", "variant": "xhigh", @@ -3166,24 +3111,23 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "anthropic/claude-opus-4-6", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, ], "model": "openai/gpt-5.4", @@ -3192,12 +3136,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "prometheus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "openai/gpt-5.4", @@ -3213,12 +3157,14 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "google/gemini-3.1-pro-preview", + "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", + "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", + "model": "github-copilot/gemini-3.1-pro-preview", }, ], "model": "anthropic/claude-opus-4-6", @@ -3227,12 +3173,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "sisyphus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "opencode/kimi-k2.5", @@ -3293,24 +3239,23 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "artistry": { "fallback_models": [ { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "anthropic/claude-opus-4-6", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "openai/gpt-5.4", @@ -3339,26 +3284,25 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "anthropic/claude-opus-4-6", "variant": "max", }, - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, { "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "google/gemini-3.1-pro-preview", + "model": "github-copilot/claude-opus-4.6", "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "google/gemini-3.1-pro-preview", "variant": "high", }, { "model": "opencode/gemini-3.1-pro", "variant": "high", }, + { + "model": "github-copilot/gemini-3.1-pro-preview", + }, ], "model": "openai/gpt-5.4", "variant": "medium", @@ -3406,24 +3350,23 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "anthropic/claude-opus-4-6", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, ], "model": "openai/gpt-5.4", @@ -3488,12 +3431,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "visual-engineering": { "fallback_models": [ { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "zai-coding-plan/glm-5", @@ -3506,12 +3448,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, ], "model": "google/gemini-3.1-pro-preview", @@ -3619,12 +3561,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "metis": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "openai/gpt-5.4", @@ -3656,26 +3598,25 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "anthropic/claude-opus-4-6", "variant": "max", }, - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, { "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "google/gemini-3.1-pro-preview", + "model": "github-copilot/claude-opus-4.6", "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "google/gemini-3.1-pro-preview", "variant": "high", }, { "model": "opencode/gemini-3.1-pro", "variant": "high", }, + { + "model": "github-copilot/gemini-3.1-pro-preview", + }, ], "model": "openai/gpt-5.4", "variant": "xhigh", @@ -3717,24 +3658,23 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "anthropic/claude-opus-4-6", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, ], "model": "openai/gpt-5.4", @@ -3743,12 +3683,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "prometheus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "openai/gpt-5.4", @@ -3764,12 +3704,14 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "google/gemini-3.1-pro-preview", + "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", + "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", + "model": "github-copilot/gemini-3.1-pro-preview", }, ], "model": "anthropic/claude-opus-4-6", @@ -3778,12 +3720,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "sisyphus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "opencode/kimi-k2.5", @@ -3844,24 +3786,23 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "artistry": { "fallback_models": [ { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "anthropic/claude-opus-4-6", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "openai/gpt-5.4", @@ -3890,26 +3831,25 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "anthropic/claude-opus-4-6", "variant": "max", }, - { - "model": "github-copilot/claude-opus-4.6", - "variant": "max", - }, { "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "google/gemini-3.1-pro-preview", + "model": "github-copilot/claude-opus-4.6", "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "google/gemini-3.1-pro-preview", "variant": "high", }, { "model": "opencode/gemini-3.1-pro", "variant": "high", }, + { + "model": "github-copilot/gemini-3.1-pro-preview", + }, ], "model": "openai/gpt-5.4", "variant": "medium", @@ -3957,24 +3897,23 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "anthropic/claude-opus-4-6", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, ], "model": "openai/gpt-5.4", @@ -3983,12 +3922,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "unspecified-high": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, { "model": "openai/gpt-5.4", @@ -4046,12 +3985,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "visual-engineering": { "fallback_models": [ { - "model": "github-copilot/gemini-3.1-pro-preview", + "model": "opencode/gemini-3.1-pro", "variant": "high", }, { - "model": "opencode/gemini-3.1-pro", - "variant": "high", + "model": "github-copilot/gemini-3.1-pro-preview", }, { "model": "zai-coding-plan/glm-5", @@ -4064,12 +4002,12 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "opencode/claude-opus-4-6", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", - "variant": "max", + "model": "github-copilot/claude-opus-4.6", + "variant": "high", }, ], "model": "google/gemini-3.1-pro-preview", diff --git a/src/hooks/model-fallback/hook.test.ts b/src/hooks/model-fallback/hook.test.ts index 637503356ab..7ce6b95d26c 100644 --- a/src/hooks/model-fallback/hook.test.ts +++ b/src/hooks/model-fallback/hook.test.ts @@ -167,10 +167,10 @@ describe("model fallback hook", () => { //#then - chain should progress to entry[1], not repeat entry[0] expect(secondOutput.message["model"]).toEqual({ - providerID: "opencode-go", - modelID: "kimi-k2.5", + providerID: "github-copilot", + modelID: "claude-opus-4.6", }) - expect(secondOutput.message["variant"]).toBeUndefined() + expect(secondOutput.message["variant"]).toBe("high") }) test("does not re-arm fallback when one is already pending", () => { diff --git a/src/plugin/event.model-fallback.test.ts b/src/plugin/event.model-fallback.test.ts index 481c5c4195a..771c6a05f7f 100644 --- a/src/plugin/event.model-fallback.test.ts +++ b/src/plugin/event.model-fallback.test.ts @@ -222,10 +222,10 @@ describe("createEventHandler - model fallback", () => { expect(abortCalls).toEqual([sessionID]) expect(promptCalls).toEqual([sessionID]) expect(output.message["model"]).toMatchObject({ - providerID: "opencode-go", - modelID: "kimi-k2.5", + providerID: "github-copilot", + modelID: "claude-opus-4.6", }) - expect(output.message["variant"]).toBeUndefined() + expect(output.message["variant"]).toBe("high") }) test("does not spam abort/prompt when session.status retry countdown updates", async () => { @@ -549,20 +549,20 @@ describe("createEventHandler - model fallback", () => { //#when - first retry cycle const first = await triggerRetryCycle() - //#then - first fallback entry applied (no-op skip: claude-opus-4-6 matches current model after normalization) + //#then - first reachable fallback is the adjacent Copilot Opus split entry expect(first.message["model"]).toMatchObject({ - providerID: "opencode-go", - modelID: "kimi-k2.5", + providerID: "github-copilot", + modelID: "claude-opus-4.6", }) - expect(first.message["variant"]).toBeUndefined() + expect(first.message["variant"]).toBe("high") //#when - second retry cycle const second = await triggerRetryCycle() - //#then - second fallback entry applied (chain advanced past opencode-go/kimi-k2.5) + //#then - chain advances past the Copilot split entry expect(second.message["model"]).toMatchObject({ - providerID: "kimi-for-coding", - modelID: "k2p5", + providerID: "opencode-go", + modelID: "kimi-k2.5", }) expect(second.message["variant"]).toBeUndefined() expect(abortCalls).toEqual([sessionID, sessionID]) From 4d91e755e15a2aa30746dcb3f15eebb8081b057e Mon Sep 17 00:00:00 2001 From: "uihyeon.cha" Date: Sun, 12 Apr 2026 03:35:58 +0900 Subject: [PATCH 3/5] test(auto-update): isolate plugin entry config lookup --- .../auto-update-checker/checker/plugin-entry.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/hooks/auto-update-checker/checker/plugin-entry.test.ts b/src/hooks/auto-update-checker/checker/plugin-entry.test.ts index 341839af014..5ee9935868a 100644 --- a/src/hooks/auto-update-checker/checker/plugin-entry.test.ts +++ b/src/hooks/auto-update-checker/checker/plugin-entry.test.ts @@ -17,10 +17,18 @@ function runFindPluginEntry( directory: string, envOverrides: Record = {}, ): { status: number | null; stdout: string; stderr: string } { + const isolatedConfigDir = path.join(directory, ".opencode-user") const command = [ - `import { findPluginEntry } from ${JSON.stringify("./src/hooks/auto-update-checker/checker/plugin-entry")};`, + "(async () => {", + `process.env.OPENCODE_CONFIG_DIR = ${JSON.stringify(isolatedConfigDir)};`, + `Object.assign(process.env, ${JSON.stringify(envOverrides)});`, + `const { findPluginEntry } = await import(${JSON.stringify("./src/hooks/auto-update-checker/checker/plugin-entry")});`, `const result = findPluginEntry(${JSON.stringify(directory)});`, "console.log(JSON.stringify(result));", + "})().catch((error) => {", + "console.error(error);", + "process.exit(1);", + "});", ].join("") const execution = spawnSync(process.execPath, ["-e", command], { From 92a482a8c6832e01f438594002b10257023a9aaf Mon Sep 17 00:00:00 2001 From: "uihyeon.cha" Date: Mon, 13 Apr 2026 20:44:14 +0900 Subject: [PATCH 4/5] test(model-fallback): sync vercel snapshot expectations --- src/cli/__snapshots__/model-fallback.test.ts.snap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index d206424aaa3..9039b87d3a9 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -4203,6 +4203,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin }, { "model": "vercel/google/gemini-3.1-pro-preview", + "variant": "high", }, ], "model": "vercel/anthropic/claude-opus-4.6", @@ -4496,6 +4497,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin }, { "model": "vercel/google/gemini-3.1-pro-preview", + "variant": "high", }, ], "model": "vercel/anthropic/claude-opus-4.6", From db01cdb43eff8799712264082c7251d02d60bce4 Mon Sep 17 00:00:00 2001 From: "uihyeon.cha" Date: Sat, 25 Apr 2026 17:12:12 +0900 Subject: [PATCH 5/5] fix(models): limit copilot opus 4.7 to medium --- .../__snapshots__/model-fallback.test.ts.snap | 106 +++++++++--------- src/hooks/anthropic-effort/hook.ts | 13 ++- src/hooks/anthropic-effort/index.test.ts | 8 +- src/hooks/model-fallback/hook.test.ts | 2 +- src/hooks/think-mode/hook.ts | 10 +- src/hooks/think-mode/index.test.ts | 4 +- src/plugin/event.model-fallback.test.ts | 4 +- src/shared/model-requirements.test.ts | 14 +-- src/shared/model-requirements.ts | 20 ++-- 9 files changed, 97 insertions(+), 84 deletions(-) diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index ebe9ac766e8..47f5dc2f6a0 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -1394,13 +1394,13 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "momus": { "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gemini-3.1-pro-preview", @@ -1419,7 +1419,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "github-copilot/gpt-5.4", @@ -1436,7 +1436,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "sisyphus": { "fallback_models": [ @@ -1446,7 +1446,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "sisyphus-junior": { "fallback_models": [ @@ -1463,7 +1463,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gemini-3.1-pro-preview", @@ -1487,7 +1487,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "github-copilot/gemini-3.1-pro-preview", @@ -1512,7 +1512,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "github-copilot/gemini-3.1-pro-preview", @@ -1562,13 +1562,13 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "momus": { "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gemini-3.1-pro-preview", @@ -1587,7 +1587,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "github-copilot/gpt-5.4", @@ -1604,7 +1604,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "sisyphus": { "fallback_models": [ @@ -1614,7 +1614,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "sisyphus-junior": { "fallback_models": [ @@ -1631,7 +1631,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gemini-3.1-pro-preview", @@ -1655,7 +1655,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "github-copilot/gemini-3.1-pro-preview", @@ -1668,7 +1668,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "unspecified-low": { "fallback_models": [ @@ -1682,7 +1682,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "github-copilot/gemini-3.1-pro-preview", @@ -2151,7 +2151,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "momus": { "fallback_models": [ @@ -2161,7 +2161,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gemini-3.1-pro-preview", @@ -2193,7 +2193,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "openai/gpt-5.4", @@ -2214,7 +2214,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "sisyphus": { "fallback_models": [ @@ -2228,7 +2228,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, ], "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, "sisyphus-junior": { "fallback_models": [ @@ -2253,7 +2253,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gemini-3.1-pro-preview", @@ -2283,7 +2283,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "openai/gpt-5.4", @@ -2317,7 +2317,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "github-copilot/gemini-3.1-pro-preview", @@ -2612,7 +2612,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gpt-5.4", @@ -2638,7 +2638,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "opencode/gemini-3.1-pro", @@ -2685,7 +2685,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "github-copilot/gpt-5.4", @@ -2695,7 +2695,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gpt-5.4", @@ -2720,7 +2720,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "fallback_models": [ { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "opencode/kimi-k2.5", @@ -2778,7 +2778,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "github-copilot/gpt-5.4", @@ -2802,7 +2802,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "opencode/gemini-3.1-pro", @@ -2853,7 +2853,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "opencode/gpt-5.4", @@ -2912,7 +2912,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "opencode/gemini-3.1-pro", @@ -3019,7 +3019,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "openai/gpt-5.4", @@ -3057,7 +3057,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "google/gemini-3.1-pro-preview", @@ -3127,7 +3127,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "openai/gpt-5.4", @@ -3141,7 +3141,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "openai/gpt-5.4", @@ -3178,7 +3178,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "opencode/kimi-k2.5", @@ -3255,7 +3255,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "openai/gpt-5.4", @@ -3290,7 +3290,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "google/gemini-3.1-pro-preview", @@ -3366,7 +3366,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "openai/gpt-5.4", @@ -3453,7 +3453,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "google/gemini-3.1-pro-preview", @@ -3566,7 +3566,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "openai/gpt-5.4", @@ -3604,7 +3604,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "google/gemini-3.1-pro-preview", @@ -3674,7 +3674,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "openai/gpt-5.4", @@ -3688,7 +3688,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "openai/gpt-5.4", @@ -3725,7 +3725,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "opencode/kimi-k2.5", @@ -3802,7 +3802,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "openai/gpt-5.4", @@ -3837,7 +3837,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "google/gemini-3.1-pro-preview", @@ -3913,7 +3913,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "openai/gpt-5.4", @@ -3927,7 +3927,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, { "model": "openai/gpt-5.4", @@ -4007,7 +4007,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, { "model": "github-copilot/claude-opus-4.7", - "variant": "high", + "variant": "medium", }, ], "model": "google/gemini-3.1-pro-preview", diff --git a/src/hooks/anthropic-effort/hook.ts b/src/hooks/anthropic-effort/hook.ts index a545768d604..c5a42dd763b 100644 --- a/src/hooks/anthropic-effort/hook.ts +++ b/src/hooks/anthropic-effort/hook.ts @@ -61,8 +61,13 @@ const MAX_VARIANT_BY_TIER: Record = { default: "high", } -function clampVariant(variant: string, isOpus: boolean, isConstrained: boolean): string { +function isCopilotOpus47(providerID: string, modelID: string): boolean { + return providerID === "github-copilot" && isOpusModel(modelID) && /opus-4[-.]7/i.test(modelID) +} + +function clampVariant(providerID: string, modelID: string, variant: string, isOpus: boolean, isConstrained: boolean): string { if (variant !== "max") return variant + if (isCopilotOpus47(providerID, modelID)) return "medium" if (isConstrained) return MAX_VARIANT_BY_TIER.default return isOpus ? MAX_VARIANT_BY_TIER.opus : MAX_VARIANT_BY_TIER.default } @@ -83,7 +88,7 @@ export function createAnthropicEffortHook() { const opus = isOpusModel(model.modelID) const constrained = isConstrainedProvider(model.providerID) - const clamped = clampVariant(message.variant, opus, constrained) + const clamped = clampVariant(model.providerID, model.modelID, message.variant, opus, constrained) output.options.effort = clamped const shouldOverrideMessageVariant = !opus || constrained @@ -94,10 +99,12 @@ export function createAnthropicEffortHook() { // caps at high even on Opus because the OAuth API only accepts // low | medium | high. ;(message as { variant?: string }).variant = clamped - log("anthropic-effort: clamped variant max→high", { + log("anthropic-effort: clamped variant", { sessionID: input.sessionID, provider: model.providerID, model: model.modelID, + from: "max", + to: clamped, reason: constrained ? "constrained-provider" : "non-opus", }) } else { diff --git a/src/hooks/anthropic-effort/index.test.ts b/src/hooks/anthropic-effort/index.test.ts index 129b6513eb2..674c5e3b3b2 100644 --- a/src/hooks/anthropic-effort/index.test.ts +++ b/src/hooks/anthropic-effort/index.test.ts @@ -153,7 +153,7 @@ describe("createAnthropicEffortHook", () => { expect(output.options.effort).toBeUndefined() }) - it("#given github-copilot + claude opus model #then effort clamped to high (constrained provider)", async () => { + it("#given github-copilot + claude opus 4.7 #then effort clamped to medium", async () => { // given const hook = createAnthropicEffortHook() const { input, output } = createMockParams({ @@ -164,9 +164,9 @@ describe("createAnthropicEffortHook", () => { // when await hook["chat.params"](input, output) - // then — github-copilot is a constrained provider, clamps max→high - expect(output.options.effort).toBe("high") - expect(input.message.variant).toBe("high") + // then + expect(output.options.effort).toBe("medium") + expect(input.message.variant).toBe("medium") }) it("#given github-copilot + claude sonnet model #then effort clamped to high", async () => { diff --git a/src/hooks/model-fallback/hook.test.ts b/src/hooks/model-fallback/hook.test.ts index adc322faedf..7a13e4b9e7a 100644 --- a/src/hooks/model-fallback/hook.test.ts +++ b/src/hooks/model-fallback/hook.test.ts @@ -172,7 +172,7 @@ describe("model fallback hook", () => { providerID: "github-copilot", modelID: "claude-opus-4.7", }) - expect(secondOutput.message["variant"]).toBe("high") + expect(secondOutput.message["variant"]).toBe("medium") }) test("does not re-arm fallback when one is already pending", () => { diff --git a/src/hooks/think-mode/hook.ts b/src/hooks/think-mode/hook.ts index 8f244238295..9fdae116774 100644 --- a/src/hooks/think-mode/hook.ts +++ b/src/hooks/think-mode/hook.ts @@ -5,6 +5,11 @@ import { log } from "../../shared" const thinkModeState = new Map() +function getThinkVariant(providerID: string, modelID: string): string { + if (providerID === "github-copilot" && /claude-opus-4[-.]7/i.test(modelID)) return "medium" + return "high" +} + export function clearThinkModeState(sessionID: string): void { thinkModeState.delete(sessionID) } @@ -56,10 +61,11 @@ export function createThinkModeHook() { return } - output.message.variant = "high" + const variant = getThinkVariant(currentModel.providerID, currentModel.modelID) + output.message.variant = variant state.modelSwitched = false state.variantSet = true - log("Think mode: variant set to high", { sessionID }) + log("Think mode: variant set", { sessionID, variant }) thinkModeState.set(sessionID, state) }, diff --git a/src/hooks/think-mode/index.test.ts b/src/hooks/think-mode/index.test.ts index f857636085a..7ef2c889e5f 100644 --- a/src/hooks/think-mode/index.test.ts +++ b/src/hooks/think-mode/index.test.ts @@ -43,7 +43,7 @@ describe("createThinkModeHook", () => { clearThinkModeState(sessionID) }) - it("sets high variant when think keyword is present", async () => { + it("sets medium variant for github-copilot opus 4.7 when think keyword is present", async () => { // given const hook = createThinkModeHook() const input = createHookInput({ @@ -57,7 +57,7 @@ describe("createThinkModeHook", () => { await hook["chat.message"](input, output) // then - expect(output.message.variant).toBe("high") + expect(output.message.variant).toBe("medium") expect(output.message.model).toBeUndefined() }) diff --git a/src/plugin/event.model-fallback.test.ts b/src/plugin/event.model-fallback.test.ts index 9c9110bcfb8..070ed21eb41 100644 --- a/src/plugin/event.model-fallback.test.ts +++ b/src/plugin/event.model-fallback.test.ts @@ -224,7 +224,7 @@ describe("createEventHandler - model fallback", () => { providerID: "github-copilot", modelID: "claude-opus-4.7", }) - expect(output.message["variant"]).toBe("high") + expect(output.message["variant"]).toBe("medium") }) test("does not spam abort/prompt when session.status retry countdown updates", async () => { @@ -551,7 +551,7 @@ describe("createEventHandler - model fallback", () => { providerID: "github-copilot", modelID: "claude-opus-4.7", }) - expect(first.message["variant"]).toBe("high") + expect(first.message["variant"]).toBe("medium") //#when - second retry cycle const second = await triggerRetryCycle() diff --git a/src/shared/model-requirements.test.ts b/src/shared/model-requirements.test.ts index 371d970053f..ec4c06d348d 100644 --- a/src/shared/model-requirements.test.ts +++ b/src/shared/model-requirements.test.ts @@ -42,7 +42,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { const second = sisyphus.fallbackChain[1] expect(second.providers).toEqual(["github-copilot"]) expect(second.model).toBe("claude-opus-4-7") - expect(second.variant).toBe("high") + expect(second.variant).toBe("medium") const third = sisyphus.fallbackChain[2] expect(third.providers).toEqual(["opencode-go", "vercel"]) @@ -162,7 +162,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(last.model).toBe("gpt-5-nano") }) - test("prometheus keeps split claude-opus-4-7 entries with Copilot high variant", () => { + test("prometheus keeps split claude-opus-4-7 entries with Copilot medium variant", () => { // #given - prometheus agent requirement const prometheus = AGENT_MODEL_REQUIREMENTS["prometheus"] @@ -180,10 +180,10 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { const sibling = prometheus.fallbackChain[1] expect(sibling.providers).toEqual(["github-copilot"]) expect(sibling.model).toBe("claude-opus-4-7") - expect(sibling.variant).toBe("high") + expect(sibling.variant).toBe("medium") }) - test("metis keeps split claude-opus-4-7 entries with Copilot high variant", () => { + test("metis keeps split claude-opus-4-7 entries with Copilot medium variant", () => { // #given - metis agent requirement const metis = AGENT_MODEL_REQUIREMENTS["metis"] @@ -201,7 +201,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { const sibling = metis.fallbackChain[1] expect(sibling.providers).toEqual(["github-copilot"]) expect(sibling.model).toBe("claude-opus-4-7") - expect(sibling.variant).toBe("high") + expect(sibling.variant).toBe("medium") const openAiFallback = metis.fallbackChain.find((entry) => entry.providers.includes("openai")) expect(openAiFallback).toEqual({ @@ -392,7 +392,7 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { const fifth = visualEngineering.fallbackChain[4] expect(fifth.providers).toEqual(["github-copilot"]) expect(fifth.model).toBe("claude-opus-4-7") - expect(fifth.variant).toBe("high") + expect(fifth.variant).toBe("medium") const sixth = visualEngineering.fallbackChain[5] expect(sixth.providers[0]).toBe("opencode-go") @@ -455,7 +455,7 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { const sibling = unspecifiedHigh.fallbackChain[1] expect(sibling.providers).toEqual(["github-copilot"]) expect(sibling.model).toBe("claude-opus-4-7") - expect(sibling.variant).toBe("high") + expect(sibling.variant).toBe("medium") const secondary = unspecifiedHigh.fallbackChain[2] expect(secondary.model).toBe("gpt-5.4") diff --git a/src/shared/model-requirements.ts b/src/shared/model-requirements.ts index 8995efd3835..4674bb6093e 100644 --- a/src/shared/model-requirements.ts +++ b/src/shared/model-requirements.ts @@ -25,7 +25,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["opencode-go", "vercel"], model: "kimi-k2.5" }, { providers: ["kimi-for-coding"], model: "k2p5" }, { @@ -74,7 +74,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, ], }, @@ -110,7 +110,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["openai", "github-copilot", "opencode", "vercel"], model: "gpt-5.4", @@ -132,7 +132,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["openai", "github-copilot", "opencode", "vercel"], model: "gpt-5.4", @@ -154,7 +154,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["google", "opencode", "vercel"], model: "gemini-3.1-pro", @@ -206,7 +206,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, { providers: ["kimi-for-coding"], model: "k2p5" }, ], @@ -229,7 +229,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, ], }, @@ -245,7 +245,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["google", "opencode", "vercel"], model: "gemini-3.1-pro", @@ -267,7 +267,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["openai", "github-copilot", "opencode", "vercel"], model: "gpt-5.4" }, ], requiresModel: "gemini-3.1-pro", @@ -316,7 +316,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-7", variant: "max", }, - { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "high" }, + { providers: ["github-copilot"], model: "claude-opus-4-7", variant: "medium" }, { providers: ["openai", "github-copilot", "opencode", "vercel"], model: "gpt-5.4",