fix(core): ensure stable fallback for restricted preview models (#26999)

This commit is contained in:
Gal Zahavi
2026-05-13 14:46:41 -07:00
committed by GitHub
parent 1814c7f358
commit 77078b3e8a
9 changed files with 50 additions and 28 deletions
@@ -29,6 +29,9 @@ describe('Auto Routing Fallback Integration', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.spyOn(Config.prototype, 'getHasAccessToPreviewModel').mockReturnValue(
true,
);
// Mock fs to avoid real file system access
vi.mocked(fs.existsSync).mockReturnValue(true);
@@ -28,6 +28,7 @@ describe('Fallback Integration', () => {
getActiveModel: () => PREVIEW_GEMINI_MODEL_AUTO,
setActiveModel: vi.fn(),
getUserTier: () => undefined,
getHasAccessToPreviewModel: () => true,
getModelAvailabilityService: () => availabilityService,
modelConfigService: undefined as unknown as ModelConfigService,
} as unknown as Config;
@@ -55,7 +55,10 @@ export function resolvePolicyChain(
const useGemini31FlashLite =
config.getGemini31FlashLiteLaunchedSync?.() ?? false;
const useCustomToolModel = config.getUseCustomToolModelSync?.() ?? false;
const hasAccessToPreview = config.getHasAccessToPreviewModel?.() ?? true;
const hasAccessToPreview = config.getHasAccessToPreviewModel?.() ?? false;
// Capture the original family intent before any normalization or early downgrade.
const isOriginallyGemini3 = isGemini3Model(modelFromConfig, config);
const resolvedModel = normalizeModelId(
resolveModel(
@@ -75,10 +78,7 @@ export function resolvePolicyChain(
// We always wrap around for Gemini 3 chains to ensure maximum availability
// between models in the same family (e.g. fallback to Pro if Flash is exhausted).
const effectiveWrapsAround =
wrapsAround ||
isAutoPreferred ||
isAutoConfigured ||
isGemini3Model(resolvedModel, config);
wrapsAround || isAutoPreferred || isAutoConfigured || isOriginallyGemini3;
// --- DYNAMIC PATH ---
if (config.getExperimentalDynamicModelConfiguration?.() === true) {
@@ -91,11 +91,7 @@ export function resolvePolicyChain(
if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
chain = config.modelConfigService.resolveChain('lite', context);
} else if (
isGemini3Model(normalizeModelId(resolvedModel), config) ||
isAutoPreferred ||
isAutoConfigured
) {
} else if (isOriginallyGemini3 || isAutoPreferred || isAutoConfigured) {
// 1. Try to find a chain specifically for the current configured alias
if (
isAutoConfigured &&
@@ -132,15 +128,11 @@ export function resolvePolicyChain(
if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
chain = getFlashLitePolicyChain();
} else if (
isGemini3Model(resolvedModel, config) ||
isAutoPreferred ||
isAutoConfigured
) {
} else if (isOriginallyGemini3 || isAutoPreferred || isAutoConfigured) {
const isAutoSelection = isAutoPreferred || isAutoConfigured;
if (hasAccessToPreview) {
const previewEnabled =
isGemini3Model(resolvedModel, config) ||
isOriginallyGemini3 ||
normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO ||
configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
chain = getModelPolicyChain({