feat(core): Save large tool outputs to a file and return truncated lines (#6240)

This commit is contained in:
Sandy Tao
2025-09-05 15:37:29 -07:00
committed by GitHub
parent 7239c5cd9a
commit dd23c77469
14 changed files with 511 additions and 10 deletions

View File

@@ -622,6 +622,8 @@ export async function loadCliConfig(
shouldUseNodePtyShell: settings.tools?.usePty,
skipNextSpeakerCheck: settings.model?.skipNextSpeakerCheck,
enablePromptCompletion: settings.general?.enablePromptCompletion ?? false,
truncateToolOutputThreshold: settings.tools?.truncateToolOutputThreshold,
truncateToolOutputLines: settings.tools?.truncateToolOutputLines,
eventEmitter: appEvents,
useSmartEdit: argv.useSmartEdit ?? settings.useSmartEdit,
});

View File

@@ -11,6 +11,10 @@ import type {
AuthType,
ChatCompressionSettings,
} from '@google/gemini-cli-core';
import {
DEFAULT_TRUNCATE_TOOL_OUTPUT_LINES,
DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD,
} from '@google/gemini-cli-core';
import type { CustomTheme } from '../ui/themes/theme.js';
export enum MergeStrategy {
@@ -654,6 +658,25 @@ export const SETTINGS_SCHEMA = {
'Use ripgrep for file content search instead of the fallback implementation. Provides faster search performance.',
showInDialog: true,
},
truncateToolOutputThreshold: {
type: 'number',
label: 'Tool Output Truncation Threshold',
category: 'General',
requiresRestart: false,
default: DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD,
description:
'Truncate tool output if it is larger than this many characters. Set to -1 to disable.',
showInDialog: true,
},
truncateToolOutputLines: {
type: 'number',
label: 'Tool Output Truncation Lines',
category: 'General',
requiresRestart: false,
default: DEFAULT_TRUNCATE_TOOL_OUTPUT_LINES,
description: 'The number of lines to keep when truncating tool output.',
showInDialog: true,
},
},
},

View File

@@ -6,7 +6,7 @@
import type React from 'react';
import { useMemo } from 'react';
import { Box } from 'ink';
import { Box, Text } from 'ink';
import type { IndividualToolCallDisplay } from '../../types.js';
import { ToolCallStatus } from '../../types.js';
import { ToolMessage } from './ToolMessage.js';
@@ -121,6 +121,11 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
terminalWidth={innerWidth}
/>
)}
{tool.outputFile && (
<Box marginX={1}>
<Text>Output too long and was saved to: {tool.outputFile}</Text>
</Box>
)}
</Box>
);
})}

View File

@@ -247,6 +247,7 @@ export function mapToDisplay(
status: mapCoreStatusToDisplayStatus(trackedCall.status),
resultDisplay: trackedCall.response.resultDisplay,
confirmationDetails: undefined,
outputFile: trackedCall.response.outputFile,
};
case 'error':
return {

View File

@@ -26,6 +26,8 @@ import type {
AnyToolInvocation,
} from '@google/gemini-cli-core';
import {
DEFAULT_TRUNCATE_TOOL_OUTPUT_LINES,
DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD,
ToolConfirmationOutcome,
ApprovalMode,
MockTool,
@@ -54,6 +56,11 @@ const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
getDebugMode: () => false,
storage: {
getProjectTempDir: () => '/tmp',
},
getTruncateToolOutputThreshold: () => DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD,
getTruncateToolOutputLines: () => DEFAULT_TRUNCATE_TOOL_OUTPUT_LINES,
getAllowedTools: vi.fn(() => []),
getContentGeneratorConfig: () => ({
model: 'test-model',

View File

@@ -61,6 +61,7 @@ export interface IndividualToolCallDisplay {
status: ToolCallStatus;
confirmationDetails: ToolCallConfirmationDetails | undefined;
renderOutputAsMarkdown?: boolean;
outputFile?: string;
}
export interface CompressionProps {