-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat(tui): remove tool group borders and collapse completed tool results #5003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,8 +13,6 @@ import { ToolMessage } from './ToolMessage.js'; | |
| import { ToolConfirmationMessage } from './ToolConfirmationMessage.js'; | ||
| import { CompactToolGroupDisplay } from './CompactToolGroupDisplay.js'; | ||
| import { InlineParallelAgentsDisplay } from './InlineParallelAgentsDisplay.js'; | ||
| import { theme } from '../../semantic-colors.js'; | ||
| import { SHELL_COMMAND_NAME, SHELL_NAME } from '../../constants.js'; | ||
| import { useConfig } from '../../contexts/ConfigContext.js'; | ||
| import { useCompactMode } from '../../contexts/CompactModeContext.js'; | ||
| import type { AgentResultDisplay } from '@qwen-code/qwen-code-core'; | ||
|
|
@@ -156,7 +154,7 @@ interface ToolGroupMessageProps { | |
| compactLabel?: string; | ||
| } | ||
|
|
||
| // Main component renders the border and maps the tools using ToolMessage | ||
| // Main component maps the tools using ToolMessage | ||
| export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({ | ||
| toolCalls, | ||
| availableTerminalHeight, | ||
|
|
@@ -292,15 +290,15 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({ | |
| // Hide the entire group when the live-phase filter leaves nothing | ||
| // inline to render — i.e. a pure-running-subagent batch with no | ||
| // pending approval. LiveAgentPanel below the composer is the | ||
| // single source of truth for those rows; an empty bordered | ||
| // container floating above the panel would just be a duplicate | ||
| // chrome line. Terminal subagents (completed / failed / cancelled) | ||
| // single source of truth for those rows; an empty | ||
| // container floating above the panel would just be noise. | ||
| // Terminal subagents (completed / failed / cancelled) | ||
| // pass through `inlineToolCalls` because `unregisterForeground`'s | ||
| // post-delete emit already dropped them from the panel snapshot, | ||
| // and the inline path must render `SubagentScrollbackSummary` | ||
| // immediately so the user keeps a record of the run. | ||
| // (Gate on `isPending` so a degenerate empty `toolCalls=[]` in the | ||
| // committed phase still falls through to the legacy empty-border | ||
| // committed phase still falls through to the legacy empty-container | ||
| // snapshot — the suppression is specifically about live-phase | ||
| // panel ownership, not about hiding empty inputs in general.) | ||
| if (isPending && inlineToolCalls.length === 0) { | ||
|
|
@@ -345,22 +343,8 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({ | |
| } | ||
|
|
||
| // Full expanded view | ||
| const hasPending = !inlineToolCalls.every( | ||
| (t) => t.status === ToolCallStatus.Success, | ||
| ); | ||
| const isShellCommand = inlineToolCalls.some( | ||
| (t) => t.name === SHELL_COMMAND_NAME || t.name === SHELL_NAME, | ||
| ); | ||
| const borderColor = | ||
| isShellCommand || isEmbeddedShellFocused | ||
| ? theme.ui.symbol | ||
| : hasPending | ||
| ? theme.status.warning | ||
| : theme.border.default; | ||
|
|
||
| const staticHeight = /* border */ 2 + /* marginBottom */ 1; | ||
| // account for border (2 chars) and padding (2 chars) | ||
| const innerWidth = contentWidth - 4; | ||
| const staticHeight = /* marginBottom */ 1; | ||
| const innerWidth = contentWidth - 2; | ||
|
|
||
| let countToolCallsWithResults = 0; | ||
| for (const tool of inlineToolCalls) { | ||
|
|
@@ -385,12 +369,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({ | |
| const readCount = memoryReadCount ?? 0; | ||
| const writeCount = memoryWriteCount ?? 0; | ||
| return ( | ||
| <Box | ||
| flexDirection="column" | ||
| borderStyle="round" | ||
| width={contentWidth} | ||
| borderColor={theme.border.default} | ||
| > | ||
| <Box flexDirection="column" width={contentWidth}> | ||
| {readCount > 0 && ( | ||
| <Box paddingLeft={1}> | ||
| <Text dimColor> | ||
|
|
@@ -412,22 +391,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({ | |
| } | ||
|
|
||
| return ( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The old code included a comment explaining that Consider adding a brief comment: {/* width={contentWidth} prevents Ink flex overflow during rapid re-renders */}
<Box flexDirection="column" width={contentWidth} gap={0}>— qwen3.7-max via Qwen Code /review |
||
| <Box | ||
| flexDirection="column" | ||
| borderStyle="round" | ||
| /* | ||
| This width constraint is highly important and protects us from an Ink rendering bug. | ||
| Since the ToolGroup can typically change rendering states frequently, it can cause | ||
| Ink to render the border of the box incorrectly and span multiple lines and even | ||
| cause tearing. | ||
| */ | ||
| width={contentWidth} | ||
| borderDimColor={ | ||
| hasPending && (!isShellCommand || !isEmbeddedShellFocused) | ||
| } | ||
| borderColor={borderColor} | ||
| gap={0} | ||
| > | ||
| <Box flexDirection="column" width={contentWidth} gap={0}> | ||
| {/* Memory badge for mixed groups (some memory ops + other ops) */} | ||
| {!isMemoryOnlyGroup && | ||
| ((memoryWriteCount ?? 0) > 0 || (memoryReadCount ?? 0) > 0) && | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -670,10 +670,12 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({ | |||||||
| // Use the custom hook to determine the display type | ||||||||
| const displayRenderer = useResultDisplayRenderer(resultDisplay); | ||||||||
| const { compactMode } = useCompactMode(); | ||||||||
| const effectiveDisplayRenderer = | ||||||||
| !compactMode || forceShowResult | ||||||||
| ? displayRenderer | ||||||||
| : { type: 'none' as const }; | ||||||||
|
|
||||||||
| const isCompleted = status === ToolCallStatus.Success; | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion]
Suggested change
— qwen3.7-max via Qwen Code /review |
||||||||
| const shouldCollapse = compactMode && isCompleted && !forceShowResult; | ||||||||
| const effectiveDisplayRenderer = shouldCollapse | ||||||||
|
chiga0 marked this conversation as resolved.
|
||||||||
| ? { type: 'none' as const } | ||||||||
| : displayRenderer; | ||||||||
|
|
||||||||
| return ( | ||||||||
| <Box paddingX={1} paddingY={0} flexDirection="column"> | ||||||||
|
|
@@ -780,6 +782,7 @@ const ToolInfo: React.FC<ToolInfo> = ({ | |||||||
| status, | ||||||||
| emphasis, | ||||||||
| }) => { | ||||||||
| const { compactMode } = useCompactMode(); | ||||||||
| const nameColor = React.useMemo<string>(() => { | ||||||||
| switch (emphasis) { | ||||||||
| case 'high': | ||||||||
|
|
@@ -794,13 +797,15 @@ const ToolInfo: React.FC<ToolInfo> = ({ | |||||||
| } | ||||||||
| } | ||||||||
| }, [emphasis]); | ||||||||
| const isDim = compactMode && status === ToolCallStatus.Success; | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion]
Suggested change
— qwen3.7-max via Qwen Code /review |
||||||||
| return ( | ||||||||
|
chiga0 marked this conversation as resolved.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion]
Suggested change
This requires threading — qwen3.7-max via Qwen Code /review |
||||||||
| <Box flexGrow={1}> | ||||||||
| <Text | ||||||||
| wrap="truncate-end" | ||||||||
| strikethrough={status === ToolCallStatus.Canceled} | ||||||||
| dimColor={isDim} | ||||||||
| > | ||||||||
| <Text color={nameColor} bold> | ||||||||
| <Text color={nameColor} bold={!isDim}> | ||||||||
| {localizeToolDisplayName(name)} | ||||||||
| </Text>{' '} | ||||||||
| <Text color={theme.text.secondary}>{description}</Text> | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] After removing the border, this memory-only branch and the main expanded view (line 393) have no
paddingXon their outer<Box>. Meanwhile,CompactToolGroupDisplaycorrectly gainedpaddingX={1}. The oldborderStyle="round"provided an implicit 1-char left offset that kept content aligned with the compact view. Without it, expanded-view content now sits 1 column to the left of compact-view content.Apply the same to line 393:
<Box flexDirection="column" width={contentWidth} paddingX={1} gap={0}>.Note: this would also affect the
innerWidthcalculation — with outerpaddingX={1}(2 chars) plus ToolMessage's ownpaddingX={1}(2 chars),innerWidthshould becomecontentWidth - 4again.— qwen3.7-max via Qwen Code /review