mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -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.',
|
description: 'Show the spinner during operations.',
|
||||||
showInDialog: true,
|
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: {
|
customWittyPhrases: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
label: 'Custom Witty Phrases',
|
label: 'Custom Witty Phrases',
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
|||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const { constrainHeight } = useUIState();
|
const { constrainHeight } = useUIState();
|
||||||
const { merged: settings } = useSettings();
|
const { merged: settings } = useSettings();
|
||||||
const isVerboseMode = settings.output?.verbosity === 'verbose';
|
const compactMode = settings.ui.enableCompactToolOutput;
|
||||||
|
|
||||||
const isEventDriven = config.isEventDrivenSchedulerEnabled();
|
const isEventDriven = config.isEventDrivenSchedulerEnabled();
|
||||||
|
|
||||||
@@ -74,18 +74,30 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
|||||||
// pre-execution states (Confirming, Pending) from the History log.
|
// pre-execution states (Confirming, Pending) from the History log.
|
||||||
// They live in the Global Queue or wait for their turn.
|
// They live in the Global Queue or wait for their turn.
|
||||||
const visibleToolCalls = useMemo(() => {
|
const visibleToolCalls = useMemo(() => {
|
||||||
if (!isEventDriven) {
|
// Standard filtering for Event Driven mode
|
||||||
return toolCalls;
|
const filteredTools = isEventDriven
|
||||||
}
|
? toolCalls.filter(
|
||||||
// Only show tools that are actually running or finished.
|
(t) =>
|
||||||
// We explicitly exclude Pending and Confirming to ensure they only
|
t.status !== ToolCallStatus.Pending &&
|
||||||
// appear in the Global Queue until they are approved and start executing.
|
t.status !== ToolCallStatus.Confirming,
|
||||||
return toolCalls.filter(
|
)
|
||||||
(t) =>
|
: toolCalls;
|
||||||
t.status !== ToolCallStatus.Pending &&
|
|
||||||
t.status !== ToolCallStatus.Confirming,
|
// Additional filtering for compact mode:
|
||||||
);
|
// In compact mode, we hide 'Pending' tools from the history log to avoid flickering
|
||||||
}, [toolCalls, isEventDriven]);
|
// 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) =>
|
const isEmbeddedShellFocused = visibleToolCalls.some((t) =>
|
||||||
isThisShellFocused(
|
isThisShellFocused(
|
||||||
@@ -172,9 +184,9 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
|||||||
const isFirst = index === 0;
|
const isFirst = index === 0;
|
||||||
const isShellToolCall = isShellTool(tool.name);
|
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 =
|
const useDenseView =
|
||||||
!isVerboseMode &&
|
compactMode &&
|
||||||
!isShellToolCall &&
|
!isShellToolCall &&
|
||||||
tool.status !== ToolCallStatus.Confirming;
|
tool.status !== ToolCallStatus.Confirming;
|
||||||
|
|
||||||
@@ -268,7 +280,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
|||||||
// HOWEVER, if borderBottomOverride is true, it means the scheduler explicitly
|
// 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
|
// 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.
|
// 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) {
|
if (borderBottomOverride !== undefined) {
|
||||||
return (
|
return (
|
||||||
@@ -292,8 +304,8 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
|||||||
const isShell = isShellTool(lastTool.name);
|
const isShell = isShellTool(lastTool.name);
|
||||||
const isConfirming = lastTool.status === ToolCallStatus.Confirming;
|
const isConfirming = lastTool.status === ToolCallStatus.Confirming;
|
||||||
|
|
||||||
// Logic: If dense view (not verbose, not shell, not confirming), hide border by default
|
// Logic: If dense view (compact mode, not shell, not confirming), hide border by default
|
||||||
const isDense = !isVerboseMode && !isShell && !isConfirming;
|
const isDense = compactMode && !isShell && !isConfirming;
|
||||||
|
|
||||||
if (isDense) return null;
|
if (isDense) return null;
|
||||||
|
|
||||||
@@ -319,7 +331,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
{!isVerboseMode
|
{compactMode
|
||||||
? null
|
? null
|
||||||
: (borderBottomOverride ?? true) &&
|
: (borderBottomOverride ?? true) &&
|
||||||
visibleToolCalls.length > 0 && (
|
visibleToolCalls.length > 0 && (
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ export const useGeminiStream = (
|
|||||||
addItem,
|
addItem,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const isVerboseMode = settings.merged.output?.verbosity === 'verbose';
|
const enableCompactToolOutput = settings.merged.ui.enableCompactToolOutput;
|
||||||
|
|
||||||
const pendingToolGroupItems = useMemo((): HistoryItemWithoutId[] => {
|
const pendingToolGroupItems = useMemo((): HistoryItemWithoutId[] => {
|
||||||
const remainingTools = toolCalls.filter(
|
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.
|
// 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).
|
// NOTE: In dense mode, we skip this if there are no shell tools (which require boxes).
|
||||||
const requiresBoxLayout =
|
const requiresBoxLayout =
|
||||||
isVerboseMode || toolCalls.some((tc) => isShellTool(tc.request.name));
|
!enableCompactToolOutput ||
|
||||||
|
toolCalls.some((tc) => isShellTool(tc.request.name));
|
||||||
|
|
||||||
if (!requiresBoxLayout) {
|
if (!requiresBoxLayout) {
|
||||||
return items;
|
return items;
|
||||||
@@ -431,7 +432,7 @@ export const useGeminiStream = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}, [toolCalls, pushedToolCallIds, isVerboseMode]);
|
}, [toolCalls, pushedToolCallIds, enableCompactToolOutput]);
|
||||||
|
|
||||||
const activeToolPtyId = useMemo(() => {
|
const activeToolPtyId = useMemo(() => {
|
||||||
const executingShellTool = toolCalls.find(
|
const executingShellTool = toolCalls.find(
|
||||||
|
|||||||
@@ -359,6 +359,13 @@
|
|||||||
"default": true,
|
"default": true,
|
||||||
"type": "boolean"
|
"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": {
|
"customWittyPhrases": {
|
||||||
"title": "Custom Witty Phrases",
|
"title": "Custom Witty Phrases",
|
||||||
"description": "Custom witty phrases to display during loading. When provided, the CLI cycles through these instead of the defaults.",
|
"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