mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-16 00:51:25 -07:00
feat(cli): core logic for dense tool output and history merging
- Update useGeminiStream to detect dense tool batches (non-verbose, non-shell). - Update useHistoryManager to merge consecutive tool_group items into a single history entry. - Add unit tests for history manager merging logic.
This commit is contained in:
@@ -80,6 +80,8 @@ import { useSessionStats } from '../contexts/SessionContext.js';
|
||||
import { useKeypress } from './useKeypress.js';
|
||||
import type { LoadedSettings } from '../../config/settings.js';
|
||||
|
||||
import { isShellTool } from '../components/messages/ToolShared.js';
|
||||
|
||||
type ToolResponseWithParts = ToolCallResponseInfo & {
|
||||
llmContent?: PartListUnion;
|
||||
};
|
||||
@@ -356,6 +358,8 @@ export const useGeminiStream = (
|
||||
addItem,
|
||||
]);
|
||||
|
||||
const isVerboseMode = settings.merged.output?.verbosity === 'verbose';
|
||||
|
||||
const pendingToolGroupItems = useMemo((): HistoryItemWithoutId[] => {
|
||||
const remainingTools = toolCalls.filter(
|
||||
(tc) => !pushedToolCallIds.has(tc.request.callId),
|
||||
@@ -375,6 +379,14 @@ export const useGeminiStream = (
|
||||
// Always show a bottom border slice if we have ANY tools in the batch
|
||||
// and we haven't finished pushing the whole batch to history yet.
|
||||
// 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));
|
||||
|
||||
if (!requiresBoxLayout) {
|
||||
return items;
|
||||
}
|
||||
|
||||
const allTerminal =
|
||||
toolCalls.length > 0 &&
|
||||
toolCalls.every(
|
||||
@@ -419,7 +431,7 @@ export const useGeminiStream = (
|
||||
}
|
||||
|
||||
return items;
|
||||
}, [toolCalls, pushedToolCallIds]);
|
||||
}, [toolCalls, pushedToolCallIds, isVerboseMode]);
|
||||
|
||||
const activeToolPtyId = useMemo(() => {
|
||||
const executingShellTool = toolCalls.find(
|
||||
|
||||
@@ -323,4 +323,29 @@ describe('useHistoryManager', () => {
|
||||
expect(thirdItem.type).toBe('tool_group');
|
||||
expect(thirdItem.tools).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should update borderBottom when merging tool groups', () => {
|
||||
const { result } = renderHook(() => useHistory());
|
||||
const timestamp = Date.now();
|
||||
const toolGroup1: HistoryItemWithoutId = {
|
||||
type: 'tool_group',
|
||||
tools: [{ callId: '1', name: 'tool-a' } as IndividualToolCallDisplay],
|
||||
borderBottom: false,
|
||||
};
|
||||
const toolGroup2: HistoryItemWithoutId = {
|
||||
type: 'tool_group',
|
||||
tools: [{ callId: '2', name: 'tool-b' } as IndividualToolCallDisplay],
|
||||
borderBottom: true,
|
||||
};
|
||||
|
||||
act(() => {
|
||||
result.current.addItem(toolGroup1, timestamp);
|
||||
result.current.addItem(toolGroup2, timestamp + 1);
|
||||
});
|
||||
|
||||
expect(result.current.history).toHaveLength(1);
|
||||
const mergedItem = result.current.history[0] as HistoryItemToolGroup;
|
||||
expect(mergedItem.tools).toHaveLength(2);
|
||||
expect(mergedItem.borderBottom).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -78,6 +78,7 @@ export function useHistory({
|
||||
const updatedLastItem: HistoryItem = {
|
||||
...lastItem,
|
||||
tools: [...lastItem.tools, ...newItem.tools],
|
||||
borderBottom: newItem.borderBottom,
|
||||
};
|
||||
return [...prevHistory.slice(0, -1), updatedLastItem];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user