fix: Restore user input when the user cancels response (#5601)
Co-authored-by: Shi Shu <shii@google.com> Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
parent
6133bea388
commit
1f0ad86544
|
@ -486,6 +486,24 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||||
setGeminiMdFileCount,
|
setGeminiMdFileCount,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const buffer = useTextBuffer({
|
||||||
|
initialText: '',
|
||||||
|
viewport: { height: 10, width: inputWidth },
|
||||||
|
stdin,
|
||||||
|
setRawMode,
|
||||||
|
isValidPath,
|
||||||
|
shellModeActive,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [userMessages, setUserMessages] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const handleUserCancel = useCallback(() => {
|
||||||
|
const lastUserMessage = userMessages.at(-1);
|
||||||
|
if (lastUserMessage) {
|
||||||
|
buffer.setText(lastUserMessage);
|
||||||
|
}
|
||||||
|
}, [buffer, userMessages]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
streamingState,
|
streamingState,
|
||||||
submitQuery,
|
submitQuery,
|
||||||
|
@ -506,6 +524,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||||
modelSwitchedFromQuotaError,
|
modelSwitchedFromQuotaError,
|
||||||
setModelSwitchedFromQuotaError,
|
setModelSwitchedFromQuotaError,
|
||||||
refreshStatic,
|
refreshStatic,
|
||||||
|
handleUserCancel,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Input handling
|
// Input handling
|
||||||
|
@ -519,15 +538,6 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||||
[submitQuery],
|
[submitQuery],
|
||||||
);
|
);
|
||||||
|
|
||||||
const buffer = useTextBuffer({
|
|
||||||
initialText: '',
|
|
||||||
viewport: { height: 10, width: inputWidth },
|
|
||||||
stdin,
|
|
||||||
setRawMode,
|
|
||||||
isValidPath,
|
|
||||||
shellModeActive,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
|
const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
|
||||||
const pendingHistoryItems = [...pendingSlashCommandHistoryItems];
|
const pendingHistoryItems = [...pendingSlashCommandHistoryItems];
|
||||||
pendingHistoryItems.push(...pendingGeminiHistoryItems);
|
pendingHistoryItems.push(...pendingGeminiHistoryItems);
|
||||||
|
@ -607,7 +617,6 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||||
}, [config, config.getGeminiMdFileCount]);
|
}, [config, config.getGeminiMdFileCount]);
|
||||||
|
|
||||||
const logger = useLogger();
|
const logger = useLogger();
|
||||||
const [userMessages, setUserMessages] = useState<string[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchUserMessages = async () => {
|
const fetchUserMessages = async () => {
|
||||||
|
|
|
@ -406,6 +406,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -560,6 +562,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -633,6 +637,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -737,6 +743,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -843,6 +851,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -943,6 +953,44 @@ describe('useGeminiStream', () => {
|
||||||
expect(result.current.streamingState).toBe(StreamingState.Idle);
|
expect(result.current.streamingState).toBe(StreamingState.Idle);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call onCancelSubmit handler when escape is pressed', async () => {
|
||||||
|
const cancelSubmitSpy = vi.fn();
|
||||||
|
const mockStream = (async function* () {
|
||||||
|
yield { type: 'content', value: 'Part 1' };
|
||||||
|
// Keep the stream open
|
||||||
|
await new Promise(() => {});
|
||||||
|
})();
|
||||||
|
mockSendMessageStream.mockReturnValue(mockStream);
|
||||||
|
|
||||||
|
const { result } = renderHook(() =>
|
||||||
|
useGeminiStream(
|
||||||
|
mockConfig.getGeminiClient(),
|
||||||
|
[],
|
||||||
|
mockAddItem,
|
||||||
|
mockConfig,
|
||||||
|
mockOnDebugMessage,
|
||||||
|
mockHandleSlashCommand,
|
||||||
|
false,
|
||||||
|
() => 'vscode' as EditorType,
|
||||||
|
() => {},
|
||||||
|
() => Promise.resolve(),
|
||||||
|
false,
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
|
cancelSubmitSpy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start a query
|
||||||
|
await act(async () => {
|
||||||
|
result.current.submitQuery('test query');
|
||||||
|
});
|
||||||
|
|
||||||
|
simulateEscapeKeyPress();
|
||||||
|
|
||||||
|
expect(cancelSubmitSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('should not do anything if escape is pressed when not responding', () => {
|
it('should not do anything if escape is pressed when not responding', () => {
|
||||||
const { result } = renderTestHook();
|
const { result } = renderTestHook();
|
||||||
|
|
||||||
|
@ -1202,6 +1250,8 @@ describe('useGeminiStream', () => {
|
||||||
mockPerformMemoryRefresh,
|
mockPerformMemoryRefresh,
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1253,6 +1303,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1301,6 +1353,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1347,6 +1401,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1394,6 +1450,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1481,6 +1539,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1535,6 +1595,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1611,6 +1673,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1663,6 +1727,8 @@ describe('useGeminiStream', () => {
|
||||||
() => Promise.resolve(),
|
() => Promise.resolve(),
|
||||||
false,
|
false,
|
||||||
() => {},
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ export const useGeminiStream = (
|
||||||
modelSwitchedFromQuotaError: boolean,
|
modelSwitchedFromQuotaError: boolean,
|
||||||
setModelSwitchedFromQuotaError: React.Dispatch<React.SetStateAction<boolean>>,
|
setModelSwitchedFromQuotaError: React.Dispatch<React.SetStateAction<boolean>>,
|
||||||
onEditorClose: () => void,
|
onEditorClose: () => void,
|
||||||
|
onCancelSubmit: () => void,
|
||||||
) => {
|
) => {
|
||||||
const [initError, setInitError] = useState<string | null>(null);
|
const [initError, setInitError] = useState<string | null>(null);
|
||||||
const abortControllerRef = useRef<AbortController | null>(null);
|
const abortControllerRef = useRef<AbortController | null>(null);
|
||||||
|
@ -200,6 +201,7 @@ export const useGeminiStream = (
|
||||||
Date.now(),
|
Date.now(),
|
||||||
);
|
);
|
||||||
setPendingHistoryItem(null);
|
setPendingHistoryItem(null);
|
||||||
|
onCancelSubmit();
|
||||||
setIsResponding(false);
|
setIsResponding(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue