mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
fix(cli): prevent race condition when restoring prompt after context overflow (#13473)
This commit is contained in:
@@ -1834,5 +1834,62 @@ describe('AppContainer State Management', () => {
|
|||||||
|
|
||||||
unmount();
|
unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('correctly restores prompt even if userMessages is stale (race condition fix)', async () => {
|
||||||
|
// Setup initial history with one message
|
||||||
|
const initialHistory = [{ type: 'user', text: 'Previous Prompt' }];
|
||||||
|
mockedUseHistory.mockReturnValue({
|
||||||
|
history: initialHistory,
|
||||||
|
addItem: vi.fn(),
|
||||||
|
updateItem: vi.fn(),
|
||||||
|
clearItems: vi.fn(),
|
||||||
|
loadHistory: vi.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mock logger to resolve so userMessages gets populated
|
||||||
|
mockedUseLogger.mockReturnValue({
|
||||||
|
getPreviousUserMessages: vi.fn().mockResolvedValue([]),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { unmount, rerender } = renderAppContainer();
|
||||||
|
|
||||||
|
// Wait for userMessages to be populated with 'Previous Prompt'
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(capturedUIState.userMessages).toContain('Previous Prompt'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Simulate a new prompt being added (e.g., user sent it, but it overflowed)
|
||||||
|
const newPrompt = 'Current Prompt that Overflowed';
|
||||||
|
const newHistory = [...initialHistory, { type: 'user', text: newPrompt }];
|
||||||
|
|
||||||
|
mockedUseHistory.mockReturnValue({
|
||||||
|
history: newHistory,
|
||||||
|
addItem: vi.fn(),
|
||||||
|
updateItem: vi.fn(),
|
||||||
|
clearItems: vi.fn(),
|
||||||
|
loadHistory: vi.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rerender to reflect the history change.
|
||||||
|
// This triggers the effect to update userMessages, but it's async.
|
||||||
|
rerender(getAppContainer());
|
||||||
|
|
||||||
|
const { onCancelSubmit } = extractUseGeminiStreamArgs(
|
||||||
|
mockedUseGeminiStream.mock.lastCall!,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Call onCancelSubmit immediately (simulating the race condition where
|
||||||
|
// the overflow event comes in before the effect updates userMessages)
|
||||||
|
act(() => {
|
||||||
|
onCancelSubmit(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// With the fix, it should wait for userMessages to update and then set the new prompt
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(mockSetText).toHaveBeenCalledWith(newPrompt);
|
||||||
|
});
|
||||||
|
|
||||||
|
unmount();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const [copyModeEnabled, setCopyModeEnabled] = useState(false);
|
const [copyModeEnabled, setCopyModeEnabled] = useState(false);
|
||||||
|
const [pendingRestorePrompt, setPendingRestorePrompt] = useState(false);
|
||||||
|
|
||||||
const [shellModeActive, setShellModeActive] = useState(false);
|
const [shellModeActive, setShellModeActive] = useState(false);
|
||||||
const [modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError] =
|
const [modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError] =
|
||||||
@@ -666,9 +667,32 @@ Logging in with Google... Please restart Gemini CLI to continue.
|
|||||||
);
|
);
|
||||||
|
|
||||||
const onCancelSubmit = useCallback((shouldRestorePrompt?: boolean) => {
|
const onCancelSubmit = useCallback((shouldRestorePrompt?: boolean) => {
|
||||||
cancelHandlerRef.current(shouldRestorePrompt);
|
if (shouldRestorePrompt) {
|
||||||
|
setPendingRestorePrompt(true);
|
||||||
|
} else {
|
||||||
|
setPendingRestorePrompt(false);
|
||||||
|
cancelHandlerRef.current(false);
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (pendingRestorePrompt) {
|
||||||
|
const lastHistoryUserMsg = historyManager.history.findLast(
|
||||||
|
(h) => h.type === 'user',
|
||||||
|
);
|
||||||
|
const lastUserMsg = userMessages.at(-1);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!lastHistoryUserMsg ||
|
||||||
|
(typeof lastHistoryUserMsg.text === 'string' &&
|
||||||
|
lastHistoryUserMsg.text === lastUserMsg)
|
||||||
|
) {
|
||||||
|
cancelHandlerRef.current(true);
|
||||||
|
setPendingRestorePrompt(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [pendingRestorePrompt, userMessages, historyManager.history]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
streamingState,
|
streamingState,
|
||||||
submitQuery,
|
submitQuery,
|
||||||
|
|||||||
Reference in New Issue
Block a user