fix: Ensure user written `!` is treated opaquely if not in shell mode\n\n- Addresses an issue where commands prefixed with `!` (e.g., `!ls`) were incorrectly handled by the shell command processor if the `!` was added after initially typing the command.\n- Ensures that such commands are correctly forwarded to the Gemini model.\n- Updates `useGeminiStream` to be aware of shell mode to properly manage streaming state.\n\nFixes https://buganizer.corp.google.com/issues/418761305

This commit is contained in:
Taylor Mullen 2025-05-19 16:11:45 -07:00 committed by N. Taylor Mullen
parent a756489f86
commit 323b1298f9
4 changed files with 6 additions and 31 deletions

View File

@ -145,6 +145,7 @@ export const App = ({
config,
setDebugMessage,
handleSlashCommand,
shellModeActive,
);
const { elapsedTime, currentLoadingPhrase } =
useLoadingIndicator(streamingState);
@ -154,16 +155,10 @@ export const App = ({
(submittedValue: string) => {
const trimmedValue = submittedValue.trim();
if (trimmedValue.length > 0) {
if (shellModeActive && !trimmedValue.startsWith('!')) {
// TODO: Don't prefix (hack) and properly submit pass throughs to a dedicated hook:
// https://b.corp.google.com/issues/418509745
submitQuery(`!${trimmedValue}`);
} else {
submitQuery(trimmedValue);
}
submitQuery(trimmedValue);
}
},
[submitQuery, shellModeActive],
[submitQuery],
);
const userMessages = useMemo(

View File

@ -8,7 +8,6 @@ import { exec as _exec } from 'child_process';
import { useCallback } from 'react';
import { Config } from '@gemini-code/server';
import { type PartListUnion } from '@google/genai';
import { getCommandFromQuery } from '../utils/commandUtils.js';
import { UseHistoryManagerReturn } from './useHistoryManager.js';
import crypto from 'crypto';
import path from 'path';
@ -34,10 +33,6 @@ export const useShellCommandProcessor = (
return false;
}
const [symbol] = getCommandFromQuery(rawQuery);
if (symbol !== '!' && symbol !== '$') {
return false;
}
let commandToExecute = rawQuery.trim().slice(1).trimStart();
// wrap command to write pwd to temporary file

View File

@ -60,6 +60,7 @@ export const useGeminiStream = (
config: Config,
onDebugMessage: (message: string) => void,
handleSlashCommand: (cmd: PartListUnion) => boolean,
shellModeActive: boolean,
) => {
const toolRegistry = config.getToolRegistry();
const [initError, setInitError] = useState<string | null>(null);
@ -120,7 +121,7 @@ export const useGeminiStream = (
if (handleSlashCommand(trimmedQuery)) {
return { queryToSend: null, shouldProceed: false };
}
if (handleShellCommand(trimmedQuery)) {
if (shellModeActive && handleShellCommand(trimmedQuery)) {
return { queryToSend: null, shouldProceed: false };
}
@ -608,6 +609,7 @@ export const useGeminiStream = (
isResponding,
setShowHelp,
handleSlashCommand,
shellModeActive,
handleShellCommand,
config,
addItem,

View File

@ -24,20 +24,3 @@ export const isAtCommand = (query: string): boolean =>
* @returns True if the query looks like an '/' command, false otherwise.
*/
export const isSlashCommand = (query: string): boolean => query.startsWith('/');
const control_symbols: string[] = ['/', '@', '!', '?', '$'];
/**
* Returns the first word of query with optional leading slash, ampersand, bang.
*
* @param query The input query string.
* @returns optional leading symbol and first word of query
*/
export const getCommandFromQuery = (
query: string,
): [string | undefined, string] => {
const word = query.trim().split(/\s/, 1)[0];
if (word.length > 0 && control_symbols.includes(word[0])) {
return [word[0], word.slice(1)];
}
return [undefined, word];
};