fix(core): preserve first-turn display content

This commit is contained in:
Adam Weidman
2026-03-26 11:04:51 -04:00
committed by Adam Weidman
parent 1088e1febf
commit bb459defe9
11 changed files with 227 additions and 120 deletions
+37 -11
View File
@@ -265,6 +265,9 @@ describe('runNonInteractive', () => {
[{ text: 'Test input' }],
expect.any(AbortSignal),
'prompt-id-1',
undefined,
false,
'Test input',
);
expect(getWrittenOutput()).toBe('Hello World\n');
// Note: Telemetry shutdown is now handled in runExitCleanup() in cleanup.ts
@@ -429,6 +432,9 @@ describe('runNonInteractive', () => {
[{ text: 'Tool response' }],
expect.any(AbortSignal),
'prompt-id-2',
undefined,
false,
undefined,
);
expect(getWrittenOutput()).toBe('Final answer\n');
});
@@ -586,6 +592,9 @@ describe('runNonInteractive', () => {
],
expect.any(AbortSignal),
'prompt-id-3',
undefined,
false,
undefined,
);
expect(getWrittenOutput()).toBe('Sorry, let me try again.\n');
});
@@ -725,6 +734,9 @@ describe('runNonInteractive', () => {
processedParts,
expect.any(AbortSignal),
'prompt-id-7',
undefined,
false,
rawInput,
);
// 6. Assert the final output is correct
@@ -758,6 +770,9 @@ describe('runNonInteractive', () => {
[{ text: 'Test input' }],
expect.any(AbortSignal),
'prompt-id-1',
undefined,
false,
'Test input',
);
expect(processStdoutSpy).toHaveBeenCalledWith(
JSON.stringify(
@@ -961,6 +976,9 @@ describe('runNonInteractive', () => {
[{ text: 'Empty response test' }],
expect.any(AbortSignal),
'prompt-id-empty',
undefined,
false,
'Empty response test',
);
// This should output JSON with empty response but include stats
@@ -1095,6 +1113,9 @@ describe('runNonInteractive', () => {
[{ text: 'Prompt from command' }],
expect.any(AbortSignal),
'prompt-id-slash',
undefined,
false,
'/testcommand',
);
expect(getWrittenOutput()).toBe('Response from command\n');
@@ -1138,6 +1159,9 @@ describe('runNonInteractive', () => {
[{ text: 'Slash command output' }],
expect.any(AbortSignal),
'prompt-id-slash',
undefined,
false,
'/help',
);
expect(getWrittenOutput()).toBe('Response to slash command\n');
handleSlashCommandSpy.mockRestore();
@@ -1268,17 +1292,16 @@ describe('runNonInteractive', () => {
(process.stdin as any).setRawMode = vi.fn();
}
const stdinOnSpy = vi.spyOn(process.stdin, 'on').mockImplementation(
(
event: string | symbol,
listener: (...args: unknown[]) => void,
) => {
if (event === 'keypress') {
listener('\u0003', { ctrl: true, name: 'c' });
}
return process.stdin;
},
);
const stdinOnSpy = vi
.spyOn(process.stdin, 'on')
.mockImplementation(
(event: string | symbol, listener: (...args: unknown[]) => void) => {
if (event === 'keypress') {
listener('\u0003', { ctrl: true, name: 'c' });
}
return process.stdin;
},
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
vi.spyOn(process.stdin as any, 'setRawMode').mockImplementation(() => true);
vi.spyOn(process.stdin, 'resume').mockImplementation(() => process.stdin);
@@ -1377,6 +1400,9 @@ describe('runNonInteractive', () => {
[{ text: '/unknowncommand' }],
expect.any(AbortSignal),
'prompt-id-unknown',
undefined,
false,
'/unknowncommand',
);
expect(getWrittenOutput()).toBe('Response to unknown\n');
+17 -13
View File
@@ -301,7 +301,10 @@ export async function runNonInteractive({
// Start the agentic loop (runs in background)
const { streamId } = await session.send({
message: geminiPartsToContentParts(query),
message: {
content: geminiPartsToContentParts(query),
displayContent: input,
},
});
if (streamId === null) {
throw new Error(
@@ -465,18 +468,17 @@ export async function runNonInteractive({
}
if (event.data?.['errorType'] === ToolErrorType.NO_SPACE_LEFT) {
runTerminalExitHandler(() =>
handleToolError(
event.name,
new Error(errorMsg),
config,
typeof event.data?.['errorType'] === 'string'
? event.data['errorType']
: undefined,
displayText,
),
terminalProcessExitHandled = true;
handleToolError(
event.name,
new Error(errorMsg),
config,
typeof event.data?.['errorType'] === 'string'
? event.data['errorType']
: undefined,
displayText,
);
break;
return;
}
handleToolError(
event.name,
@@ -528,7 +530,9 @@ export async function runNonInteractive({
typeof event.data?.['turnCount'] === 'number';
if (isConfiguredTurnLimit) {
runTerminalExitHandler(() => handleMaxTurnsExceededError(config));
runTerminalExitHandler(() =>
handleMaxTurnsExceededError(config),
);
} else if (streamFormatter) {
streamFormatter.emitEvent({
type: JsonStreamEventType.ERROR,
+1
View File
@@ -18,6 +18,7 @@ import {
isFatalToolError,
debugLogger,
coreEvents,
getErrorType,
getErrorMessage,
getErrorType,
} from '@google/gemini-cli-core';