mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-29 15:30:40 -07:00
feat(cli): decouple history filtering from tool output layout
- Introduce 'ui.enableCompactToolOutput' (default: true) to control tool output layout. - Separated the overloaded 'output.verbosity' setting into two distinct concerns: 'output.verbosity' now strictly filters history content, while 'ui.enableCompactToolOutput' toggles between dense and boxed layouts. - Update useGeminiStream and ToolGroupMessage to respect the new architectural separation.
This commit is contained in:
@@ -606,6 +606,16 @@ const SETTINGS_SCHEMA = {
|
||||
description: 'Show the spinner during operations.',
|
||||
showInDialog: true,
|
||||
},
|
||||
enableCompactToolOutput: {
|
||||
type: 'boolean',
|
||||
label: 'Enable Compact Tool Output',
|
||||
category: 'UI',
|
||||
requiresRestart: false,
|
||||
default: true,
|
||||
description:
|
||||
'Render tool outputs in a compact, single-line format when possible.',
|
||||
showInDialog: true,
|
||||
},
|
||||
customWittyPhrases: {
|
||||
type: 'array',
|
||||
label: 'Custom Witty Phrases',
|
||||
|
||||
@@ -66,7 +66,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
const config = useConfig();
|
||||
const { constrainHeight } = useUIState();
|
||||
const { merged: settings } = useSettings();
|
||||
const isVerboseMode = settings.output?.verbosity === 'verbose';
|
||||
const compactMode = settings.ui.enableCompactToolOutput;
|
||||
|
||||
const isEventDriven = config.isEventDrivenSchedulerEnabled();
|
||||
|
||||
@@ -74,18 +74,30 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
// pre-execution states (Confirming, Pending) from the History log.
|
||||
// They live in the Global Queue or wait for their turn.
|
||||
const visibleToolCalls = useMemo(() => {
|
||||
if (!isEventDriven) {
|
||||
return toolCalls;
|
||||
}
|
||||
// Only show tools that are actually running or finished.
|
||||
// We explicitly exclude Pending and Confirming to ensure they only
|
||||
// appear in the Global Queue until they are approved and start executing.
|
||||
return toolCalls.filter(
|
||||
(t) =>
|
||||
t.status !== ToolCallStatus.Pending &&
|
||||
t.status !== ToolCallStatus.Confirming,
|
||||
);
|
||||
}, [toolCalls, isEventDriven]);
|
||||
// Standard filtering for Event Driven mode
|
||||
const filteredTools = isEventDriven
|
||||
? toolCalls.filter(
|
||||
(t) =>
|
||||
t.status !== ToolCallStatus.Pending &&
|
||||
t.status !== ToolCallStatus.Confirming,
|
||||
)
|
||||
: toolCalls;
|
||||
|
||||
// Additional filtering for compact mode:
|
||||
// In compact mode, we hide 'Pending' tools from the history log to avoid flickering
|
||||
// unless we are in a non-compact (boxed) view where we want to show the placeholder.
|
||||
return filteredTools.filter((tool) => {
|
||||
const isShellToolCall = isShellTool(tool.name);
|
||||
const useDenseView =
|
||||
compactMode &&
|
||||
!isShellToolCall &&
|
||||
tool.status !== ToolCallStatus.Confirming;
|
||||
|
||||
if (!useDenseView) return true;
|
||||
// In dense view, we only show tools that have started or finished.
|
||||
return tool.status !== ToolCallStatus.Pending;
|
||||
});
|
||||
}, [toolCalls, isEventDriven, compactMode]);
|
||||
|
||||
const isEmbeddedShellFocused = visibleToolCalls.some((t) =>
|
||||
isThisShellFocused(
|
||||
@@ -172,9 +184,9 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
const isFirst = index === 0;
|
||||
const isShellToolCall = isShellTool(tool.name);
|
||||
|
||||
// Use dense view if not verbose, not a shell tool (for interactivity), and not confirming (needs prompt)
|
||||
// Use dense view if compact mode is enabled, not a shell tool (for interactivity), and not confirming (needs prompt)
|
||||
const useDenseView =
|
||||
!isVerboseMode &&
|
||||
compactMode &&
|
||||
!isShellToolCall &&
|
||||
tool.status !== ToolCallStatus.Confirming;
|
||||
|
||||
@@ -268,7 +280,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
// HOWEVER, if borderBottomOverride is true, it means the scheduler explicitly
|
||||
// wants to close a box. Since dense tools don't have boxes, this must be closing
|
||||
// a non-dense (e.g. shell) tool box. So we must allow it.
|
||||
if (!isVerboseMode && borderBottomOverride !== true) return null;
|
||||
if (compactMode && borderBottomOverride !== true) return null;
|
||||
|
||||
if (borderBottomOverride !== undefined) {
|
||||
return (
|
||||
@@ -292,8 +304,8 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
const isShell = isShellTool(lastTool.name);
|
||||
const isConfirming = lastTool.status === ToolCallStatus.Confirming;
|
||||
|
||||
// Logic: If dense view (not verbose, not shell, not confirming), hide border by default
|
||||
const isDense = !isVerboseMode && !isShell && !isConfirming;
|
||||
// Logic: If dense view (compact mode, not shell, not confirming), hide border by default
|
||||
const isDense = compactMode && !isShell && !isConfirming;
|
||||
|
||||
if (isDense) return null;
|
||||
|
||||
@@ -319,7 +331,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
/>
|
||||
);
|
||||
})()}
|
||||
{!isVerboseMode
|
||||
{compactMode
|
||||
? null
|
||||
: (borderBottomOverride ?? true) &&
|
||||
visibleToolCalls.length > 0 && (
|
||||
|
||||
@@ -358,7 +358,7 @@ export const useGeminiStream = (
|
||||
addItem,
|
||||
]);
|
||||
|
||||
const isVerboseMode = settings.merged.output?.verbosity === 'verbose';
|
||||
const enableCompactToolOutput = settings.merged.ui.enableCompactToolOutput;
|
||||
|
||||
const pendingToolGroupItems = useMemo((): HistoryItemWithoutId[] => {
|
||||
const remainingTools = toolCalls.filter(
|
||||
@@ -381,7 +381,8 @@ export const useGeminiStream = (
|
||||
// Once all tools are terminal and pushed, the last history item handles the closing border.
|
||||
// NOTE: In dense mode, we skip this if there are no shell tools (which require boxes).
|
||||
const requiresBoxLayout =
|
||||
isVerboseMode || toolCalls.some((tc) => isShellTool(tc.request.name));
|
||||
!enableCompactToolOutput ||
|
||||
toolCalls.some((tc) => isShellTool(tc.request.name));
|
||||
|
||||
if (!requiresBoxLayout) {
|
||||
return items;
|
||||
@@ -431,7 +432,7 @@ export const useGeminiStream = (
|
||||
}
|
||||
|
||||
return items;
|
||||
}, [toolCalls, pushedToolCallIds, isVerboseMode]);
|
||||
}, [toolCalls, pushedToolCallIds, enableCompactToolOutput]);
|
||||
|
||||
const activeToolPtyId = useMemo(() => {
|
||||
const executingShellTool = toolCalls.find(
|
||||
|
||||
@@ -359,6 +359,13 @@
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"enableCompactToolOutput": {
|
||||
"title": "Enable Compact Tool Output",
|
||||
"description": "Render tool outputs in a compact, single-line format when possible.",
|
||||
"markdownDescription": "Render tool outputs in a compact, single-line format when possible.\n\n- Category: `UI`\n- Requires restart: `no`\n- Default: `true`",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"customWittyPhrases": {
|
||||
"title": "Custom Witty Phrases",
|
||||
"description": "Custom witty phrases to display during loading. When provided, the CLI cycles through these instead of the defaults.",
|
||||
|
||||
Reference in New Issue
Block a user