mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-15 08:31:14 -07:00
Output Layout, Borders and Spacing
- fix(ui): update ToolGroupMessage to support stitched borders and dynamic margins
- fix(ui): implement border stitching in history pushing to eliminate gaps
- test(ui): update snapshots and test assertions for new layout
- style(ui): wrap dense tool payloads with vertical margins
- Adds margins above and below dense payload content to allow compact output to consume a single line until expanded.
- fix(ui): unify spacing logic and border handling for tool groups
- Corrects transitions between compact and standard tools to not add redundant empty lines and ensures history stitching respects boundaries.
- fix(ui): ensure top border is rendered within completed history for standard tool output when following compact tool output
- Addresses an issue where non-compact tools pushed to history at the end of a batch (via onComplete) were missing their top border and proper margin if they followed compact tools already pushed to history.
- The fix updates the onComplete callback in useGeminiStream.ts to be transition-aware. It now explicitly detects when a final push starts with a non-compact tool following a compact tool from the same batch, forcing borderTop: true in that case.
- Previously, the logic relied solely on isFirstToolInGroupRef, which would be false if any earlier tools in the batch had already been pushed, causing the final non-compact tools to incorrectly inherit a borderless state from the preceding compact tools.
----------------------
Note: ToolGroupMessage.tsx and ToolGroupMessage.compact.test.tsx contain 'any' usage/unsafe assertions to be addressed before PR.
This commit is contained in:
@@ -37,10 +37,13 @@ Tips for getting started:
|
||||
2. /help for more information
|
||||
3. Ask coding questions, edit code or run commands
|
||||
4. Be specific for the best results
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool1 Description for tool 1 │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool2 Description for tool 2 │
|
||||
│ │
|
||||
@@ -81,10 +84,13 @@ Tips for getting started:
|
||||
2. /help for more information
|
||||
3. Ask coding questions, edit code or run commands
|
||||
4. Be specific for the best results
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool1 Description for tool 1 │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool2 Description for tool 2 │
|
||||
│ │
|
||||
|
||||
@@ -3,16 +3,15 @@
|
||||
exports[`MainContent > MainContent Tool Output Height Logic > 'ASB mode - Focused shell should expand' 1`] = `
|
||||
"ScrollableList
|
||||
AppHeader(full)
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ Shell Command Running a long command... │
|
||||
│ │
|
||||
│ Line 10 │
|
||||
│ Line 11 │
|
||||
│ Line 12 │
|
||||
│ Line 13 │
|
||||
│ Line 14 │
|
||||
│ Line 15 █ │
|
||||
│ Line 16 █ │
|
||||
│ Line 15 │
|
||||
│ Line 16 │
|
||||
│ Line 17 █ │
|
||||
│ Line 18 █ │
|
||||
│ Line 19 █ │
|
||||
@@ -24,16 +23,15 @@ AppHeader(full)
|
||||
exports[`MainContent > MainContent Tool Output Height Logic > 'ASB mode - Unfocused shell' 1`] = `
|
||||
"ScrollableList
|
||||
AppHeader(full)
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ Shell Command Running a long command... │
|
||||
│ │
|
||||
│ Line 10 │
|
||||
│ Line 11 │
|
||||
│ Line 12 │
|
||||
│ Line 13 │
|
||||
│ Line 14 │
|
||||
│ Line 15 █ │
|
||||
│ Line 16 █ │
|
||||
│ Line 15 │
|
||||
│ Line 16 │
|
||||
│ Line 17 █ │
|
||||
│ Line 18 █ │
|
||||
│ Line 19 █ │
|
||||
@@ -44,12 +42,11 @@ AppHeader(full)
|
||||
|
||||
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Constrained height' 1`] = `
|
||||
"AppHeader(full)
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ Shell Command Running a long command... │
|
||||
│ │
|
||||
│ ... first 11 lines hidden (Ctrl+O to show) ... │
|
||||
│ Line 12 │
|
||||
│ Line 13 │
|
||||
│ ... first 13 lines hidden (Ctrl+O to show) ... │
|
||||
│ Line 14 │
|
||||
│ Line 15 │
|
||||
│ Line 16 │
|
||||
@@ -63,6 +60,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Con
|
||||
|
||||
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Unconstrained height' 1`] = `
|
||||
"AppHeader(full)
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ Shell Command Running a long command... │
|
||||
│ │
|
||||
@@ -92,6 +90,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Unc
|
||||
|
||||
exports[`MainContent > renders a split tool group without a gap between static and pending areas 1`] = `
|
||||
"AppHeader(full)
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ test-tool A tool for testing │
|
||||
│ │
|
||||
|
||||
@@ -536,6 +536,7 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
|
||||
<Box
|
||||
marginLeft={6}
|
||||
marginTop={1}
|
||||
marginBottom={1}
|
||||
paddingX={1}
|
||||
flexDirection="column"
|
||||
height={
|
||||
@@ -562,13 +563,13 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
|
||||
)}
|
||||
|
||||
{showPayload && (!isAlternateBuffer || !diff) && viewParts.payload && (
|
||||
<Box marginLeft={6} marginTop={1}>
|
||||
<Box marginLeft={6} marginTop={1} marginBottom={1}>
|
||||
{viewParts.payload}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{showPayload && outputFile && (
|
||||
<Box marginLeft={6} marginTop={1}>
|
||||
<Box marginLeft={6} marginTop={1} marginBottom={1}>
|
||||
<Text color={theme.text.secondary}>
|
||||
(Output saved to: {outputFile})
|
||||
</Text>
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('ToolGroupMessage Compact Rendering', () => {
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('adds an empty line between a compact tool and a standard tool', async () => {
|
||||
it('does not add an extra empty line between a compact tool and a standard tool', async () => {
|
||||
const toolCalls = [
|
||||
{
|
||||
callId: 'call1',
|
||||
@@ -81,7 +81,7 @@ describe('ToolGroupMessage Compact Rendering', () => {
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('adds an empty line if a compact tool has a dense payload', async () => {
|
||||
it('does not add an extra empty line if a compact tool has a dense payload', async () => {
|
||||
const toolCalls = [
|
||||
{
|
||||
callId: 'call1',
|
||||
@@ -107,7 +107,7 @@ describe('ToolGroupMessage Compact Rendering', () => {
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('adds an empty line between a standard tool and a compact tool', async () => {
|
||||
it('does not add an extra empty line between a standard tool and a compact tool', async () => {
|
||||
const toolCalls = [
|
||||
{
|
||||
callId: 'call1',
|
||||
|
||||
@@ -54,7 +54,7 @@ const COMPACT_OUTPUT_ALLOWLIST = new Set([
|
||||
]);
|
||||
|
||||
// Helper to identify if a tool should use the compact view
|
||||
const isCompactTool = (
|
||||
export const isCompactTool = (
|
||||
tool: IndividualToolCallDisplay,
|
||||
isCompactModeEnabled: boolean,
|
||||
): boolean => {
|
||||
@@ -68,7 +68,7 @@ const isCompactTool = (
|
||||
};
|
||||
|
||||
// Helper to identify if a compact tool has a payload (diff, list, etc.)
|
||||
const hasDensePayload = (tool: IndividualToolCallDisplay): boolean => {
|
||||
export const hasDensePayload = (tool: IndividualToolCallDisplay): boolean => {
|
||||
if (tool.outputFile) return true;
|
||||
const res = tool.resultDisplay;
|
||||
if (!res) return false;
|
||||
@@ -121,7 +121,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
toolCalls: allToolCalls,
|
||||
availableTerminalHeight,
|
||||
terminalWidth,
|
||||
// borderTop: borderTopOverride,
|
||||
borderTop: borderTopOverride,
|
||||
borderBottom: borderBottomOverride,
|
||||
isExpandable,
|
||||
}) => {
|
||||
@@ -207,29 +207,26 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
const prevIsCompact = prevTool
|
||||
? isCompactTool(prevTool, isCompactModeEnabled)
|
||||
: false;
|
||||
const hasPayload = hasDensePayload(tool);
|
||||
const prevHasPayload = prevTool ? hasDensePayload(prevTool) : false;
|
||||
|
||||
if (isCompact) {
|
||||
height += 1; // Base height for compact tool
|
||||
// Spacing logic (matching marginTop)
|
||||
if (
|
||||
isFirst ||
|
||||
isCompact !== prevIsCompact ||
|
||||
hasPayload ||
|
||||
prevHasPayload
|
||||
) {
|
||||
if (isFirst) {
|
||||
height += borderTopOverride ?? true ? 1 : 0;
|
||||
} else if (!prevIsCompact) {
|
||||
height += 1;
|
||||
}
|
||||
} else {
|
||||
height += 3; // Static overhead for standard tool
|
||||
if (isFirst || prevIsCompact) {
|
||||
height += 1;
|
||||
if (isFirst) {
|
||||
height += borderTopOverride ?? true ? 1 : 0;
|
||||
} else {
|
||||
height += 1; // marginTop is always 1 for non-compact tools (not first)
|
||||
}
|
||||
}
|
||||
}
|
||||
return height;
|
||||
}, [visibleToolCalls, isCompactModeEnabled]);
|
||||
}, [visibleToolCalls, isCompactModeEnabled, borderTopOverride]);
|
||||
|
||||
let countToolCallsWithResults = 0;
|
||||
for (const tool of visibleToolCalls) {
|
||||
@@ -273,20 +270,18 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
*/
|
||||
width={terminalWidth}
|
||||
paddingRight={TOOL_MESSAGE_HORIZONTAL_MARGIN}
|
||||
marginBottom={1}
|
||||
marginBottom={borderBottomOverride ?? true ? 1 : 0}
|
||||
>
|
||||
{visibleToolCalls.map((tool, index) => {
|
||||
const isFirst = index === 0;
|
||||
const isLast = index === visibleToolCalls.length - 1;
|
||||
const isShellToolCall = isShellTool(tool.name);
|
||||
const isCompact = isCompactTool(tool, isCompactModeEnabled);
|
||||
const hasPayload = hasDensePayload(tool);
|
||||
|
||||
const prevTool = index > 0 ? visibleToolCalls[index - 1] : null;
|
||||
const prevIsCompact = prevTool
|
||||
? isCompactTool(prevTool, isCompactModeEnabled)
|
||||
: false;
|
||||
const prevHasPayload = prevTool ? hasDensePayload(prevTool) : false;
|
||||
|
||||
const nextTool = !isLast ? visibleToolCalls[index + 1] : null;
|
||||
const nextIsCompact = nextTool
|
||||
@@ -295,12 +290,8 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
|
||||
let marginTop = 0;
|
||||
if (isFirst) {
|
||||
marginTop = 1;
|
||||
} else if (isCompact !== prevIsCompact) {
|
||||
marginTop = 1;
|
||||
} else if (isCompact && (hasPayload || prevHasPayload)) {
|
||||
marginTop = 1;
|
||||
} else if (!isCompact && prevIsCompact) {
|
||||
marginTop = borderTopOverride ?? true ? 1 : 0;
|
||||
} else if (!(isCompact && prevIsCompact)) {
|
||||
marginTop = 1;
|
||||
}
|
||||
|
||||
@@ -309,7 +300,11 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
availableTerminalHeight: availableTerminalHeightPerToolMessage,
|
||||
terminalWidth: contentWidth,
|
||||
emphasis: 'medium' as const,
|
||||
isFirst: isCompact ? false : prevIsCompact || isFirst,
|
||||
isFirst: isCompact
|
||||
? false
|
||||
: isFirst
|
||||
? (borderTopOverride ?? true)
|
||||
: prevIsCompact,
|
||||
borderColor,
|
||||
borderDimColor,
|
||||
isExpandable,
|
||||
@@ -358,7 +353,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
borderLeft={true}
|
||||
borderRight={true}
|
||||
borderTop={false}
|
||||
borderBottom={borderBottomOverride ?? true}
|
||||
borderBottom={isLast ? (borderBottomOverride ?? true) : true}
|
||||
borderColor={borderColor}
|
||||
borderDimColor={borderDimColor}
|
||||
borderStyle="round"
|
||||
|
||||
@@ -123,9 +123,9 @@ describe('ToolMessage Sticky Header Regression', () => {
|
||||
// Content lines 1-4 should be scrolled off
|
||||
expect(lastFrame()).not.toContain('c1-01');
|
||||
expect(lastFrame()).not.toContain('c1-04');
|
||||
// Line 6 and 7 should be visible (terminalHeight=5 means only 2 lines of content show below 3-line header)
|
||||
// Line 5 and 6 should be visible (terminalHeight=5 means only 2 lines of content show below 3-line header + margin)
|
||||
expect(lastFrame()).toContain('c1-05');
|
||||
expect(lastFrame()).toContain('c1-06');
|
||||
expect(lastFrame()).toContain('c1-07');
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
|
||||
// Scroll further so tool-1 is completely gone and tool-2's header should be stuck
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`DenseToolMessage > Toggleable Diff View (Alternate Buffer) > hides diff content by default when in alternate buffer mode 1`] = `
|
||||
" ✓ test-tool test.ts → Accepted [Show Diff]
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > Toggleable Diff View (Alternate Buffer) > shows diff content by default when NOT in alternate buffer mode 1`] = `
|
||||
" ✓ test-tool test.ts → Accepted
|
||||
|
||||
1 - old line
|
||||
1 + new line
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > does not render result arrow if resultDisplay is missing 1`] = `
|
||||
" o test-tool Test description
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > flattens newlines in string results 1`] = `
|
||||
" ✓ test-tool Test description → Line 1 Line 2
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for Edit tool using confirmationDetails 1`] = `
|
||||
" ? Edit styles.scss → Confirming
|
||||
|
||||
1 - body { color: blue; }
|
||||
1 + body { color: red; }
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for Errored Edit tool 1`] = `
|
||||
" x Edit styles.scss → Failed [Show Diff]
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for ReadManyFiles results 1`] = `
|
||||
" ✓ test-tool Attempting to read files from **/*.ts → Read 3 file(s) (1 ignored)
|
||||
|
||||
file1.ts
|
||||
file2.ts
|
||||
file3.ts
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for Rejected Edit tool 1`] = `
|
||||
" - Edit styles.scss → Rejected (+1, -1)
|
||||
|
||||
1 - old line
|
||||
1 + new line
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for Rejected Edit tool with confirmationDetails and diffStat 1`] = `
|
||||
" - Edit styles.scss → Rejected (+1, -1)
|
||||
|
||||
1 - body { color: blue; }
|
||||
1 + body { color: red; }
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for Rejected WriteFile tool 1`] = `
|
||||
" - WriteFile config.json → Rejected
|
||||
|
||||
1 - old content
|
||||
1 + new content
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for WriteFile tool 1`] = `
|
||||
" ✓ WriteFile config.json → Accepted (+1, -1)
|
||||
|
||||
1 - old content
|
||||
1 + new content
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for a successful string result 1`] = `
|
||||
" ✓ test-tool Test description → Success result
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for error status with string message 1`] = `
|
||||
" x test-tool Test description → Error occurred
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for file diff results with stats 1`] = `
|
||||
" ✓ test-tool test.ts → Accepted (+15, -6)
|
||||
|
||||
1 - old line
|
||||
1 + diff content
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for grep results 1`] = `
|
||||
" ✓ test-tool Test description → Found 2 matches
|
||||
|
||||
file1.ts:10: match 1
|
||||
file2.ts:20: match 2
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for ls results 1`] = `
|
||||
" ✓ test-tool Test description → Listed 2 files. (1 ignored)
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders correctly for todo updates 1`] = `
|
||||
" ✓ test-tool Test description → Todos updated
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders generic failure message for error status without string message 1`] = `
|
||||
" x test-tool Test description → Failed
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > renders generic output message for unknown object results 1`] = `
|
||||
" ✓ test-tool Test description → Output received
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`DenseToolMessage > truncates long string results 1`] = `
|
||||
" ✓ test-tool Test description
|
||||
→
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAA...
|
||||
"
|
||||
`;
|
||||
@@ -1,8 +1,8 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`ToolGroupMessage Compact Rendering > adds an empty line between a compact tool and a standard tool 1`] = `
|
||||
exports[`ToolGroupMessage Compact Rendering > does not add an extra empty line between a compact tool and a standard tool 1`] = `
|
||||
"
|
||||
✓ list_directory → file1.txt
|
||||
✓ ReadFolder → file1.txt
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ non-compact-tool │
|
||||
@@ -12,7 +12,7 @@ exports[`ToolGroupMessage Compact Rendering > adds an empty line between a compa
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ToolGroupMessage Compact Rendering > adds an empty line between a standard tool and a compact tool 1`] = `
|
||||
exports[`ToolGroupMessage Compact Rendering > does not add an extra empty line between a standard tool and a compact tool 1`] = `
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ non-compact-tool │
|
||||
@@ -20,21 +20,20 @@ exports[`ToolGroupMessage Compact Rendering > adds an empty line between a stand
|
||||
│ some large output │
|
||||
╰──────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
✓ list_directory → file1.txt
|
||||
✓ ReadFolder → file1.txt
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ToolGroupMessage Compact Rendering > adds an empty line if a compact tool has a dense payload 1`] = `
|
||||
exports[`ToolGroupMessage Compact Rendering > does not add an extra empty line if a compact tool has a dense payload 1`] = `
|
||||
"
|
||||
✓ list_directory → file1.txt
|
||||
|
||||
✓ ReadFolder → file1.txt
|
||||
✓ ReadFile → read file
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ToolGroupMessage Compact Rendering > renders consecutive compact tools without empty lines between them 1`] = `
|
||||
"
|
||||
✓ list_directory → file1.txt file2.txt
|
||||
✓ list_directory → file3.txt
|
||||
✓ ReadFolder → file1.txt file2.txt
|
||||
✓ ReadFolder → file3.txt
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status='error' and hasResult='error message' 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ x Ask User │
|
||||
│ │
|
||||
│ error message │
|
||||
@@ -10,7 +11,8 @@ exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status=
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status='success' and hasResult='test result' 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ Ask User │
|
||||
│ │
|
||||
│ test result │
|
||||
@@ -19,7 +21,8 @@ exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status=
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Ask User Filtering > shows other tools when ask_user is filtered out 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ other-tool A tool for testing │
|
||||
│ │
|
||||
│ Test result │
|
||||
@@ -28,7 +31,8 @@ exports[`<ToolGroupMessage /> > Ask User Filtering > shows other tools when ask_
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Border Color Logic > uses gray border when all tools are successful and no shell commands 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ test-tool A tool for testing │
|
||||
│ │
|
||||
│ Test result │
|
||||
@@ -41,7 +45,8 @@ exports[`<ToolGroupMessage /> > Border Color Logic > uses gray border when all t
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Border Color Logic > uses yellow border for shell commands even when successful 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ run_shell_command A tool for testing │
|
||||
│ │
|
||||
│ Test result │
|
||||
@@ -55,18 +60,19 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders header when scrolled
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool-1 Description 1. This is a long description that will need to b… │
|
||||
│──────────────────────────────────────────────────────────────────────────│
|
||||
│ line5 │ █
|
||||
│ │ █
|
||||
│ │ ▄
|
||||
│ ✓ tool-2 Description 2 │ █
|
||||
│ │ █
|
||||
│ line1 │ █
|
||||
│ line2 │ █
|
||||
╰──────────────────────────────────────────────────────────────────────────╯ █
|
||||
█
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders mixed tool calls including shell command 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ read_file Read a file │
|
||||
│ │
|
||||
│ Test result │
|
||||
@@ -83,7 +89,8 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders mixed tool calls incl
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders multiple tool calls with different statuses (only visible ones) 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ successful-tool This tool succeeded │
|
||||
│ │
|
||||
│ Test result │
|
||||
@@ -100,7 +107,8 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders multiple tool calls w
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders single successful tool call 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ test-tool A tool for testing │
|
||||
│ │
|
||||
│ Test result │
|
||||
@@ -109,7 +117,8 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders single successful too
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders tool call with outputFile 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool-with-file Tool that saved output to file │
|
||||
│ │
|
||||
│ Test result │
|
||||
@@ -119,17 +128,18 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders tool call with output
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders two tool groups where only the last line of the previous group is visible 1`] = `
|
||||
"╰──────────────────────────────────────────────────────────────────────────╯
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool-2 Description 2 │
|
||||
│ │ ▄
|
||||
│ line1 │ █
|
||||
│ │
|
||||
│ line1 │
|
||||
╰──────────────────────────────────────────────────────────────────────────╯ █
|
||||
█
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders with limited terminal height 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool-with-result Tool with output │
|
||||
│ │
|
||||
│ This is a long result that might need height constraints │
|
||||
@@ -142,7 +152,8 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders with limited terminal
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Golden Snapshots > renders with narrow terminal width 1`] = `
|
||||
"╭──────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────╮
|
||||
│ ✓ very-long-tool-name-that-mig… │
|
||||
│ │
|
||||
│ Test result │
|
||||
@@ -151,7 +162,8 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders with narrow terminal
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Height Calculation > calculates available height correctly with multiple tools with results 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
"
|
||||
╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ test-tool A tool for testing │
|
||||
│ │
|
||||
│ Result 1 │
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`ToolMessage Sticky Header Regression > verifies that ShellToolMessage in a ToolGroupMessage in a ScrollableList has sticky headers 1`] = `
|
||||
"╭────────────────────────────────────────────────────────────────────────╮ █
|
||||
│ ✓ Shell Command Description for Shell Command │ █
|
||||
" █
|
||||
╭────────────────────────────────────────────────────────────────────────╮ ▀
|
||||
│ ✓ Shell Command Description for Shell Command │
|
||||
│ │
|
||||
│ shell-01 │
|
||||
│ shell-02 │
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -13,17 +13,17 @@ exports[`ToolMessage Sticky Header Regression > verifies that ShellToolMessage i
|
||||
"╭────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ Shell Command Description for Shell Command │ ▄
|
||||
│────────────────────────────────────────────────────────────────────────│ █
|
||||
│ shell-06 │ ▀
|
||||
│ shell-07 │
|
||||
│ shell-05 │
|
||||
│ shell-06 │
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ToolMessage Sticky Header Regression > verifies that multiple ToolMessages in a ToolGroupMessage in a ScrollableList have sticky headers 1`] = `
|
||||
"╭────────────────────────────────────────────────────────────────────────╮ █
|
||||
" █
|
||||
╭────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool-1 Description for tool-1 │
|
||||
│ │
|
||||
│ c1-01 │
|
||||
│ c1-02 │
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -31,8 +31,8 @@ exports[`ToolMessage Sticky Header Regression > verifies that multiple ToolMessa
|
||||
"╭────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ tool-1 Description for tool-1 │ █
|
||||
│────────────────────────────────────────────────────────────────────────│
|
||||
│ c1-05 │
|
||||
│ c1-06 │
|
||||
│ c1-07 │
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -40,7 +40,7 @@ exports[`ToolMessage Sticky Header Regression > verifies that multiple ToolMessa
|
||||
"│ │
|
||||
│ ✓ tool-2 Description for tool-2 │
|
||||
│────────────────────────────────────────────────────────────────────────│
|
||||
│ c2-10 │
|
||||
╰────────────────────────────────────────────────────────────────────────╯ █
|
||||
│ c2-09 │ ▄
|
||||
│ c2-10 │ ▀
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -75,6 +75,9 @@ import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
import { useLogger } from './useLogger.js';
|
||||
import { SHELL_COMMAND_NAME } from '../constants.js';
|
||||
import { mapToDisplay as mapTrackedToolCallsToDisplay } from './toolMapping.js';
|
||||
import {
|
||||
isCompactTool,
|
||||
} from '../components/messages/ToolGroupMessage.js';
|
||||
import {
|
||||
useToolScheduler,
|
||||
type TrackedToolCall,
|
||||
@@ -291,9 +294,34 @@ export const useGeminiStream = (
|
||||
(tc) => !pushedToolCallIdsRef.current.has(tc.request.callId),
|
||||
);
|
||||
if (toolsToPush.length > 0) {
|
||||
const isCompactModeEnabled =
|
||||
settings.merged.ui?.compactToolOutput === true;
|
||||
const firstToolToPush = toolsToPush[0];
|
||||
const tcIndex = toolCalls.indexOf(firstToolToPush);
|
||||
const prevTool = tcIndex > 0 ? toolCalls[tcIndex - 1] : null;
|
||||
|
||||
let borderTop = isFirstToolInGroupRef.current;
|
||||
if (!borderTop && prevTool) {
|
||||
// If the first tool in this push is non-compact but follows a compact tool,
|
||||
// we must start a new border group.
|
||||
const currentIsCompact = isCompactTool(
|
||||
mapTrackedToolCallsToDisplay(firstToolToPush as TrackedToolCall)
|
||||
.tools[0],
|
||||
isCompactModeEnabled,
|
||||
);
|
||||
const prevWasCompact = isCompactTool(
|
||||
mapTrackedToolCallsToDisplay(prevTool as TrackedToolCall)
|
||||
.tools[0],
|
||||
isCompactModeEnabled,
|
||||
);
|
||||
if (!currentIsCompact && prevWasCompact) {
|
||||
borderTop = true;
|
||||
}
|
||||
}
|
||||
|
||||
addItem(
|
||||
mapTrackedToolCallsToDisplay(toolsToPush as TrackedToolCall[], {
|
||||
borderTop: isFirstToolInGroupRef.current,
|
||||
borderTop,
|
||||
borderBottom: true,
|
||||
borderColor: theme.border.default,
|
||||
borderDimColor: false,
|
||||
@@ -426,14 +454,18 @@ export const useGeminiStream = (
|
||||
if (toolsToPush.length > 0) {
|
||||
const newPushed = new Set(pushedToolCallIdsRef.current);
|
||||
let isFirst = isFirstToolInGroupRef.current;
|
||||
const isCompactModeEnabled =
|
||||
settings.merged.ui?.compactToolOutput === true;
|
||||
|
||||
for (const tc of toolsToPush) {
|
||||
newPushed.add(tc.request.callId);
|
||||
const tcIndex = toolCalls.indexOf(tc);
|
||||
const prevTool = tcIndex > 0 ? toolCalls[tcIndex - 1] : null;
|
||||
const nextTool =
|
||||
tcIndex < toolCalls.length - 1 ? toolCalls[tcIndex + 1] : null;
|
||||
const isLastInBatch = tc === toolCalls[toolCalls.length - 1];
|
||||
|
||||
const historyItem = mapTrackedToolCallsToDisplay(tc, {
|
||||
borderTop: isFirst,
|
||||
borderBottom: isLastInBatch,
|
||||
...getToolGroupBorderAppearance(
|
||||
{ type: 'tool_group', tools: toolCalls },
|
||||
activeShellPtyId,
|
||||
@@ -442,6 +474,33 @@ export const useGeminiStream = (
|
||||
backgroundShells,
|
||||
),
|
||||
});
|
||||
|
||||
const currentIsCompact = historyItem.tools[0]
|
||||
? isCompactTool(historyItem.tools[0], isCompactModeEnabled)
|
||||
: false;
|
||||
|
||||
let nextIsCompact = false;
|
||||
if (nextTool) {
|
||||
const nextHistoryItem = mapTrackedToolCallsToDisplay(nextTool);
|
||||
nextIsCompact = nextHistoryItem.tools[0]
|
||||
? isCompactTool(nextHistoryItem.tools[0], isCompactModeEnabled)
|
||||
: false;
|
||||
}
|
||||
|
||||
let prevWasCompact = false;
|
||||
if (prevTool) {
|
||||
const prevHistoryItem = mapTrackedToolCallsToDisplay(prevTool);
|
||||
prevWasCompact = prevHistoryItem.tools[0]
|
||||
? isCompactTool(prevHistoryItem.tools[0], isCompactModeEnabled)
|
||||
: false;
|
||||
}
|
||||
|
||||
historyItem.borderTop =
|
||||
isFirst || (!currentIsCompact && prevWasCompact);
|
||||
historyItem.borderBottom = currentIsCompact
|
||||
? isLastInBatch && !nextIsCompact
|
||||
: isLastInBatch || nextIsCompact;
|
||||
|
||||
addItem(historyItem);
|
||||
isFirst = false;
|
||||
}
|
||||
@@ -459,6 +518,7 @@ export const useGeminiStream = (
|
||||
activeShellPtyId,
|
||||
isShellFocused,
|
||||
backgroundShells,
|
||||
settings.merged.ui?.compactToolOutput,
|
||||
]);
|
||||
|
||||
const pendingToolGroupItems = useMemo((): HistoryItemWithoutId[] => {
|
||||
@@ -502,8 +562,7 @@ export const useGeminiStream = (
|
||||
toolCalls.length > 0 &&
|
||||
toolCalls.every((tc) => pushedToolCallIds.has(tc.request.callId));
|
||||
|
||||
const anyVisibleInHistory = pushedToolCallIds.size > 0;
|
||||
const anyVisibleInPending = remainingTools.some((tc) => {
|
||||
const isToolVisible = (tc: TrackedToolCall) => {
|
||||
// AskUser tools are rendered by AskUserDialog, not ToolGroupMessage
|
||||
const isInProgress =
|
||||
tc.status !== 'success' &&
|
||||
@@ -517,12 +576,28 @@ export const useGeminiStream = (
|
||||
tc.status !== 'validating' &&
|
||||
tc.status !== 'awaiting_approval'
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const anyVisibleInHistory = pushedToolCallIds.size > 0;
|
||||
const anyVisibleInPending = remainingTools.some(isToolVisible);
|
||||
|
||||
let lastVisibleIsCompact = false;
|
||||
const isCompactModeEnabled = settings.merged.ui?.compactToolOutput === true;
|
||||
for (let i = toolCalls.length - 1; i >= 0; i--) {
|
||||
if (isToolVisible(toolCalls[i])) {
|
||||
const mapped = mapTrackedToolCallsToDisplay(toolCalls[i]);
|
||||
lastVisibleIsCompact = mapped.tools[0]
|
||||
? isCompactTool(mapped.tools[0], isCompactModeEnabled)
|
||||
: false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
toolCalls.length > 0 &&
|
||||
!(allTerminal && allPushed) &&
|
||||
(anyVisibleInHistory || anyVisibleInPending)
|
||||
(anyVisibleInHistory || anyVisibleInPending) &&
|
||||
!lastVisibleIsCompact
|
||||
) {
|
||||
items.push({
|
||||
type: 'tool_group' as const,
|
||||
@@ -540,6 +615,7 @@ export const useGeminiStream = (
|
||||
activeShellPtyId,
|
||||
isShellFocused,
|
||||
backgroundShells,
|
||||
settings.merged.ui?.compactToolOutput,
|
||||
]);
|
||||
|
||||
const lastQueryRef = useRef<PartListUnion | null>(null);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="207" viewBox="0 0 920 207">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="224" viewBox="0 0 920 224">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="207" fill="#000000" />
|
||||
<rect width="920" height="224" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="18" y="19" fill="#4796e4" textLength="9" lengthAdjust="spacingAndGlyphs">▝</text>
|
||||
<text x="27" y="19" fill="#6688d9" textLength="9" lengthAdjust="spacingAndGlyphs">▜</text>
|
||||
@@ -17,16 +17,16 @@
|
||||
<text x="45" y="53" fill="#a471a7" textLength="9" lengthAdjust="spacingAndGlyphs">▀</text>
|
||||
<text x="18" y="70" fill="#4796e4" textLength="9" lengthAdjust="spacingAndGlyphs">▝</text>
|
||||
<text x="27" y="70" fill="#6688d9" textLength="9" lengthAdjust="spacingAndGlyphs">▀</text>
|
||||
<text x="0" y="104" fill="#ffffaf" textLength="864" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────────────────────────╮</text>
|
||||
<text x="0" y="121" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="121" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">⊶</text>
|
||||
<text x="45" y="121" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs" font-weight="bold">google_web_search</text>
|
||||
<text x="855" y="121" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#ffffaf" textLength="864" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────────────────────────╮</text>
|
||||
<text x="0" y="138" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="138" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">⊶</text>
|
||||
<text x="45" y="138" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs" font-weight="bold">google_web_search</text>
|
||||
<text x="855" y="138" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="155" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Searching...</text>
|
||||
<text x="855" y="155" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="172" fill="#ffffaf" textLength="864" lengthAdjust="spacingAndGlyphs">╰──────────────────────────────────────────────────────────────────────────────────────────────╯</text>
|
||||
<text x="0" y="172" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="172" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Searching...</text>
|
||||
<text x="855" y="172" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="189" fill="#ffffaf" textLength="864" lengthAdjust="spacingAndGlyphs">╰──────────────────────────────────────────────────────────────────────────────────────────────╯</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -1,8 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="207" viewBox="0 0 920 207">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="224" viewBox="0 0 920 224">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="207" fill="#000000" />
|
||||
<rect width="920" height="224" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="18" y="19" fill="#4796e4" textLength="9" lengthAdjust="spacingAndGlyphs">▝</text>
|
||||
<text x="27" y="19" fill="#6688d9" textLength="9" lengthAdjust="spacingAndGlyphs">▜</text>
|
||||
@@ -17,16 +17,16 @@
|
||||
<text x="45" y="53" fill="#a471a7" textLength="9" lengthAdjust="spacingAndGlyphs">▀</text>
|
||||
<text x="18" y="70" fill="#4796e4" textLength="9" lengthAdjust="spacingAndGlyphs">▝</text>
|
||||
<text x="27" y="70" fill="#6688d9" textLength="9" lengthAdjust="spacingAndGlyphs">▀</text>
|
||||
<text x="0" y="104" fill="#87afff" textLength="864" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────────────────────────╮</text>
|
||||
<text x="0" y="121" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="121" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">⊶</text>
|
||||
<text x="45" y="121" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs" font-weight="bold">run_shell_command</text>
|
||||
<text x="855" y="121" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#87afff" textLength="864" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────────────────────────╮</text>
|
||||
<text x="0" y="138" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="138" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">⊶</text>
|
||||
<text x="45" y="138" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs" font-weight="bold">run_shell_command</text>
|
||||
<text x="855" y="138" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="155" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Running command...</text>
|
||||
<text x="855" y="155" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="172" fill="#87afff" textLength="864" lengthAdjust="spacingAndGlyphs">╰──────────────────────────────────────────────────────────────────────────────────────────────╯</text>
|
||||
<text x="0" y="172" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="172" fill="#ffffff" textLength="162" lengthAdjust="spacingAndGlyphs">Running command...</text>
|
||||
<text x="855" y="172" fill="#87afff" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="189" fill="#87afff" textLength="864" lengthAdjust="spacingAndGlyphs">╰──────────────────────────────────────────────────────────────────────────────────────────────╯</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -1,8 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="207" viewBox="0 0 920 207">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="920" height="224" viewBox="0 0 920 224">
|
||||
<style>
|
||||
text { font-family: Consolas, "Courier New", monospace; font-size: 14px; dominant-baseline: text-before-edge; white-space: pre; }
|
||||
</style>
|
||||
<rect width="920" height="207" fill="#000000" />
|
||||
<rect width="920" height="224" fill="#000000" />
|
||||
<g transform="translate(10, 10)">
|
||||
<text x="18" y="19" fill="#4796e4" textLength="9" lengthAdjust="spacingAndGlyphs">▝</text>
|
||||
<text x="27" y="19" fill="#6688d9" textLength="9" lengthAdjust="spacingAndGlyphs">▜</text>
|
||||
@@ -17,16 +17,16 @@
|
||||
<text x="45" y="53" fill="#a471a7" textLength="9" lengthAdjust="spacingAndGlyphs">▀</text>
|
||||
<text x="18" y="70" fill="#4796e4" textLength="9" lengthAdjust="spacingAndGlyphs">▝</text>
|
||||
<text x="27" y="70" fill="#6688d9" textLength="9" lengthAdjust="spacingAndGlyphs">▀</text>
|
||||
<text x="0" y="104" fill="#ffffaf" textLength="864" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────────────────────────╮</text>
|
||||
<text x="0" y="121" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="121" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">⊶</text>
|
||||
<text x="45" y="121" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs" font-weight="bold">google_web_search</text>
|
||||
<text x="855" y="121" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="121" fill="#ffffaf" textLength="864" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────────────────────────╮</text>
|
||||
<text x="0" y="138" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="138" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">⊶</text>
|
||||
<text x="45" y="138" fill="#ffffff" textLength="153" lengthAdjust="spacingAndGlyphs" font-weight="bold">google_web_search</text>
|
||||
<text x="855" y="138" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="155" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="155" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Searching...</text>
|
||||
<text x="855" y="155" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="172" fill="#ffffaf" textLength="864" lengthAdjust="spacingAndGlyphs">╰──────────────────────────────────────────────────────────────────────────────────────────────╯</text>
|
||||
<text x="0" y="172" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="18" y="172" fill="#ffffff" textLength="108" lengthAdjust="spacingAndGlyphs">Searching...</text>
|
||||
<text x="855" y="172" fill="#ffffaf" textLength="9" lengthAdjust="spacingAndGlyphs">│</text>
|
||||
<text x="0" y="189" fill="#ffffaf" textLength="864" lengthAdjust="spacingAndGlyphs">╰──────────────────────────────────────────────────────────────────────────────────────────────╯</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -7,11 +7,13 @@ exports[`MainContent tool group border SVG snapshots > should render SVG snapsho
|
||||
▗▟▀
|
||||
▝▀
|
||||
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ google_web_search │
|
||||
│ │
|
||||
│ Searching... │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`MainContent tool group border SVG snapshots > should render SVG snapshot for a shell tool 1`] = `
|
||||
@@ -21,11 +23,13 @@ exports[`MainContent tool group border SVG snapshots > should render SVG snapsho
|
||||
▗▟▀
|
||||
▝▀
|
||||
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ run_shell_command │
|
||||
│ │
|
||||
│ Running command... │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`MainContent tool group border SVG snapshots > should render SVG snapshot for an empty slice following a search tool 1`] = `
|
||||
@@ -35,9 +39,11 @@ exports[`MainContent tool group border SVG snapshots > should render SVG snapsho
|
||||
▗▟▀
|
||||
▝▀
|
||||
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ⊶ google_web_search │
|
||||
│ │
|
||||
│ Searching... │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user