feat: launch Gemini 3 Flash in Gemini CLI ️ (#15196)

Co-authored-by: gemini-cli-robot <gemini-cli-robot@google.com>
Co-authored-by: joshualitt <joshualitt@google.com>
Co-authored-by: Sehoon Shon <sshon@google.com>
Co-authored-by: Adam Weidman <65992621+adamfweidman@users.noreply.github.com>
Co-authored-by: Adib234 <30782825+Adib234@users.noreply.github.com>
Co-authored-by: Jenna Inouye <jinouye@google.com>
This commit is contained in:
Tommaso Sciortino
2025-12-17 09:43:21 -08:00
committed by GitHub
parent 18698d6929
commit bf90b59935
65 changed files with 1898 additions and 2060 deletions

View File

@@ -261,7 +261,7 @@ describe('useQuotaAndFallback', () => {
expect(mockHistoryManager.addItem).not.toHaveBeenCalled();
const message = request!.message;
expect(message).toContain(
'model-A is currently experiencing high demand. We apologize and appreciate your patience.',
'We are currently experiencing high demand.',
);
// Simulate the user choosing to continue with the fallback model
@@ -283,7 +283,7 @@ describe('useQuotaAndFallback', () => {
const lastCall = (mockHistoryManager.addItem as Mock).mock
.calls[0][0];
expect(lastCall.type).toBe(MessageType.INFO);
expect(lastCall.text).toContain('Switched to fallback model.');
expect(lastCall.text).toContain('Switched to fallback model model-B');
});
}
@@ -316,9 +316,9 @@ describe('useQuotaAndFallback', () => {
const message = request!.message;
expect(message).toBe(
`It seems like you don't have access to Gemini 3.
`It seems like you don't have access to gemini-3-pro-preview.
Learn more at https://goo.gle/enable-preview-features
To disable Gemini 3, disable "Preview features" in /settings.`,
To disable gemini-3-pro-preview, disable "Preview features" in /settings.`,
);
// Simulate the user choosing to switch
@@ -415,7 +415,9 @@ To disable Gemini 3, disable "Preview features" in /settings.`,
expect(mockHistoryManager.addItem).toHaveBeenCalledTimes(1);
const lastCall = (mockHistoryManager.addItem as Mock).mock.calls[0][0];
expect(lastCall.type).toBe(MessageType.INFO);
expect(lastCall.text).toContain('Switched to fallback model.');
expect(lastCall.text).toContain(
'Switched to fallback model gemini-flash',
);
});
it('should show a special message when falling back from the preview model', async () => {
@@ -449,7 +451,7 @@ To disable Gemini 3, disable "Preview features" in /settings.`,
const lastCall = (mockHistoryManager.addItem as Mock).mock.calls[0][0];
expect(lastCall.type).toBe(MessageType.INFO);
expect(lastCall.text).toContain(
`Switched to fallback model gemini-2.5-pro. We will periodically check if ${PREVIEW_GEMINI_MODEL} is available again.`,
`Switched to fallback model gemini-2.5-pro`,
);
});
@@ -484,7 +486,7 @@ To disable Gemini 3, disable "Preview features" in /settings.`,
const lastCall = (mockHistoryManager.addItem as Mock).mock.calls[0][0];
expect(lastCall.type).toBe(MessageType.INFO);
expect(lastCall.text).toContain(
`Switched to fallback model gemini-2.5-flash.`,
`Switched to fallback model gemini-2.5-flash`,
);
});
});

View File

@@ -14,6 +14,7 @@ import {
type UserTierId,
PREVIEW_GEMINI_MODEL,
DEFAULT_GEMINI_MODEL,
VALID_GEMINI_MODELS,
} from '@google/gemini-cli-core';
import { useCallback, useEffect, useRef, useState } from 'react';
import { type UseHistoryManagerReturn } from './useHistoryManager.js';
@@ -68,19 +69,28 @@ export function useQuotaAndFallback({
`Usage limit reached for ${usageLimitReachedModel}.`,
error.retryDelayMs ? getResetTimeMessage(error.retryDelayMs) : null,
`/stats for usage details`,
`/model to switch models.`,
`/auth to switch to API key.`,
].filter(Boolean);
message = messageLines.join('\n');
} else if (error instanceof ModelNotFoundError) {
} else if (
error instanceof ModelNotFoundError &&
VALID_GEMINI_MODELS.has(failedModel)
) {
isModelNotFoundError = true;
const messageLines = [
`It seems like you don't have access to Gemini 3.`,
`It seems like you don't have access to ${failedModel}.`,
`Learn more at https://goo.gle/enable-preview-features`,
`To disable Gemini 3, disable "Preview features" in /settings.`,
`To disable ${failedModel}, disable "Preview features" in /settings.`,
];
message = messageLines.join('\n');
} else {
message = `${failedModel} is currently experiencing high demand. We apologize and appreciate your patience.`;
const messageLines = [
`We are currently experiencing high demand.`,
'We apologize and appreciate your patience.',
'/model to switch models.',
];
message = messageLines.join('\n');
}
setModelSwitchedFromQuotaError(true);
@@ -120,30 +130,20 @@ export function useQuotaAndFallback({
isDialogPending.current = false; // Reset the flag here
if (choice === 'retry_always') {
// If we were recovering from a Preview Model failure, show a specific message.
if (proQuotaRequest.failedModel === PREVIEW_GEMINI_MODEL) {
const showPeriodicalCheckMessage =
!proQuotaRequest.isModelNotFoundError &&
proQuotaRequest.fallbackModel === DEFAULT_GEMINI_MODEL;
historyManager.addItem(
{
type: MessageType.INFO,
text: `Switched to fallback model ${proQuotaRequest.fallbackModel}. ${showPeriodicalCheckMessage ? `We will periodically check if ${PREVIEW_GEMINI_MODEL} is available again.` : ''}`,
},
Date.now(),
);
} else {
historyManager.addItem(
{
type: MessageType.INFO,
text: 'Switched to fallback model.',
},
Date.now(),
);
}
// Explicitly set the model to the fallback model to persist the user's choice.
// This ensures the Footer updates and future turns use this model.
config.setModel(proQuotaRequest.fallbackModel);
historyManager.addItem(
{
type: MessageType.INFO,
text: `Switched to fallback model ${proQuotaRequest.fallbackModel}`,
},
Date.now(),
);
}
},
[proQuotaRequest, historyManager],
[proQuotaRequest, historyManager, config],
);
return {