revert: remove invasive ToolDisplay logic from legacy UI components

This commit is contained in:
Michael Bleigh
2026-04-11 19:04:36 -07:00
parent 383cb7d795
commit 410e675837
7 changed files with 17 additions and 165 deletions

View File

@@ -17,14 +17,12 @@ import {
isGrepResult,
isListResult,
isReadManyFilesResult,
type ToolDisplay,
} from '@google/gemini-cli-core';
import {
type IndividualToolCallDisplay,
type ToolResultDisplay,
isTodoList,
} from '../../types.js';
import { isCompactTool } from './ToolGroupMessage.js';
import { useAlternateBuffer } from '../../hooks/useAlternateBuffer.js';
import { ToolStatusIndicator } from './ToolShared.js';
import { theme } from '../../semantic-colors.js';
@@ -48,7 +46,6 @@ const PAYLOAD_SCROLL_GUTTER = 4;
const PAYLOAD_MAX_WIDTH = 120 + PAYLOAD_SCROLL_GUTTER;
interface DenseToolMessageProps extends IndividualToolCallDisplay {
display?: ToolDisplay;
terminalWidth: number;
availableTerminalHeight?: number;
}
@@ -272,7 +269,6 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
terminalWidth,
availableTerminalHeight,
description: originalDescription,
display,
} = props;
const settings = useSettings();
@@ -287,7 +283,6 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
const [isFocused, setIsFocused] = useState(false);
const toggleRef = useRef<DOMElement>(null);
const isActuallyCompact = useMemo(() => isCompactTool(props, true), [props]);
// Unified File Data Extraction (Safely bridge resultDisplay and confirmationDetails)
const diff = useMemo((): FileDiff | undefined => {
@@ -327,83 +322,6 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
// State-to-View Coordination
const viewParts = useMemo((): ViewParts => {
if (display) {
const descriptionText = (
<Text color={theme.text.secondary} wrap="truncate-end">
{display.description || originalDescription}
</Text>
);
const summaryText = display.resultSummary ? (
<Text color={theme.text.accent} wrap="truncate-end">
{display.resultSummary}
</Text>
) : status === CoreToolCallStatus.Error ? (
<Text color={theme.status.error} wrap="truncate-end">
{typeof resultDisplay === 'string' ? resultDisplay : 'Failed'}
</Text>
) : undefined;
// For now, DenseToolMessage still handles complex resultDisplay types
// like FileDiff or ListResult manually if display.result is not provided
// or doesn't cover them.
if (!display.result) {
if (diff) {
return {
...getFileOpData(
diff,
status,
resultDisplay,
terminalWidth,
availableTerminalHeight,
isAlternateBuffer,
),
description: descriptionText,
summary: summaryText,
};
}
if (isListResult(resultDisplay)) {
return {
...getListResultData(resultDisplay, originalDescription),
description: descriptionText,
summary: summaryText,
};
}
}
// If we have a display.result, use it as the payload
let payload: React.ReactNode;
if (display.result) {
if (display.result.type === 'text') {
const text = display.result.text;
if (text) {
payload = (
<Text color={theme.text.secondary} wrap="truncate-end">
{text}
</Text>
);
}
}
// Step 5 will expand this to handle 'diff' type
}
// Compact tools should elide text payloads by default unless expanded.
if (
isActuallyCompact &&
!isExpanded &&
display.result?.type === 'text' &&
!isAlternateBuffer
) {
payload = undefined;
}
return {
description: descriptionText,
summary: summaryText,
payload,
};
}
if (diff) {
return getFileOpData(
diff,
@@ -465,9 +383,6 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
availableTerminalHeight,
originalDescription,
isAlternateBuffer,
display,
isActuallyCompact,
isExpanded,
]);
const { description, summary } = viewParts;
@@ -505,10 +420,6 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
}, [diff, isExpanded, isAlternateBuffer, terminalWidth, settings, status]);
const showPayload = useMemo(() => {
// If we are using the new display protocol and it's a compact tool,
// hide the payload by default unless expanded.
if (display && isActuallyCompact && !isExpanded) return false;
const policy = !isAlternateBuffer || !diff || isExpanded;
if (!policy) return false;
@@ -528,8 +439,6 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
diffLines.length,
viewParts.payload,
outputFile,
isActuallyCompact,
display,
]);
const keyExtractor = (_item: React.ReactNode, index: number) =>
@@ -540,16 +449,7 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
return (
<Box flexDirection="column">
<Box
marginLeft={2}
flexDirection="row"
flexWrap="wrap"
ref={
isActuallyCompact || (isAlternateBuffer && diff)
? toggleRef
: undefined
}
>
<Box marginLeft={2} flexDirection="row" flexWrap="wrap">
<Box flexDirection="row" flexShrink={1}>
<ToolStatusIndicator status={status} name={name} />
<Box maxWidth={25} flexShrink={0} flexGrow={0}>
@@ -563,7 +463,12 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
</Box>
{summary && (
<Box key="tool-summary" marginLeft={1} flexGrow={0}>
<Box
key="tool-summary"
ref={isAlternateBuffer && diff ? toggleRef : undefined}
marginLeft={1}
flexGrow={0}
>
{summary}
</Box>
)}

View File

@@ -43,7 +43,6 @@ export interface ShellToolMessageProps extends ToolMessageProps {
export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
name,
description,
display,
resultDisplay,
status,
availableTerminalHeight,
@@ -168,7 +167,6 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
name={name}
status={status}
description={description}
display={display}
emphasis={emphasis}
originalRequestName={originalRequestName}
/>

View File

@@ -61,9 +61,7 @@ export const isCompactTool = (
tool: IndividualToolCallDisplay,
isCompactModeEnabled: boolean,
): boolean => {
const hasCompactOutputSupport = COMPACT_OUTPUT_ALLOWLIST.has(
tool.originalRequestName || tool.name,
);
const hasCompactOutputSupport = COMPACT_OUTPUT_ALLOWLIST.has(tool.name);
const displayStatus = mapCoreStatusToDisplayStatus(tool.status);
return (
isCompactModeEnabled &&
@@ -121,7 +119,6 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
isToolGroupBoundary,
}) => {
const settings = useSettings();
const isLowErrorVerbosity = settings.merged.ui?.errorVerbosity !== 'full';
const isCompactModeEnabled = settings.merged.ui?.compactToolOutput === true;

View File

@@ -21,20 +21,13 @@ import {
useFocusHint,
FocusHint,
} from './ToolShared.js';
import {
type Config,
CoreToolCallStatus,
Kind,
type ToolDisplay,
} from '@google/gemini-cli-core';
import { type Config, CoreToolCallStatus, Kind } from '@google/gemini-cli-core';
import { ShellInputPrompt } from '../ShellInputPrompt.js';
import { SUBAGENT_MAX_LINES } from '../../constants.js';
export type { TextEmphasis };
export interface ToolMessageProps extends IndividualToolCallDisplay {
description: string;
display?: ToolDisplay;
availableTerminalHeight?: number;
terminalWidth: number;
emphasis?: TextEmphasis;
@@ -51,7 +44,6 @@ export interface ToolMessageProps extends IndividualToolCallDisplay {
export const ToolMessage: React.FC<ToolMessageProps> = ({
name,
description,
display,
resultDisplay,
status,
kind,
@@ -87,11 +79,6 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
resultDisplay,
);
const effectiveResultDisplay =
display?.resultSummary && !display.result
? display.resultSummary
: resultDisplay;
return (
// It is crucial we don't replace this <> with a Box because otherwise the
// sticky header inside it would be sticky to that box rather than to the
@@ -112,11 +99,9 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
name={name}
status={status}
description={description}
display={display}
emphasis={emphasis}
progressMessage={progressMessage}
originalRequestName={originalRequestName}
hideSummary={!display?.result && !!display?.resultSummary}
/>
<FocusHint
shouldShowFocusHint={shouldShowFocusHint}
@@ -145,7 +130,7 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
/>
)}
<ToolResultDisplay
resultDisplay={effectiveResultDisplay}
resultDisplay={resultDisplay}
availableTerminalHeight={availableTerminalHeight}
terminalWidth={terminalWidth}
renderOutputAsMarkdown={renderOutputAsMarkdown}

View File

@@ -21,7 +21,6 @@ import {
isCompletedAskUserTool,
type ToolResultDisplay,
CoreToolCallStatus,
type ToolDisplay,
} from '@google/gemini-cli-core';
import { useInactivityTimer } from '../../hooks/useInactivityTimer.js';
import { formatCommand } from '../../key/keybindingUtils.js';
@@ -193,10 +192,8 @@ type ToolInfoProps = {
description: string;
status: CoreToolCallStatus;
emphasis: TextEmphasis;
display?: ToolDisplay;
progressMessage?: string;
originalRequestName?: string;
hideSummary?: boolean;
};
export const ToolInfo: React.FC<ToolInfoProps> = ({
@@ -204,10 +201,8 @@ export const ToolInfo: React.FC<ToolInfoProps> = ({
description,
status: coreStatus,
emphasis,
display,
progressMessage: _progressMessage,
originalRequestName,
hideSummary,
}) => {
const status = mapCoreStatusToDisplayStatus(coreStatus);
const nameColor = React.useMemo<string>(() => {
@@ -228,15 +223,11 @@ export const ToolInfo: React.FC<ToolInfoProps> = ({
// Hide description for completed Ask User tools (the result display speaks for itself)
const isCompletedAskUser = isCompletedAskUserTool(name, status);
const displayName = display?.name || name;
const displayDescription = display?.description || description;
const displaySummary = hideSummary ? undefined : display?.resultSummary;
return (
<Box overflow="hidden" height={1} flexGrow={1} flexShrink={1}>
<Text strikethrough={status === ToolCallStatus.Canceled} wrap="truncate">
<Text color={nameColor} bold>
{displayName}
{name}
</Text>
{originalRequestName && originalRequestName !== name && (
<Text color={theme.text.secondary} italic>
@@ -247,13 +238,7 @@ export const ToolInfo: React.FC<ToolInfoProps> = ({
{!isCompletedAskUser && (
<>
{' '}
<Text color={theme.text.secondary}>{displayDescription}</Text>
</>
)}
{displaySummary && (
<>
<Text color={theme.text.accent}> </Text>
<Text color={theme.text.accent}>{displaySummary}</Text>
<Text color={theme.text.secondary}>{description}</Text>
</>
)}
</Text>

View File

@@ -8,7 +8,6 @@ import {
type ToolCall,
type SerializableConfirmationDetails,
type ToolResultDisplay,
type ToolDisplay,
debugLogger,
CoreToolCallStatus,
type SubagentActivityItem,
@@ -36,17 +35,10 @@ export function mapToDisplay(
borderBottom?: boolean;
borderColor?: string;
borderDimColor?: boolean;
isAgentSessionInteractive?: boolean;
} = {},
): HistoryItemToolGroup {
const toolCalls = Array.isArray(toolOrTools) ? toolOrTools : [toolOrTools];
const {
borderTop,
borderBottom,
borderColor,
borderDimColor,
isAgentSessionInteractive,
} = options;
const { borderTop, borderBottom, borderColor, borderDimColor } = options;
const toolDisplays = toolCalls.map((call): IndividualToolCallDisplay => {
let description: string;
@@ -71,7 +63,6 @@ export function mapToDisplay(
};
let resultDisplay: ToolResultDisplay | undefined = undefined;
let display: ToolDisplay | undefined = undefined;
let confirmationDetails: SerializableConfirmationDetails | undefined =
undefined;
let outputFile: string | undefined = undefined;
@@ -84,17 +75,11 @@ export function mapToDisplay(
switch (call.status) {
case CoreToolCallStatus.Success:
resultDisplay = call.response.resultDisplay;
if (isAgentSessionInteractive) {
display = call.response.display;
}
outputFile = call.response.outputFile;
break;
case CoreToolCallStatus.Error:
case CoreToolCallStatus.Cancelled:
resultDisplay = call.response.resultDisplay;
if (isAgentSessionInteractive) {
display = call.response.display;
}
break;
case CoreToolCallStatus.AwaitingApproval:
correlationId = call.correlationId;
@@ -127,7 +112,6 @@ export function mapToDisplay(
status: call.status,
isClientInitiated: !!call.request.isClientInitiated,
kind: call.tool?.kind,
display,
resultDisplay,
confirmationDetails,
outputFile,

View File

@@ -224,9 +224,9 @@ export const useAgentStream = ({
else if (evtStatus === 'success')
status = CoreToolCallStatus.Success;
const display = event.display?.result;
const liveOutput =
displayContentToString(event.display?.result) ??
tc.resultDisplay;
displayContentToString(display) ?? tc.resultDisplay;
const progressMessage =
legacyState?.progressMessage ?? tc.progressMessage;
const progress = legacyState?.progress ?? tc.progress;
@@ -237,7 +237,6 @@ export const useAgentStream = ({
return {
...tc,
name: event.display?.name ?? tc.name,
status,
display: event.display
? { ...tc.display, ...event.display }
@@ -260,13 +259,12 @@ export const useAgentStream = ({
const legacyState = event._meta?.legacyState;
const outputFile = legacyState?.outputFile;
const display = event.display;
const display = event.display?.result;
const resultDisplay =
displayContentToString(display?.result) ?? tc.resultDisplay;
displayContentToString(display) ?? tc.resultDisplay;
return {
...tc,
name: display?.name ?? tc.name,
status: event.isError
? CoreToolCallStatus.Error
: CoreToolCallStatus.Success,