summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli/src/ui/hooks/useGeminiStream.test.tsx')
-rw-r--r--packages/cli/src/ui/hooks/useGeminiStream.test.tsx110
1 files changed, 39 insertions, 71 deletions
diff --git a/packages/cli/src/ui/hooks/useGeminiStream.test.tsx b/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
index 6a41234b..3a002919 100644
--- a/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
+++ b/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
@@ -19,7 +19,12 @@ import {
import { Config, EditorType, AuthType } from '@google/gemini-cli-core';
import { Part, PartListUnion } from '@google/genai';
import { UseHistoryManagerReturn } from './useHistoryManager.js';
-import { HistoryItem, MessageType, StreamingState } from '../types.js';
+import {
+ HistoryItem,
+ MessageType,
+ SlashCommandProcessorResult,
+ StreamingState,
+} from '../types.js';
import { Dispatch, SetStateAction } from 'react';
import { LoadedSettings } from '../../config/settings.js';
@@ -360,10 +365,7 @@ describe('useGeminiStream', () => {
onDebugMessage: (message: string) => void;
handleSlashCommand: (
cmd: PartListUnion,
- ) => Promise<
- | import('./slashCommandProcessor.js').SlashCommandActionReturn
- | boolean
- >;
+ ) => Promise<SlashCommandProcessorResult | false>;
shellModeActive: boolean;
loadedSettings: LoadedSettings;
toolCalls?: TrackedToolCall[]; // Allow passing updated toolCalls
@@ -396,10 +398,7 @@ describe('useGeminiStream', () => {
onDebugMessage: mockOnDebugMessage,
handleSlashCommand: mockHandleSlashCommand as unknown as (
cmd: PartListUnion,
- ) => Promise<
- | import('./slashCommandProcessor.js').SlashCommandActionReturn
- | boolean
- >,
+ ) => Promise<SlashCommandProcessorResult | false>,
shellModeActive: false,
loadedSettings: mockLoadedSettings,
toolCalls: initialToolCalls,
@@ -966,83 +965,52 @@ describe('useGeminiStream', () => {
});
});
- describe('Client-Initiated Tool Calls', () => {
- it('should execute a client-initiated tool without sending a response to Gemini', async () => {
- const clientToolRequest = {
- shouldScheduleTool: true,
+ describe('Slash Command Handling', () => {
+ it('should schedule a tool call when the command processor returns a schedule_tool action', async () => {
+ const clientToolRequest: SlashCommandProcessorResult = {
+ type: 'schedule_tool',
toolName: 'save_memory',
toolArgs: { fact: 'test fact' },
};
mockHandleSlashCommand.mockResolvedValue(clientToolRequest);
- const completedToolCall: TrackedCompletedToolCall = {
- request: {
- callId: 'client-call-1',
- name: clientToolRequest.toolName,
- args: clientToolRequest.toolArgs,
- isClientInitiated: true,
- },
- status: 'success',
- responseSubmittedToGemini: false,
- response: {
- callId: 'client-call-1',
- responseParts: [{ text: 'Memory saved' }],
- resultDisplay: 'Success: Memory saved',
- error: undefined,
- },
- tool: {
- name: clientToolRequest.toolName,
- description: 'Saves memory',
- getDescription: vi.fn(),
- } as any,
- };
+ const { result } = renderTestHook();
- // Capture the onComplete callback
- let capturedOnComplete:
- | ((completedTools: TrackedToolCall[]) => Promise<void>)
- | null = null;
+ await act(async () => {
+ await result.current.submitQuery('/memory add "test fact"');
+ });
- mockUseReactToolScheduler.mockImplementation((onComplete) => {
- capturedOnComplete = onComplete;
- return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted];
+ await waitFor(() => {
+ expect(mockScheduleToolCalls).toHaveBeenCalledWith(
+ [
+ expect.objectContaining({
+ name: 'save_memory',
+ args: { fact: 'test fact' },
+ isClientInitiated: true,
+ }),
+ ],
+ expect.any(AbortSignal),
+ );
+ expect(mockSendMessageStream).not.toHaveBeenCalled();
});
+ });
- const { result } = renderHook(() =>
- useGeminiStream(
- new MockedGeminiClientClass(mockConfig),
- [],
- mockAddItem,
- mockSetShowHelp,
- mockConfig,
- mockOnDebugMessage,
- mockHandleSlashCommand,
- false,
- () => 'vscode' as EditorType,
- () => {},
- () => Promise.resolve(),
- ),
- );
+ it('should stop processing and not call Gemini when a command is handled without a tool call', async () => {
+ const uiOnlyCommandResult: SlashCommandProcessorResult = {
+ type: 'handled',
+ };
+ mockHandleSlashCommand.mockResolvedValue(uiOnlyCommandResult);
- // --- User runs the slash command ---
- await act(async () => {
- await result.current.submitQuery('/memory add "test fact"');
- });
+ const { result } = renderTestHook();
- // Trigger the onComplete callback with the completed client-initiated tool
await act(async () => {
- if (capturedOnComplete) {
- await capturedOnComplete([completedToolCall]);
- }
+ await result.current.submitQuery('/help');
});
- // --- Assert the outcome ---
await waitFor(() => {
- // The tool should be marked as submitted locally
- expect(mockMarkToolsAsSubmitted).toHaveBeenCalledWith([
- 'client-call-1',
- ]);
- // Crucially, no message should be sent to the Gemini API
- expect(mockSendMessageStream).not.toHaveBeenCalled();
+ expect(mockHandleSlashCommand).toHaveBeenCalledWith('/help');
+ expect(mockScheduleToolCalls).not.toHaveBeenCalled();
+ expect(mockSendMessageStream).not.toHaveBeenCalled(); // No LLM call made
});
});
});