mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 21:03:05 -07:00
refactor: use CoreToolCallStatus in the the history data model (#19033)
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
||||
uiTelemetryService,
|
||||
FatalInputError,
|
||||
CoreEvent,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { Part } from '@google/genai';
|
||||
import { runNonInteractive } from './nonInteractiveCli.js';
|
||||
@@ -327,7 +328,7 @@ describe('runNonInteractive', () => {
|
||||
const toolResponse: Part[] = [{ text: 'Tool response' }];
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
request: {
|
||||
callId: 'tool-1',
|
||||
name: 'testTool',
|
||||
@@ -403,7 +404,7 @@ describe('runNonInteractive', () => {
|
||||
// 2. Mock the execution of the tools. We just need them to succeed.
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
request: toolCallEvent.value, // This is generic enough for both calls
|
||||
tool: {} as AnyDeclarativeTool,
|
||||
invocation: {} as AnyToolInvocation,
|
||||
@@ -469,7 +470,7 @@ describe('runNonInteractive', () => {
|
||||
};
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'error',
|
||||
status: CoreToolCallStatus.Error,
|
||||
request: {
|
||||
callId: 'tool-1',
|
||||
name: 'errorTool',
|
||||
@@ -573,7 +574,7 @@ describe('runNonInteractive', () => {
|
||||
};
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'error',
|
||||
status: CoreToolCallStatus.Error,
|
||||
request: {
|
||||
callId: 'tool-1',
|
||||
name: 'nonexistentTool',
|
||||
@@ -748,7 +749,7 @@ describe('runNonInteractive', () => {
|
||||
const toolResponse: Part[] = [{ text: 'Tool executed successfully' }];
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
request: {
|
||||
callId: 'tool-1',
|
||||
name: 'testTool',
|
||||
@@ -1344,7 +1345,7 @@ describe('runNonInteractive', () => {
|
||||
const toolResponse: Part[] = [{ text: 'file.txt' }];
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
request: {
|
||||
callId: 'tool-shell-1',
|
||||
name: 'ShellTool',
|
||||
@@ -1543,7 +1544,7 @@ describe('runNonInteractive', () => {
|
||||
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
request: toolCallEvent.value,
|
||||
tool: {} as AnyDeclarativeTool,
|
||||
invocation: {} as AnyToolInvocation,
|
||||
@@ -1735,7 +1736,7 @@ describe('runNonInteractive', () => {
|
||||
};
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
request: toolCallEvent.value,
|
||||
tool: {} as AnyDeclarativeTool,
|
||||
invocation: {} as AnyToolInvocation,
|
||||
@@ -1818,7 +1819,7 @@ describe('runNonInteractive', () => {
|
||||
// Mock tool execution returning STOP_EXECUTION
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'error',
|
||||
status: CoreToolCallStatus.Error,
|
||||
request: toolCallEvent.value,
|
||||
tool: {} as AnyDeclarativeTool,
|
||||
invocation: {} as AnyToolInvocation,
|
||||
@@ -1880,7 +1881,7 @@ describe('runNonInteractive', () => {
|
||||
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'error',
|
||||
status: CoreToolCallStatus.Error,
|
||||
request: toolCallEvent.value,
|
||||
tool: {} as AnyDeclarativeTool,
|
||||
invocation: {} as AnyToolInvocation,
|
||||
@@ -1944,7 +1945,7 @@ describe('runNonInteractive', () => {
|
||||
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'error',
|
||||
status: CoreToolCallStatus.Error,
|
||||
request: toolCallEvent.value,
|
||||
tool: {} as AnyDeclarativeTool,
|
||||
invocation: {} as AnyToolInvocation,
|
||||
@@ -2187,7 +2188,7 @@ describe('runNonInteractive', () => {
|
||||
// Mock the scheduler to return a cancelled status
|
||||
mockSchedulerSchedule.mockResolvedValue([
|
||||
{
|
||||
status: 'cancelled',
|
||||
status: CoreToolCallStatus.Cancelled,
|
||||
request: toolCallEvent.value,
|
||||
tool: {} as AnyDeclarativeTool,
|
||||
invocation: {} as AnyToolInvocation,
|
||||
|
||||
@@ -10,8 +10,8 @@ import { renderWithProviders } from '../test-utils/render.js';
|
||||
import { Text, useIsScreenReaderEnabled, type DOMElement } from 'ink';
|
||||
import { App } from './App.js';
|
||||
import { type UIState } from './contexts/UIStateContext.js';
|
||||
import { StreamingState, ToolCallStatus } from './types.js';
|
||||
import { makeFakeConfig } from '@google/gemini-cli-core';
|
||||
import { StreamingState } from './types.js';
|
||||
import { makeFakeConfig, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
vi.mock('ink', async (importOriginal) => {
|
||||
const original = await importOriginal<typeof import('ink')>();
|
||||
@@ -202,7 +202,7 @@ describe('App', () => {
|
||||
callId: 'call-1',
|
||||
name: 'ls',
|
||||
description: 'list directory',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
resultDisplay: '',
|
||||
confirmationDetails: {
|
||||
type: 'exec' as const,
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
type ResumedSessionData,
|
||||
AuthType,
|
||||
type AgentDefinition,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
|
||||
// Mock coreEvents
|
||||
@@ -1412,7 +1413,7 @@ describe('AppContainer State Management', () => {
|
||||
name: 'run_shell_command',
|
||||
args: { command: 'ls > out' },
|
||||
},
|
||||
status: 'executing',
|
||||
status: CoreToolCallStatus.Executing,
|
||||
} as unknown as TrackedToolCall,
|
||||
],
|
||||
activePtyId: 'pty-1',
|
||||
|
||||
@@ -30,7 +30,6 @@ import {
|
||||
import { ConfigContext } from './contexts/ConfigContext.js';
|
||||
import {
|
||||
type HistoryItem,
|
||||
ToolCallStatus,
|
||||
type HistoryItemWithoutId,
|
||||
type HistoryItemToolGroup,
|
||||
AuthState,
|
||||
@@ -79,6 +78,7 @@ import {
|
||||
type ConsentRequestPayload,
|
||||
type AgentsDiscoveredPayload,
|
||||
ChangeAuthRequestedError,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { validateAuthMethod } from '../config/auth.js';
|
||||
import process from 'node:process';
|
||||
@@ -161,7 +161,7 @@ function isToolExecuting(pendingHistoryItems: HistoryItemWithoutId[]) {
|
||||
return pendingHistoryItems.some((item) => {
|
||||
if (item && item.type === 'tool_group') {
|
||||
return item.tools.some(
|
||||
(tool) => ToolCallStatus.Executing === tool.status,
|
||||
(tool) => CoreToolCallStatus.Executing === tool.status,
|
||||
);
|
||||
}
|
||||
return false;
|
||||
@@ -174,7 +174,9 @@ function isToolAwaitingConfirmation(
|
||||
return pendingHistoryItems
|
||||
.filter((item): item is HistoryItemToolGroup => item.type === 'tool_group')
|
||||
.some((item) =>
|
||||
item.tools.some((tool) => ToolCallStatus.Confirming === tool.status),
|
||||
item.tools.some(
|
||||
(tool) => CoreToolCallStatus.AwaitingApproval === tool.status,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
} from '../../test-utils/render.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { AlternateBufferQuittingDisplay } from './AlternateBufferQuittingDisplay.js';
|
||||
import { ToolCallStatus } from '../types.js';
|
||||
import type { HistoryItem, HistoryItemWithoutId } from '../types.js';
|
||||
import { Text } from 'ink';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
vi.mock('../utils/terminalSetup.js', () => ({
|
||||
getTerminalProgram: () => null,
|
||||
@@ -51,7 +51,7 @@ const mockHistory: HistoryItem[] = [
|
||||
callId: 'call1',
|
||||
name: 'tool1',
|
||||
description: 'Description for tool 1',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: undefined,
|
||||
confirmationDetails: undefined,
|
||||
},
|
||||
@@ -65,7 +65,7 @@ const mockHistory: HistoryItem[] = [
|
||||
callId: 'call2',
|
||||
name: 'tool2',
|
||||
description: 'Description for tool 2',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: undefined,
|
||||
confirmationDetails: undefined,
|
||||
},
|
||||
@@ -81,7 +81,7 @@ const mockPendingHistoryItems: HistoryItemWithoutId[] = [
|
||||
callId: 'call3',
|
||||
name: 'tool3',
|
||||
description: 'Description for tool 3',
|
||||
status: ToolCallStatus.Pending,
|
||||
status: CoreToolCallStatus.Scheduled,
|
||||
resultDisplay: undefined,
|
||||
confirmationDetails: undefined,
|
||||
},
|
||||
@@ -176,7 +176,7 @@ describe('AlternateBufferQuittingDisplay', () => {
|
||||
callId: 'call4',
|
||||
name: 'confirming_tool',
|
||||
description: 'Confirming tool description',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
resultDisplay: undefined,
|
||||
confirmationDetails: {
|
||||
type: 'info',
|
||||
|
||||
@@ -24,9 +24,13 @@ vi.mock('../contexts/VimModeContext.js', () => ({
|
||||
vimMode: 'INSERT',
|
||||
})),
|
||||
}));
|
||||
import { ApprovalMode, tokenLimit } from '@google/gemini-cli-core';
|
||||
import {
|
||||
ApprovalMode,
|
||||
tokenLimit,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { Config } from '@google/gemini-cli-core';
|
||||
import { StreamingState, ToolCallStatus } from '../types.js';
|
||||
import { StreamingState } from '../types.js';
|
||||
import { TransientMessageType } from '../../utils/events.js';
|
||||
import type { LoadedSettings } from '../../config/settings.js';
|
||||
import type { SessionMetrics } from '../contexts/SessionContext.js';
|
||||
@@ -426,7 +430,7 @@ describe('Composer', () => {
|
||||
callId: 'call-1',
|
||||
name: 'edit',
|
||||
description: 'edit file',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
resultDisplay: undefined,
|
||||
confirmationDetails: undefined,
|
||||
},
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { Box, Text, useIsScreenReaderEnabled } from 'ink';
|
||||
import { ApprovalMode, tokenLimit } from '@google/gemini-cli-core';
|
||||
import {
|
||||
ApprovalMode,
|
||||
tokenLimit,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { LoadingIndicator } from './LoadingIndicator.js';
|
||||
import { StatusDisplay } from './StatusDisplay.js';
|
||||
import { ToastDisplay, shouldShowToast } from './ToastDisplay.js';
|
||||
@@ -30,11 +34,7 @@ import { useVimMode } from '../contexts/VimModeContext.js';
|
||||
import { useConfig } from '../contexts/ConfigContext.js';
|
||||
import { useSettings } from '../contexts/SettingsContext.js';
|
||||
import { useAlternateBuffer } from '../hooks/useAlternateBuffer.js';
|
||||
import {
|
||||
StreamingState,
|
||||
type HistoryItemToolGroup,
|
||||
ToolCallStatus,
|
||||
} from '../types.js';
|
||||
import { StreamingState, type HistoryItemToolGroup } from '../types.js';
|
||||
import { ConfigInitDisplay } from '../components/ConfigInitDisplay.js';
|
||||
import { TodoTray } from './messages/Todo.js';
|
||||
import { getInlineThinkingMode } from '../utils/inlineThinkingMode.js';
|
||||
@@ -67,7 +67,9 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
|
||||
(item): item is HistoryItemToolGroup => item.type === 'tool_group',
|
||||
)
|
||||
.some((item) =>
|
||||
item.tools.some((tool) => tool.status === ToolCallStatus.Confirming),
|
||||
item.tools.some(
|
||||
(tool) => tool.status === CoreToolCallStatus.AwaitingApproval,
|
||||
),
|
||||
),
|
||||
[uiState.pendingHistoryItems],
|
||||
);
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { HistoryItemDisplay } from './HistoryItemDisplay.js';
|
||||
import { type HistoryItem, ToolCallStatus } from '../types.js';
|
||||
import { type HistoryItem } from '../types.js';
|
||||
import { MessageType } from '../types.js';
|
||||
import { SessionStatsProvider } from '../contexts/SessionContext.js';
|
||||
import type {
|
||||
Config,
|
||||
ToolExecuteConfirmationDetails,
|
||||
import {
|
||||
type Config,
|
||||
type ToolExecuteConfirmationDetails,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { ToolGroupMessage } from './messages/ToolGroupMessage.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
@@ -203,7 +204,7 @@ describe('<HistoryItemDisplay />', () => {
|
||||
name: 'run_shell_command',
|
||||
description: 'Run a shell command',
|
||||
resultDisplay: 'blank',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: {
|
||||
type: 'exec',
|
||||
title: 'Run Shell Command',
|
||||
|
||||
@@ -11,13 +11,13 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { Box, Text } from 'ink';
|
||||
import { act, useState, type JSX } from 'react';
|
||||
import { useAlternateBuffer } from '../hooks/useAlternateBuffer.js';
|
||||
import { ToolCallStatus } from '../types.js';
|
||||
import { SHELL_COMMAND_NAME } from '../constants.js';
|
||||
import {
|
||||
UIStateContext,
|
||||
useUIState,
|
||||
type UIState,
|
||||
} from '../contexts/UIStateContext.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('../contexts/SettingsContext.js', async () => {
|
||||
@@ -264,7 +264,7 @@ describe('MainContent', () => {
|
||||
{
|
||||
callId: 'call_1',
|
||||
name: SHELL_COMMAND_NAME,
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
description: 'Running a long command...',
|
||||
// 20 lines of output.
|
||||
// Default max is 15, so Line 1-5 will be truncated/scrolled out if not expanded.
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { Box } from 'ink';
|
||||
import { ToolConfirmationQueue } from './ToolConfirmationQueue.js';
|
||||
import { ToolCallStatus, StreamingState } from '../types.js';
|
||||
import { StreamingState } from '../types.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import type { Config } from '@google/gemini-cli-core';
|
||||
import { type Config, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import type { ConfirmingToolState } from '../hooks/useConfirmingTool.js';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
|
||||
@@ -63,7 +63,7 @@ describe('ToolConfirmationQueue', () => {
|
||||
callId: 'call-1',
|
||||
name: 'ls',
|
||||
description: 'list files',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: {
|
||||
type: 'exec' as const,
|
||||
title: 'Confirm execution',
|
||||
@@ -105,7 +105,7 @@ describe('ToolConfirmationQueue', () => {
|
||||
tool: {
|
||||
callId: 'call-1',
|
||||
name: 'ls',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: undefined,
|
||||
},
|
||||
index: 1,
|
||||
@@ -134,7 +134,7 @@ describe('ToolConfirmationQueue', () => {
|
||||
callId: 'call-1',
|
||||
name: 'replace',
|
||||
description: 'edit file',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: {
|
||||
type: 'edit' as const,
|
||||
title: 'Confirm edit',
|
||||
@@ -181,7 +181,7 @@ describe('ToolConfirmationQueue', () => {
|
||||
callId: 'call-1',
|
||||
name: 'replace',
|
||||
description: 'edit file',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: {
|
||||
type: 'edit' as const,
|
||||
title: 'Confirm edit',
|
||||
@@ -230,7 +230,7 @@ describe('ToolConfirmationQueue', () => {
|
||||
callId: 'call-1',
|
||||
name: 'replace',
|
||||
description: 'edit file',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: {
|
||||
type: 'edit' as const,
|
||||
title: 'Confirm edit',
|
||||
@@ -271,7 +271,7 @@ describe('ToolConfirmationQueue', () => {
|
||||
callId: 'call-1',
|
||||
name: 'ask_user',
|
||||
description: 'ask user',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: {
|
||||
type: 'ask_user' as const,
|
||||
questions: [],
|
||||
@@ -307,7 +307,7 @@ describe('ToolConfirmationQueue', () => {
|
||||
callId: 'call-1',
|
||||
name: 'exit_plan_mode',
|
||||
description: 'exit plan mode',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: {
|
||||
type: 'exit_plan_mode' as const,
|
||||
planPath: '/path/to/plan',
|
||||
|
||||
@@ -9,12 +9,15 @@ import {
|
||||
ShellToolMessage,
|
||||
type ShellToolMessageProps,
|
||||
} from './ShellToolMessage.js';
|
||||
import { StreamingState, ToolCallStatus } from '../../types.js';
|
||||
import type { Config } from '@google/gemini-cli-core';
|
||||
import { StreamingState } from '../../types.js';
|
||||
import {
|
||||
type Config,
|
||||
SHELL_TOOL_NAME,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { SHELL_TOOL_NAME } from '@google/gemini-cli-core';
|
||||
import { SHELL_COMMAND_NAME, ACTIVE_SHELL_MAX_LINES } from '../../constants.js';
|
||||
|
||||
describe('<ShellToolMessage />', () => {
|
||||
@@ -23,7 +26,7 @@ describe('<ShellToolMessage />', () => {
|
||||
name: SHELL_COMMAND_NAME,
|
||||
description: 'A shell command',
|
||||
resultDisplay: 'Test result',
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
terminalWidth: 80,
|
||||
confirmationDetails: undefined,
|
||||
emphasis: 'medium',
|
||||
@@ -78,10 +81,12 @@ describe('<ShellToolMessage />', () => {
|
||||
});
|
||||
});
|
||||
it('resets focus when shell finishes', async () => {
|
||||
let updateStatus: (s: ToolCallStatus) => void = () => {};
|
||||
let updateStatus: (s: CoreToolCallStatus) => void = () => {};
|
||||
|
||||
const Wrapper = () => {
|
||||
const [status, setStatus] = React.useState(ToolCallStatus.Executing);
|
||||
const [status, setStatus] = React.useState(
|
||||
CoreToolCallStatus.Executing,
|
||||
);
|
||||
updateStatus = setStatus;
|
||||
return (
|
||||
<ShellToolMessage
|
||||
@@ -106,7 +111,7 @@ describe('<ShellToolMessage />', () => {
|
||||
|
||||
// Now update status to Success
|
||||
await act(async () => {
|
||||
updateStatus(ToolCallStatus.Success);
|
||||
updateStatus(CoreToolCallStatus.Success);
|
||||
});
|
||||
|
||||
// Should call setEmbeddedShellFocused(false) because isThisShellFocused became false
|
||||
@@ -121,23 +126,23 @@ describe('<ShellToolMessage />', () => {
|
||||
it.each([
|
||||
[
|
||||
'renders in Executing state',
|
||||
{ status: ToolCallStatus.Executing },
|
||||
{ status: CoreToolCallStatus.Executing },
|
||||
undefined,
|
||||
],
|
||||
[
|
||||
'renders in Success state (history mode)',
|
||||
{ status: ToolCallStatus.Success },
|
||||
{ status: CoreToolCallStatus.Success },
|
||||
undefined,
|
||||
],
|
||||
[
|
||||
'renders in Error state',
|
||||
{ status: ToolCallStatus.Error, resultDisplay: 'Error output' },
|
||||
{ status: CoreToolCallStatus.Error, resultDisplay: 'Error output' },
|
||||
undefined,
|
||||
],
|
||||
[
|
||||
'renders in Alternate Buffer mode while focused',
|
||||
{
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
embeddedShellFocused: true,
|
||||
activeShellPtyId: 1,
|
||||
ptyId: 1,
|
||||
@@ -147,7 +152,7 @@ describe('<ShellToolMessage />', () => {
|
||||
[
|
||||
'renders in Alternate Buffer mode while unfocused',
|
||||
{
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
embeddedShellFocused: false,
|
||||
activeShellPtyId: 1,
|
||||
ptyId: 1,
|
||||
@@ -196,7 +201,7 @@ describe('<ShellToolMessage />', () => {
|
||||
availableTerminalHeight,
|
||||
activeShellPtyId: 1,
|
||||
ptyId: focused ? 1 : 2,
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
embeddedShellFocused: focused,
|
||||
},
|
||||
{ useAlternateBuffer: true },
|
||||
|
||||
@@ -22,13 +22,12 @@ import {
|
||||
FocusHint,
|
||||
} from './ToolShared.js';
|
||||
import type { ToolMessageProps } from './ToolMessage.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import {
|
||||
ACTIVE_SHELL_MAX_LINES,
|
||||
COMPLETED_SHELL_MAX_LINES,
|
||||
} from '../../constants.js';
|
||||
import { useAlternateBuffer } from '../../hooks/useAlternateBuffer.js';
|
||||
import type { Config } from '@google/gemini-cli-core';
|
||||
import { type Config, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
export interface ShellToolMessageProps extends ToolMessageProps {
|
||||
activeShellPtyId?: number | null;
|
||||
@@ -190,15 +189,15 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
|
||||
* This function ensures a finite number of lines is always returned to prevent performance issues.
|
||||
*/
|
||||
function getShellMaxLines(
|
||||
status: ToolCallStatus,
|
||||
status: CoreToolCallStatus,
|
||||
isAlternateBuffer: boolean,
|
||||
isThisShellFocused: boolean,
|
||||
availableTerminalHeight: number | undefined,
|
||||
): number {
|
||||
if (
|
||||
status === ToolCallStatus.Success ||
|
||||
status === ToolCallStatus.Error ||
|
||||
status === ToolCallStatus.Canceled
|
||||
status === CoreToolCallStatus.Success ||
|
||||
status === CoreToolCallStatus.Error ||
|
||||
status === CoreToolCallStatus.Cancelled
|
||||
) {
|
||||
return COMPLETED_SHELL_MAX_LINES;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { Todo } from '@google/gemini-cli-core';
|
||||
import type { UIState } from '../../contexts/UIStateContext.js';
|
||||
import { UIStateContext } from '../../contexts/UIStateContext.js';
|
||||
import type { HistoryItem } from '../../types.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
const createTodoHistoryItem = (todos: Todo[]): HistoryItem =>
|
||||
({
|
||||
@@ -22,7 +22,7 @@ const createTodoHistoryItem = (todos: Todo[]): HistoryItem =>
|
||||
{
|
||||
name: 'write_todos',
|
||||
callId: 'tool-1',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: {
|
||||
todos,
|
||||
},
|
||||
|
||||
@@ -8,9 +8,12 @@ import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { ToolGroupMessage } from './ToolGroupMessage.js';
|
||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { Scrollable } from '../shared/Scrollable.js';
|
||||
import { ASK_USER_DISPLAY_NAME, makeFakeConfig } from '@google/gemini-cli-core';
|
||||
import {
|
||||
ASK_USER_DISPLAY_NAME,
|
||||
makeFakeConfig,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import os from 'node:os';
|
||||
|
||||
describe('<ToolGroupMessage />', () => {
|
||||
@@ -25,7 +28,7 @@ describe('<ToolGroupMessage />', () => {
|
||||
name: 'test-tool',
|
||||
description: 'A tool for testing',
|
||||
resultDisplay: 'Test result',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
confirmationDetails: undefined,
|
||||
renderOutputAsMarkdown: false,
|
||||
...overrides,
|
||||
@@ -65,7 +68,7 @@ describe('<ToolGroupMessage />', () => {
|
||||
const toolCalls = [
|
||||
createToolCall({
|
||||
callId: 'confirm-tool',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
confirmationDetails: {
|
||||
type: 'info',
|
||||
title: 'Confirm tool',
|
||||
@@ -90,19 +93,19 @@ describe('<ToolGroupMessage />', () => {
|
||||
callId: 'tool-1',
|
||||
name: 'successful-tool',
|
||||
description: 'This tool succeeded',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
}),
|
||||
createToolCall({
|
||||
callId: 'tool-2',
|
||||
name: 'pending-tool',
|
||||
description: 'This tool is pending',
|
||||
status: ToolCallStatus.Pending,
|
||||
status: CoreToolCallStatus.Scheduled,
|
||||
}),
|
||||
createToolCall({
|
||||
callId: 'tool-3',
|
||||
name: 'error-tool',
|
||||
description: 'This tool failed',
|
||||
status: ToolCallStatus.Error,
|
||||
status: CoreToolCallStatus.Error,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -130,19 +133,19 @@ describe('<ToolGroupMessage />', () => {
|
||||
callId: 'tool-1',
|
||||
name: 'read_file',
|
||||
description: 'Read a file',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
}),
|
||||
createToolCall({
|
||||
callId: 'tool-2',
|
||||
name: 'run_shell_command',
|
||||
description: 'Run command',
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
}),
|
||||
createToolCall({
|
||||
callId: 'tool-3',
|
||||
name: 'write_file',
|
||||
description: 'Write to file',
|
||||
status: ToolCallStatus.Pending,
|
||||
status: CoreToolCallStatus.Scheduled,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -273,7 +276,7 @@ describe('<ToolGroupMessage />', () => {
|
||||
callId: 'tool-output-file',
|
||||
name: 'tool-with-file',
|
||||
description: 'Tool that saved output to file',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
outputFile: '/path/to/output.txt',
|
||||
}),
|
||||
];
|
||||
@@ -333,7 +336,7 @@ describe('<ToolGroupMessage />', () => {
|
||||
const toolCalls = [
|
||||
createToolCall({
|
||||
name: 'run_shell_command',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
}),
|
||||
];
|
||||
const { lastFrame, unmount } = renderWithProviders(
|
||||
@@ -351,11 +354,11 @@ describe('<ToolGroupMessage />', () => {
|
||||
|
||||
it('uses gray border when all tools are successful and no shell commands', () => {
|
||||
const toolCalls = [
|
||||
createToolCall({ status: ToolCallStatus.Success }),
|
||||
createToolCall({ status: CoreToolCallStatus.Success }),
|
||||
createToolCall({
|
||||
callId: 'tool-2',
|
||||
name: 'another-tool',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
}),
|
||||
];
|
||||
const { lastFrame, unmount } = renderWithProviders(
|
||||
@@ -409,28 +412,28 @@ describe('<ToolGroupMessage />', () => {
|
||||
describe('Ask User Filtering', () => {
|
||||
it.each([
|
||||
{
|
||||
status: ToolCallStatus.Pending,
|
||||
status: CoreToolCallStatus.Scheduled,
|
||||
resultDisplay: 'test result',
|
||||
shouldHide: true,
|
||||
},
|
||||
{
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
resultDisplay: 'test result',
|
||||
shouldHide: true,
|
||||
},
|
||||
{
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
resultDisplay: 'test result',
|
||||
shouldHide: true,
|
||||
},
|
||||
{
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: 'test result',
|
||||
shouldHide: false,
|
||||
},
|
||||
{ status: ToolCallStatus.Error, resultDisplay: '', shouldHide: true },
|
||||
{ status: CoreToolCallStatus.Error, resultDisplay: '', shouldHide: true },
|
||||
{
|
||||
status: ToolCallStatus.Error,
|
||||
status: CoreToolCallStatus.Error,
|
||||
resultDisplay: 'error message',
|
||||
shouldHide: false,
|
||||
},
|
||||
@@ -465,12 +468,12 @@ describe('<ToolGroupMessage />', () => {
|
||||
createToolCall({
|
||||
callId: 'other-tool',
|
||||
name: 'other-tool',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
}),
|
||||
createToolCall({
|
||||
callId: 'ask-user-pending',
|
||||
name: ASK_USER_DISPLAY_NAME,
|
||||
status: ToolCallStatus.Pending,
|
||||
status: CoreToolCallStatus.Scheduled,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -491,7 +494,7 @@ describe('<ToolGroupMessage />', () => {
|
||||
createToolCall({
|
||||
callId: 'ask-user-tool',
|
||||
name: ASK_USER_DISPLAY_NAME,
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
}),
|
||||
];
|
||||
|
||||
|
||||
@@ -8,13 +8,16 @@ import type React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { ToolCallStatus, mapCoreStatusToDisplayStatus } from '../../types.js';
|
||||
import { ToolMessage } from './ToolMessage.js';
|
||||
import { ShellToolMessage } from './ShellToolMessage.js';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { useConfig } from '../../contexts/ConfigContext.js';
|
||||
import { isShellTool, isThisShellFocused } from './ToolShared.js';
|
||||
import { shouldHideAskUserTool } from '@google/gemini-cli-core';
|
||||
import {
|
||||
shouldHideAskUserTool,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { ShowMoreLines } from '../ShowMoreLines.js';
|
||||
import { useUIState } from '../../contexts/UIStateContext.js';
|
||||
|
||||
@@ -45,9 +48,10 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
// Filter out Ask User tools that should be hidden (e.g. in-progress or errors without result)
|
||||
const toolCalls = useMemo(
|
||||
() =>
|
||||
allToolCalls.filter(
|
||||
(t) => !shouldHideAskUserTool(t.name, t.status, !!t.resultDisplay),
|
||||
),
|
||||
allToolCalls.filter((t) => {
|
||||
const displayStatus = mapCoreStatusToDisplayStatus(t.status);
|
||||
return !shouldHideAskUserTool(t.name, displayStatus, !!t.resultDisplay);
|
||||
}),
|
||||
[allToolCalls],
|
||||
);
|
||||
|
||||
@@ -61,11 +65,13 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
// appear in the Global Queue until they are approved and start executing.
|
||||
const visibleToolCalls = useMemo(
|
||||
() =>
|
||||
toolCalls.filter(
|
||||
(t) =>
|
||||
t.status !== ToolCallStatus.Pending &&
|
||||
t.status !== ToolCallStatus.Confirming,
|
||||
),
|
||||
toolCalls.filter((t) => {
|
||||
const displayStatus = mapCoreStatusToDisplayStatus(t.status);
|
||||
return (
|
||||
displayStatus !== ToolCallStatus.Pending &&
|
||||
displayStatus !== ToolCallStatus.Confirming
|
||||
);
|
||||
}),
|
||||
[toolCalls],
|
||||
);
|
||||
|
||||
@@ -80,7 +86,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
);
|
||||
|
||||
const hasPending = !visibleToolCalls.every(
|
||||
(t) => t.status === ToolCallStatus.Success,
|
||||
(t) => t.status === CoreToolCallStatus.Success,
|
||||
);
|
||||
|
||||
const isShellCommand = toolCalls.some((t) => isShellTool(t.name));
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
import type React from 'react';
|
||||
import { ToolMessage, type ToolMessageProps } from './ToolMessage.js';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { StreamingState, ToolCallStatus } from '../../types.js';
|
||||
import { StreamingState } from '../../types.js';
|
||||
import { Text } from 'ink';
|
||||
import type { AnsiOutput } from '@google/gemini-cli-core';
|
||||
import { type AnsiOutput, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { tryParseJSON } from '../../../utils/jsonoutput.js';
|
||||
|
||||
@@ -33,7 +33,7 @@ describe('<ToolMessage />', () => {
|
||||
name: 'test-tool',
|
||||
description: 'A tool for testing',
|
||||
resultDisplay: 'Test result',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
terminalWidth: 80,
|
||||
confirmationDetails: undefined,
|
||||
emphasis: 'medium',
|
||||
@@ -195,7 +195,7 @@ describe('<ToolMessage />', () => {
|
||||
describe('ToolStatusIndicator rendering', () => {
|
||||
it('shows ✓ for Success status', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...baseProps} status={ToolCallStatus.Success} />,
|
||||
<ToolMessage {...baseProps} status={CoreToolCallStatus.Success} />,
|
||||
StreamingState.Idle,
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -203,7 +203,7 @@ describe('<ToolMessage />', () => {
|
||||
|
||||
it('shows o for Pending status', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...baseProps} status={ToolCallStatus.Pending} />,
|
||||
<ToolMessage {...baseProps} status={CoreToolCallStatus.Scheduled} />,
|
||||
StreamingState.Idle,
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -211,7 +211,10 @@ describe('<ToolMessage />', () => {
|
||||
|
||||
it('shows ? for Confirming status', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...baseProps} status={ToolCallStatus.Confirming} />,
|
||||
<ToolMessage
|
||||
{...baseProps}
|
||||
status={CoreToolCallStatus.AwaitingApproval}
|
||||
/>,
|
||||
StreamingState.Idle,
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -219,7 +222,7 @@ describe('<ToolMessage />', () => {
|
||||
|
||||
it('shows - for Canceled status', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...baseProps} status={ToolCallStatus.Canceled} />,
|
||||
<ToolMessage {...baseProps} status={CoreToolCallStatus.Cancelled} />,
|
||||
StreamingState.Idle,
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -227,7 +230,7 @@ describe('<ToolMessage />', () => {
|
||||
|
||||
it('shows x for Error status', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...baseProps} status={ToolCallStatus.Error} />,
|
||||
<ToolMessage {...baseProps} status={CoreToolCallStatus.Error} />,
|
||||
StreamingState.Idle,
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -235,7 +238,7 @@ describe('<ToolMessage />', () => {
|
||||
|
||||
it('shows paused spinner for Executing status when streamingState is Idle', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...baseProps} status={ToolCallStatus.Executing} />,
|
||||
<ToolMessage {...baseProps} status={CoreToolCallStatus.Executing} />,
|
||||
StreamingState.Idle,
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -243,7 +246,7 @@ describe('<ToolMessage />', () => {
|
||||
|
||||
it('shows paused spinner for Executing status when streamingState is WaitingForConfirmation', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...baseProps} status={ToolCallStatus.Executing} />,
|
||||
<ToolMessage {...baseProps} status={CoreToolCallStatus.Executing} />,
|
||||
StreamingState.WaitingForConfirmation,
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -251,7 +254,7 @@ describe('<ToolMessage />', () => {
|
||||
|
||||
it('shows MockRespondingSpinner for Executing status when streamingState is Responding', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...baseProps} status={ToolCallStatus.Executing} />,
|
||||
<ToolMessage {...baseProps} status={CoreToolCallStatus.Executing} />,
|
||||
StreamingState.Responding, // Simulate app still responding
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
|
||||
@@ -7,14 +7,18 @@
|
||||
import { act } from 'react';
|
||||
import { ToolMessage } from './ToolMessage.js';
|
||||
import { ShellToolMessage } from './ShellToolMessage.js';
|
||||
import { ToolCallStatus, StreamingState } from '../../types.js';
|
||||
import { StreamingState } from '../../types.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import {
|
||||
SHELL_COMMAND_NAME,
|
||||
SHELL_FOCUS_HINT_DELAY_MS,
|
||||
} from '../../constants.js';
|
||||
import type { Config, ToolResultDisplay } from '@google/gemini-cli-core';
|
||||
import {
|
||||
type Config,
|
||||
type ToolResultDisplay,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
|
||||
vi.mock('../GeminiRespondingSpinner.js', () => ({
|
||||
GeminiRespondingSpinner: () => null,
|
||||
@@ -34,7 +38,7 @@ describe('Focus Hint', () => {
|
||||
name: SHELL_COMMAND_NAME,
|
||||
description: 'A tool for testing',
|
||||
resultDisplay: undefined as ToolResultDisplay | undefined,
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
terminalWidth: 80,
|
||||
confirmationDetails: undefined,
|
||||
emphasis: 'medium' as const,
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type { ToolMessageProps } from './ToolMessage.js';
|
||||
import { ToolMessage } from './ToolMessage.js';
|
||||
import { StreamingState, ToolCallStatus } from '../../types.js';
|
||||
import { StreamingState } from '../../types.js';
|
||||
import { StreamingContext } from '../../contexts/StreamingContext.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
describe('<ToolMessage /> - Raw Markdown Display Snapshots', () => {
|
||||
const baseProps: ToolMessageProps = {
|
||||
@@ -16,7 +18,7 @@ describe('<ToolMessage /> - Raw Markdown Display Snapshots', () => {
|
||||
name: 'test-tool',
|
||||
description: 'A tool for testing',
|
||||
resultDisplay: 'Test **bold** and `code` markdown',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
terminalWidth: 80,
|
||||
confirmationDetails: undefined,
|
||||
emphasis: 'medium',
|
||||
|
||||
@@ -7,13 +7,10 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ToolGroupMessage } from './ToolGroupMessage.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import {
|
||||
StreamingState,
|
||||
ToolCallStatus,
|
||||
type IndividualToolCallDisplay,
|
||||
} from '../../types.js';
|
||||
import { StreamingState, type IndividualToolCallDisplay } from '../../types.js';
|
||||
import { OverflowProvider } from '../../contexts/OverflowContext.js';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
describe('ToolResultDisplay Overflow', () => {
|
||||
it('should display "press ctrl-o" hint when content overflows in ToolGroupMessage', async () => {
|
||||
@@ -29,7 +26,7 @@ describe('ToolResultDisplay Overflow', () => {
|
||||
callId: 'call-1',
|
||||
name: 'test-tool',
|
||||
description: 'a test tool',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay,
|
||||
confirmationDetails: undefined,
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { ToolCallStatus, mapCoreStatusToDisplayStatus } from '../../types.js';
|
||||
import { GeminiRespondingSpinner } from '../GeminiRespondingSpinner.js';
|
||||
import {
|
||||
SHELL_COMMAND_NAME,
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
SHELL_TOOL_NAME,
|
||||
isCompletedAskUserTool,
|
||||
type ToolResultDisplay,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { useInactivityTimer } from '../../hooks/useInactivityTimer.js';
|
||||
import { formatCommand } from '../../utils/keybindingUtils.js';
|
||||
@@ -43,12 +44,12 @@ export function isShellTool(name: string): boolean {
|
||||
*/
|
||||
export function isThisShellFocusable(
|
||||
name: string,
|
||||
status: ToolCallStatus,
|
||||
status: CoreToolCallStatus,
|
||||
config?: Config,
|
||||
): boolean {
|
||||
return !!(
|
||||
isShellTool(name) &&
|
||||
status === ToolCallStatus.Executing &&
|
||||
status === CoreToolCallStatus.Executing &&
|
||||
config?.getEnableInteractiveShell()
|
||||
);
|
||||
}
|
||||
@@ -58,14 +59,14 @@ export function isThisShellFocusable(
|
||||
*/
|
||||
export function isThisShellFocused(
|
||||
name: string,
|
||||
status: ToolCallStatus,
|
||||
status: CoreToolCallStatus,
|
||||
ptyId?: number,
|
||||
activeShellPtyId?: number | null,
|
||||
embeddedShellFocused?: boolean,
|
||||
): boolean {
|
||||
return !!(
|
||||
isShellTool(name) &&
|
||||
status === ToolCallStatus.Executing &&
|
||||
status === CoreToolCallStatus.Executing &&
|
||||
ptyId === activeShellPtyId &&
|
||||
embeddedShellFocused
|
||||
);
|
||||
@@ -130,14 +131,15 @@ export const FocusHint: React.FC<{
|
||||
export type TextEmphasis = 'high' | 'medium' | 'low';
|
||||
|
||||
type ToolStatusIndicatorProps = {
|
||||
status: ToolCallStatus;
|
||||
status: CoreToolCallStatus;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const ToolStatusIndicator: React.FC<ToolStatusIndicatorProps> = ({
|
||||
status,
|
||||
status: coreStatus,
|
||||
name,
|
||||
}) => {
|
||||
const status = mapCoreStatusToDisplayStatus(coreStatus);
|
||||
const isShell = isShellTool(name);
|
||||
const statusColor = isShell ? theme.ui.symbol : theme.status.warning;
|
||||
|
||||
@@ -179,16 +181,17 @@ export const ToolStatusIndicator: React.FC<ToolStatusIndicatorProps> = ({
|
||||
type ToolInfoProps = {
|
||||
name: string;
|
||||
description: string;
|
||||
status: ToolCallStatus;
|
||||
status: CoreToolCallStatus;
|
||||
emphasis: TextEmphasis;
|
||||
};
|
||||
|
||||
export const ToolInfo: React.FC<ToolInfoProps> = ({
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
status: coreStatus,
|
||||
emphasis,
|
||||
}) => {
|
||||
const status = mapCoreStatusToDisplayStatus(coreStatus);
|
||||
const nameColor = React.useMemo<string>(() => {
|
||||
switch (emphasis) {
|
||||
case 'high':
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { ToolGroupMessage } from './ToolGroupMessage.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import {
|
||||
ScrollableList,
|
||||
type ScrollableListRef,
|
||||
@@ -16,6 +15,7 @@ import { Box, Text } from 'ink';
|
||||
import { act, useRef, useEffect } from 'react';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { SHELL_COMMAND_NAME } from '../../constants.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
// Mock child components that might be complex
|
||||
vi.mock('../TerminalOutput.js', () => ({
|
||||
@@ -51,7 +51,7 @@ describe('ToolMessage Sticky Header Regression', () => {
|
||||
{ length: 10 },
|
||||
(_, i) => `${resultPrefix}-${String(i + 1).padStart(2, '0')}`,
|
||||
).join('\n'),
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
confirmationDetails: undefined,
|
||||
renderOutputAsMarkdown: false,
|
||||
});
|
||||
@@ -144,7 +144,7 @@ describe('ToolMessage Sticky Header Regression', () => {
|
||||
const toolCalls = [
|
||||
{
|
||||
...createToolCall('1', SHELL_COMMAND_NAME, 'shell'),
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status='Error' and hasResult='error message' 1`] = `
|
||||
exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status='error' and hasResult='error message' 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ x Ask User │
|
||||
│ │
|
||||
@@ -8,7 +8,7 @@ exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status=
|
||||
╰──────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status='Success' and hasResult='test result' 1`] = `
|
||||
exports[`<ToolGroupMessage /> > Ask User Filtering > filtering logic for status='success' and hasResult='test result' 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────╮
|
||||
│ ✓ Ask User │
|
||||
│ │
|
||||
|
||||
@@ -14,8 +14,9 @@ import {
|
||||
ToolConfirmationOutcome,
|
||||
MessageBusType,
|
||||
IdeClient,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { ToolCallStatus, type IndividualToolCallDisplay } from '../types.js';
|
||||
import { type IndividualToolCallDisplay } from '../types.js';
|
||||
|
||||
// Mock IdeClient
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
@@ -45,7 +46,7 @@ describe('ToolActionsContext', () => {
|
||||
correlationId: 'corr-123',
|
||||
name: 'test-tool',
|
||||
description: 'desc',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
resultDisplay: undefined,
|
||||
confirmationDetails: { type: 'info', title: 'title', prompt: 'prompt' },
|
||||
},
|
||||
@@ -54,7 +55,7 @@ describe('ToolActionsContext', () => {
|
||||
correlationId: 'corr-edit',
|
||||
name: 'edit-tool',
|
||||
description: 'desc',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
resultDisplay: undefined,
|
||||
confirmationDetails: {
|
||||
type: 'edit',
|
||||
|
||||
@@ -17,10 +17,10 @@ import {
|
||||
COMMON_IGNORE_PATTERNS,
|
||||
GEMINI_IGNORE_FILE_NAME,
|
||||
// DEFAULT_FILE_EXCLUDES,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import * as core from '@google/gemini-cli-core';
|
||||
import * as os from 'node:os';
|
||||
import { ToolCallStatus } from '../types.js';
|
||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
import * as fsPromises from 'node:fs/promises';
|
||||
import * as path from 'node:path';
|
||||
@@ -212,7 +212,9 @@ describe('handleAtCommand', () => {
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: 'tool_group',
|
||||
tools: [expect.objectContaining({ status: ToolCallStatus.Success })],
|
||||
tools: [
|
||||
expect.objectContaining({ status: CoreToolCallStatus.Success }),
|
||||
],
|
||||
}),
|
||||
125,
|
||||
);
|
||||
@@ -314,7 +316,9 @@ describe('handleAtCommand', () => {
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: 'tool_group',
|
||||
tools: [expect.objectContaining({ status: ToolCallStatus.Success })],
|
||||
tools: [
|
||||
expect.objectContaining({ status: CoreToolCallStatus.Success }),
|
||||
],
|
||||
}),
|
||||
125,
|
||||
);
|
||||
@@ -1431,7 +1435,7 @@ describe('handleAtCommand', () => {
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: 'tool_group',
|
||||
tools: [expect.objectContaining({ status: ToolCallStatus.Error })],
|
||||
tools: [expect.objectContaining({ status: CoreToolCallStatus.Error })],
|
||||
}),
|
||||
134,
|
||||
);
|
||||
|
||||
@@ -18,10 +18,10 @@ import {
|
||||
ReadManyFilesTool,
|
||||
REFERENCE_CONTENT_START,
|
||||
REFERENCE_CONTENT_END,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import type { HistoryItem, IndividualToolCallDisplay } from '../types.js';
|
||||
import { ToolCallStatus } from '../types.js';
|
||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
|
||||
const REF_CONTENT_HEADER = `\n${REFERENCE_CONTENT_START}`;
|
||||
@@ -409,7 +409,7 @@ async function readMcpResources(
|
||||
callId: `mcp-resource-${resource.serverName}-${resource.uri}`,
|
||||
name: `resources/read (${resource.serverName})`,
|
||||
description: resource.uri,
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: `Successfully read resource ${resource.uri}`,
|
||||
confirmationDetails: undefined,
|
||||
} as IndividualToolCallDisplay,
|
||||
@@ -423,7 +423,7 @@ async function readMcpResources(
|
||||
callId: `mcp-resource-${resource.serverName}-${resource.uri}`,
|
||||
name: `resources/read (${resource.serverName})`,
|
||||
description: resource.uri,
|
||||
status: ToolCallStatus.Error,
|
||||
status: CoreToolCallStatus.Error,
|
||||
resultDisplay: `Error reading resource ${resource.uri}: ${getErrorMessage(error)}`,
|
||||
confirmationDetails: undefined,
|
||||
} as IndividualToolCallDisplay,
|
||||
@@ -447,7 +447,9 @@ async function readMcpResources(
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
const firstError = displays.find((d) => d.status === ToolCallStatus.Error);
|
||||
const firstError = displays.find(
|
||||
(d) => d.status === CoreToolCallStatus.Error,
|
||||
);
|
||||
return {
|
||||
parts: [],
|
||||
displays,
|
||||
@@ -500,7 +502,7 @@ async function readLocalFiles(
|
||||
callId: `client-read-${userMessageTimestamp}`,
|
||||
name: readManyFilesTool.displayName,
|
||||
description: invocation.getDescription(),
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay:
|
||||
result.returnDisplay ||
|
||||
`Successfully read: ${fileLabelsForDisplay.join(', ')}`,
|
||||
@@ -559,7 +561,7 @@ async function readLocalFiles(
|
||||
description:
|
||||
invocation?.getDescription() ??
|
||||
'Error attempting to execute tool to read files',
|
||||
status: ToolCallStatus.Error,
|
||||
status: CoreToolCallStatus.Error,
|
||||
resultDisplay: `Error reading files (${fileLabelsForDisplay.join(', ')}): ${getErrorMessage(error)}`,
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
|
||||
@@ -75,12 +75,12 @@ import {
|
||||
type GeminiClient,
|
||||
type ShellExecutionResult,
|
||||
type ShellOutputEvent,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import * as fs from 'node:fs';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import * as crypto from 'node:crypto';
|
||||
import { ToolCallStatus } from '../types.js';
|
||||
|
||||
describe('useShellCommandProcessor', () => {
|
||||
let addItemToHistoryMock: Mock;
|
||||
@@ -201,7 +201,7 @@ describe('useShellCommandProcessor', () => {
|
||||
tools: [
|
||||
expect.objectContaining({
|
||||
name: 'Shell Command',
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -240,7 +240,7 @@ describe('useShellCommandProcessor', () => {
|
||||
expect.objectContaining({
|
||||
tools: [
|
||||
expect.objectContaining({
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: 'ok',
|
||||
}),
|
||||
],
|
||||
@@ -269,7 +269,7 @@ describe('useShellCommandProcessor', () => {
|
||||
await act(async () => await execPromise);
|
||||
|
||||
const finalHistoryItem = addItemToHistoryMock.mock.calls[1][0];
|
||||
expect(finalHistoryItem.tools[0].status).toBe(ToolCallStatus.Error);
|
||||
expect(finalHistoryItem.tools[0].status).toBe(CoreToolCallStatus.Error);
|
||||
expect(finalHistoryItem.tools[0].resultDisplay).toContain(
|
||||
'Command exited with code 127',
|
||||
);
|
||||
@@ -483,7 +483,7 @@ describe('useShellCommandProcessor', () => {
|
||||
await act(async () => await execPromise);
|
||||
|
||||
const finalHistoryItem = addItemToHistoryMock.mock.calls[1][0];
|
||||
expect(finalHistoryItem.tools[0].status).toBe(ToolCallStatus.Success);
|
||||
expect(finalHistoryItem.tools[0].status).toBe(CoreToolCallStatus.Success);
|
||||
expect(finalHistoryItem.tools[0].resultDisplay).toBe(
|
||||
'[Command produced binary output, which is not shown.]',
|
||||
);
|
||||
|
||||
@@ -8,10 +8,13 @@ import type {
|
||||
HistoryItemWithoutId,
|
||||
IndividualToolCallDisplay,
|
||||
} 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';
|
||||
import {
|
||||
isBinary,
|
||||
ShellExecutionService,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { type PartListUnion } from '@google/genai';
|
||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
import { SHELL_COMMAND_NAME } from '../constants.js';
|
||||
@@ -301,7 +304,7 @@ export const useShellCommandProcessor = (
|
||||
callId,
|
||||
name: SHELL_COMMAND_NAME,
|
||||
description: rawQuery,
|
||||
status: ToolCallStatus.Executing,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
resultDisplay: '',
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
@@ -447,22 +450,22 @@ export const useShellCommandProcessor = (
|
||||
}
|
||||
|
||||
let finalOutput = mainContent;
|
||||
let finalStatus = ToolCallStatus.Success;
|
||||
let finalStatus = CoreToolCallStatus.Success;
|
||||
|
||||
if (result.error) {
|
||||
finalStatus = ToolCallStatus.Error;
|
||||
finalStatus = CoreToolCallStatus.Error;
|
||||
finalOutput = `${result.error.message}\n${finalOutput}`;
|
||||
} else if (result.aborted) {
|
||||
finalStatus = ToolCallStatus.Canceled;
|
||||
finalStatus = CoreToolCallStatus.Cancelled;
|
||||
finalOutput = `Command was cancelled.\n${finalOutput}`;
|
||||
} else if (result.backgrounded) {
|
||||
finalStatus = ToolCallStatus.Success;
|
||||
finalStatus = CoreToolCallStatus.Success;
|
||||
finalOutput = `Command moved to background (PID: ${result.pid}). Output hidden. Press Ctrl+B to view.`;
|
||||
} else if (result.signal) {
|
||||
finalStatus = ToolCallStatus.Error;
|
||||
finalStatus = CoreToolCallStatus.Error;
|
||||
finalOutput = `Command terminated by signal: ${result.signal}.\n${finalOutput}`;
|
||||
} else if (result.exitCode !== 0) {
|
||||
finalStatus = ToolCallStatus.Error;
|
||||
finalStatus = CoreToolCallStatus.Error;
|
||||
finalOutput = `Command exited with code ${result.exitCode}.\n${finalOutput}`;
|
||||
}
|
||||
|
||||
@@ -480,7 +483,7 @@ export const useShellCommandProcessor = (
|
||||
resultDisplay: finalOutput,
|
||||
};
|
||||
|
||||
if (finalStatus !== ToolCallStatus.Canceled) {
|
||||
if (finalStatus !== CoreToolCallStatus.Cancelled) {
|
||||
addItemToHistory(
|
||||
{
|
||||
type: 'tool_group',
|
||||
|
||||
@@ -1003,7 +1003,7 @@ describe('useSlashCommandProcessor', () => {
|
||||
command: '/fail',
|
||||
expectedLog: {
|
||||
command: 'fail',
|
||||
status: 'error',
|
||||
status: SlashCommandStatus.ERROR,
|
||||
subcommand: undefined,
|
||||
},
|
||||
desc: 'failure event for failed command',
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
addMCPStatusChangeListener,
|
||||
removeMCPStatusChangeListener,
|
||||
MCPDiscoveryState,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { useSessionStats } from '../contexts/SessionContext.js';
|
||||
import type {
|
||||
@@ -44,7 +45,7 @@ import type {
|
||||
ConfirmationRequest,
|
||||
IndividualToolCallDisplay,
|
||||
} from '../types.js';
|
||||
import { MessageType, ToolCallStatus } from '../types.js';
|
||||
import { MessageType } from '../types.js';
|
||||
import type { LoadedSettings } from '../../config/settings.js';
|
||||
import { type CommandContext, type SlashCommand } from '../commands/types.js';
|
||||
import { CommandService } from '../../services/CommandService.js';
|
||||
@@ -554,7 +555,7 @@ export const useSlashCommandProcessor = (
|
||||
callId,
|
||||
name: 'Expansion',
|
||||
description: 'Command expansion needs shell access',
|
||||
status: ToolCallStatus.Confirming,
|
||||
status: CoreToolCallStatus.AwaitingApproval,
|
||||
resultDisplay: undefined,
|
||||
confirmationDetails,
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { mapCoreStatusToDisplayStatus, mapToDisplay } from './toolMapping.js';
|
||||
import { mapToDisplay } from './toolMapping.js';
|
||||
import {
|
||||
type AnyDeclarativeTool,
|
||||
type AnyToolInvocation,
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
type CancelledToolCall,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { ToolCallStatus } from '../types.js';
|
||||
import { ToolCallStatus, mapCoreStatusToDisplayStatus } from '../types.js';
|
||||
|
||||
describe('toolMapping', () => {
|
||||
beforeEach(() => {
|
||||
@@ -131,7 +131,7 @@ describe('toolMapping', () => {
|
||||
name: 'Test Tool',
|
||||
description: 'Calling test_tool with args...',
|
||||
renderOutputAsMarkdown: true,
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: 'Success output',
|
||||
outputFile: '/tmp/output.txt',
|
||||
}),
|
||||
@@ -151,7 +151,7 @@ describe('toolMapping', () => {
|
||||
const result = mapToDisplay(toolCall);
|
||||
const displayTool = result.tools[0];
|
||||
|
||||
expect(displayTool.status).toBe(ToolCallStatus.Executing);
|
||||
expect(displayTool.status).toBe(CoreToolCallStatus.Executing);
|
||||
expect(displayTool.resultDisplay).toBe('Loading...');
|
||||
expect(displayTool.ptyId).toBe(12345);
|
||||
});
|
||||
@@ -178,7 +178,7 @@ describe('toolMapping', () => {
|
||||
const result = mapToDisplay(toolCall);
|
||||
const displayTool = result.tools[0];
|
||||
|
||||
expect(displayTool.status).toBe(ToolCallStatus.Confirming);
|
||||
expect(displayTool.status).toBe(CoreToolCallStatus.AwaitingApproval);
|
||||
expect(displayTool.confirmationDetails).toEqual(confirmationDetails);
|
||||
});
|
||||
|
||||
@@ -221,7 +221,7 @@ describe('toolMapping', () => {
|
||||
const result = mapToDisplay(toolCall);
|
||||
const displayTool = result.tools[0];
|
||||
|
||||
expect(displayTool.status).toBe(ToolCallStatus.Error);
|
||||
expect(displayTool.status).toBe(CoreToolCallStatus.Error);
|
||||
expect(displayTool.name).toBe('test_tool'); // falls back to request.name
|
||||
expect(displayTool.description).toBe('{"arg1":"val1"}'); // falls back to stringified args
|
||||
expect(displayTool.resultDisplay).toBe('Tool not found');
|
||||
@@ -243,7 +243,7 @@ describe('toolMapping', () => {
|
||||
const result = mapToDisplay(toolCall);
|
||||
const displayTool = result.tools[0];
|
||||
|
||||
expect(displayTool.status).toBe(ToolCallStatus.Canceled);
|
||||
expect(displayTool.status).toBe(CoreToolCallStatus.Cancelled);
|
||||
expect(displayTool.resultDisplay).toBe('User cancelled');
|
||||
});
|
||||
|
||||
@@ -273,7 +273,7 @@ describe('toolMapping', () => {
|
||||
|
||||
const result = mapToDisplay(toolCall);
|
||||
expect(result.tools[0].resultDisplay).toBeUndefined();
|
||||
expect(result.tools[0].status).toBe(ToolCallStatus.Pending);
|
||||
expect(result.tools[0].status).toBe(CoreToolCallStatus.Scheduled);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,42 +6,16 @@
|
||||
|
||||
import {
|
||||
type ToolCall,
|
||||
type Status as CoreStatus,
|
||||
type SerializableConfirmationDetails,
|
||||
type ToolResultDisplay,
|
||||
debugLogger,
|
||||
CoreToolCallStatus,
|
||||
checkExhaustive,
|
||||
} from '@google/gemini-cli-core';
|
||||
import {
|
||||
ToolCallStatus,
|
||||
type HistoryItemToolGroup,
|
||||
type IndividualToolCallDisplay,
|
||||
} from '../types.js';
|
||||
|
||||
export function mapCoreStatusToDisplayStatus(
|
||||
coreStatus: CoreStatus,
|
||||
): ToolCallStatus {
|
||||
switch (coreStatus) {
|
||||
case CoreToolCallStatus.Validating:
|
||||
return ToolCallStatus.Pending;
|
||||
case CoreToolCallStatus.AwaitingApproval:
|
||||
return ToolCallStatus.Confirming;
|
||||
case CoreToolCallStatus.Executing:
|
||||
return ToolCallStatus.Executing;
|
||||
case CoreToolCallStatus.Success:
|
||||
return ToolCallStatus.Success;
|
||||
case CoreToolCallStatus.Cancelled:
|
||||
return ToolCallStatus.Canceled;
|
||||
case CoreToolCallStatus.Error:
|
||||
return ToolCallStatus.Error;
|
||||
case CoreToolCallStatus.Scheduled:
|
||||
return ToolCallStatus.Pending;
|
||||
default:
|
||||
return checkExhaustive(coreStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms `ToolCall` objects into `HistoryItemToolGroup` objects for UI
|
||||
* display. This is a pure projection layer and does not track interaction
|
||||
@@ -115,7 +89,7 @@ export function mapToDisplay(
|
||||
|
||||
return {
|
||||
...baseDisplayProperties,
|
||||
status: mapCoreStatusToDisplayStatus(call.status),
|
||||
status: call.status,
|
||||
resultDisplay,
|
||||
confirmationDetails,
|
||||
outputFile,
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useUIState } from '../contexts/UIStateContext.js';
|
||||
import {
|
||||
ToolCallStatus,
|
||||
type IndividualToolCallDisplay,
|
||||
type HistoryItemToolGroup,
|
||||
} from '../types.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
|
||||
export interface ConfirmingToolState {
|
||||
tool: IndividualToolCallDisplay;
|
||||
@@ -37,7 +37,7 @@ export function useConfirmingTool(): ConfirmingToolState | null {
|
||||
|
||||
// 2. Filter for those requiring confirmation
|
||||
const confirmingTools = allPendingTools.filter(
|
||||
(t) => t.status === ToolCallStatus.Confirming,
|
||||
(t) => t.status === CoreToolCallStatus.AwaitingApproval,
|
||||
);
|
||||
|
||||
if (confirmingTools.length === 0) {
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
import type { Part, PartListUnion } from '@google/genai';
|
||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
import type { SlashCommandProcessorResult } from '../types.js';
|
||||
import { MessageType, StreamingState, ToolCallStatus } from '../types.js';
|
||||
import { MessageType, StreamingState } from '../types.js';
|
||||
import type { LoadedSettings } from '../../config/settings.js';
|
||||
|
||||
// --- MOCKS ---
|
||||
@@ -2380,7 +2380,7 @@ describe('useGeminiStream', () => {
|
||||
callId: 'client-read-123',
|
||||
name: 'read_file',
|
||||
description: toolExecutionMessage,
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: toolExecutionMessage,
|
||||
confirmationDetails: undefined,
|
||||
},
|
||||
@@ -2434,7 +2434,7 @@ describe('useGeminiStream', () => {
|
||||
tools: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: 'read_file',
|
||||
status: ToolCallStatus.Success,
|
||||
status: CoreToolCallStatus.Success,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
ValidationRequiredError,
|
||||
coreEvents,
|
||||
CoreEvent,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type {
|
||||
Config,
|
||||
@@ -58,7 +59,7 @@ import type {
|
||||
SlashCommandProcessorResult,
|
||||
HistoryItemModel,
|
||||
} from '../types.js';
|
||||
import { StreamingState, MessageType, ToolCallStatus } from '../types.js';
|
||||
import { StreamingState, MessageType } from '../types.js';
|
||||
import { isAtCommand, isSlashCommand } from '../utils/commandUtils.js';
|
||||
import { useShellCommandProcessor } from './shellCommandProcessor.js';
|
||||
import { handleAtCommand } from './atCommandProcessor.js';
|
||||
@@ -126,16 +127,18 @@ function calculateStreamingState(
|
||||
isResponding: boolean,
|
||||
toolCalls: TrackedToolCall[],
|
||||
): StreamingState {
|
||||
if (toolCalls.some((tc) => tc.status === 'awaiting_approval')) {
|
||||
if (
|
||||
toolCalls.some((tc) => tc.status === CoreToolCallStatus.AwaitingApproval)
|
||||
) {
|
||||
return StreamingState.WaitingForConfirmation;
|
||||
}
|
||||
|
||||
const isAnyToolActive = toolCalls.some((tc) => {
|
||||
// These statuses indicate active processing
|
||||
if (
|
||||
tc.status === 'executing' ||
|
||||
tc.status === 'scheduled' ||
|
||||
tc.status === 'validating'
|
||||
tc.status === CoreToolCallStatus.Executing ||
|
||||
tc.status === CoreToolCallStatus.Scheduled ||
|
||||
tc.status === CoreToolCallStatus.Validating
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -143,9 +146,9 @@ function calculateStreamingState(
|
||||
// Terminal statuses (success, error, cancelled) still count as "Responding"
|
||||
// if the result hasn't been submitted back to Gemini yet.
|
||||
if (
|
||||
tc.status === 'success' ||
|
||||
tc.status === 'error' ||
|
||||
tc.status === 'cancelled'
|
||||
tc.status === CoreToolCallStatus.Success ||
|
||||
tc.status === CoreToolCallStatus.Error ||
|
||||
tc.status === CoreToolCallStatus.Cancelled
|
||||
) {
|
||||
return !(tc as TrackedCompletedToolCall | TrackedCancelledToolCall)
|
||||
.responseSubmittedToGemini;
|
||||
@@ -562,7 +565,7 @@ export const useGeminiStream = (
|
||||
if (tool.name === SHELL_COMMAND_NAME) {
|
||||
return {
|
||||
...tool,
|
||||
status: ToolCallStatus.Canceled,
|
||||
status: CoreToolCallStatus.Cancelled,
|
||||
resultDisplay: tool.resultDisplay,
|
||||
};
|
||||
}
|
||||
@@ -830,12 +833,14 @@ export const useGeminiStream = (
|
||||
if (pendingHistoryItemRef.current.type === 'tool_group') {
|
||||
const updatedTools = pendingHistoryItemRef.current.tools.map(
|
||||
(tool) =>
|
||||
tool.status === ToolCallStatus.Pending ||
|
||||
tool.status === ToolCallStatus.Confirming ||
|
||||
tool.status === ToolCallStatus.Executing
|
||||
? { ...tool, status: ToolCallStatus.Canceled }
|
||||
tool.status === CoreToolCallStatus.Validating ||
|
||||
tool.status === CoreToolCallStatus.Scheduled ||
|
||||
tool.status === CoreToolCallStatus.AwaitingApproval ||
|
||||
tool.status === CoreToolCallStatus.Executing
|
||||
? { ...tool, status: CoreToolCallStatus.Cancelled }
|
||||
: tool,
|
||||
);
|
||||
|
||||
const pendingItem: HistoryItemToolGroup = {
|
||||
...pendingHistoryItemRef.current,
|
||||
tools: updatedTools,
|
||||
@@ -1530,7 +1535,7 @@ export const useGeminiStream = (
|
||||
|
||||
// If all the tools were cancelled, don't submit a response to Gemini.
|
||||
const allToolsCancelled = geminiTools.every(
|
||||
(tc) => tc.status === 'cancelled',
|
||||
(tc) => tc.status === CoreToolCallStatus.Cancelled,
|
||||
);
|
||||
|
||||
if (allToolsCancelled) {
|
||||
@@ -1618,7 +1623,7 @@ export const useGeminiStream = (
|
||||
const restorableToolCalls = toolCalls.filter(
|
||||
(toolCall) =>
|
||||
EDIT_TOOL_NAMES.has(toolCall.request.name) &&
|
||||
toolCall.status === 'awaiting_approval',
|
||||
toolCall.status === CoreToolCallStatus.AwaitingApproval,
|
||||
);
|
||||
|
||||
if (restorableToolCalls.length > 0) {
|
||||
|
||||
@@ -14,10 +14,11 @@ import {
|
||||
import * as fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { getSessionFiles, type SessionInfo } from '../../utils/sessionUtils.js';
|
||||
import type {
|
||||
Config,
|
||||
ConversationRecord,
|
||||
MessageRecord,
|
||||
import {
|
||||
type Config,
|
||||
type ConversationRecord,
|
||||
type MessageRecord,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { coreEvents } from '@google/gemini-cli-core';
|
||||
|
||||
@@ -238,7 +239,7 @@ describe('convertSessionToHistoryFormats', () => {
|
||||
id: 'call_1',
|
||||
name: 'get_time',
|
||||
args: {},
|
||||
status: 'success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
result: '12:00',
|
||||
},
|
||||
],
|
||||
@@ -258,7 +259,7 @@ describe('convertSessionToHistoryFormats', () => {
|
||||
expect.objectContaining({
|
||||
callId: 'call_1',
|
||||
name: 'get_time',
|
||||
status: 'Success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { act } from 'react';
|
||||
import { renderHook } from '../../test-utils/render.js';
|
||||
import { useToolScheduler } from './useToolScheduler.js';
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
type AnyDeclarativeTool,
|
||||
type AnyToolInvocation,
|
||||
ROOT_SCHEDULER_ID,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { createMockMessageBus } from '@google/gemini-cli-core/src/test-utils/mock-message-bus.js';
|
||||
|
||||
@@ -98,7 +99,7 @@ describe('useToolScheduler', () => {
|
||||
);
|
||||
|
||||
const mockToolCall = {
|
||||
status: 'executing' as const,
|
||||
status: CoreToolCallStatus.Executing as const,
|
||||
request: {
|
||||
callId: 'call-1',
|
||||
name: 'test_tool',
|
||||
@@ -124,7 +125,7 @@ describe('useToolScheduler', () => {
|
||||
// Expect Core Object structure, not Display Object
|
||||
expect(toolCalls[0]).toMatchObject({
|
||||
request: { callId: 'call-1', name: 'test_tool' },
|
||||
status: 'executing', // Core status
|
||||
status: CoreToolCallStatus.Executing,
|
||||
liveOutput: 'Loading...',
|
||||
responseSubmittedToGemini: false,
|
||||
});
|
||||
@@ -140,7 +141,7 @@ describe('useToolScheduler', () => {
|
||||
);
|
||||
|
||||
const mockToolCall = {
|
||||
status: 'success' as const,
|
||||
status: CoreToolCallStatus.Success as const,
|
||||
request: {
|
||||
callId: 'call-1',
|
||||
name: 'test',
|
||||
@@ -206,7 +207,7 @@ describe('useToolScheduler', () => {
|
||||
type: MessageBusType.TOOL_CALLS_UPDATE,
|
||||
toolCalls: [
|
||||
{
|
||||
status: 'executing' as const,
|
||||
status: CoreToolCallStatus.Executing as const,
|
||||
request: {
|
||||
callId: 'call-1',
|
||||
name: 'test',
|
||||
@@ -252,7 +253,7 @@ describe('useToolScheduler', () => {
|
||||
const onComplete = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
const completedToolCall = {
|
||||
status: 'success' as const,
|
||||
status: CoreToolCallStatus.Success as const,
|
||||
request: {
|
||||
callId: 'call-1',
|
||||
name: 'test',
|
||||
@@ -316,7 +317,7 @@ describe('useToolScheduler', () => {
|
||||
);
|
||||
|
||||
const callRoot = {
|
||||
status: 'success' as const,
|
||||
status: CoreToolCallStatus.Success as const,
|
||||
request: {
|
||||
callId: 'call-root',
|
||||
name: 'test',
|
||||
@@ -390,7 +391,7 @@ describe('useToolScheduler', () => {
|
||||
act(() => {
|
||||
void mockMessageBus.publish({
|
||||
type: MessageBusType.TOOL_CALLS_UPDATE,
|
||||
toolCalls: [{ ...callRoot, status: 'executing' }],
|
||||
toolCalls: [{ ...callRoot, status: CoreToolCallStatus.Executing }],
|
||||
schedulerId: ROOT_SCHEDULER_ID,
|
||||
} as ToolCallsUpdateMessage);
|
||||
});
|
||||
@@ -399,7 +400,7 @@ describe('useToolScheduler', () => {
|
||||
expect(toolCalls).toHaveLength(2);
|
||||
expect(
|
||||
toolCalls.find((t) => t.request.callId === 'call-root')?.status,
|
||||
).toBe('executing');
|
||||
).toBe(CoreToolCallStatus.Executing);
|
||||
expect(
|
||||
toolCalls.find((t) => t.request.callId === 'call-sub')?.schedulerId,
|
||||
).toBe('subagent-1');
|
||||
|
||||
@@ -8,7 +8,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { renderHook } from '../../test-utils/render.js';
|
||||
import { useTurnActivityMonitor } from './useTurnActivityMonitor.js';
|
||||
import { StreamingState } from '../types.js';
|
||||
import { hasRedirection } from '@google/gemini-cli-core';
|
||||
import { hasRedirection, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import { type TrackedToolCall } from './useToolScheduler.js';
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
@@ -93,7 +93,7 @@ describe('useTurnActivityMonitor', () => {
|
||||
name: 'run_shell_command',
|
||||
args: { command: 'ls -la' },
|
||||
},
|
||||
status: 'executing',
|
||||
status: CoreToolCallStatus.Executing,
|
||||
} as unknown as TrackedToolCall,
|
||||
],
|
||||
});
|
||||
@@ -108,7 +108,7 @@ describe('useTurnActivityMonitor', () => {
|
||||
name: 'run_shell_command',
|
||||
args: { command: 'ls > tool_out.txt' },
|
||||
},
|
||||
status: 'executing',
|
||||
status: CoreToolCallStatus.Executing,
|
||||
} as unknown as TrackedToolCall,
|
||||
],
|
||||
});
|
||||
|
||||
@@ -4,16 +4,18 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type {
|
||||
CompressionStatus,
|
||||
GeminiCLIExtension,
|
||||
MCPServerConfig,
|
||||
ThoughtSummary,
|
||||
SerializableConfirmationDetails,
|
||||
ToolResultDisplay,
|
||||
RetrieveUserQuotaResponse,
|
||||
SkillDefinition,
|
||||
AgentDefinition,
|
||||
import {
|
||||
type CompressionStatus,
|
||||
type GeminiCLIExtension,
|
||||
type MCPServerConfig,
|
||||
type ThoughtSummary,
|
||||
type SerializableConfirmationDetails,
|
||||
type ToolResultDisplay,
|
||||
type RetrieveUserQuotaResponse,
|
||||
type SkillDefinition,
|
||||
type AgentDefinition,
|
||||
CoreToolCallStatus,
|
||||
checkExhaustive,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { PartListUnion } from '@google/genai';
|
||||
import { type ReactNode } from 'react';
|
||||
@@ -56,9 +58,35 @@ export enum ToolCallStatus {
|
||||
Error = 'Error',
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps core tool call status to a simplified UI status.
|
||||
*/
|
||||
export function mapCoreStatusToDisplayStatus(
|
||||
coreStatus: CoreToolCallStatus,
|
||||
): ToolCallStatus {
|
||||
switch (coreStatus) {
|
||||
case CoreToolCallStatus.Validating:
|
||||
return ToolCallStatus.Pending;
|
||||
case CoreToolCallStatus.AwaitingApproval:
|
||||
return ToolCallStatus.Confirming;
|
||||
case CoreToolCallStatus.Executing:
|
||||
return ToolCallStatus.Executing;
|
||||
case CoreToolCallStatus.Success:
|
||||
return ToolCallStatus.Success;
|
||||
case CoreToolCallStatus.Cancelled:
|
||||
return ToolCallStatus.Canceled;
|
||||
case CoreToolCallStatus.Error:
|
||||
return ToolCallStatus.Error;
|
||||
case CoreToolCallStatus.Scheduled:
|
||||
return ToolCallStatus.Pending;
|
||||
default:
|
||||
return checkExhaustive(coreStatus);
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolCallEvent {
|
||||
type: 'tool_call';
|
||||
status: ToolCallStatus;
|
||||
status: CoreToolCallStatus;
|
||||
callId: string;
|
||||
name: string;
|
||||
args: Record<string, never>;
|
||||
@@ -72,7 +100,7 @@ export interface IndividualToolCallDisplay {
|
||||
name: string;
|
||||
description: string;
|
||||
resultDisplay: ToolResultDisplay | undefined;
|
||||
status: ToolCallStatus;
|
||||
status: CoreToolCallStatus;
|
||||
confirmationDetails: SerializableConfirmationDetails | undefined;
|
||||
renderOutputAsMarkdown?: boolean;
|
||||
ptyId?: number;
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
checkExhaustive,
|
||||
partListUnionToString,
|
||||
SESSION_FILE_PREFIX,
|
||||
CoreToolCallStatus,
|
||||
type Config,
|
||||
type ConversationRecord,
|
||||
type MessageRecord,
|
||||
@@ -16,11 +17,7 @@ import * as fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { stripUnsafeCharacters } from '../ui/utils/textUtils.js';
|
||||
import type { Part } from '@google/genai';
|
||||
import {
|
||||
MessageType,
|
||||
ToolCallStatus,
|
||||
type HistoryItemWithoutId,
|
||||
} from '../ui/types.js';
|
||||
import { MessageType, type HistoryItemWithoutId } from '../ui/types.js';
|
||||
|
||||
/**
|
||||
* Constant for the resume "latest" identifier.
|
||||
@@ -585,8 +582,8 @@ export function convertSessionToHistoryFormats(
|
||||
renderOutputAsMarkdown: tool.renderOutputAsMarkdown ?? true,
|
||||
status:
|
||||
tool.status === 'success'
|
||||
? ToolCallStatus.Success
|
||||
: ToolCallStatus.Error,
|
||||
? CoreToolCallStatus.Success
|
||||
: CoreToolCallStatus.Error,
|
||||
resultDisplay: tool.resultDisplay,
|
||||
confirmationDetails: undefined,
|
||||
})),
|
||||
|
||||
@@ -15,7 +15,11 @@ import {
|
||||
} from 'vitest';
|
||||
import { GeminiAgent } from './zedIntegration.js';
|
||||
import * as acp from '@agentclientprotocol/sdk';
|
||||
import { AuthType, type Config } from '@google/gemini-cli-core';
|
||||
import {
|
||||
AuthType,
|
||||
type Config,
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { loadCliConfig, type CliArgs } from '../config/config.js';
|
||||
import {
|
||||
SessionSelector,
|
||||
@@ -98,7 +102,7 @@ describe('GeminiAgent Session Resume', () => {
|
||||
id: 'call-1',
|
||||
name: 'test_tool',
|
||||
displayName: 'Test Tool',
|
||||
status: 'success',
|
||||
status: CoreToolCallStatus.Success,
|
||||
resultDisplay: 'Tool output',
|
||||
},
|
||||
],
|
||||
@@ -111,7 +115,7 @@ describe('GeminiAgent Session Resume', () => {
|
||||
id: 'call-2',
|
||||
name: 'write_file',
|
||||
displayName: 'Write File',
|
||||
status: 'error',
|
||||
status: CoreToolCallStatus.Error,
|
||||
resultDisplay: 'Permission denied',
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user