mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-26 04:54:25 -07:00
Add support for running available commands prior to MCP servers loading (#15596)
This commit is contained in:
@@ -36,6 +36,7 @@ import {
|
||||
debugLogger,
|
||||
coreEvents,
|
||||
CoreEvent,
|
||||
MCPDiscoveryState,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { Part, PartListUnion } from '@google/genai';
|
||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
@@ -178,6 +179,11 @@ describe('useGeminiStream', () => {
|
||||
return clientInstance;
|
||||
});
|
||||
|
||||
const mockMcpClientManager = {
|
||||
getDiscoveryState: vi.fn().mockReturnValue(MCPDiscoveryState.COMPLETED),
|
||||
getMcpServerCount: vi.fn().mockReturnValue(0),
|
||||
};
|
||||
|
||||
const contentGeneratorConfig = {
|
||||
model: 'test-model',
|
||||
apiKey: 'test-key',
|
||||
@@ -211,6 +217,7 @@ describe('useGeminiStream', () => {
|
||||
getProjectRoot: vi.fn(() => '/test/dir'),
|
||||
getCheckpointingEnabled: vi.fn(() => false),
|
||||
getGeminiClient: mockGetGeminiClient,
|
||||
getMcpClientManager: () => mockMcpClientManager as any,
|
||||
getApprovalMode: () => ApprovalMode.DEFAULT,
|
||||
getUsageStatisticsEnabled: () => true,
|
||||
getDebugMode: () => false,
|
||||
@@ -254,6 +261,7 @@ describe('useGeminiStream', () => {
|
||||
.mockClear()
|
||||
.mockReturnValue((async function* () {})());
|
||||
handleAtCommandSpy = vi.spyOn(atCommandProcessor, 'handleAtCommand');
|
||||
vi.spyOn(coreEvents, 'emitFeedback');
|
||||
});
|
||||
|
||||
const mockLoadedSettings: LoadedSettings = {
|
||||
@@ -1954,6 +1962,73 @@ describe('useGeminiStream', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('MCP Discovery State', () => {
|
||||
it('should block non-slash command queries when discovery is in progress and servers exist', async () => {
|
||||
const mockMcpClientManager = {
|
||||
getDiscoveryState: vi
|
||||
.fn()
|
||||
.mockReturnValue(MCPDiscoveryState.IN_PROGRESS),
|
||||
getMcpServerCount: vi.fn().mockReturnValue(1),
|
||||
};
|
||||
mockConfig.getMcpClientManager = () => mockMcpClientManager as any;
|
||||
|
||||
const { result } = renderTestHook();
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('test query');
|
||||
});
|
||||
|
||||
expect(coreEvents.emitFeedback).toHaveBeenCalledWith(
|
||||
'info',
|
||||
'Waiting for MCP servers to initialize... Slash commands are still available.',
|
||||
);
|
||||
expect(mockSendMessageStream).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT block queries when discovery is NOT_STARTED but there are no servers', async () => {
|
||||
const mockMcpClientManager = {
|
||||
getDiscoveryState: vi
|
||||
.fn()
|
||||
.mockReturnValue(MCPDiscoveryState.NOT_STARTED),
|
||||
getMcpServerCount: vi.fn().mockReturnValue(0),
|
||||
};
|
||||
mockConfig.getMcpClientManager = () => mockMcpClientManager as any;
|
||||
|
||||
const { result } = renderTestHook();
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('test query');
|
||||
});
|
||||
|
||||
expect(coreEvents.emitFeedback).not.toHaveBeenCalledWith(
|
||||
'info',
|
||||
'Waiting for MCP servers to initialize... Slash commands are still available.',
|
||||
);
|
||||
expect(mockSendMessageStream).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT block slash commands even when discovery is in progress', async () => {
|
||||
const mockMcpClientManager = {
|
||||
getDiscoveryState: vi
|
||||
.fn()
|
||||
.mockReturnValue(MCPDiscoveryState.IN_PROGRESS),
|
||||
getMcpServerCount: vi.fn().mockReturnValue(1),
|
||||
};
|
||||
mockConfig.getMcpClientManager = () => mockMcpClientManager as any;
|
||||
|
||||
const { result } = renderTestHook();
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('/help');
|
||||
});
|
||||
|
||||
expect(coreEvents.emitFeedback).not.toHaveBeenCalledWith(
|
||||
'info',
|
||||
'Waiting for MCP servers to initialize... Slash commands are still available.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleFinishedEvent', () => {
|
||||
it('should add info message for MAX_TOKENS finish reason', async () => {
|
||||
// Setup mock to return a stream with MAX_TOKENS finish reason
|
||||
@@ -3015,4 +3090,68 @@ describe('useGeminiStream', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('MCP Server Initialization', () => {
|
||||
it('should allow slash commands to run while MCP servers are initializing', async () => {
|
||||
const mockMcpClientManager = {
|
||||
getDiscoveryState: vi
|
||||
.fn()
|
||||
.mockReturnValue(MCPDiscoveryState.IN_PROGRESS),
|
||||
getMcpServerCount: vi.fn().mockReturnValue(1),
|
||||
};
|
||||
mockConfig.getMcpClientManager = () => mockMcpClientManager as any;
|
||||
|
||||
const { result } = renderTestHook();
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('/help');
|
||||
});
|
||||
|
||||
// Slash command should be handled, and no Gemini call should be made.
|
||||
expect(mockHandleSlashCommand).toHaveBeenCalledWith('/help');
|
||||
expect(coreEvents.emitFeedback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should block normal prompts and provide feedback while MCP servers are initializing', async () => {
|
||||
const mockMcpClientManager = {
|
||||
getDiscoveryState: vi
|
||||
.fn()
|
||||
.mockReturnValue(MCPDiscoveryState.IN_PROGRESS),
|
||||
getMcpServerCount: vi.fn().mockReturnValue(1),
|
||||
};
|
||||
mockConfig.getMcpClientManager = () => mockMcpClientManager as any;
|
||||
const { result } = renderTestHook();
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('a normal prompt');
|
||||
});
|
||||
|
||||
// No slash command, no Gemini call, but feedback should be emitted.
|
||||
expect(mockHandleSlashCommand).not.toHaveBeenCalled();
|
||||
expect(mockSendMessageStream).not.toHaveBeenCalled();
|
||||
expect(coreEvents.emitFeedback).toHaveBeenCalledWith(
|
||||
'info',
|
||||
'Waiting for MCP servers to initialize... Slash commands are still available.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow normal prompts to run when MCP servers are finished initializing', async () => {
|
||||
const mockMcpClientManager = {
|
||||
getDiscoveryState: vi.fn().mockReturnValue(MCPDiscoveryState.COMPLETED),
|
||||
getMcpServerCount: vi.fn().mockReturnValue(1),
|
||||
};
|
||||
mockConfig.getMcpClientManager = () => mockMcpClientManager as any;
|
||||
|
||||
const { result } = renderTestHook();
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('a normal prompt');
|
||||
});
|
||||
|
||||
// Prompt should be sent to Gemini.
|
||||
expect(mockHandleSlashCommand).not.toHaveBeenCalled();
|
||||
expect(mockSendMessageStream).toHaveBeenCalled();
|
||||
expect(coreEvents.emitFeedback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user