feat(cli): remove output verbosity settings and logic

This commit is contained in:
Jarrod Whelan
2026-02-10 11:51:15 -08:00
parent f58d4ba696
commit fbfb2a72e3
15 changed files with 12 additions and 250 deletions

View File

@@ -862,7 +862,7 @@ Logging in with Google... Restarting Gemini CLI to continue.
const performMemoryRefresh = useCallback(async () => {
historyManager.addItem(
{
type: MessageType.VERBOSE,
type: MessageType.INFO,
text: 'Refreshing hierarchical memory (GEMINI.md or other context files)...',
},
Date.now(),
@@ -873,7 +873,7 @@ Logging in with Google... Restarting Gemini CLI to continue.
historyManager.addItem(
{
type: MessageType.VERBOSE,
type: MessageType.INFO,
text: `Memory refreshed successfully. ${
memoryContent.length > 0
? `Loaded ${memoryContent.length} characters from ${fileCount} file(s).`

View File

@@ -171,18 +171,6 @@ describe('<HistoryItemDisplay />', () => {
expect(lastFrame()).toContain('Agent powering down. Goodbye!');
});
it('renders InfoMessage for "debug" type with gear icon', () => {
const item: HistoryItem = {
...baseItem,
type: MessageType.DEBUG,
text: 'Debug info',
};
const { lastFrame } = renderWithProviders(
<HistoryItemDisplay {...baseItem} item={item} />,
);
expect(lastFrame()).toContain('⚙ Debug info');
});
it('should escape ANSI codes in text content', () => {
const historyItem: HistoryItem = {
id: 1,

View File

@@ -18,7 +18,6 @@ import { GeminiMessageContent } from './messages/GeminiMessageContent.js';
import { CompressionMessage } from './messages/CompressionMessage.js';
import { WarningMessage } from './messages/WarningMessage.js';
import { Box } from 'ink';
import { theme } from '../semantic-colors.js';
import { AboutBox } from './AboutBox.js';
import { StatsDisplay } from './StatsDisplay.js';
import { ModelStatsDisplay } from './ModelStatsDisplay.js';
@@ -97,27 +96,6 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
color={itemForDisplay.color}
/>
)}
{itemForDisplay.type === 'verbose' && (
<InfoMessage
text={itemForDisplay.text}
icon={itemForDisplay.icon || ' '}
color={theme.text.secondary}
/>
)}
{itemForDisplay.type === 'debug' && (
<InfoMessage
text={itemForDisplay.text}
icon={'⚙ '}
color={theme.text.accent}
/>
)}
{itemForDisplay.type === 'trace' && (
<InfoMessage
text={itemForDisplay.text}
icon={'🔍 '}
color={theme.text.accent}
/>
)}
{itemForDisplay.type === 'warning' && (
<WarningMessage text={itemForDisplay.text} />
)}

View File

@@ -14,7 +14,6 @@ import { useAlternateBuffer } from '../hooks/useAlternateBuffer.js';
import { ToolCallStatus } from '../types.js';
import { SHELL_COMMAND_NAME } from '../constants.js';
import type { UIState } from '../contexts/UIStateContext.js';
import type { HistoryItem } from '../types.js';
// Mock dependencies
vi.mock('../contexts/AppContext.js', async () => {
@@ -29,9 +28,6 @@ vi.mock('../contexts/AppContext.js', async () => {
const mockSettings = {
merged: {
output: {
verbosity: 'info',
},
ui: {
enableCompactToolOutput: false,
},
@@ -99,7 +95,6 @@ describe('MainContent', () => {
beforeEach(() => {
vi.mocked(useAlternateBuffer).mockReturnValue(false);
mockSettings.merged.output.verbosity = 'info';
mockSettings.merged.ui.enableCompactToolOutput = false;
});
@@ -248,38 +243,4 @@ describe('MainContent', () => {
},
);
});
it('filters out verbose items when verbosity is info', async () => {
const history: HistoryItem[] = [
{ id: 1, type: 'user', text: 'Visible User Message' },
{ id: 2, type: 'verbose', text: 'Hidden Verbose Log' },
];
mockSettings.merged.output.verbosity = 'info';
const { lastFrame } = renderWithProviders(<MainContent />, {
uiState: { ...defaultMockUiState, history } as Partial<UIState>,
});
await waitFor(() => expect(lastFrame()).toContain('AppHeader'));
const output = lastFrame();
expect(output).toContain('Visible User Message');
expect(output).not.toContain('Hidden Verbose Log');
});
it('shows verbose items when verbosity is verbose', async () => {
const history: HistoryItem[] = [
{ id: 1, type: 'user', text: 'Visible User Message' },
{ id: 2, type: 'verbose', text: 'Visible Verbose Log' },
];
mockSettings.merged.output.verbosity = 'verbose';
const { lastFrame } = renderWithProviders(<MainContent />, {
uiState: { ...defaultMockUiState, history } as Partial<UIState>,
});
await waitFor(() => expect(lastFrame()).toContain('AppHeader'));
const output = lastFrame();
expect(output).toContain('Visible User Message');
expect(output).toContain('Visible Verbose Log');
});
});

View File

@@ -20,8 +20,6 @@ import { MAX_GEMINI_MESSAGE_LINES } from '../constants.js';
import { useConfirmingTool } from '../hooks/useConfirmingTool.js';
import { ToolConfirmationQueue } from './ToolConfirmationQueue.js';
import { useConfig } from '../contexts/ConfigContext.js';
import { VERBOSITY_MAPPING, Verbosity } from '../types.js';
import { useSettings } from '../contexts/SettingsContext.js';
const MemoizedHistoryItemDisplay = memo(HistoryItemDisplay);
const MemoizedAppHeader = memo(AppHeader);
@@ -34,7 +32,6 @@ export const MainContent = () => {
const { version } = useAppContext();
const uiState = useUIState();
const config = useConfig();
const settings = useSettings();
const isAlternateBuffer = useAlternateBuffer();
const confirmingTool = useConfirmingTool();
@@ -56,24 +53,9 @@ export const MainContent = () => {
availableTerminalHeight,
} = uiState;
const currentVerbosity =
VERBOSITY_MAPPING[settings.merged.output?.verbosity ?? 'info'] ??
Verbosity.INFO;
const filteredHistory = useMemo(
() =>
uiState.history.filter((item) => {
const itemType = item.type;
const itemVerbosity =
item.verbosity ?? VERBOSITY_MAPPING[itemType] ?? Verbosity.INFO;
return itemVerbosity <= currentVerbosity;
}),
[uiState.history, currentVerbosity],
);
const historyItems = useMemo(
() =>
filteredHistory.map((h) => (
uiState.history.map((h) => (
<MemoizedHistoryItemDisplay
terminalWidth={mainAreaWidth}
availableTerminalHeight={staticAreaMaxItemHeight}
@@ -85,7 +67,7 @@ export const MainContent = () => {
/>
)),
[
filteredHistory,
uiState.history,
mainAreaWidth,
staticAreaMaxItemHeight,
uiState.slashCommands,
@@ -134,10 +116,10 @@ export const MainContent = () => {
const virtualizedData = useMemo(
() => [
{ type: 'header' as const },
...filteredHistory.map((item) => ({ type: 'history' as const, item })),
...uiState.history.map((item) => ({ type: 'history' as const, item })),
{ type: 'pending' as const },
],
[filteredHistory],
[uiState.history],
);
const renderItem = useCallback(

View File

@@ -8,7 +8,7 @@ import type {
HistoryItemWithoutId,
IndividualToolCallDisplay,
} from '../types.js';
import { ToolCallStatus, Verbosity } from '../types.js';
import { ToolCallStatus } from '../types.js';
import { useCallback, useReducer, useRef, useEffect } from 'react';
import type { AnsiOutput, Config, GeminiClient } from '@google/gemini-cli-core';
import { isBinary, ShellExecutionService } from '@google/gemini-cli-core';
@@ -487,7 +487,6 @@ export const useShellCommandProcessor = (
addItemToHistory(
{
type: 'tool_group',
verbosity: Verbosity.INFO,
tools: [finalToolDisplay],
} as HistoryItemWithoutId,
userMessageTimestamp,

View File

@@ -19,7 +19,7 @@ import {
type WaitingToolCall,
type CancelledToolCall,
} from '@google/gemini-cli-core';
import { ToolCallStatus, Verbosity } from '../types.js';
import { ToolCallStatus } from '../types.js';
describe('toolMapping', () => {
beforeEach(() => {
@@ -274,27 +274,5 @@ describe('toolMapping', () => {
expect(result.tools[0].resultDisplay).toBeUndefined();
expect(result.tools[0].status).toBe(ToolCallStatus.Pending);
});
it('sets verbosity to INFO for client-initiated tools', () => {
const toolCall: ScheduledToolCall = {
status: 'scheduled',
request: { ...mockRequest, isClientInitiated: true },
tool: mockTool,
invocation: mockInvocation,
};
const result = mapToDisplay(toolCall);
expect(result.verbosity).toBe(Verbosity.INFO);
});
it('sets verbosity to undefined (defaulting to VERBOSE) for autonomous tools', () => {
const toolCall: ScheduledToolCall = {
status: 'scheduled',
request: { ...mockRequest, isClientInitiated: false },
tool: mockTool,
invocation: mockInvocation,
};
const result = mapToDisplay(toolCall);
expect(result.verbosity).toBeUndefined();
});
});
});

View File

@@ -14,7 +14,6 @@ import {
} from '@google/gemini-cli-core';
import {
ToolCallStatus,
Verbosity,
type HistoryItemToolGroup,
type IndividualToolCallDisplay,
} from '../types.js';
@@ -55,9 +54,6 @@ export function mapToDisplay(
): HistoryItemToolGroup {
const toolCalls = Array.isArray(toolOrTools) ? toolOrTools : [toolOrTools];
const { borderTop, borderBottom } = options;
const isClientInitiated = toolCalls.some(
(tc) => tc.request.isClientInitiated,
);
const toolDisplays = toolCalls.map((call): IndividualToolCallDisplay => {
let description: string;
@@ -133,7 +129,6 @@ export function mapToDisplay(
return {
type: 'tool_group',
verbosity: isClientInitiated ? Verbosity.INFO : undefined,
tools: toolDisplays,
borderTop,
borderBottom,

View File

@@ -261,28 +261,6 @@ describe('useHistoryManager', () => {
});
});
it('should store all items regardless of verbosity level (filtering is done at render time)', () => {
// @ts-expect-error - verbosity prop was removed, but we want to ensure it's ignored if passed by mistake
const { result } = renderHook(() => useHistory({ verbosity: 'info' }));
const timestamp = Date.now();
const verboseItem: HistoryItemWithoutId = {
type: 'verbose',
text: 'Hidden detail',
verbosity: 3, // Verbosity.VERBOSE
};
act(() => {
result.current.addItem(verboseItem, timestamp);
});
expect(result.current.history).toHaveLength(1);
expect(result.current.history[0]).toEqual(
expect.objectContaining({
text: 'Hidden detail',
}),
);
});
it('should merge consecutive tool_group items', () => {
const { result } = renderHook(() => useHistory());
const timestamp = Date.now();

View File

@@ -103,7 +103,6 @@ export function useHistory({
switch (itemData.type) {
case 'compression':
case 'verbose':
case 'info':
chatRecordingService?.recordMessage({
model: undefined,

View File

@@ -101,7 +101,6 @@ export const emptyIcon = ' ';
export interface HistoryItemBase {
text?: string; // Text content for user/gemini/info/error messages
verbosity?: Verbosity;
}
export type HistoryItemUser = HistoryItemBase & {
@@ -136,23 +135,6 @@ export type HistoryItemWarning = HistoryItemBase & {
text: string;
};
export type HistoryItemVerbose = HistoryItemBase & {
type: 'verbose';
text: string;
icon?: string;
color?: string;
};
export type HistoryItemDebug = HistoryItemBase & {
type: 'debug';
text: string;
};
export type HistoryItemTrace = HistoryItemBase & {
type: 'trace';
text: string;
};
export type HistoryItemAbout = HistoryItemBase & {
type: 'about';
cliVersion: string;
@@ -336,9 +318,6 @@ export type HistoryItemWithoutId =
| HistoryItemInfo
| HistoryItemError
| HistoryItemWarning
| HistoryItemVerbose
| HistoryItemDebug
| HistoryItemTrace
| HistoryItemAbout
| HistoryItemHelp
| HistoryItemToolGroup
@@ -363,9 +342,6 @@ export type HistoryItem = HistoryItemWithoutId & { id: number };
// Message types used by internal command feedback (subset of HistoryItem types)
export enum MessageType {
INFO = 'info',
VERBOSE = 'verbose',
DEBUG = 'debug',
TRACE = 'trace',
ERROR = 'error',
WARNING = 'warning',
USER = 'user',
@@ -386,52 +362,10 @@ export enum MessageType {
HOOKS_LIST = 'hooks_list',
}
export enum Verbosity {
ERROR = 0,
WARN = 1,
INFO = 2,
VERBOSE = 3,
DEBUG = 4,
TRACE = 5,
}
export const VERBOSITY_MAPPING: Record<HistoryItemType, Verbosity> = {
error: Verbosity.ERROR,
warning: Verbosity.WARN,
info: Verbosity.INFO,
user: Verbosity.INFO,
gemini: Verbosity.INFO,
gemini_content: Verbosity.INFO,
tool_group: Verbosity.INFO,
user_shell: Verbosity.INFO,
about: Verbosity.INFO,
stats: Verbosity.INFO,
model_stats: Verbosity.INFO,
tool_stats: Verbosity.INFO,
model: Verbosity.INFO,
quit: Verbosity.INFO,
extensions_list: Verbosity.INFO,
tools_list: Verbosity.INFO,
skills_list: Verbosity.INFO,
agents_list: Verbosity.INFO,
mcp_status: Verbosity.INFO,
chat_list: Verbosity.INFO,
hooks_list: Verbosity.INFO,
help: Verbosity.INFO,
verbose: Verbosity.VERBOSE,
compression: Verbosity.VERBOSE,
debug: Verbosity.DEBUG,
trace: Verbosity.TRACE,
};
// Simplified message structure for internal feedback
export type Message =
| {
type:
| MessageType.INFO
| MessageType.VERBOSE
| MessageType.ERROR
| MessageType.USER;
type: MessageType.INFO | MessageType.ERROR | MessageType.USER;
content: string; // Renamed from text for clarity in this context
timestamp: Date;
}