mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-18 15:52:53 -07:00
fix(cli): fix tests and remove unused imports in non-interactive agent session
This commit is contained in:
@@ -686,7 +686,7 @@ describe('runNonInteractive', () => {
|
||||
input: 'Trigger loop',
|
||||
prompt_id: 'prompt-id-6',
|
||||
}),
|
||||
).rejects.toThrow('process.exit(53) called');
|
||||
).rejects.toThrow('Reached max session turns for this session');
|
||||
});
|
||||
|
||||
it('should preprocess @include commands before sending to the model', async () => {
|
||||
@@ -1194,14 +1194,7 @@ describe('runNonInteractive', () => {
|
||||
() => process.stdin,
|
||||
);
|
||||
|
||||
// Spy on handleCancellationError to verify it's called
|
||||
const errors = await import('./utils/errors.js');
|
||||
const cancellationSentinel = new Error('Cancelled');
|
||||
const handleCancellationErrorSpy = vi
|
||||
.spyOn(errors, 'handleCancellationError')
|
||||
.mockImplementation(() => {
|
||||
throw cancellationSentinel;
|
||||
});
|
||||
// Cancellation will throw FatalCancellationError directly
|
||||
|
||||
const events: ServerGeminiStreamEvent[] = [
|
||||
{ type: GeminiEventType.Content, value: 'Thinking...' },
|
||||
@@ -1249,10 +1242,7 @@ describe('runNonInteractive', () => {
|
||||
keypressHandler('\u0003', { ctrl: true, name: 'c' });
|
||||
}
|
||||
|
||||
// The Ctrl+C path should route through handleCancellationError rather than
|
||||
// surfacing the raw stream abort.
|
||||
await expect(runPromise).rejects.toBe(cancellationSentinel);
|
||||
expect(handleCancellationErrorSpy).toHaveBeenCalledTimes(1);
|
||||
await expect(runPromise).rejects.toThrow('Operation cancelled.');
|
||||
|
||||
expect(
|
||||
processStderrSpy.mock.calls.some(
|
||||
@@ -1261,8 +1251,6 @@ describe('runNonInteractive', () => {
|
||||
),
|
||||
).toBe(true);
|
||||
|
||||
handleCancellationErrorSpy.mockRestore();
|
||||
|
||||
// Restore original values
|
||||
Object.defineProperty(process.stdin, 'isTTY', {
|
||||
value: originalIsTTY,
|
||||
@@ -1311,13 +1299,7 @@ describe('runNonInteractive', () => {
|
||||
() => process.stdin,
|
||||
);
|
||||
|
||||
const errors = await import('./utils/errors.js');
|
||||
const cancellationSentinel = new Error('Cancelled before send');
|
||||
const handleCancellationErrorSpy = vi
|
||||
.spyOn(errors, 'handleCancellationError')
|
||||
.mockImplementation(() => {
|
||||
throw cancellationSentinel;
|
||||
});
|
||||
// Cancellation will throw FatalCancellationError directly
|
||||
|
||||
const { LegacyAgentSession } = await import('@google/gemini-cli-core');
|
||||
const sendSpy = vi.spyOn(LegacyAgentSession.prototype, 'send');
|
||||
@@ -1329,13 +1311,10 @@ describe('runNonInteractive', () => {
|
||||
input: 'Cancelled query',
|
||||
prompt_id: 'prompt-id-pre-send-cancel',
|
||||
}),
|
||||
).rejects.toBe(cancellationSentinel);
|
||||
).rejects.toThrow('Operation cancelled.');
|
||||
|
||||
expect(handleCancellationErrorSpy).toHaveBeenCalledTimes(1);
|
||||
expect(sendSpy).not.toHaveBeenCalled();
|
||||
expect(stdinOnSpy).toHaveBeenCalled();
|
||||
|
||||
handleCancellationErrorSpy.mockRestore();
|
||||
sendSpy.mockRestore();
|
||||
|
||||
Object.defineProperty(process.stdin, 'isTTY', {
|
||||
|
||||
@@ -46,12 +46,7 @@ import stripAnsi from 'strip-ansi';
|
||||
import { handleSlashCommand } from './nonInteractiveCliCommands.js';
|
||||
import { ConsolePatcher } from './ui/utils/ConsolePatcher.js';
|
||||
import { handleAtCommand } from './ui/hooks/atCommandProcessor.js';
|
||||
import {
|
||||
handleError,
|
||||
handleToolError,
|
||||
handleCancellationError,
|
||||
handleMaxTurnsExceededError,
|
||||
} from './utils/errors.js';
|
||||
import { handleError, handleToolError } from './utils/errors.js';
|
||||
import { TextOutput } from './ui/utils/textOutput.js';
|
||||
|
||||
interface RunNonInteractiveParams {
|
||||
@@ -188,7 +183,6 @@ export async function runNonInteractive({
|
||||
};
|
||||
|
||||
let errorToHandle: unknown | undefined;
|
||||
let terminalProcessExitHandled = false;
|
||||
let abortSession = () => {};
|
||||
try {
|
||||
consolePatcher.patch();
|
||||
@@ -213,6 +207,8 @@ export async function runNonInteractive({
|
||||
process.stdout.on('error', (err: NodeJS.ErrnoException) => {
|
||||
if (err.code === 'EPIPE') {
|
||||
// Exit gracefully if the pipe is closed.
|
||||
cleanupStdinCancellation();
|
||||
consolePatcher.cleanup();
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
@@ -303,7 +299,7 @@ export async function runNonInteractive({
|
||||
};
|
||||
abortController.signal.addEventListener('abort', abortSession);
|
||||
if (abortController.signal.aborted) {
|
||||
return handleCancellationError(config);
|
||||
throw new FatalCancellationError('Operation cancelled.');
|
||||
}
|
||||
|
||||
// Start the agentic loop (runs in background)
|
||||
@@ -417,11 +413,6 @@ export async function runNonInteractive({
|
||||
return errToThrow;
|
||||
};
|
||||
|
||||
const runTerminalExitHandler = (handler: () => never): never => {
|
||||
terminalProcessExitHandled = true;
|
||||
return handler();
|
||||
};
|
||||
|
||||
// Consume AgentEvents for output formatting
|
||||
let responseText = '';
|
||||
let preToolResponseText: string | undefined;
|
||||
@@ -515,17 +506,12 @@ export async function runNonInteractive({
|
||||
}
|
||||
|
||||
if (event.data?.['errorType'] === ToolErrorType.NO_SPACE_LEFT) {
|
||||
terminalProcessExitHandled = true;
|
||||
handleToolError(
|
||||
event.name,
|
||||
new Error(errorMsg),
|
||||
config,
|
||||
typeof event.data?.['errorType'] === 'string'
|
||||
? event.data['errorType']
|
||||
: undefined,
|
||||
displayText,
|
||||
throw new FatalToolExecutionError(
|
||||
'Error executing tool ' +
|
||||
event.name +
|
||||
': ' +
|
||||
(displayText || errorMsg),
|
||||
);
|
||||
return;
|
||||
}
|
||||
handleToolError(
|
||||
event.name,
|
||||
@@ -570,15 +556,15 @@ export async function runNonInteractive({
|
||||
}
|
||||
case 'agent_end': {
|
||||
if (event.reason === 'aborted') {
|
||||
runTerminalExitHandler(() => handleCancellationError(config));
|
||||
throw new FatalCancellationError('Operation cancelled.');
|
||||
} else if (event.reason === 'max_turns') {
|
||||
const isConfiguredTurnLimit =
|
||||
typeof event.data?.['maxTurns'] === 'number' ||
|
||||
typeof event.data?.['turnCount'] === 'number';
|
||||
|
||||
if (isConfiguredTurnLimit) {
|
||||
runTerminalExitHandler(() =>
|
||||
handleMaxTurnsExceededError(config),
|
||||
throw new FatalTurnLimitedError(
|
||||
'Reached max session turns for this session. Increase the number of turns by specifying maxSessionTurns in settings.json.',
|
||||
);
|
||||
} else if (streamFormatter) {
|
||||
streamFormatter.emitEvent({
|
||||
@@ -629,9 +615,6 @@ export async function runNonInteractive({
|
||||
}
|
||||
|
||||
if (errorToHandle) {
|
||||
if (terminalProcessExitHandled) {
|
||||
throw errorToHandle;
|
||||
}
|
||||
handleError(errorToHandle, config);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user