diff --git a/src/resources/extensions/gsd/auto-model-selection.ts b/src/resources/extensions/gsd/auto-model-selection.ts index 6b8aabe70..ad26edca8 100644 --- a/src/resources/extensions/gsd/auto-model-selection.ts +++ b/src/resources/extensions/gsd/auto-model-selection.ts @@ -77,9 +77,20 @@ export async function selectAndApplyModel( // Disable routing for flat-rate providers like GitHub Copilot (#3453). // All models cost the same per request, so downgrading to a cheaper // model provides no cost benefit — it only degrades quality. + // Fail-closed: if primary model can't be resolved, fall back to + // provider-level signals rather than allowing unwanted downgrades. if (routingConfig.enabled) { const primaryModel = resolveModelId(modelConfig.primary, availableModels, ctx.model?.provider); - if (primaryModel && isFlatRateProvider(primaryModel.provider)) { + if (primaryModel) { + if (isFlatRateProvider(primaryModel.provider)) { + routingConfig.enabled = false; + } + } else if ( + (autoModeStartModel && isFlatRateProvider(autoModeStartModel.provider)) + || (ctx.model?.provider && isFlatRateProvider(ctx.model.provider)) + ) { + // Primary model unresolvable but provider signals indicate flat-rate — + // disable routing to prevent quality degradation. routingConfig.enabled = false; } } @@ -337,9 +348,11 @@ export function resolveModelId( /** * Flat-rate providers charge the same per request regardless of model. * Dynamic routing provides no cost benefit — it only degrades quality (#3453). + * Uses case-insensitive matching with alias support to prevent fail-open on + * provider naming variations (e.g. "copilot" vs "github-copilot"). */ -const FLAT_RATE_PROVIDERS = new Set(["github-copilot"]); +const FLAT_RATE_PROVIDERS = new Set(["github-copilot", "copilot"]); export function isFlatRateProvider(provider: string): boolean { - return FLAT_RATE_PROVIDERS.has(provider); + return FLAT_RATE_PROVIDERS.has(provider.toLowerCase()); } diff --git a/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts b/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts index a02b0b9f6..64a93608f 100644 --- a/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +++ b/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts @@ -14,6 +14,16 @@ describe("flat-rate provider routing guard (#3453)", () => { assert.equal(isFlatRateProvider("github-copilot"), true); }); + test("isFlatRateProvider returns true for copilot alias", () => { + assert.equal(isFlatRateProvider("copilot"), true); + }); + + test("isFlatRateProvider is case-insensitive", () => { + assert.equal(isFlatRateProvider("GitHub-Copilot"), true); + assert.equal(isFlatRateProvider("GITHUB-COPILOT"), true); + assert.equal(isFlatRateProvider("Copilot"), true); + }); + test("isFlatRateProvider returns false for anthropic", () => { assert.equal(isFlatRateProvider("anthropic"), false); });