mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 22:21:22 -07:00
(fix): appcontainer should not poll and footer should use currentModel from ui state (#11923)
This commit is contained in:
@@ -64,6 +64,7 @@ const baseMockUiState = {
|
||||
streamingState: StreamingState.Idle,
|
||||
mainAreaWidth: 100,
|
||||
terminalWidth: 120,
|
||||
currentModel: 'gemini-pro',
|
||||
};
|
||||
|
||||
export const renderWithProviders = (
|
||||
|
||||
@@ -261,20 +261,18 @@ export const AppContainer = (props: AppContainerProps) => {
|
||||
[historyManager.addItem],
|
||||
);
|
||||
|
||||
// Watch for model changes (e.g., from Flash fallback)
|
||||
// Subscribe to fallback mode changes from core
|
||||
useEffect(() => {
|
||||
const checkModelChange = () => {
|
||||
const handleFallbackModeChanged = () => {
|
||||
const effectiveModel = getEffectiveModel();
|
||||
if (effectiveModel !== currentModel) {
|
||||
setCurrentModel(effectiveModel);
|
||||
}
|
||||
setCurrentModel(effectiveModel);
|
||||
};
|
||||
|
||||
checkModelChange();
|
||||
const interval = setInterval(checkModelChange, 1000); // Check every second
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [config, currentModel, getEffectiveModel]);
|
||||
coreEvents.on(CoreEvent.FallbackModeChanged, handleFallbackModeChanged);
|
||||
return () => {
|
||||
coreEvents.off(CoreEvent.FallbackModeChanged, handleFallbackModeChanged);
|
||||
};
|
||||
}, [getEffectiveModel]);
|
||||
|
||||
const {
|
||||
consoleMessages,
|
||||
|
||||
@@ -256,3 +256,31 @@ describe('<Footer />', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('fallback mode display', () => {
|
||||
it('should display Flash model when in fallback mode, not the configured Pro model', () => {
|
||||
const { lastFrame } = renderWithProviders(<Footer />, {
|
||||
width: 120,
|
||||
uiState: {
|
||||
sessionStats: mockSessionStats,
|
||||
currentModel: 'gemini-2.5-flash', // Fallback active, showing Flash
|
||||
},
|
||||
});
|
||||
|
||||
// Footer should show the effective model (Flash), not the config model (Pro)
|
||||
expect(lastFrame()).toContain('gemini-2.5-flash');
|
||||
expect(lastFrame()).not.toContain('gemini-2.5-pro');
|
||||
});
|
||||
|
||||
it('should display Pro model when NOT in fallback mode', () => {
|
||||
const { lastFrame } = renderWithProviders(<Footer />, {
|
||||
width: 120,
|
||||
uiState: {
|
||||
sessionStats: mockSessionStats,
|
||||
currentModel: 'gemini-2.5-pro', // Normal mode, showing Pro
|
||||
},
|
||||
});
|
||||
|
||||
expect(lastFrame()).toContain('gemini-2.5-pro');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,6 @@ import { MemoryUsageDisplay } from './MemoryUsageDisplay.js';
|
||||
import { ContextUsageDisplay } from './ContextUsageDisplay.js';
|
||||
import { DebugProfiler } from './DebugProfiler.js';
|
||||
import { isDevelopment } from '../../utils/installationInfo.js';
|
||||
|
||||
import { useUIState } from '../contexts/UIStateContext.js';
|
||||
import { useConfig } from '../contexts/ConfigContext.js';
|
||||
import { useSettings } from '../contexts/SettingsContext.js';
|
||||
@@ -41,7 +40,7 @@ export const Footer: React.FC = () => {
|
||||
isTrustedFolder,
|
||||
mainAreaWidth,
|
||||
} = {
|
||||
model: config.getModel(),
|
||||
model: uiState.currentModel,
|
||||
targetDir: config.getTargetDir(),
|
||||
debugMode: config.getDebugMode(),
|
||||
branchName: uiState.branchName,
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { Config } from '../config/config.js';
|
||||
import { AuthType } from '../core/contentGenerator.js';
|
||||
import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js';
|
||||
import { logFlashFallback, FlashFallbackEvent } from '../telemetry/index.js';
|
||||
import { coreEvents } from '../utils/events.js';
|
||||
|
||||
export async function handleFallback(
|
||||
config: Config,
|
||||
@@ -62,6 +63,7 @@ export async function handleFallback(
|
||||
function activateFallbackMode(config: Config, authType: string | undefined) {
|
||||
if (!config.isInFallbackMode()) {
|
||||
config.setFallbackMode(true);
|
||||
coreEvents.emitFallbackModeChanged(true);
|
||||
if (authType) {
|
||||
logFlashFallback(config, new FlashFallbackEvent(authType));
|
||||
}
|
||||
|
||||
@@ -33,8 +33,19 @@ export interface UserFeedbackPayload {
|
||||
error?: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payload for the 'fallback-mode-changed' event.
|
||||
*/
|
||||
export interface FallbackModeChangedPayload {
|
||||
/**
|
||||
* Whether fallback mode is now active.
|
||||
*/
|
||||
isInFallbackMode: boolean;
|
||||
}
|
||||
|
||||
export enum CoreEvent {
|
||||
UserFeedback = 'user-feedback',
|
||||
FallbackModeChanged = 'fallback-mode-changed',
|
||||
}
|
||||
|
||||
export class CoreEventEmitter extends EventEmitter {
|
||||
@@ -66,6 +77,15 @@ export class CoreEventEmitter extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies subscribers that fallback mode has changed.
|
||||
* This is synchronous and doesn't use backlog (UI should already be initialized).
|
||||
*/
|
||||
emitFallbackModeChanged(isInFallbackMode: boolean): void {
|
||||
const payload: FallbackModeChangedPayload = { isInFallbackMode };
|
||||
this.emit(CoreEvent.FallbackModeChanged, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes buffered messages. Call this immediately after primary UI listener
|
||||
* subscribes.
|
||||
@@ -82,6 +102,10 @@ export class CoreEventEmitter extends EventEmitter {
|
||||
event: CoreEvent.UserFeedback,
|
||||
listener: (payload: UserFeedbackPayload) => void,
|
||||
): this;
|
||||
override on(
|
||||
event: CoreEvent.FallbackModeChanged,
|
||||
listener: (payload: FallbackModeChangedPayload) => void,
|
||||
): this;
|
||||
override on(
|
||||
event: string | symbol,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -94,6 +118,10 @@ export class CoreEventEmitter extends EventEmitter {
|
||||
event: CoreEvent.UserFeedback,
|
||||
listener: (payload: UserFeedbackPayload) => void,
|
||||
): this;
|
||||
override off(
|
||||
event: CoreEvent.FallbackModeChanged,
|
||||
listener: (payload: FallbackModeChangedPayload) => void,
|
||||
): this;
|
||||
override off(
|
||||
event: string | symbol,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -106,6 +134,10 @@ export class CoreEventEmitter extends EventEmitter {
|
||||
event: CoreEvent.UserFeedback,
|
||||
payload: UserFeedbackPayload,
|
||||
): boolean;
|
||||
override emit(
|
||||
event: CoreEvent.FallbackModeChanged,
|
||||
payload: FallbackModeChangedPayload,
|
||||
): boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
override emit(event: string | symbol, ...args: any[]): boolean {
|
||||
return super.emit(event, ...args);
|
||||
|
||||
Reference in New Issue
Block a user