Skip to content

Commit bbd8483

Browse files
chrstnbscidomino
authored andcommitted
feat(core,ui): Add experiment-gated support for gemini flash 3.1 lite (#23794)
1 parent 29ab3bb commit bbd8483

30 files changed

Lines changed: 376 additions & 52 deletions

docs/reference/configuration.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,11 @@ their corresponding top-level category object in your `settings.json` file.
645645
"model": "gemini-3-flash-preview"
646646
}
647647
},
648+
"chat-compression-3.1-flash-lite": {
649+
"modelConfig": {
650+
"model": "gemini-3.1-flash-lite-preview"
651+
}
652+
},
648653
"chat-compression-2.5-pro": {
649654
"modelConfig": {
650655
"model": "gemini-2.5-pro"
@@ -973,6 +978,17 @@ their corresponding top-level category object in your `settings.json` file.
973978
"auto-gemini-2.5": {
974979
"default": "gemini-2.5-pro"
975980
},
981+
"gemini-3.1-flash-lite-preview": {
982+
"default": "gemini-3.1-flash-lite-preview",
983+
"contexts": [
984+
{
985+
"condition": {
986+
"useGemini3_1FlashLite": false
987+
},
988+
"target": "gemini-2.5-flash-lite"
989+
}
990+
]
991+
},
976992
"flash": {
977993
"default": "gemini-3-flash-preview",
978994
"contexts": [
@@ -985,7 +1001,15 @@ their corresponding top-level category object in your `settings.json` file.
9851001
]
9861002
},
9871003
"flash-lite": {
988-
"default": "gemini-2.5-flash-lite"
1004+
"default": "gemini-2.5-flash-lite",
1005+
"contexts": [
1006+
{
1007+
"condition": {
1008+
"useGemini3_1FlashLite": true
1009+
},
1010+
"target": "gemini-3.1-flash-lite-preview"
1011+
}
1012+
]
9891013
}
9901014
}
9911015
```

packages/cli/src/config/settingsSchema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3014,6 +3014,7 @@ export const SETTINGS_SCHEMA_DEFINITIONS: Record<
30143014
type: 'object',
30153015
properties: {
30163016
useGemini3_1: { type: 'boolean' },
3017+
useGemini3_1FlashLite: { type: 'boolean' },
30173018
useCustomTools: { type: 'boolean' },
30183019
hasAccessToPreview: { type: 'boolean' },
30193020
requestedModels: {

packages/cli/src/ui/components/ModelDialog.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ describe('<ModelDialog />', () => {
5353
const mockOnClose = vi.fn();
5454
const mockGetHasAccessToPreviewModel = vi.fn();
5555
const mockGetGemini31LaunchedSync = vi.fn();
56+
const mockGetGemini31FlashLiteLaunchedSync = vi.fn();
5657
const mockGetProModelNoAccess = vi.fn();
5758
const mockGetProModelNoAccessSync = vi.fn();
5859
const mockGetUserTier = vi.fn();
@@ -63,6 +64,7 @@ describe('<ModelDialog />', () => {
6364
getHasAccessToPreviewModel: () => boolean;
6465
getIdeMode: () => boolean;
6566
getGemini31LaunchedSync: () => boolean;
67+
getGemini31FlashLiteLaunchedSync: () => boolean;
6668
getProModelNoAccess: () => Promise<boolean>;
6769
getProModelNoAccessSync: () => boolean;
6870
getUserTier: () => UserTierId | undefined;
@@ -74,6 +76,7 @@ describe('<ModelDialog />', () => {
7476
getHasAccessToPreviewModel: mockGetHasAccessToPreviewModel,
7577
getIdeMode: () => false,
7678
getGemini31LaunchedSync: mockGetGemini31LaunchedSync,
79+
getGemini31FlashLiteLaunchedSync: mockGetGemini31FlashLiteLaunchedSync,
7780
getProModelNoAccess: mockGetProModelNoAccess,
7881
getProModelNoAccessSync: mockGetProModelNoAccessSync,
7982
getUserTier: mockGetUserTier,
@@ -84,6 +87,7 @@ describe('<ModelDialog />', () => {
8487
mockGetModel.mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO);
8588
mockGetHasAccessToPreviewModel.mockReturnValue(false);
8689
mockGetGemini31LaunchedSync.mockReturnValue(false);
90+
mockGetGemini31FlashLiteLaunchedSync.mockReturnValue(false);
8791
mockGetProModelNoAccess.mockResolvedValue(false);
8892
mockGetProModelNoAccessSync.mockReturnValue(false);
8993
mockGetUserTier.mockReturnValue(UserTierId.STANDARD);
@@ -131,6 +135,7 @@ describe('<ModelDialog />', () => {
131135
mockGetProModelNoAccessSync.mockReturnValue(true);
132136
mockGetProModelNoAccess.mockResolvedValue(true);
133137
mockGetHasAccessToPreviewModel.mockReturnValue(true);
138+
mockGetGemini31FlashLiteLaunchedSync.mockReturnValue(true);
134139
mockGetUserTier.mockReturnValue(UserTierId.FREE);
135140
mockGetDisplayString.mockImplementation((val: string) => val);
136141

@@ -463,6 +468,7 @@ describe('<ModelDialog />', () => {
463468
mockGetProModelNoAccessSync.mockReturnValue(false);
464469
mockGetProModelNoAccess.mockResolvedValue(false);
465470
mockGetHasAccessToPreviewModel.mockReturnValue(true);
471+
mockGetGemini31FlashLiteLaunchedSync.mockReturnValue(true);
466472
mockGetUserTier.mockReturnValue(UserTierId.FREE);
467473
const { lastFrame, stdin, waitUntilReady, unmount } =
468474
await renderComponent();

packages/cli/src/ui/components/ModelDialog.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
6363

6464
const shouldShowPreviewModels = config?.getHasAccessToPreviewModel();
6565
const useGemini31 = config?.getGemini31LaunchedSync?.() ?? false;
66+
const useGemini31FlashLite =
67+
config?.getGemini31FlashLiteLaunchedSync?.() ?? false;
6668
const selectedAuthType = settings.merged.security.auth.selectedType;
6769
const useCustomToolModel =
6870
useGemini31 && selectedAuthType === AuthType.USE_GEMINI;
@@ -86,6 +88,7 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
8688
PREVIEW_GEMINI_MODEL,
8789
PREVIEW_GEMINI_3_1_MODEL,
8890
PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL,
91+
PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL,
8992
PREVIEW_GEMINI_FLASH_MODEL,
9093
];
9194
if (manualModels.includes(preferredModel)) {
@@ -210,19 +213,24 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
210213

211214
// Flag Guard: Versioned models only show if their flag is active.
212215
if (id === PREVIEW_GEMINI_3_1_MODEL && !useGemini31) return false;
213-
if (id === PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL && !useGemini31)
216+
if (
217+
id === PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL &&
218+
!useGemini31FlashLite
219+
)
214220
return false;
215221

216222
return true;
217223
})
218224
.map(([id, m]) => {
219225
const resolvedId = config.modelConfigService.resolveModelId(id, {
220226
useGemini3_1: useGemini31,
227+
useGemini3_1FlashLite: useGemini31FlashLite,
221228
useCustomTools: useCustomToolModel,
222229
});
223230
// Title ID is the resolved ID without custom tools flag
224231
const titleId = config.modelConfigService.resolveModelId(id, {
225232
useGemini3_1: useGemini31,
233+
useGemini3_1FlashLite: useGemini31FlashLite,
226234
});
227235
return {
228236
value: resolvedId,
@@ -284,7 +292,7 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
284292
},
285293
];
286294

287-
if (isFreeTier) {
295+
if (isFreeTier && useGemini31FlashLite) {
288296
previewOptions.push({
289297
value: PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL,
290298
title: getDisplayString(PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL),
@@ -304,6 +312,7 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
304312
}, [
305313
shouldShowPreviewModels,
306314
useGemini31,
315+
useGemini31FlashLite,
307316
useCustomToolModel,
308317
hasAccessToProModel,
309318
config,

packages/cli/src/ui/components/StatsDisplay.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const buildModelRows = (
9292
config: Config,
9393
quotas?: RetrieveUserQuotaResponse,
9494
useGemini3_1 = false,
95+
useGemini3_1FlashLite = false,
9596
useCustomToolModel = false,
9697
) => {
9798
const getBaseModelName = (name: string) => name.replace('-001', '');
@@ -124,7 +125,12 @@ const buildModelRows = (
124125
?.filter(
125126
(b) =>
126127
b.modelId &&
127-
isActiveModel(b.modelId, useGemini3_1, useCustomToolModel) &&
128+
isActiveModel(
129+
b.modelId,
130+
useGemini3_1,
131+
useGemini3_1FlashLite,
132+
useCustomToolModel,
133+
) &&
128134
!usedModelNames.has(getDisplayString(b.modelId, config)),
129135
)
130136
.map((bucket) => ({
@@ -152,6 +158,7 @@ const ModelUsageTable: React.FC<{
152158
pooledLimit?: number;
153159
pooledResetTime?: string;
154160
useGemini3_1?: boolean;
161+
useGemini3_1FlashLite?: boolean;
155162
useCustomToolModel?: boolean;
156163
}> = ({
157164
models,
@@ -164,6 +171,7 @@ const ModelUsageTable: React.FC<{
164171
pooledLimit,
165172
pooledResetTime,
166173
useGemini3_1,
174+
useGemini3_1FlashLite,
167175
useCustomToolModel,
168176
}) => {
169177
const { stdout } = useStdout();
@@ -173,6 +181,7 @@ const ModelUsageTable: React.FC<{
173181
config,
174182
quotas,
175183
useGemini3_1,
184+
useGemini3_1FlashLite,
176185
useCustomToolModel,
177186
);
178187

@@ -541,6 +550,8 @@ export const StatsDisplay: React.FC<StatsDisplayProps> = ({
541550
const settings = useSettings();
542551
const config = useConfig();
543552
const useGemini3_1 = config.getGemini31LaunchedSync?.() ?? false;
553+
const useGemini3_1FlashLite =
554+
config.getGemini31FlashLiteLaunchedSync?.() ?? false;
544555
const useCustomToolModel =
545556
useGemini3_1 &&
546557
config.getContentGeneratorConfig().authType === AuthType.USE_GEMINI;
@@ -697,6 +708,7 @@ export const StatsDisplay: React.FC<StatsDisplayProps> = ({
697708
pooledLimit={pooledLimit}
698709
pooledResetTime={pooledResetTime}
699710
useGemini3_1={useGemini3_1}
711+
useGemini3_1FlashLite={useGemini3_1FlashLite}
700712
useCustomToolModel={useCustomToolModel}
701713
/>
702714
{renderFooter()}

packages/core/src/availability/policyCatalog.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ describe('policyCatalog', () => {
2828
const chain = getModelPolicyChain({
2929
previewEnabled: true,
3030
useGemini31: true,
31+
useGemini31FlashLite: false,
3132
});
3233
expect(chain[0]?.model).toBe(PREVIEW_GEMINI_3_1_MODEL);
3334
expect(chain).toHaveLength(2);
@@ -38,6 +39,7 @@ describe('policyCatalog', () => {
3839
const chain = getModelPolicyChain({
3940
previewEnabled: true,
4041
useGemini31: true,
42+
useGemini31FlashLite: false,
4143
useCustomToolModel: true,
4244
});
4345
expect(chain[0]?.model).toBe(PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL);

packages/core/src/availability/policyCatalog.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface ModelPolicyOptions {
3030
previewEnabled: boolean;
3131
userTier?: UserTierId;
3232
useGemini31?: boolean;
33+
useGemini31FlashLite?: boolean;
3334
useCustomToolModel?: boolean;
3435
}
3536

@@ -85,6 +86,7 @@ export function getModelPolicyChain(
8586
const previewModel = resolveModel(
8687
PREVIEW_GEMINI_MODEL,
8788
options.useGemini31,
89+
options.useGemini31FlashLite,
8890
options.useCustomToolModel,
8991
);
9092
return [

packages/core/src/availability/policyHelpers.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const createMockConfig = (overrides: Partial<Config> = {}): Config => {
2727
getUserTier: () => undefined,
2828
getModel: () => 'gemini-2.5-pro',
2929
getGemini31LaunchedSync: () => false,
30+
getGemini31FlashLiteLaunchedSync: () => false,
3031
getUseCustomToolModelSync: () => {
3132
const useGemini31 = config.getGemini31LaunchedSync();
3233
const authType = config.getContentGeneratorConfig().authType;
@@ -203,6 +204,7 @@ describe('policyHelpers', () => {
203204
getExperimentalDynamicModelConfiguration: () => dynamic,
204205
getModel: () => model,
205206
getGemini31LaunchedSync: () => useGemini31 ?? false,
207+
getGemini31FlashLiteLaunchedSync: () => false,
206208
getHasAccessToPreviewModel: () => hasAccess ?? true,
207209
getContentGeneratorConfig: () => ({ authType }),
208210
modelConfigService: new ModelConfigService(DEFAULT_MODEL_CONFIGS),

packages/core/src/availability/policyHelpers.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,15 @@ export function resolvePolicyChain(
4545

4646
let chain;
4747
const useGemini31 = config.getGemini31LaunchedSync?.() ?? false;
48+
const useGemini31FlashLite =
49+
config.getGemini31FlashLiteLaunchedSync?.() ?? false;
4850
const useCustomToolModel = config.getUseCustomToolModelSync?.() ?? false;
4951
const hasAccessToPreview = config.getHasAccessToPreviewModel?.() ?? true;
5052

5153
const resolvedModel = resolveModel(
5254
modelFromConfig,
5355
useGemini31,
56+
useGemini31FlashLite,
5457
useCustomToolModel,
5558
hasAccessToPreview,
5659
config,
@@ -64,6 +67,7 @@ export function resolvePolicyChain(
6467
if (config.getExperimentalDynamicModelConfiguration?.() === true) {
6568
const context = {
6669
useGemini3_1: useGemini31,
70+
useGemini3_1FlashLite: useGemini31FlashLite,
6771
useCustomTools: useCustomToolModel,
6872
};
6973

@@ -120,6 +124,7 @@ export function resolvePolicyChain(
120124
previewEnabled,
121125
userTier: config.getUserTier(),
122126
useGemini31,
127+
useGemini31FlashLite,
123128
useCustomToolModel,
124129
});
125130
} else {
@@ -129,6 +134,7 @@ export function resolvePolicyChain(
129134
previewEnabled: false,
130135
userTier: config.getUserTier(),
131136
useGemini31,
137+
useGemini31FlashLite,
132138
useCustomToolModel,
133139
});
134140
}

packages/core/src/code_assist/experiments/flagNames.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const ExperimentFlags = {
1818
MASKING_PROTECT_LATEST_TURN: 45758819,
1919
GEMINI_3_1_PRO_LAUNCHED: 45760185,
2020
PRO_MODEL_NO_ACCESS: 45768879,
21+
GEMINI_3_1_FLASH_LITE_LAUNCHED: 45771641,
2122
} as const;
2223

2324
export type ExperimentFlagName =

0 commit comments

Comments
 (0)