feat(core): Isolate and cleanup truncated tool outputs (#17594)

This commit is contained in:
Sandy Tao
2026-01-29 15:20:11 -08:00
committed by GitHub
parent fdda3a2399
commit 59e3624ada
7 changed files with 474 additions and 8 deletions
@@ -16,6 +16,7 @@ import type { BaseLlmClient } from '../core/baseLlmClient.js';
import type { GeminiChat } from '../core/geminiChat.js';
import type { Config } from '../config/config.js';
import * as fileUtils from '../utils/fileUtils.js';
import { TOOL_OUTPUT_DIR } from '../utils/fileUtils.js';
import { getInitialChatHistory } from '../utils/environmentContext.js';
import * as tokenCalculation from '../utils/tokenCalculation.js';
import { tokenLimit } from '../core/tokenLimits.js';
@@ -510,8 +511,9 @@ describe('ChatCompressionService', () => {
'Output too large.',
);
// Verify a file was actually created
const files = fs.readdirSync(testTempDir);
// Verify a file was actually created in the tool_output subdirectory
const toolOutputDir = path.join(testTempDir, TOOL_OUTPUT_DIR);
const files = fs.readdirSync(toolOutputDir);
expect(files.length).toBeGreaterThan(0);
expect(files[0]).toMatch(/grep_.*\.txt/);
});
+7 -1
View File
@@ -1076,7 +1076,11 @@ describe('fileUtils', () => {
tempRootDir,
);
const expectedOutputFile = path.join(tempRootDir, 'shell_123.txt');
const expectedOutputFile = path.join(
tempRootDir,
'tool_output',
'shell_123.txt',
);
expect(result.outputFile).toBe(expectedOutputFile);
expect(result.totalLines).toBe(1);
@@ -1102,6 +1106,7 @@ describe('fileUtils', () => {
// ../../dangerous/tool -> ______dangerous_tool
const expectedOutputFile = path.join(
tempRootDir,
'tool_output',
'______dangerous_tool_1.txt',
);
expect(result.outputFile).toBe(expectedOutputFile);
@@ -1122,6 +1127,7 @@ describe('fileUtils', () => {
// ../../etc/passwd -> ______etc_passwd
const expectedOutputFile = path.join(
tempRootDir,
'tool_output',
'shell_______etc_passwd.txt',
);
expect(result.outputFile).toBe(expectedOutputFile);
+5 -1
View File
@@ -566,6 +566,8 @@ ${processedLines.join('\n')}`;
/**
* Saves tool output to a temporary file for later retrieval.
*/
export const TOOL_OUTPUT_DIR = 'tool_output';
export async function saveTruncatedToolOutput(
content: string,
toolName: string,
@@ -578,8 +580,10 @@ export async function saveTruncatedToolOutput(
.replace(/[^a-z0-9]/gi, '_')
.toLowerCase();
const fileName = `${safeToolName}_${safeId}.txt`;
const outputFile = path.join(projectTempDir, fileName);
const toolOutputDir = path.join(projectTempDir, TOOL_OUTPUT_DIR);
const outputFile = path.join(toolOutputDir, fileName);
await fsPromises.mkdir(toolOutputDir, { recursive: true });
await fsPromises.writeFile(outputFile, content);
const lines = content.split('\n');