mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-28 22:14:52 -07:00
Checkpoint of shell optimization
fix(cli): Write shell command output to a file and limit memory buffered in UI Fixes. Checkpoint. fix(core, cli): await outputStream.end() to prevent race conditions This commit fixes a critical race condition where was called synchronously without being awaited. This led to potential file truncation or EBUSY errors on Windows when attempting to manipulate the file immediately after the call. Additionally, this change removes fixed wait times (`setTimeout`) that were previously used in test files as a band-aid. fix(core): stream processed xterm output to file to remove spurious escape codes test(core): update shell regression tests to use file_data events
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import fsPromises from 'node:fs/promises';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import type {
|
||||
ToolCallRequestInfo,
|
||||
ToolCallResponseInfo,
|
||||
@@ -23,6 +25,7 @@ import { executeToolWithHooks } from '../core/coreToolHookTriggers.js';
|
||||
import {
|
||||
saveTruncatedToolOutput,
|
||||
formatTruncatedToolOutput,
|
||||
moveToolOutputToFile,
|
||||
} from '../utils/fileUtils.js';
|
||||
import { convertToFunctionResponse } from '../utils/generateContentResponseUtilities.js';
|
||||
import type {
|
||||
@@ -119,6 +122,16 @@ export class ToolExecutor {
|
||||
spanMetadata.output = toolResult;
|
||||
|
||||
if (signal.aborted) {
|
||||
if (toolResult.fullOutputFilePath) {
|
||||
await fsPromises
|
||||
.unlink(toolResult.fullOutputFilePath)
|
||||
.catch((error) => {
|
||||
debugLogger.warn(
|
||||
`Failed to delete temporary tool output file on abort: ${toolResult.fullOutputFilePath}`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
}
|
||||
return this.createCancelledResult(
|
||||
call,
|
||||
'User cancelled tool execution.',
|
||||
@@ -126,6 +139,16 @@ export class ToolExecutor {
|
||||
} else if (toolResult.error === undefined) {
|
||||
return await this.createSuccessResult(call, toolResult);
|
||||
} else {
|
||||
if (toolResult.fullOutputFilePath) {
|
||||
await fsPromises
|
||||
.unlink(toolResult.fullOutputFilePath)
|
||||
.catch((error) => {
|
||||
debugLogger.warn(
|
||||
`Failed to delete temporary tool output file on error: ${toolResult.fullOutputFilePath}`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
}
|
||||
const displayText =
|
||||
typeof toolResult.returnDisplay === 'string'
|
||||
? toolResult.returnDisplay
|
||||
@@ -210,7 +233,34 @@ export class ToolExecutor {
|
||||
const toolName = call.request.originalRequestName || call.request.name;
|
||||
const callId = call.request.callId;
|
||||
|
||||
if (typeof content === 'string' && toolName === SHELL_TOOL_NAME) {
|
||||
if (toolResult.fullOutputFilePath) {
|
||||
const threshold = this.config.getTruncateToolOutputThreshold();
|
||||
if (
|
||||
threshold > 0 &&
|
||||
typeof content === 'string' &&
|
||||
content.length > threshold
|
||||
) {
|
||||
const { outputFile: savedPath } = await moveToolOutputToFile(
|
||||
toolResult.fullOutputFilePath,
|
||||
toolName,
|
||||
callId,
|
||||
this.config.storage.getProjectTempDir(),
|
||||
this.config.getSessionId(),
|
||||
);
|
||||
outputFile = savedPath;
|
||||
content = formatTruncatedToolOutput(content, outputFile, threshold);
|
||||
} else {
|
||||
// If the content is not truncated, we don't need the temporary file.
|
||||
try {
|
||||
await fsPromises.unlink(toolResult.fullOutputFilePath);
|
||||
} catch (error) {
|
||||
debugLogger.warn(
|
||||
`Failed to delete temporary tool output file: ${toolResult.fullOutputFilePath}`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (typeof content === 'string' && toolName === SHELL_TOOL_NAME) {
|
||||
const threshold = this.config.getTruncateToolOutputThreshold();
|
||||
|
||||
if (threshold > 0 && content.length > threshold) {
|
||||
@@ -242,6 +292,7 @@ export class ToolExecutor {
|
||||
callId,
|
||||
content,
|
||||
this.config.getActiveModel(),
|
||||
outputFile,
|
||||
);
|
||||
|
||||
const successResponse: ToolCallResponseInfo = {
|
||||
|
||||
Reference in New Issue
Block a user