diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx
index 2a9be3f7b5..2bda2d5b4e 100644
--- a/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx
+++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx
@@ -663,6 +663,31 @@ describe('', () => {
expect(output).toMatchSnapshot();
unmount();
});
+
+ it('renders nothing when only tool is in-progress AskUser with borderBottom=false', () => {
+ // AskUser tools in progress are rendered by AskUserDialog, not ToolGroupMessage.
+ // When AskUser is the only tool and borderBottom=false (no border to close),
+ // the component should render nothing.
+ const toolCalls = [
+ createToolCall({
+ callId: 'ask-user-tool',
+ name: 'Ask User',
+ status: ToolCallStatus.Executing,
+ }),
+ ];
+
+ const { lastFrame, unmount } = renderWithProviders(
+ ,
+ { config: baseMockConfig },
+ );
+ // AskUser tools in progress are rendered by AskUserDialog, so we expect nothing.
+ expect(lastFrame()).toMatchSnapshot();
+ unmount();
+ });
});
describe('Ask User Filtering', () => {
diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx
index 80c74baa58..14272995d5 100644
--- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx
+++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx
@@ -116,13 +116,11 @@ export const ToolGroupMessage: React.FC = ({
[toolCalls, isEventDriven],
);
- // If all tools are hidden (e.g. group only contains confirming or pending tools),
- // render nothing in the history log unless we have a border override.
- if (
- visibleToolCalls.length === 0 &&
- borderTopOverride === undefined &&
- borderBottomOverride === undefined
- ) {
+ // If all tools are filtered out (e.g., in-progress AskUser tools, confirming tools
+ // in event-driven mode), only render if we need to close a border from previous
+ // tool groups. borderBottomOverride=true means we must render the closing border;
+ // undefined or false means there's nothing to display.
+ if (visibleToolCalls.length === 0 && borderBottomOverride !== true) {
return null;
}
diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap
index 422c3de760..925568daa6 100644
--- a/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap
+++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap
@@ -110,6 +110,8 @@ exports[` > Confirmation Handling > shows confirmation dialo
exports[` > Event-Driven Scheduler > hides confirming tools when event-driven scheduler is enabled 1`] = `""`;
+exports[` > Event-Driven Scheduler > renders nothing when only tool is in-progress AskUser with borderBottom=false 1`] = `""`;
+
exports[` > Event-Driven Scheduler > shows only successful tools when mixed with confirming tools 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────╮
│ ✓ success-tool A tool for testing │
diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts
index 7ae0fdab6a..0d5260b82f 100644
--- a/packages/cli/src/ui/hooks/useGeminiStream.ts
+++ b/packages/cli/src/ui/hooks/useGeminiStream.ts
@@ -25,6 +25,7 @@ import {
debugLogger,
runInDevTraceSpan,
EDIT_TOOL_NAMES,
+ ASK_USER_TOOL_NAME,
processRestorableToolCalls,
recordToolCallInteractions,
ToolErrorType,
@@ -367,6 +368,14 @@ export const useGeminiStream = (
const isEventDriven = config.isEventDrivenSchedulerEnabled();
const anyVisibleInHistory = pushedToolCallIds.size > 0;
const anyVisibleInPending = remainingTools.some((tc) => {
+ // AskUser tools are rendered by AskUserDialog, not ToolGroupMessage
+ const isInProgress =
+ tc.status !== 'success' &&
+ tc.status !== 'error' &&
+ tc.status !== 'cancelled';
+ if (tc.request.name === ASK_USER_TOOL_NAME && isInProgress) {
+ return false;
+ }
if (!isEventDriven) return true;
return (
tc.status !== 'scheduled' &&