fix(gsd): harden flat-rate routing guard against alias/resolution gaps
The flat-rate provider guard from #3552 can fail open in two scenarios: 1. Provider alias mismatch — isFlatRateProvider only matched the exact string "github-copilot", but "copilot" appears as a provider alias in the codebase. Case variations could also bypass the check. Fix: add "copilot" alias and lowercase input before set membership. 2. Unresolved primary model — when resolveModelId returns undefined (stale model ID, registry mismatch), the guard was skipped entirely, allowing dynamic routing to downgrade models on a flat-rate backend. Fix: fall back to autoModeStartModel.provider and ctx.model.provider when primary resolution fails, disabling routing if either indicates a flat-rate provider. Ref: #3453
This commit is contained in:
parent
9ab675a843
commit
3a1e9e3416
2 changed files with 26 additions and 3 deletions
|
|
@ -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<T extends { id: string; provider: string }>(
|
|||
/**
|
||||
* 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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue