From 80b04dc505bf1c784a54c5d80d971310b05144cc Mon Sep 17 00:00:00 2001 From: Taylor Mullen Date: Tue, 22 Apr 2025 07:48:12 -0400 Subject: [PATCH] Update UI of tool messages - Bring tool messages in line with original envisioned UI of: https://screenshot.googleplex.com/9yZCX636LzpMrgc - In particular this represents more descriptive names. FWIW we already had this tech we just weren't passing around information correctly (`displayName` vs. `name`) - Add gray to our list of color pallete's and removed Background (unused) - Re-enabled representing canceled messages - Migrated back towards a cleaner tool message design of status symbols & border colors vs. overly verbose text. - Removed border from confirmation diffs. Fixes https://b.corp.google.com/issues/412598909 --- packages/cli/src/ui/colors.ts | 2 +- .../ui/components/messages/DiffRenderer.tsx | 8 +- .../ui/components/messages/GeminiMessage.tsx | 23 +--- .../components/messages/ToolGroupMessage.tsx | 13 ++- .../ui/components/messages/ToolMessage.tsx | 105 ++++++++---------- .../ui/components/messages/UserMessage.tsx | 6 +- packages/cli/src/ui/hooks/useGeminiStream.ts | 2 +- packages/cli/src/ui/types.ts | 2 +- 8 files changed, 70 insertions(+), 91 deletions(-) diff --git a/packages/cli/src/ui/colors.ts b/packages/cli/src/ui/colors.ts index 946be512..f320d856 100644 --- a/packages/cli/src/ui/colors.ts +++ b/packages/cli/src/ui/colors.ts @@ -5,7 +5,6 @@ */ export const Colors = { - Background: '#1E1E2E', Foreground: 'white', LightBlue: '#CDD6F4', AccentBlue: '#89B4FA', @@ -15,4 +14,5 @@ export const Colors = { AccentYellow: '#F9E2AF', AccentRed: '#F38BA8', SubtleComment: '#6C7086', + Gray: 'gray', }; diff --git a/packages/cli/src/ui/components/messages/DiffRenderer.tsx b/packages/cli/src/ui/components/messages/DiffRenderer.tsx index 01cc4938..eb3133c3 100644 --- a/packages/cli/src/ui/components/messages/DiffRenderer.tsx +++ b/packages/cli/src/ui/components/messages/DiffRenderer.tsx @@ -138,11 +138,7 @@ export const DiffRenderer: React.FC = ({ // --- End Modification --- return ( - + {/* Iterate over the lines that should be displayed (already normalized) */} {displayableLines.map((line, index) => { const key = `diff-line-${index}`; @@ -179,7 +175,7 @@ export const DiffRenderer: React.FC = ({ return ( // Using your original rendering structure - {gutterNumStr} + {gutterNumStr} {prefixSymbol}{' '} diff --git a/packages/cli/src/ui/components/messages/GeminiMessage.tsx b/packages/cli/src/ui/components/messages/GeminiMessage.tsx index 584c7729..11449b18 100644 --- a/packages/cli/src/ui/components/messages/GeminiMessage.tsx +++ b/packages/cli/src/ui/components/messages/GeminiMessage.tsx @@ -16,28 +16,13 @@ interface GeminiMessageProps { export const GeminiMessage: React.FC = ({ text }) => { const prefix = '✦ '; const prefixWidth = prefix.length; - - // Handle potentially null or undefined text gracefully - const safeText = text || ''; - - // Use the static render method from the MarkdownRenderer class - // Pass safeText which is guaranteed to be a string - const renderedBlocks = MarkdownRenderer.render(safeText); - - // If the original text was actually empty/null, render the minimal state - if (!safeText && renderedBlocks.length === 0) { - return ( - - - {prefix} - - - - ); - } + const renderedBlocks = MarkdownRenderer.render(text); return ( + + {prefix} + {renderedBlocks} diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx index 448ed4c5..0675411f 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx @@ -22,11 +22,18 @@ export const ToolGroupMessage: React.FC = ({ toolCalls, onSubmit, }) => { - const hasPending = toolCalls.some((t) => t.status === ToolCallStatus.Pending); - const borderColor = hasPending ? Colors.AccentYellow : Colors.AccentBlue; + const hasPending = !toolCalls.every( + (t) => t.status === ToolCallStatus.Success, + ); + const borderColor = hasPending ? Colors.AccentYellow : Colors.AccentCyan; return ( - + {toolCalls.map((tool) => ( = ({ - callId, name, description, resultDisplay, status, }) => { - const typedResultDisplay = resultDisplay as ToolResultDisplay | undefined; - - let color = Colors.SubtleComment; - let prefix = ''; - switch (status) { - case ToolCallStatus.Pending: - prefix = 'Pending:'; - break; - case ToolCallStatus.Invoked: - prefix = 'Executing:'; - break; - case ToolCallStatus.Confirming: - color = Colors.AccentYellow; - prefix = 'Confirm:'; - break; - case ToolCallStatus.Success: - color = Colors.AccentGreen; - prefix = 'Success:'; - break; - case ToolCallStatus.Error: - color = Colors.AccentRed; - prefix = 'Error:'; - break; - default: - // Handle unexpected status if necessary, or just break - break; - } - - const title = `${prefix} ${name}`; - + const statusIndicatorWidth = 3; + const hasResult = resultDisplay && resultDisplay.toString().trim().length > 0; return ( - - - {status === ToolCallStatus.Invoked && ( - - - - - - )} - - {title} - - - {status === ToolCallStatus.Error && typedResultDisplay - ? `: ${typedResultDisplay}` - : ` - ${description}`} - - - {status === ToolCallStatus.Success && typedResultDisplay && ( - - {typeof typedResultDisplay === 'string' ? ( - {typedResultDisplay} - ) : ( - + + + {/* Status Indicator */} + + {status === ToolCallStatus.Pending && } + {status === ToolCallStatus.Success && ( + )} + {status === ToolCallStatus.Confirming && ( + ? + )} + {status === ToolCallStatus.Canceled && ( + + - + + )} + {status === ToolCallStatus.Error && ( + + x + + )} + + + + {name}{' '} + {description} + + + + {hasResult && ( + + + {/* Use default text color (white) or gray instead of dimColor */} + {typeof resultDisplay === 'string' && ( + + {MarkdownRenderer.render(resultDisplay)} + + )} + {typeof resultDisplay === 'object' && ( + + )} + )} diff --git a/packages/cli/src/ui/components/messages/UserMessage.tsx b/packages/cli/src/ui/components/messages/UserMessage.tsx index e9771b82..a83ffea7 100644 --- a/packages/cli/src/ui/components/messages/UserMessage.tsx +++ b/packages/cli/src/ui/components/messages/UserMessage.tsx @@ -19,10 +19,12 @@ export const UserMessage: React.FC = ({ text }) => { return ( - {prefix} + {prefix} - {text} + + {text} + ); diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts index ffdd9967..5baebe09 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.ts +++ b/packages/cli/src/ui/hooks/useGeminiStream.ts @@ -269,7 +269,7 @@ export const useGeminiStream = ( // Create the UI display object matching IndividualToolCallDisplay const toolCallDisplay: IndividualToolCallDisplay = { callId, - name, + name: cliTool.displayName, description, status: ToolCallStatus.Pending, resultDisplay: undefined, diff --git a/packages/cli/src/ui/types.ts b/packages/cli/src/ui/types.ts index fe135909..70ecca67 100644 --- a/packages/cli/src/ui/types.ts +++ b/packages/cli/src/ui/types.ts @@ -25,7 +25,7 @@ export enum GeminiEventType { export enum ToolCallStatus { Pending = 'Pending', - Invoked = 'Invoked', + Canceled = 'Canceled', Confirming = 'Confirming', Success = 'Success', Error = 'Error',