Add low/full CLI error verbosity mode for cleaner UI (#20399)

This commit is contained in:
Dmitry Lyalin
2026-02-27 14:15:10 -05:00
committed by GitHub
parent 1c8951334a
commit 7f8ce8657c
25 changed files with 689 additions and 32 deletions
+99 -3
View File
@@ -107,6 +107,11 @@ enum StreamProcessingStatus {
Error,
}
const SUPPRESSED_TOOL_ERRORS_NOTE =
'Some internal tool attempts failed before this final error. Press F12 for diagnostics, or set ui.errorVerbosity to full for full details.';
const LOW_VERBOSITY_FAILURE_NOTE =
'This request failed. Press F12 for diagnostics, or set ui.errorVerbosity to full for full details.';
function isShellToolData(data: unknown): data is ShellToolData {
if (typeof data !== 'object' || data === null) {
return false;
@@ -202,6 +207,10 @@ export const useGeminiStream = (
const [retryStatus, setRetryStatus] = useState<RetryAttemptPayload | null>(
null,
);
const isLowErrorVerbosity = settings.merged.ui?.errorVerbosity !== 'full';
const suppressedToolErrorCountRef = useRef(0);
const suppressedToolErrorNoteShownRef = useRef(false);
const lowVerbosityFailureNoteShownRef = useRef(false);
const abortControllerRef = useRef<AbortController | null>(null);
const turnCancelledRef = useRef(false);
const activeQueryIdRef = useRef<string | null>(null);
@@ -559,6 +568,51 @@ export const useGeminiStream = (
}
}, [isResponding]);
const maybeAddSuppressedToolErrorNote = useCallback(
(userMessageTimestamp?: number) => {
if (!isLowErrorVerbosity) {
return;
}
if (suppressedToolErrorCountRef.current === 0) {
return;
}
if (suppressedToolErrorNoteShownRef.current) {
return;
}
addItem(
{
type: MessageType.INFO,
text: SUPPRESSED_TOOL_ERRORS_NOTE,
},
userMessageTimestamp,
);
suppressedToolErrorNoteShownRef.current = true;
},
[addItem, isLowErrorVerbosity],
);
const maybeAddLowVerbosityFailureNote = useCallback(
(userMessageTimestamp?: number) => {
if (!isLowErrorVerbosity || config.getDebugMode()) {
return;
}
if (lowVerbosityFailureNoteShownRef.current) {
return;
}
addItem(
{
type: MessageType.INFO,
text: LOW_VERBOSITY_FAILURE_NOTE,
},
userMessageTimestamp,
);
lowVerbosityFailureNoteShownRef.current = true;
},
[addItem, config, isLowErrorVerbosity],
);
const cancelOngoingRequest = useCallback(() => {
if (
streamingState !== StreamingState.Responding &&
@@ -908,6 +962,7 @@ export const useGeminiStream = (
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
setPendingHistoryItem(null);
}
maybeAddSuppressedToolErrorNote(userMessageTimestamp);
addItem(
{
type: MessageType.ERROR,
@@ -921,9 +976,18 @@ export const useGeminiStream = (
},
userMessageTimestamp,
);
maybeAddLowVerbosityFailureNote(userMessageTimestamp);
setThought(null); // Reset thought when there's an error
},
[addItem, pendingHistoryItemRef, setPendingHistoryItem, config, setThought],
[
addItem,
pendingHistoryItemRef,
setPendingHistoryItem,
config,
setThought,
maybeAddSuppressedToolErrorNote,
maybeAddLowVerbosityFailureNote,
],
);
const handleCitationEvent = useCallback(
@@ -1086,6 +1150,7 @@ export const useGeminiStream = (
},
userMessageTimestamp,
);
maybeAddLowVerbosityFailureNote(userMessageTimestamp);
if (contextCleared) {
addItem(
{
@@ -1097,7 +1162,13 @@ export const useGeminiStream = (
}
setIsResponding(false);
},
[addItem, pendingHistoryItemRef, setPendingHistoryItem, setIsResponding],
[
addItem,
pendingHistoryItemRef,
setPendingHistoryItem,
setIsResponding,
maybeAddLowVerbosityFailureNote,
],
);
const handleAgentExecutionBlockedEvent = useCallback(
@@ -1118,6 +1189,7 @@ export const useGeminiStream = (
},
userMessageTimestamp,
);
maybeAddLowVerbosityFailureNote(userMessageTimestamp);
if (contextCleared) {
addItem(
{
@@ -1128,7 +1200,12 @@ export const useGeminiStream = (
);
}
},
[addItem, pendingHistoryItemRef, setPendingHistoryItem],
[
addItem,
pendingHistoryItemRef,
setPendingHistoryItem,
maybeAddLowVerbosityFailureNote,
],
);
const processGeminiStreamEvents = useCallback(
@@ -1286,6 +1363,9 @@ export const useGeminiStream = (
if (!options?.isContinuation) {
setModelSwitchedFromQuotaError(false);
config.setQuotaErrorOccurred(false);
suppressedToolErrorCountRef.current = 0;
suppressedToolErrorNoteShownRef.current = false;
lowVerbosityFailureNoteShownRef.current = false;
}
abortControllerRef.current = new AbortController();
@@ -1402,6 +1482,7 @@ export const useGeminiStream = (
) {
// Error was handled by validation dialog, don't display again
} else if (!isNodeError(error) || error.name !== 'AbortError') {
maybeAddSuppressedToolErrorNote(userMessageTimestamp);
addItem(
{
type: MessageType.ERROR,
@@ -1415,6 +1496,7 @@ export const useGeminiStream = (
},
userMessageTimestamp,
);
maybeAddLowVerbosityFailureNote(userMessageTimestamp);
}
} finally {
if (activeQueryIdRef.current === queryId) {
@@ -1439,6 +1521,8 @@ export const useGeminiStream = (
startNewPrompt,
getPromptCount,
setThought,
maybeAddSuppressedToolErrorNote,
maybeAddLowVerbosityFailureNote,
],
);
@@ -1587,6 +1671,13 @@ export const useGeminiStream = (
(t) => !t.request.isClientInitiated,
);
if (isLowErrorVerbosity) {
// Low-mode suppression applies only to model-initiated tool failures.
suppressedToolErrorCountRef.current += geminiTools.filter(
(tc) => tc.status === CoreToolCallStatus.Error,
).length;
}
if (geminiTools.length === 0) {
return;
}
@@ -1597,10 +1688,12 @@ export const useGeminiStream = (
);
if (stopExecutionTool && stopExecutionTool.response.error) {
maybeAddSuppressedToolErrorNote();
addItem({
type: MessageType.INFO,
text: `Agent execution stopped: ${stopExecutionTool.response.error.message}`,
});
maybeAddLowVerbosityFailureNote();
setIsResponding(false);
const callIdsToMarkAsSubmitted = geminiTools.map(
@@ -1706,6 +1799,9 @@ export const useGeminiStream = (
registerBackgroundShell,
consumeUserHint,
config,
isLowErrorVerbosity,
maybeAddSuppressedToolErrorNote,
maybeAddLowVerbosityFailureNote,
],
);