mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-22 07:41:23 -07:00
refactor(cli): migrate core tools to native ToolDisplay property and fix UI rendering (#25186)
This commit is contained in:
@@ -26,7 +26,7 @@ import type {
|
||||
HistoryItemWithoutId,
|
||||
LoopDetectionConfirmationRequest,
|
||||
IndividualToolCallDisplay,
|
||||
HistoryItemToolGroup,
|
||||
HistoryItemToolDisplayGroup,
|
||||
} from '../types.js';
|
||||
import { StreamingState, MessageType } from '../types.js';
|
||||
import { findLastSafeSplitPoint } from '../utils/markdownUtilities.js';
|
||||
@@ -81,6 +81,8 @@ export const useAgentStream = ({
|
||||
useStateAndRef<Set<string>>(new Set());
|
||||
const [_isFirstToolInGroup, isFirstToolInGroupRef, setIsFirstToolInGroup] =
|
||||
useStateAndRef<boolean>(true);
|
||||
const [_hasEmittedBoxInTurn, hasEmittedBoxInTurnRef, setHasEmittedBoxInTurn] =
|
||||
useStateAndRef<boolean>(false);
|
||||
|
||||
const { startNewPrompt } = useSessionStats();
|
||||
|
||||
@@ -408,32 +410,27 @@ export const useAgentStream = ({
|
||||
|
||||
// Push completed tools to history
|
||||
useEffect(() => {
|
||||
const toolsToPush: IndividualToolCallDisplay[] = [];
|
||||
for (let i = 0; i < trackedTools.length; i++) {
|
||||
const tc = trackedTools[i];
|
||||
if (pushedToolCallIdsRef.current.has(tc.callId)) continue;
|
||||
if (trackedTools.length === 0) return;
|
||||
|
||||
if (
|
||||
// We only push to history once all currently known tools in the turn are terminal.
|
||||
// This allows ToolGroupDisplay to correctly hoist ALL notices (topics) for the turn.
|
||||
const allTerminal = trackedTools.every(
|
||||
(tc) =>
|
||||
tc.status === 'success' ||
|
||||
tc.status === 'error' ||
|
||||
tc.status === 'cancelled'
|
||||
) {
|
||||
toolsToPush.push(tc);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tc.status === 'cancelled',
|
||||
);
|
||||
|
||||
if (toolsToPush.length > 0) {
|
||||
const toolsToPush = trackedTools.filter(
|
||||
(tc) => !pushedToolCallIdsRef.current.has(tc.callId),
|
||||
);
|
||||
|
||||
if (allTerminal && toolsToPush.length > 0) {
|
||||
const newPushed = new Set(pushedToolCallIdsRef.current);
|
||||
for (const tc of toolsToPush) {
|
||||
newPushed.add(tc.callId);
|
||||
}
|
||||
|
||||
const isLastInBatch =
|
||||
toolsToPush[toolsToPush.length - 1] ===
|
||||
trackedTools[trackedTools.length - 1];
|
||||
|
||||
const appearance = getToolGroupBorderAppearance(
|
||||
{ type: 'tool_group', tools: trackedTools },
|
||||
activePtyId,
|
||||
@@ -442,24 +439,43 @@ export const useAgentStream = ({
|
||||
backgroundTasks,
|
||||
);
|
||||
|
||||
const historyItem: HistoryItemToolGroup = {
|
||||
type: 'tool_group',
|
||||
tools: toolsToPush,
|
||||
borderTop: isFirstToolInGroupRef.current,
|
||||
borderBottom: isLastInBatch,
|
||||
const hasBoxInBatch = toolsToPush.some(
|
||||
(tc) => tc.display?.format !== 'notice',
|
||||
);
|
||||
const shouldStartNewBlock =
|
||||
isFirstToolInGroupRef.current ||
|
||||
(!hasEmittedBoxInTurnRef.current && hasBoxInBatch);
|
||||
|
||||
const historyItem: HistoryItemToolDisplayGroup = {
|
||||
type: 'tool_display_group',
|
||||
tools: toolsToPush.map((tc) => ({
|
||||
name: tc.name,
|
||||
description: tc.description,
|
||||
...tc.display,
|
||||
status: tc.status,
|
||||
originalRequestName: tc.originalRequestName,
|
||||
})),
|
||||
borderTop: shouldStartNewBlock,
|
||||
borderBottom: true,
|
||||
...appearance,
|
||||
};
|
||||
|
||||
addItem(historyItem);
|
||||
setPushedToolCallIds(newPushed);
|
||||
|
||||
if (hasBoxInBatch) {
|
||||
setHasEmittedBoxInTurn(true);
|
||||
}
|
||||
setIsFirstToolInGroup(false);
|
||||
}
|
||||
}, [
|
||||
trackedTools,
|
||||
pushedToolCallIdsRef,
|
||||
isFirstToolInGroupRef,
|
||||
hasEmittedBoxInTurnRef,
|
||||
setPushedToolCallIds,
|
||||
setIsFirstToolInGroup,
|
||||
setHasEmittedBoxInTurn,
|
||||
addItem,
|
||||
activePtyId,
|
||||
isShellFocused,
|
||||
@@ -468,7 +484,7 @@ export const useAgentStream = ({
|
||||
|
||||
const pendingToolGroupItems = useMemo((): HistoryItemWithoutId[] => {
|
||||
const remainingTools = trackedTools.filter(
|
||||
(tc) => !pushedToolCallIds.has(tc.callId),
|
||||
(tc) => !pushedToolCallIdsRef.current.has(tc.callId),
|
||||
);
|
||||
|
||||
const items: HistoryItemWithoutId[] = [];
|
||||
@@ -482,10 +498,23 @@ export const useAgentStream = ({
|
||||
);
|
||||
|
||||
if (remainingTools.length > 0) {
|
||||
const hasBoxInPending = remainingTools.some(
|
||||
(tc) => tc.display?.format !== 'notice',
|
||||
);
|
||||
const shouldStartNewBlock =
|
||||
pushedToolCallIds.size === 0 ||
|
||||
(!hasEmittedBoxInTurnRef.current && hasBoxInPending);
|
||||
|
||||
items.push({
|
||||
type: 'tool_group',
|
||||
tools: remainingTools,
|
||||
borderTop: pushedToolCallIds.size === 0,
|
||||
type: 'tool_display_group',
|
||||
tools: remainingTools.map((tc) => ({
|
||||
name: tc.name,
|
||||
description: tc.description,
|
||||
...tc.display,
|
||||
status: tc.status,
|
||||
originalRequestName: tc.originalRequestName,
|
||||
})),
|
||||
borderTop: shouldStartNewBlock,
|
||||
borderBottom: false,
|
||||
...appearance,
|
||||
});
|
||||
@@ -513,7 +542,7 @@ export const useAgentStream = ({
|
||||
(anyVisibleInHistory || anyVisibleInPending)
|
||||
) {
|
||||
items.push({
|
||||
type: 'tool_group' as const,
|
||||
type: 'tool_display_group',
|
||||
tools: [],
|
||||
borderTop: false,
|
||||
borderBottom: true,
|
||||
@@ -525,6 +554,8 @@ export const useAgentStream = ({
|
||||
}, [
|
||||
trackedTools,
|
||||
pushedToolCallIds,
|
||||
pushedToolCallIdsRef,
|
||||
hasEmittedBoxInTurnRef,
|
||||
activePtyId,
|
||||
isShellFocused,
|
||||
backgroundTasks,
|
||||
|
||||
Reference in New Issue
Block a user