mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-27 03:37:27 -07:00
feat: promote Gemini 3.1 Flash Lite to GA and support Gemini 3.5 Flash
This commit is contained in:
@@ -19,6 +19,7 @@ import type * as acp from '@agentclientprotocol/sdk';
|
||||
import {
|
||||
AuthType,
|
||||
type Config,
|
||||
GEMINI_MODEL_ALIAS_AUTO,
|
||||
type MessageBus,
|
||||
type Storage,
|
||||
} from '@google/gemini-cli-core';
|
||||
@@ -208,20 +209,19 @@ describe('AcpSessionManager', () => {
|
||||
expect(response.models?.availableModels).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
modelId: 'auto-gemini-3',
|
||||
modelId: GEMINI_MODEL_ALIAS_AUTO,
|
||||
name: expect.stringContaining('Auto'),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should include gemini-3.1-flash-lite when useGemini31FlashLite is true', async () => {
|
||||
it('should NOT include retired preview models (none) in available models', async () => {
|
||||
mockConfig.getContentGeneratorConfig = vi.fn().mockReturnValue({
|
||||
apiKey: 'test-key',
|
||||
});
|
||||
mockConfig.getHasAccessToPreviewModel = vi.fn().mockReturnValue(true);
|
||||
mockConfig.getGemini31LaunchedSync = vi.fn().mockReturnValue(true);
|
||||
mockConfig.getGemini31FlashLiteLaunchedSync = vi.fn().mockReturnValue(true);
|
||||
|
||||
const response = await manager.newSession(
|
||||
{
|
||||
@@ -231,14 +231,9 @@ describe('AcpSessionManager', () => {
|
||||
{},
|
||||
);
|
||||
|
||||
expect(response.models?.availableModels).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
modelId: 'gemini-3.1-flash-lite',
|
||||
name: 'gemini-3.1-flash-lite',
|
||||
}),
|
||||
]),
|
||||
);
|
||||
const modelIds =
|
||||
response.models?.availableModels?.map((m) => m.modelId) ?? [];
|
||||
expect(modelIds).not.toContain('none');
|
||||
});
|
||||
|
||||
it('should return modes with plan mode when plan is enabled', async () => {
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
type ToolCallConfirmationDetails,
|
||||
Kind,
|
||||
ApprovalMode,
|
||||
DEFAULT_GEMINI_MODEL_AUTO,
|
||||
PREVIEW_GEMINI_MODEL_AUTO,
|
||||
GEMINI_MODEL_ALIAS_AUTO,
|
||||
DEFAULT_GEMINI_MODEL,
|
||||
DEFAULT_GEMINI_FLASH_MODEL,
|
||||
DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
@@ -19,10 +18,11 @@ import {
|
||||
PREVIEW_GEMINI_MODEL,
|
||||
PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL,
|
||||
PREVIEW_GEMINI_FLASH_MODEL,
|
||||
GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
PREVIEW_GEMINI_FLASH_LITE_MODEL,
|
||||
getDisplayString,
|
||||
AuthType,
|
||||
ToolConfirmationOutcome,
|
||||
getAutoModelDescription,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type * as acp from '@agentclientprotocol/sdk';
|
||||
import { z } from 'zod';
|
||||
@@ -262,11 +262,10 @@ export function buildAvailableModels(
|
||||
}>;
|
||||
currentModelId: string;
|
||||
} {
|
||||
const preferredModel = config.getModel() || DEFAULT_GEMINI_MODEL_AUTO;
|
||||
const preferredModel = config.getModel() || GEMINI_MODEL_ALIAS_AUTO;
|
||||
const shouldShowPreviewModels = config.getHasAccessToPreviewModel();
|
||||
const useGemini31 = config.getGemini31LaunchedSync?.() ?? false;
|
||||
const useGemini31FlashLite =
|
||||
config.getGemini31FlashLiteLaunchedSync?.() ?? false;
|
||||
const useGemini3_5Flash = config.hasGemini35FlashGAAccess?.() ?? false;
|
||||
const selectedAuthType = settings.merged.security.auth.selectedType;
|
||||
const useCustomToolModel =
|
||||
useGemini31 && selectedAuthType === AuthType.USE_GEMINI;
|
||||
@@ -278,7 +277,7 @@ export function buildAvailableModels(
|
||||
) {
|
||||
const options = config.getModelConfigService().getAvailableModelOptions({
|
||||
useGemini3_1: useGemini31,
|
||||
useGemini3_1FlashLite: useGemini31FlashLite,
|
||||
useGemini3_5Flash,
|
||||
useCustomTools: useCustomToolModel,
|
||||
hasAccessToPreview: shouldShowPreviewModels,
|
||||
});
|
||||
@@ -290,37 +289,35 @@ export function buildAvailableModels(
|
||||
}
|
||||
|
||||
// --- LEGACY PATH ---
|
||||
const defaultFlashModel =
|
||||
config.getDefaultGeminiFlashModel?.() ?? DEFAULT_GEMINI_FLASH_MODEL;
|
||||
const previewFlashModel =
|
||||
config.getPreviewGeminiFlashModel?.() ?? PREVIEW_GEMINI_FLASH_MODEL;
|
||||
|
||||
const mainOptions = [
|
||||
{
|
||||
value: DEFAULT_GEMINI_MODEL_AUTO,
|
||||
title: getDisplayString(DEFAULT_GEMINI_MODEL_AUTO),
|
||||
description:
|
||||
'Let Gemini CLI decide the best model for the task: gemini-2.5-pro, gemini-2.5-flash',
|
||||
value: GEMINI_MODEL_ALIAS_AUTO,
|
||||
title: getDisplayString(GEMINI_MODEL_ALIAS_AUTO, config),
|
||||
description: getAutoModelDescription(
|
||||
shouldShowPreviewModels,
|
||||
useGemini31,
|
||||
useGemini3_5Flash,
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
if (shouldShowPreviewModels) {
|
||||
mainOptions.unshift({
|
||||
value: PREVIEW_GEMINI_MODEL_AUTO,
|
||||
title: getDisplayString(PREVIEW_GEMINI_MODEL_AUTO),
|
||||
description: useGemini31
|
||||
? 'Let Gemini CLI decide the best model for the task: gemini-3.1-pro, gemini-3-flash'
|
||||
: 'Let Gemini CLI decide the best model for the task: gemini-3-pro, gemini-3-flash',
|
||||
});
|
||||
}
|
||||
|
||||
const manualOptions = [
|
||||
{
|
||||
value: DEFAULT_GEMINI_MODEL,
|
||||
title: getDisplayString(DEFAULT_GEMINI_MODEL),
|
||||
title: getDisplayString(DEFAULT_GEMINI_MODEL, config),
|
||||
},
|
||||
{
|
||||
value: DEFAULT_GEMINI_FLASH_MODEL,
|
||||
title: getDisplayString(DEFAULT_GEMINI_FLASH_MODEL),
|
||||
value: defaultFlashModel,
|
||||
title: getDisplayString(defaultFlashModel, config),
|
||||
},
|
||||
{
|
||||
value: DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
title: getDisplayString(DEFAULT_GEMINI_FLASH_LITE_MODEL),
|
||||
title: getDisplayString(DEFAULT_GEMINI_FLASH_LITE_MODEL, config),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -336,18 +333,18 @@ export function buildAvailableModels(
|
||||
const previewOptions = [
|
||||
{
|
||||
value: previewProValue,
|
||||
title: getDisplayString(previewProModel),
|
||||
title: getDisplayString(previewProModel, config),
|
||||
},
|
||||
{
|
||||
value: PREVIEW_GEMINI_FLASH_MODEL,
|
||||
title: getDisplayString(PREVIEW_GEMINI_FLASH_MODEL),
|
||||
value: previewFlashModel,
|
||||
title: getDisplayString(previewFlashModel, config),
|
||||
},
|
||||
];
|
||||
|
||||
if (useGemini31FlashLite) {
|
||||
if (PREVIEW_GEMINI_FLASH_LITE_MODEL !== 'none') {
|
||||
previewOptions.push({
|
||||
value: GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
title: getDisplayString(GEMINI_3_1_FLASH_LITE_MODEL),
|
||||
value: PREVIEW_GEMINI_FLASH_LITE_MODEL,
|
||||
title: getDisplayString(PREVIEW_GEMINI_FLASH_LITE_MODEL, config),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@ import { waitFor } from '../../test-utils/async.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import {
|
||||
DEFAULT_GEMINI_MODEL,
|
||||
DEFAULT_GEMINI_MODEL_AUTO,
|
||||
GEMINI_MODEL_ALIAS_AUTO,
|
||||
DEFAULT_GEMINI_FLASH_MODEL,
|
||||
DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
PREVIEW_GEMINI_MODEL,
|
||||
PREVIEW_GEMINI_3_1_MODEL,
|
||||
PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL,
|
||||
PREVIEW_GEMINI_FLASH_MODEL,
|
||||
GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
PREVIEW_GEMINI_FLASH_LITE_MODEL,
|
||||
AuthType,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { Config, ModelSlashCommandEvent } from '@google/gemini-cli-core';
|
||||
@@ -34,6 +34,11 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
return {
|
||||
...actual,
|
||||
getAutoModelDescription: (
|
||||
hasAccessToPreview: boolean,
|
||||
useGemini3_1?: boolean,
|
||||
) =>
|
||||
`Auto Model Description (preview: ${hasAccessToPreview}, 3.1: ${useGemini3_1})`,
|
||||
getDisplayString: (val: string) => mockGetDisplayString(val),
|
||||
logModelSlashCommand: (config: Config, event: ModelSlashCommandEvent) =>
|
||||
mockLogModelSlashCommand(config, event),
|
||||
@@ -42,8 +47,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
mockModelSlashCommandEvent(model);
|
||||
}
|
||||
},
|
||||
PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL: 'gemini-3.1-flash-lite-preview',
|
||||
GEMINI_3_1_FLASH_LITE_MODEL: 'gemini-3.1-flash-lite',
|
||||
PREVIEW_GEMINI_FLASH_LITE_MODEL: 'none',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -63,7 +67,6 @@ describe('<ModelDialog />', () => {
|
||||
getHasAccessToPreviewModel: () => boolean;
|
||||
getIdeMode: () => boolean;
|
||||
getGemini31LaunchedSync: () => boolean;
|
||||
getGemini31FlashLiteLaunchedSync: () => boolean;
|
||||
getProModelNoAccess: () => Promise<boolean>;
|
||||
getProModelNoAccessSync: () => boolean;
|
||||
getExperimentalGemma: () => boolean;
|
||||
@@ -84,7 +87,6 @@ describe('<ModelDialog />', () => {
|
||||
getHasAccessToPreviewModel: mockGetHasAccessToPreviewModel,
|
||||
getIdeMode: () => false,
|
||||
getGemini31LaunchedSync: mockGetGemini31LaunchedSync,
|
||||
getGemini31FlashLiteLaunchedSync: mockGetGemini31FlashLiteLaunchedSync,
|
||||
getProModelNoAccess: mockGetProModelNoAccess,
|
||||
getProModelNoAccessSync: mockGetProModelNoAccessSync,
|
||||
getExperimentalGemma: () => false,
|
||||
@@ -94,17 +96,15 @@ describe('<ModelDialog />', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
mockGetModel.mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO);
|
||||
mockGetModel.mockReturnValue(GEMINI_MODEL_ALIAS_AUTO);
|
||||
mockGetHasAccessToPreviewModel.mockReturnValue(false);
|
||||
mockGetGemini31LaunchedSync.mockReturnValue(false);
|
||||
mockGetGemini31FlashLiteLaunchedSync.mockReturnValue(false);
|
||||
mockGetProModelNoAccess.mockResolvedValue(false);
|
||||
mockGetProModelNoAccessSync.mockReturnValue(false);
|
||||
|
||||
// Default implementation for getDisplayString
|
||||
mockGetDisplayString.mockImplementation((val: string) => {
|
||||
if (val === 'auto-gemini-2.5') return 'Auto (Gemini 2.5)';
|
||||
if (val === 'auto-gemini-3') return 'Auto (Preview)';
|
||||
if (val === 'auto') return 'Auto';
|
||||
return val;
|
||||
});
|
||||
});
|
||||
@@ -154,15 +154,13 @@ describe('<ModelDialog />', () => {
|
||||
expect(output).not.toContain(DEFAULT_GEMINI_MODEL);
|
||||
expect(output).not.toContain(PREVIEW_GEMINI_MODEL);
|
||||
|
||||
// Verify order: Flash Preview -> Flash Lite Preview -> Flash -> Flash Lite
|
||||
// Verify order: Flash Preview -> Flash Lite (Preview/Default) -> Flash
|
||||
const flashPreviewIdx = output.indexOf(PREVIEW_GEMINI_FLASH_MODEL);
|
||||
const flashLitePreviewIdx = output.indexOf(GEMINI_3_1_FLASH_LITE_MODEL);
|
||||
const flashIdx = output.indexOf(DEFAULT_GEMINI_FLASH_MODEL);
|
||||
const flashLiteIdx = output.indexOf(DEFAULT_GEMINI_FLASH_LITE_MODEL);
|
||||
const flashIdx = output.indexOf(DEFAULT_GEMINI_FLASH_MODEL);
|
||||
|
||||
expect(flashPreviewIdx).toBeLessThan(flashLitePreviewIdx);
|
||||
expect(flashLitePreviewIdx).toBeLessThan(flashIdx);
|
||||
expect(flashIdx).toBeLessThan(flashLiteIdx);
|
||||
expect(flashPreviewIdx).toBeLessThan(flashLiteIdx);
|
||||
expect(flashLiteIdx).toBeLessThan(flashIdx);
|
||||
|
||||
expect(output).not.toContain('Auto');
|
||||
unmount();
|
||||
@@ -233,7 +231,7 @@ describe('<ModelDialog />', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockSetModel).toHaveBeenCalledWith(
|
||||
DEFAULT_GEMINI_MODEL_AUTO,
|
||||
GEMINI_MODEL_ALIAS_AUTO,
|
||||
true, // Session only by default
|
||||
);
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
@@ -291,7 +289,7 @@ describe('<ModelDialog />', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockSetModel).toHaveBeenCalledWith(
|
||||
DEFAULT_GEMINI_MODEL_AUTO,
|
||||
GEMINI_MODEL_ALIAS_AUTO,
|
||||
false, // Persist enabled
|
||||
);
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
@@ -354,7 +352,7 @@ describe('<ModelDialog />', () => {
|
||||
mockGetModel.mockReturnValue(DEFAULT_GEMINI_MODEL);
|
||||
mockGetDisplayString.mockImplementation((val: string) => {
|
||||
if (val === DEFAULT_GEMINI_MODEL) return 'My Custom Model Display';
|
||||
if (val === 'auto-gemini-2.5') return 'Auto (Gemini 2.5)';
|
||||
if (val === 'auto') return 'Auto';
|
||||
return val;
|
||||
});
|
||||
const { lastFrame, unmount } = await renderComponent();
|
||||
@@ -368,9 +366,9 @@ describe('<ModelDialog />', () => {
|
||||
mockGetHasAccessToPreviewModel.mockReturnValue(true);
|
||||
});
|
||||
|
||||
it('shows Auto (Preview) in main view when access is granted', async () => {
|
||||
it('shows Auto in main view when access is granted', async () => {
|
||||
const { lastFrame, unmount } = await renderComponent();
|
||||
expect(lastFrame()).toContain('Auto (Preview)');
|
||||
expect(lastFrame()).toContain('Auto');
|
||||
unmount();
|
||||
});
|
||||
|
||||
@@ -448,7 +446,7 @@ describe('<ModelDialog />', () => {
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('shows Flash Lite Preview model regardless of tier when flag is enabled', async () => {
|
||||
it('does not show Flash Lite Preview model when it is retired (none) even if flag is enabled', async () => {
|
||||
mockGetProModelNoAccessSync.mockReturnValue(false);
|
||||
mockGetProModelNoAccess.mockResolvedValue(false);
|
||||
mockGetHasAccessToPreviewModel.mockReturnValue(true);
|
||||
@@ -467,7 +465,8 @@ describe('<ModelDialog />', () => {
|
||||
await waitUntilReady();
|
||||
|
||||
const output = lastFrame();
|
||||
expect(output).toContain(GEMINI_3_1_FLASH_LITE_MODEL);
|
||||
expect(output).not.toContain(PREVIEW_GEMINI_FLASH_LITE_MODEL);
|
||||
expect(output).toContain(DEFAULT_GEMINI_FLASH_LITE_MODEL);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,13 +13,11 @@ import {
|
||||
PREVIEW_GEMINI_MODEL,
|
||||
PREVIEW_GEMINI_3_1_MODEL,
|
||||
PREVIEW_GEMINI_FLASH_MODEL,
|
||||
PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
PREVIEW_GEMINI_MODEL_AUTO,
|
||||
GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
PREVIEW_GEMINI_FLASH_LITE_MODEL,
|
||||
DEFAULT_GEMINI_MODEL,
|
||||
DEFAULT_GEMINI_FLASH_MODEL,
|
||||
DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
DEFAULT_GEMINI_MODEL_AUTO,
|
||||
GEMINI_MODEL_ALIAS_AUTO,
|
||||
GEMMA_4_31B_IT_MODEL,
|
||||
GEMMA_4_26B_A4B_IT_MODEL,
|
||||
ModelSlashCommandEvent,
|
||||
@@ -28,6 +26,7 @@ import {
|
||||
AuthType,
|
||||
PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL,
|
||||
isProModel,
|
||||
getAutoModelDescription,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { useKeypress } from '../hooks/useKeypress.js';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
@@ -64,12 +63,11 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
}, [config]);
|
||||
|
||||
// Determine the Preferred Model (read once when the dialog opens).
|
||||
const preferredModel = config?.getModel() || DEFAULT_GEMINI_MODEL_AUTO;
|
||||
const preferredModel = config?.getModel() || GEMINI_MODEL_ALIAS_AUTO;
|
||||
|
||||
const shouldShowPreviewModels = config?.getHasAccessToPreviewModel();
|
||||
const shouldShowPreviewModels = config?.getHasAccessToPreviewModel() ?? false;
|
||||
const useGemini31 = config?.getGemini31LaunchedSync?.() ?? false;
|
||||
const useGemini31FlashLite =
|
||||
config?.getGemini31FlashLiteLaunchedSync?.() ?? false;
|
||||
const useGemini3_5Flash = config?.hasGemini35FlashGAAccess?.() ?? false;
|
||||
const selectedAuthType = settings.merged.security.auth.selectedType;
|
||||
const useCustomToolModel =
|
||||
useGemini31 && selectedAuthType === AuthType.USE_GEMINI;
|
||||
@@ -88,17 +86,21 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
: '';
|
||||
}
|
||||
|
||||
const defaultFlashModel =
|
||||
config?.getDefaultGeminiFlashModel?.() ?? DEFAULT_GEMINI_FLASH_MODEL;
|
||||
const previewFlashModel =
|
||||
config?.getPreviewGeminiFlashModel?.() ?? PREVIEW_GEMINI_FLASH_MODEL;
|
||||
|
||||
const manualModels = [
|
||||
DEFAULT_GEMINI_MODEL,
|
||||
DEFAULT_GEMINI_FLASH_MODEL,
|
||||
defaultFlashModel,
|
||||
DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
PREVIEW_GEMINI_MODEL,
|
||||
PREVIEW_GEMINI_3_1_MODEL,
|
||||
PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL,
|
||||
PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
PREVIEW_GEMINI_FLASH_MODEL,
|
||||
];
|
||||
PREVIEW_GEMINI_FLASH_LITE_MODEL,
|
||||
previewFlashModel,
|
||||
].filter((m) => m !== 'none');
|
||||
if (manualModels.includes(preferredModel)) {
|
||||
return preferredModel;
|
||||
}
|
||||
@@ -123,7 +125,6 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
},
|
||||
{ isActive: true },
|
||||
);
|
||||
|
||||
const mainOptions = useMemo(() => {
|
||||
// --- DYNAMIC PATH ---
|
||||
if (
|
||||
@@ -134,7 +135,7 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
.getModelConfigService()
|
||||
.getAvailableModelOptions({
|
||||
useGemini3_1: useGemini31,
|
||||
useGemini3_1FlashLite: useGemini31FlashLite,
|
||||
useGemini3_5Flash,
|
||||
useCustomTools: useCustomToolModel,
|
||||
hasAccessToPreview: shouldShowPreviewModels,
|
||||
hasAccessToProModel,
|
||||
@@ -163,11 +164,14 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
// --- LEGACY PATH ---
|
||||
const list = [
|
||||
{
|
||||
value: DEFAULT_GEMINI_MODEL_AUTO,
|
||||
title: getDisplayString(DEFAULT_GEMINI_MODEL_AUTO),
|
||||
description:
|
||||
'Let Gemini CLI decide the best model for the task: gemini-2.5-pro, gemini-2.5-flash',
|
||||
key: DEFAULT_GEMINI_MODEL_AUTO,
|
||||
value: GEMINI_MODEL_ALIAS_AUTO,
|
||||
title: getDisplayString(GEMINI_MODEL_ALIAS_AUTO),
|
||||
description: getAutoModelDescription(
|
||||
shouldShowPreviewModels,
|
||||
useGemini31,
|
||||
useGemini3_5Flash,
|
||||
),
|
||||
key: GEMINI_MODEL_ALIAS_AUTO,
|
||||
},
|
||||
{
|
||||
value: 'Manual',
|
||||
@@ -179,23 +183,13 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
},
|
||||
];
|
||||
|
||||
if (shouldShowPreviewModels) {
|
||||
list.unshift({
|
||||
value: PREVIEW_GEMINI_MODEL_AUTO,
|
||||
title: getDisplayString(PREVIEW_GEMINI_MODEL_AUTO),
|
||||
description: useGemini31
|
||||
? 'Let Gemini CLI decide the best model for the task: gemini-3.1-pro, gemini-3-flash'
|
||||
: 'Let Gemini CLI decide the best model for the task: gemini-3-pro, gemini-3-flash',
|
||||
key: PREVIEW_GEMINI_MODEL_AUTO,
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}, [
|
||||
config,
|
||||
shouldShowPreviewModels,
|
||||
manualModelSelected,
|
||||
useGemini31,
|
||||
useGemini31FlashLite,
|
||||
useGemini3_5Flash,
|
||||
useCustomToolModel,
|
||||
hasAccessToProModel,
|
||||
]);
|
||||
@@ -210,7 +204,7 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
.getModelConfigService()
|
||||
.getAvailableModelOptions({
|
||||
useGemini3_1: useGemini31,
|
||||
useGemini3_1FlashLite: useGemini31FlashLite,
|
||||
useGemini3_5Flash,
|
||||
useCustomTools: useCustomToolModel,
|
||||
hasAccessToPreview: shouldShowPreviewModels,
|
||||
hasAccessToProModel,
|
||||
@@ -227,22 +221,29 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
|
||||
// --- LEGACY PATH ---
|
||||
const showGemmaModels = config?.getExperimentalGemma() ?? false;
|
||||
const defaultFlashModel =
|
||||
config?.getDefaultGeminiFlashModel?.() ?? DEFAULT_GEMINI_FLASH_MODEL;
|
||||
const previewFlashModel =
|
||||
config?.getPreviewGeminiFlashModel?.() ?? PREVIEW_GEMINI_FLASH_MODEL;
|
||||
|
||||
const options = [
|
||||
{
|
||||
value: DEFAULT_GEMINI_MODEL,
|
||||
title: getDisplayString(DEFAULT_GEMINI_MODEL),
|
||||
title: getDisplayString(DEFAULT_GEMINI_MODEL, config ?? undefined),
|
||||
key: DEFAULT_GEMINI_MODEL,
|
||||
},
|
||||
{
|
||||
value: DEFAULT_GEMINI_FLASH_MODEL,
|
||||
title: getDisplayString(DEFAULT_GEMINI_FLASH_MODEL),
|
||||
key: DEFAULT_GEMINI_FLASH_MODEL,
|
||||
value: DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
title: getDisplayString(
|
||||
DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
config ?? undefined,
|
||||
),
|
||||
key: DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
},
|
||||
{
|
||||
value: DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
title: getDisplayString(DEFAULT_GEMINI_FLASH_LITE_MODEL),
|
||||
key: DEFAULT_GEMINI_FLASH_LITE_MODEL,
|
||||
value: defaultFlashModel,
|
||||
title: getDisplayString(defaultFlashModel, config ?? undefined),
|
||||
key: defaultFlashModel,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -250,12 +251,15 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
options.push(
|
||||
{
|
||||
value: GEMMA_4_31B_IT_MODEL,
|
||||
title: getDisplayString(GEMMA_4_31B_IT_MODEL),
|
||||
title: getDisplayString(GEMMA_4_31B_IT_MODEL, config ?? undefined),
|
||||
key: GEMMA_4_31B_IT_MODEL,
|
||||
},
|
||||
{
|
||||
value: GEMMA_4_26B_A4B_IT_MODEL,
|
||||
title: getDisplayString(GEMMA_4_26B_A4B_IT_MODEL),
|
||||
title: getDisplayString(
|
||||
GEMMA_4_26B_A4B_IT_MODEL,
|
||||
config ?? undefined,
|
||||
),
|
||||
key: GEMMA_4_26B_A4B_IT_MODEL,
|
||||
},
|
||||
);
|
||||
@@ -273,21 +277,24 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
const previewOptions = [
|
||||
{
|
||||
value: previewProValue,
|
||||
title: getDisplayString(previewProModel),
|
||||
title: getDisplayString(previewProModel, config ?? undefined),
|
||||
key: previewProModel,
|
||||
},
|
||||
{
|
||||
value: PREVIEW_GEMINI_FLASH_MODEL,
|
||||
title: getDisplayString(PREVIEW_GEMINI_FLASH_MODEL),
|
||||
key: PREVIEW_GEMINI_FLASH_MODEL,
|
||||
value: previewFlashModel,
|
||||
title: getDisplayString(previewFlashModel, config ?? undefined),
|
||||
key: previewFlashModel,
|
||||
},
|
||||
];
|
||||
|
||||
if (useGemini31FlashLite) {
|
||||
if (PREVIEW_GEMINI_FLASH_LITE_MODEL !== 'none') {
|
||||
previewOptions.push({
|
||||
value: GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
title: getDisplayString(GEMINI_3_1_FLASH_LITE_MODEL),
|
||||
key: GEMINI_3_1_FLASH_LITE_MODEL,
|
||||
value: PREVIEW_GEMINI_FLASH_LITE_MODEL,
|
||||
title: getDisplayString(
|
||||
PREVIEW_GEMINI_FLASH_LITE_MODEL,
|
||||
config ?? undefined,
|
||||
),
|
||||
key: PREVIEW_GEMINI_FLASH_LITE_MODEL,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -303,13 +310,23 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
}, [
|
||||
shouldShowPreviewModels,
|
||||
useGemini31,
|
||||
useGemini31FlashLite,
|
||||
useGemini3_5Flash,
|
||||
useCustomToolModel,
|
||||
hasAccessToProModel,
|
||||
config,
|
||||
]);
|
||||
|
||||
const options = view === 'main' ? mainOptions : manualOptions;
|
||||
const options = useMemo(() => {
|
||||
const rawOptions = view === 'main' ? mainOptions : manualOptions;
|
||||
const seen = new Set<string>();
|
||||
return rawOptions.filter((option) => {
|
||||
if (seen.has(option.value)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(option.value);
|
||||
return true;
|
||||
});
|
||||
}, [view, mainOptions, manualOptions]);
|
||||
|
||||
// Calculate the initial index based on the preferred model.
|
||||
const initialIndex = useMemo(() => {
|
||||
|
||||
@@ -353,6 +353,49 @@ describe('<ModelStatsDisplay />', () => {
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should resolve gemini-3-flash to gemini-3.5-flash via getDisplayString', async () => {
|
||||
const { lastFrame, unmount } = await renderWithMockedStats({
|
||||
models: {
|
||||
'gemini-3-flash': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
|
||||
tokens: {
|
||||
input: 5,
|
||||
prompt: 10,
|
||||
candidates: 20,
|
||||
total: 30,
|
||||
cached: 5,
|
||||
thoughts: 2,
|
||||
tool: 1,
|
||||
},
|
||||
roles: {},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
totalCalls: 0,
|
||||
totalSuccess: 0,
|
||||
totalFail: 0,
|
||||
totalDurationMs: 0,
|
||||
totalDecisions: {
|
||||
accept: 0,
|
||||
reject: 0,
|
||||
modify: 0,
|
||||
[ToolCallDecision.AUTO_ACCEPT]: 0,
|
||||
},
|
||||
byName: {},
|
||||
},
|
||||
files: {
|
||||
totalLinesAdded: 0,
|
||||
totalLinesRemoved: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('gemini-3.5-flash');
|
||||
expect(output).not.toContain('gemini-3-flash');
|
||||
expect(output).toMatchSnapshot();
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should handle models with long names (gemini-3-*-preview) without layout breaking', async () => {
|
||||
const { lastFrame, unmount } = await renderWithMockedStats(
|
||||
{
|
||||
|
||||
@@ -299,7 +299,7 @@ export const ModelStatsDisplay: React.FC<ModelStatsDisplayProps> = ({
|
||||
},
|
||||
...modelNames.map((name) => ({
|
||||
key: name,
|
||||
header: name,
|
||||
header: getDisplayString(name),
|
||||
flexGrow: 1,
|
||||
renderCell: (row: StatRowData) => {
|
||||
// Don't render anything for section headers in model columns
|
||||
|
||||
+6
@@ -6,6 +6,12 @@ Sort: s Reverse: r First/Last: g/G
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`SessionBrowser Search and Navigation Components > NavigationHelp renders correctly 2`] = `
|
||||
"Navigate: ↑/↓ Resume: Enter Search: / Delete: x Quit: q
|
||||
Sort: s Reverse: r First/Last: g/G
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`SessionBrowser Search and Navigation Components > NoResultsDisplay renders correctly 1`] = `
|
||||
"
|
||||
No sessions found matching 'no match'.
|
||||
|
||||
+6
@@ -6,6 +6,12 @@ exports[`SessionBrowser UI States > SessionBrowserEmpty renders correctly 1`] =
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`SessionBrowser UI States > SessionBrowserEmpty renders correctly 2`] = `
|
||||
" No auto-saved conversations found.
|
||||
Press q to exit
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`SessionBrowser UI States > SessionBrowserError renders correctly 1`] = `
|
||||
" Error: Test error message
|
||||
Press q to exit
|
||||
|
||||
@@ -131,6 +131,33 @@ describe('<StatsDisplay />', () => {
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('resolves gemini-3-flash to gemini-3.5-flash in the model usage table', async () => {
|
||||
const metrics = createTestMetrics({
|
||||
models: {
|
||||
'gemini-3-flash': {
|
||||
api: { totalRequests: 5, totalErrors: 0, totalLatencyMs: 3000 },
|
||||
tokens: {
|
||||
input: 1000,
|
||||
prompt: 2000,
|
||||
candidates: 3000,
|
||||
total: 5000,
|
||||
cached: 500,
|
||||
thoughts: 100,
|
||||
tool: 50,
|
||||
},
|
||||
roles: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { lastFrame } = await renderWithMockedStats(metrics);
|
||||
const output = lastFrame();
|
||||
|
||||
expect(output).toContain('gemini-3.5-flash');
|
||||
expect(output).not.toContain('gemini-3-flash\u0020'); // Avoid matching parts of substrings if not intended
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders role breakdown correctly under models', async () => {
|
||||
const metrics = createTestMetrics({
|
||||
models: {
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
import { computeSessionStats } from '../utils/computeStats.js';
|
||||
import { useSettings } from '../contexts/SettingsContext.js';
|
||||
import type { QuotaStats } from '../types.js';
|
||||
import { LlmRole } from '@google/gemini-cli-core';
|
||||
import { LlmRole, getDisplayString } from '@google/gemini-cli-core';
|
||||
|
||||
// A more flexible and powerful StatRow component
|
||||
interface StatRowProps {
|
||||
@@ -101,7 +101,7 @@ const ModelUsageTable: React.FC<ModelUsageTableProps> = ({ models }) => {
|
||||
Object.entries(models).forEach(([name, metrics]) => {
|
||||
rows.push({
|
||||
name,
|
||||
displayName: name,
|
||||
displayName: getDisplayString(name),
|
||||
requests: metrics.api.totalRequests,
|
||||
cachedTokens: metrics.tokens.cached.toLocaleString(),
|
||||
inputTokens: metrics.tokens.prompt.toLocaleString(),
|
||||
|
||||
+50
@@ -84,6 +84,33 @@ exports[`AlternateBufferQuittingDisplay > renders with history but no pending it
|
||||
|
||||
|
||||
|
||||
Tips for getting started:
|
||||
1. Create GEMINI.md files to customize your interactions
|
||||
2. /help for more information
|
||||
3. Ask coding questions, edit code or run commands
|
||||
4. Be specific for the best results
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool1 Description for tool 1 │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────╯
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool2 Description for tool 2 │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AlternateBufferQuittingDisplay > renders with pending items but no history > with_history_no_pending 1`] = `
|
||||
"
|
||||
▝▜▄ ▗█▀▀▜▙▝█▛▀▀▌▜██▖▟██▘▜█▘▜██▖▝█▛▝█▛
|
||||
▝▜▄ █▌ █▙▟ ▐█▝█▛▐█ ▐█ ▐█▝█▖█▌ █▌
|
||||
▗▟▀ ▜▙ ▝█▛ █▌▝ ▖▐█ ▐█ ▐█ ▐█ ▝██▌ █▌
|
||||
▝▀ ▀▀▀▀▘▝▀▀▀▀▘▀▀▘ ▀▀▘▀▀▘▀▀▘ ▝▀▀▝▀▀
|
||||
|
||||
Gemini CLI v0.10.0
|
||||
|
||||
|
||||
|
||||
Tips for getting started:
|
||||
1. Create GEMINI.md files to customize your interactions
|
||||
2. /help for more information
|
||||
@@ -123,6 +150,29 @@ Tips for getting started:
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AlternateBufferQuittingDisplay > renders with user and gemini messages > with_confirming_tool 1`] = `
|
||||
"
|
||||
▝▜▄ ▗█▀▀▜▙▝█▛▀▀▌▜██▖▟██▘▜█▘▜██▖▝█▛▝█▛
|
||||
▝▜▄ █▌ █▙▟ ▐█▝█▛▐█ ▐█ ▐█▝█▖█▌ █▌
|
||||
▗▟▀ ▜▙ ▝█▛ █▌▝ ▖▐█ ▐█ ▐█ ▐█ ▝██▌ █▌
|
||||
▝▀ ▀▀▀▀▘▝▀▀▀▀▘▀▀▘ ▀▀▘▀▀▘▀▀▘ ▝▀▀▝▀▀
|
||||
|
||||
Gemini CLI v0.10.0
|
||||
|
||||
|
||||
|
||||
Tips for getting started:
|
||||
1. Create GEMINI.md files to customize your interactions
|
||||
2. /help for more information
|
||||
3. Ask coding questions, edit code or run commands
|
||||
4. Be specific for the best results
|
||||
|
||||
Action Required (was prompted):
|
||||
|
||||
? confirming_tool Confirming tool description
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`AlternateBufferQuittingDisplay > renders with user and gemini messages > with_user_gemini_messages 1`] = `
|
||||
"
|
||||
▝▜▄ ▗█▀▀▜▙▝█▛▀▀▌▜██▖▟██▘▜█▘▜██▖▝█▛▝█▛
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="88" viewBox="0 0 920 88">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="88" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="0" y="2" fill="#333333" textLength="720" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────────╮</text>
|
||||
<text x="0" y="19" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="19" fill="#4796e4" textLength="9" lengthAdjust="spacingAndGlyphs">L</text>
|
||||
<text x="27" y="19" fill="#6688d9" textLength="9" lengthAdjust="spacingAndGlyphs">i</text>
|
||||
<text x="36" y="19" fill="#847ace" textLength="9" lengthAdjust="spacingAndGlyphs">n</text>
|
||||
<text x="45" y="19" fill="#9974b4" textLength="9" lengthAdjust="spacingAndGlyphs">e</text>
|
||||
<text x="63" y="19" fill="#c3677f" textLength="9" lengthAdjust="spacingAndGlyphs">1</text>
|
||||
<text x="711" y="19" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="36" fill="#ffffff" textLength="54" lengthAdjust="spacingAndGlyphs">Line 2</text>
|
||||
<text x="711" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="53" fill="#333333" textLength="720" lengthAdjust="spacingAndGlyphs">╰──────────────────────────────────────────────────────────────────────────────╯</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -7,6 +7,13 @@ exports[`Banner > handles newlines in text 1`] = `
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
exports[`Banner > handles newlines in text 2`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Line 1 │
|
||||
│ Line 2 │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
exports[`Banner > renders in info mode 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Info Message │
|
||||
|
||||
@@ -11,6 +11,17 @@ exports[`<Checklist /> > renders expanded view correctly 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<Checklist /> > renders expanded view correctly 2`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Test List 1/3 completed (toggle me)
|
||||
|
||||
✓ Task 1
|
||||
» Task 2
|
||||
☐ Task 3
|
||||
✗ Task 4
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<Checklist /> > renders summary view correctly (collapsed) 1`] = `
|
||||
"────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Test List 1/3 completed (toggle me) » Task 2
|
||||
|
||||
@@ -5,6 +5,11 @@ exports[`<ContextSummaryDisplay /> > should not render empty parts 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ContextSummaryDisplay /> > should not render empty parts 2`] = `
|
||||
" 1 open file (F4 to view)
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ContextSummaryDisplay /> > should render on a single line on a wide screen 1`] = `
|
||||
" 1 open file (F4 to view) · 1 GEMINI.md file · 1 MCP server · 1 skill
|
||||
"
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`LoopDetectionConfirmation > contains the expected options 1`] = `
|
||||
" ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ? A potential loop was detected │
|
||||
│ │
|
||||
│ This can happen due to repetitive tool calls or other model behavior. Do you want to keep loop │
|
||||
│ detection enabled or disable it for this session? │
|
||||
│ │
|
||||
│ ● 1. Keep loop detection enabled (esc) │
|
||||
│ 2. Disable loop detection for this session │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`LoopDetectionConfirmation > renders correctly 1`] = `
|
||||
" ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ? A potential loop was detected │
|
||||
|
||||
@@ -215,3 +215,26 @@ exports[`<ModelStatsDisplay /> > should render "no API calls" message when there
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ModelStatsDisplay /> > should resolve gemini-3-flash to gemini-3.5-flash via getDisplayString 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ Model Stats For Nerds │
|
||||
│ │
|
||||
│ │
|
||||
│ Metric gemini-3.5-flash │
|
||||
│ ────────────────────────────────────────────────────────────────────────────────────────────── │
|
||||
│ API │
|
||||
│ Requests 1 │
|
||||
│ Errors 0 (0.0%) │
|
||||
│ Avg Latency 100ms │
|
||||
│ Tokens │
|
||||
│ Total 30 │
|
||||
│ ↳ Input 5 │
|
||||
│ ↳ Cache Reads 5 (50.0%) │
|
||||
│ ↳ Thoughts 2 │
|
||||
│ ↳ Tool 1 │
|
||||
│ ↳ Output 20 │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -16,6 +16,22 @@ exports[`ShortcutsHelp > renders correctly in 'narrow' mode on 'linux' 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ShortcutsHelp > renders correctly in 'narrow' mode on 'linux' 2`] = `
|
||||
"────────────────────────────────────────
|
||||
Shortcuts See /help for more
|
||||
! shell mode
|
||||
@ select file or folder
|
||||
Double Esc clear & rewind
|
||||
Tab focus UI
|
||||
Ctrl+Y YOLO mode
|
||||
Shift+Tab cycle mode
|
||||
Ctrl+V paste images
|
||||
Alt+M raw markdown mode
|
||||
Ctrl+R reverse-search history
|
||||
Ctrl+G open external editor
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ShortcutsHelp > renders correctly in 'narrow' mode on 'mac' 1`] = `
|
||||
"────────────────────────────────────────
|
||||
Shortcuts See /help for more
|
||||
|
||||
@@ -292,3 +292,30 @@ exports[`<StatsDisplay /> > renders role breakdown correctly under models 1`] =
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<StatsDisplay /> > resolves gemini-3-flash to gemini-3.5-flash in the model usage table 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ Session Stats │
|
||||
│ │
|
||||
│ Interaction Summary │
|
||||
│ Session ID: test-session-id │
|
||||
│ Tool Calls: 0 ( ✓ 0 x 0 ) │
|
||||
│ Success Rate: 0.0% │
|
||||
│ │
|
||||
│ Performance │
|
||||
│ Wall Time: 1s │
|
||||
│ Agent Active: 3.0s │
|
||||
│ » API Time: 3.0s (100.0%) │
|
||||
│ » Tool Time: 0s (0.0%) │
|
||||
│ │
|
||||
│ │
|
||||
│ Model Usage │
|
||||
│ Use /model to view model quota information │
|
||||
│ │
|
||||
│ Model Reqs Input Tokens Cache Reads Output Tokens │
|
||||
│ ────────────────────────────────────────────────────────────────────────────────────────────── │
|
||||
│ gemini-3.5-flash 5 2,000 500 3,000 │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -25,6 +25,31 @@ exports[`Initial Theme Selection > should default to a dark theme when terminal
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Initial Theme Selection > should default to a dark theme when terminal background is dark and no theme is set 2`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ > Select Theme Preview │
|
||||
│ ▲ ┌─────────────────────────────────────────────────┐ │
|
||||
│ 1. ANSI Dark │ │ │
|
||||
│ 2. Atom One Dark │ 1 # function │ │
|
||||
│ 3. Ayu Dark │ 2 def fibonacci(n): │ │
|
||||
│ ● 4. Default Dark (Matches terminal) │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Dracula Dark │ 4 for _ in range(n): │ │
|
||||
│ 6. GitHub Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. GitHub Dark Colorblind Dark │ 6 return a │ │
|
||||
│ 8. Holiday Dark │ │ │
|
||||
│ 9. Shades Of Purple Dark │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Solarized Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Tokyo Night Dark │ │ │
|
||||
│ 12. ANSI Light (Incompatible) └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Initial Theme Selection > should default to a light theme when terminal background is light and no theme is set 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
@@ -89,6 +114,20 @@ exports[`ThemeDialog Snapshots > should render correctly in scope selector mode
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ThemeDialog Snapshots > should render correctly in scope selector mode 2`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ > Apply To │
|
||||
│ ● 1. User Settings │
|
||||
│ 2. Workspace Settings │
|
||||
│ 3. System Settings │
|
||||
│ │
|
||||
│ (Use Enter to apply scope, Tab to select theme, Esc to close) │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ThemeDialog Snapshots > should render correctly in theme selection mode (isDevelopment: false) 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
|
||||
@@ -18,3 +18,12 @@ Tips for getting started:
|
||||
3. Be specific for the best results
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Tips > 'renders fewer tips when GEMINI.md exi…' 2`] = `
|
||||
"
|
||||
Tips for getting started:
|
||||
1. /help for more information
|
||||
2. Ask coding questions, edit code or run commands
|
||||
3. Be specific for the best results
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -41,6 +41,27 @@ exports[`<ToolStatsDisplay /> > should display stats for multiple tools correctl
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ToolStatsDisplay /> > should display stats for multiple tools correctly 2`] = `
|
||||
"╭────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ Tool Stats For Nerds │
|
||||
│ │
|
||||
│ Tool Name Calls Success Rate Avg Duration │
|
||||
│ ──────────────────────────────────────────────────────────────── │
|
||||
│ tool-a 2 50.0% 100ms │
|
||||
│ tool-b 1 100.0% 100ms │
|
||||
│ │
|
||||
│ User Decision Summary │
|
||||
│ Total Reviewed Suggestions: 3 │
|
||||
│ » Accepted: 1 │
|
||||
│ » Rejected: 1 │
|
||||
│ » Modified: 1 │
|
||||
│ ──────────────────────────────────────────────────────────────── │
|
||||
│ Overall Agreement Rate: 33.3% │
|
||||
╰────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ToolStatsDisplay /> > should handle large values without wrapping or overlapping 1`] = `
|
||||
"╭────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
|
||||
@@ -6,6 +6,12 @@ exports[`ErrorMessage > renders multiline error messages 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ErrorMessage > renders multiline error messages 2`] = `
|
||||
"✕ Error line 1
|
||||
Error line 2
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ErrorMessage > renders with the correct prefix and text 1`] = `
|
||||
"✕ Something went wrong
|
||||
"
|
||||
|
||||
@@ -16,6 +16,13 @@ exports[`<GeminiMessage /> - Raw Markdown Display Snapshots > renders pending st
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<GeminiMessage /> - Raw Markdown Display Snapshots > renders pending state with renderMarkdown=true 2`] = `
|
||||
"✦ Test bold and code markdown
|
||||
|
||||
1 const x = 1;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<GeminiMessage /> - Raw Markdown Display Snapshots > renders with renderMarkdown=false '(raw markdown with syntax highlightin…' 1`] = `
|
||||
"✦ Test **bold** and \`code\` markdown
|
||||
|
||||
@@ -40,3 +47,12 @@ exports[`<GeminiMessage /> - Raw Markdown Display Snapshots > wraps long lines c
|
||||
truncation
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<GeminiMessage /> - Raw Markdown Display Snapshots > wraps long lines correctly in raw markdown mode 2`] = `
|
||||
"✦ This is a long
|
||||
line that should
|
||||
wrap correctly
|
||||
without
|
||||
truncation
|
||||
"
|
||||
`;
|
||||
|
||||
+6
@@ -26,6 +26,12 @@ exports[`ToolGroupMessage Compact Rendering > does not add an extra empty line i
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ToolGroupMessage Compact Rendering > does not add an extra empty line if a compact tool has a dense payload 2`] = `
|
||||
" ✓ ReadFolder Listing files → file1.txt
|
||||
✓ ReadFile Reading file → read file
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ToolGroupMessage Compact Rendering > renders consecutive compact tools without empty lines between them 1`] = `
|
||||
" ✓ ReadFolder Listing files → file1.txt file2.txt
|
||||
✓ ReadFolder Listing files → file3.txt
|
||||
|
||||
+8
@@ -16,6 +16,14 @@ exports[`<ToolMessage /> - Raw Markdown Display Snapshots > renders with renderM
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ToolMessage /> - Raw Markdown Display Snapshots > renders with renderMarkdown=false, useAlternateBuffer=true '(raw markdown, alternate buffer)' 2`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ test-tool A tool for testing │
|
||||
│ │
|
||||
│ Test **bold** and \`code\` markdown │
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ToolMessage /> - Raw Markdown Display Snapshots > renders with renderMarkdown=true, useAlternateBuffer=false '(constrained height, regular buffer -…' 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ test-tool A tool for testing │
|
||||
|
||||
@@ -8,6 +8,14 @@ exports[`UserMessage > renders multiline user message 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`UserMessage > renders multiline user message 2`] = `
|
||||
"▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
||||
> Line 1
|
||||
Line 2
|
||||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`UserMessage > renders normal user message with correct prefix 1`] = `
|
||||
"▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
||||
> Hello Gemini
|
||||
|
||||
@@ -7,6 +7,13 @@ exports[`WarningMessage > renders multiline warning messages 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`WarningMessage > renders multiline warning messages 2`] = `
|
||||
"
|
||||
⚠ Warning line 1
|
||||
Warning line 2
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`WarningMessage > renders with the correct prefix and text 1`] = `
|
||||
"
|
||||
⚠ Watch out!
|
||||
|
||||
@@ -9,6 +9,15 @@ Note: Newest last, oldest first
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ChatList /> > handles invalid date formats gracefully 2`] = `
|
||||
"List of saved conversations:
|
||||
|
||||
- bad-date-chat (Invalid Date)
|
||||
|
||||
Note: Newest last, oldest first
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ChatList /> > renders correctly with a list of chats 1`] = `
|
||||
"List of saved conversations:
|
||||
|
||||
|
||||
@@ -30,6 +30,20 @@ BackgroundTaskDisplay
|
||||
|
||||
|
||||
|
||||
Notifications
|
||||
CopyModeWarning
|
||||
Composer
|
||||
ExitWarning
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<DefaultAppLayout /> > shows BackgroundTaskDisplay when StreamingState is NOT WaitingForConfirmation 2`] = `
|
||||
"MainContent
|
||||
BackgroundTaskDisplay
|
||||
|
||||
|
||||
|
||||
|
||||
Notifications
|
||||
CopyModeWarning
|
||||
Composer
|
||||
|
||||
Reference in New Issue
Block a user