chore: finish truncation and stream logging logic

This commit is contained in:
Spencer
2026-04-07 22:59:55 +00:00
parent 7cdfaaa6bd
commit 886025f6b9
6 changed files with 139 additions and 52 deletions

View File

@@ -21,6 +21,7 @@ import {
ExecutionLifecycleService,
CoreToolCallStatus,
moveToolOutputToFile,
debugLogger,
} from '@google/gemini-cli-core';
import { type PartListUnion } from '@google/genai';
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
@@ -378,11 +379,6 @@ export const useExecutionLifecycle = (
let cumulativeStdout: string | AnsiOutput = '';
let isBinaryStream = false;
let binaryBytesReceived = 0;
let totalBytesWritten = 0;
const outputFileName = `gemini_shell_output_${crypto.randomBytes(6).toString('hex')}.log`;
const outputFilePath = path.join(os.tmpdir(), outputFileName);
const outputStream = fs.createWriteStream(outputFilePath);
const initialToolDisplay: IndividualToolCallDisplay = {
callId,
@@ -400,7 +396,6 @@ export const useExecutionLifecycle = (
});
let executionPid: number | undefined;
let fullOutputReturned = false;
const abortHandler = () => {
onDebugMessage(
@@ -431,25 +426,13 @@ export const useExecutionLifecycle = (
switch (event.type) {
case 'raw_data':
// We rely on 'file_data' for the clean output stream.
break;
case 'file_data':
if (!isBinaryStream) {
outputStream.write(event.chunk);
totalBytesWritten += Buffer.byteLength(event.chunk);
}
break;
case 'data':
if (isBinaryStream) break;
if (typeof event.chunk === 'string') {
if (typeof cumulativeStdout === 'string') {
cumulativeStdout += event.chunk;
// Keep a small buffer for the UI to prevent memory spikes and Ink lagging
const MAX_UI_LENGTH = 100000; // 100KB
if (cumulativeStdout.length > MAX_UI_LENGTH) {
cumulativeStdout =
cumulativeStdout.slice(-MAX_UI_LENGTH);
}
} else {
cumulativeStdout = event.chunk;
}
@@ -535,9 +518,6 @@ export const useExecutionLifecycle = (
}
const result = await resultPromise;
await new Promise<void>((resolve) => {
outputStream.end(resolve);
});
setPendingHistoryItem(null);
if (result.backgrounded && result.pid) {
@@ -557,10 +537,9 @@ export const useExecutionLifecycle = (
} else {
mainContent =
result.output.trim() || '(Command produced no output)';
const threshold = config.getTruncateToolOutputThreshold();
if (threshold > 0 && totalBytesWritten >= threshold) {
if (result.fullOutputFilePath) {
const { outputFile: savedPath } = await moveToolOutputToFile(
outputFilePath,
result.fullOutputFilePath,
SHELL_COMMAND_NAME,
callId,
config.storage.getProjectTempDir(),
@@ -575,7 +554,6 @@ export const useExecutionLifecycle = (
warning,
)
: `${mainContent}\n\n${warning}`;
fullOutputReturned = true;
}
}
@@ -679,19 +657,17 @@ export const useExecutionLifecycle = (
);
} finally {
abortSignal.removeEventListener('abort', abortHandler);
if (!outputStream.closed) {
outputStream.destroy();
}
if (pwdFilePath) {
fs.promises.unlink(pwdFilePath).catch(() => {});
fs.promises.unlink(pwdFilePath).catch((err) => {
debugLogger.warn(
`Failed to cleanup pwd file: ${pwdFilePath}`,
err,
);
});
}
dispatch({ type: 'SET_ACTIVE_PTY', pid: null });
setShellInputFocused(false);
if (!fullOutputReturned) {
fs.promises.unlink(outputFilePath).catch(() => {});
}
}
};