mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 22:21:22 -07:00
Opt-in to persist model from /model (#15820)
This commit is contained in:
@@ -47,7 +47,7 @@ describe('<ModelDialog />', () => {
|
||||
const mockGetHasAccessToPreviewModel = vi.fn();
|
||||
|
||||
interface MockConfig extends Partial<Config> {
|
||||
setModel: (model: string) => void;
|
||||
setModel: (model: string, isTemporary?: boolean) => void;
|
||||
getModel: () => string;
|
||||
getPreviewFeatures: () => boolean;
|
||||
getHasAccessToPreviewModel: () => boolean;
|
||||
@@ -89,9 +89,7 @@ describe('<ModelDialog />', () => {
|
||||
it('renders the initial "main" view correctly', () => {
|
||||
const { lastFrame } = renderComponent();
|
||||
expect(lastFrame()).toContain('Select Model');
|
||||
expect(lastFrame()).toContain(
|
||||
'Applies to this session and future Gemini CLI sessions.',
|
||||
);
|
||||
expect(lastFrame()).toContain('Remember model for future sessions: false');
|
||||
expect(lastFrame()).toContain('Auto');
|
||||
expect(lastFrame()).toContain('Manual');
|
||||
});
|
||||
@@ -148,7 +146,10 @@ describe('<ModelDialog />', () => {
|
||||
stdin.write('\r');
|
||||
await waitForUpdate();
|
||||
|
||||
expect(mockSetModel).toHaveBeenCalledWith(DEFAULT_GEMINI_MODEL_AUTO);
|
||||
expect(mockSetModel).toHaveBeenCalledWith(
|
||||
DEFAULT_GEMINI_MODEL_AUTO,
|
||||
true, // Session only by default
|
||||
);
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -165,7 +166,29 @@ describe('<ModelDialog />', () => {
|
||||
stdin.write('\r');
|
||||
await waitForUpdate();
|
||||
|
||||
expect(mockSetModel).toHaveBeenCalledWith(DEFAULT_GEMINI_MODEL);
|
||||
expect(mockSetModel).toHaveBeenCalledWith(DEFAULT_GEMINI_MODEL, true);
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('toggles persist mode with Tab key', async () => {
|
||||
const { lastFrame, stdin } = renderComponent();
|
||||
|
||||
expect(lastFrame()).toContain('Remember model for future sessions: false');
|
||||
|
||||
// Press Tab to toggle persist mode
|
||||
stdin.write('\t');
|
||||
await waitForUpdate();
|
||||
|
||||
expect(lastFrame()).toContain('Remember model for future sessions: true');
|
||||
|
||||
// Select "Auto" (index 0)
|
||||
stdin.write('\r');
|
||||
await waitForUpdate();
|
||||
|
||||
expect(mockSetModel).toHaveBeenCalledWith(
|
||||
DEFAULT_GEMINI_MODEL_AUTO,
|
||||
false, // Persist enabled
|
||||
);
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ interface ModelDialogProps {
|
||||
export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
const config = useContext(ConfigContext);
|
||||
const [view, setView] = useState<'main' | 'manual'>('main');
|
||||
const [persistMode, setPersistMode] = useState(false);
|
||||
|
||||
// Determine the Preferred Model (read once when the dialog opens).
|
||||
const preferredModel = config?.getModel() || DEFAULT_GEMINI_MODEL_AUTO;
|
||||
@@ -62,6 +63,9 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
if (key.name === 'tab') {
|
||||
setPersistMode((prev) => !prev);
|
||||
}
|
||||
},
|
||||
{ isActive: true },
|
||||
);
|
||||
@@ -157,13 +161,13 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
}
|
||||
|
||||
if (config) {
|
||||
config.setModel(model);
|
||||
config.setModel(model, persistMode ? false : true);
|
||||
const event = new ModelSlashCommandEvent(model);
|
||||
logModelSlashCommand(config, event);
|
||||
}
|
||||
onClose();
|
||||
},
|
||||
[config, onClose],
|
||||
[config, onClose, persistMode],
|
||||
);
|
||||
|
||||
let header;
|
||||
@@ -213,9 +217,15 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element {
|
||||
/>
|
||||
</Box>
|
||||
<Box marginTop={1} flexDirection="column">
|
||||
<Text color={theme.text.secondary}>
|
||||
Applies to this session and future Gemini CLI sessions.
|
||||
</Text>
|
||||
<Box>
|
||||
<Text color={theme.text.primary}>
|
||||
Remember model for future sessions:{' '}
|
||||
</Text>
|
||||
<Text color={theme.text.secondary}>
|
||||
{persistMode ? 'true' : 'false'}
|
||||
</Text>
|
||||
</Box>
|
||||
<Text color={theme.text.secondary}>(Press Tab to toggle)</Text>
|
||||
</Box>
|
||||
<Box marginTop={1} flexDirection="column">
|
||||
<Text color={theme.text.secondary}>
|
||||
|
||||
@@ -1630,19 +1630,19 @@ describe('Config getHooks', () => {
|
||||
expect(config.getActiveModel()).toBe(originalModel);
|
||||
});
|
||||
|
||||
it('should call onModelChange when a new model is set', () => {
|
||||
it('should call onModelChange when a new model is set and should persist', () => {
|
||||
const onModelChange = vi.fn();
|
||||
const config = new Config({
|
||||
...baseParams,
|
||||
onModelChange,
|
||||
});
|
||||
|
||||
config.setModel(DEFAULT_GEMINI_MODEL);
|
||||
config.setModel(DEFAULT_GEMINI_MODEL, false);
|
||||
|
||||
expect(onModelChange).toHaveBeenCalledWith(DEFAULT_GEMINI_MODEL);
|
||||
});
|
||||
|
||||
it('should NOT call onModelChange when a new model is set as a fallback', () => {
|
||||
it('should NOT call onModelChange when a new model is temporary', () => {
|
||||
const onModelChange = vi.fn();
|
||||
const config = new Config({
|
||||
...baseParams,
|
||||
|
||||
@@ -909,13 +909,13 @@ export class Config {
|
||||
return this.model;
|
||||
}
|
||||
|
||||
setModel(newModel: string, isFallbackModel: boolean = false): void {
|
||||
setModel(newModel: string, isTemporary: boolean = true): void {
|
||||
if (this.model !== newModel || this._activeModel !== newModel) {
|
||||
this.model = newModel;
|
||||
// When the user explicitly sets a model, that becomes the active model.
|
||||
this._activeModel = newModel;
|
||||
coreEvents.emitModelChanged(newModel);
|
||||
if (this.onModelChange && !isFallbackModel) {
|
||||
if (this.onModelChange && !isTemporary) {
|
||||
this.onModelChange(newModel);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user