Download packages/cli/src/ui/commands/agentsCommand.test.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 15.8 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/commands/agentsCommand.test.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/cli/src/ui/commands/agentsCommand.test.ts
-
curl -L -o agentsCommand.test.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/commands/agentsCommand.test.ts
15.8 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { vi, describe, it, expect, beforeEach } from 'vitest'; | |
| import { agentsCommand } from './agentsCommand.js'; | |
| import { createMockCommandContext } from '../../test-utils/mockCommandContext.js'; | |
| import type { Config } from '@google/gemini-cli-core'; | |
| import type { LoadedSettings } from '../../config/settings.js'; | |
| import { MessageType } from '../types.js'; | |
| import { enableAgent, disableAgent } from '../../utils/agentSettings.js'; | |
| import { renderAgentActionFeedback } from '../../utils/agentUtils.js'; | |
| vi.mock('../../utils/agentSettings.js', () => ({ | |
| enableAgent: vi.fn(), | |
| disableAgent: vi.fn(), | |
| })); | |
| vi.mock('../../utils/agentUtils.js', () => ({ | |
| renderAgentActionFeedback: vi.fn(), | |
| })); | |
| describe('agentsCommand', () => { | |
| let mockContext: ReturnType<typeof createMockCommandContext>; | |
| let mockConfig: { | |
| getAgentRegistry: ReturnType<typeof vi.fn>; | |
| config: Config; | |
| }; | |
| beforeEach(() => { | |
| vi.clearAllMocks(); | |
| mockConfig = { | |
| getAgentRegistry: vi.fn().mockReturnValue({ | |
| getAllDefinitions: vi.fn().mockReturnValue([]), | |
| getAllAgentNames: vi.fn().mockReturnValue([]), | |
| reload: vi.fn(), | |
| }), | |
| get config() { | |
| return this as unknown as Config; | |
| }, | |
| }; | |
| mockContext = createMockCommandContext({ | |
| services: { | |
| agentContext: mockConfig as unknown as Config, | |
| settings: { | |
| workspace: { path: '/mock/path' }, | |
| merged: { agents: { overrides: {} } }, | |
| } as unknown as LoadedSettings, | |
| }, | |
| }); | |
| }); | |
| it('should show an error if config is not available', async () => { | |
| const contextWithoutConfig = createMockCommandContext({ | |
| services: { | |
| agentContext: null, | |
| }, | |
| }); | |
| const result = await agentsCommand.action!(contextWithoutConfig, ''); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Config not loaded.', | |
| }); | |
| }); | |
| it('should show an error if agent registry is not available', async () => { | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue(undefined); | |
| const result = await agentsCommand.action!(mockContext, ''); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Agent registry not found.', | |
| }); | |
| }); | |
| it('should call addItem with correct agents list', async () => { | |
| const mockAgents = [ | |
| { | |
| name: 'agent1', | |
| displayName: 'Agent One', | |
| description: 'desc1', | |
| kind: 'local', | |
| }, | |
| { | |
| name: 'agent2', | |
| displayName: undefined, | |
| description: 'desc2', | |
| kind: 'remote', | |
| }, | |
| ]; | |
| mockConfig.getAgentRegistry().getAllDefinitions.mockReturnValue(mockAgents); | |
| await agentsCommand.action!(mockContext, ''); | |
| expect(mockContext.ui.addItem).toHaveBeenCalledWith( | |
| expect.objectContaining({ | |
| type: MessageType.AGENTS_LIST, | |
| agents: mockAgents, | |
| }), | |
| ); | |
| }); | |
| it('should reload the agent registry when reload subcommand is called', async () => { | |
| const reloadSpy = vi.fn().mockResolvedValue({ | |
| totalLoaded: 3, | |
| localCount: 2, | |
| remoteCount: 1, | |
| newAgents: ['new-agent'], | |
| updatedAgents: ['updated-agent'], | |
| deletedAgents: ['deleted-agent'], | |
| errors: [], | |
| }); | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue({ | |
| reload: reloadSpy, | |
| }); | |
| const reloadCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'reload', | |
| ); | |
| expect(reloadCommand).toBeDefined(); | |
| const result = (await reloadCommand!.action!(mockContext, '')) as { | |
| type: 'message'; | |
| content: string; | |
| }; | |
| expect(reloadSpy).toHaveBeenCalled(); | |
| expect(mockContext.ui.addItem).toHaveBeenCalledWith( | |
| expect.objectContaining({ | |
| type: MessageType.INFO, | |
| text: 'Reloading agent registry...', | |
| }), | |
| ); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'info', | |
| content: expect.stringContaining('Agents reloaded successfully:'), | |
| }); | |
| expect(result.content).toContain('- Total: 3 (2 local, 1 remote)'); | |
| expect(result.content).toContain('- New: new-agent'); | |
| expect(result.content).toContain('- Updated: updated-agent'); | |
| expect(result.content).toContain('- Deleted: deleted-agent'); | |
| expect(result.content).toContain( | |
| 'Run /agents list to see all available agents.', | |
| ); | |
| }); | |
| it('should show "reloaded with errors" if errors occurred during reload', async () => { | |
| const reloadSpy = vi.fn().mockResolvedValue({ | |
| totalLoaded: 1, | |
| localCount: 1, | |
| remoteCount: 0, | |
| newAgents: [], | |
| updatedAgents: [], | |
| deletedAgents: [], | |
| errors: ['Some error'], | |
| }); | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue({ | |
| reload: reloadSpy, | |
| }); | |
| const reloadCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'reload', | |
| ); | |
| const result = (await reloadCommand!.action!(mockContext, '')) as { | |
| type: 'message'; | |
| content: string; | |
| }; | |
| expect(result.content).toContain('Agents reloaded with errors:'); | |
| expect(result.content).toContain('- Errors: 1 encountered during reload'); | |
| }); | |
| it('should show an error if agent registry is not available during reload', async () => { | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue(undefined); | |
| const reloadCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'reload', | |
| ); | |
| const result = await reloadCommand!.action!(mockContext, ''); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Agent registry not found.', | |
| }); | |
| }); | |
| it('should enable an agent successfully', async () => { | |
| const reloadSpy = vi.fn().mockResolvedValue(undefined); | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue({ | |
| getAllAgentNames: vi.fn().mockReturnValue([]), | |
| reload: reloadSpy, | |
| }); | |
| // Add agent to disabled overrides so validation passes | |
| mockContext.services.settings.merged.agents.overrides['test-agent'] = { | |
| enabled: false, | |
| }; | |
| vi.mocked(enableAgent).mockReturnValue({ | |
| status: 'success', | |
| agentName: 'test-agent', | |
| action: 'enable', | |
| modifiedScopes: [], | |
| alreadyInStateScopes: [], | |
| }); | |
| vi.mocked(renderAgentActionFeedback).mockReturnValue('Enabled test-agent.'); | |
| const enableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'enable', | |
| ); | |
| expect(enableCommand).toBeDefined(); | |
| const result = await enableCommand!.action!(mockContext, 'test-agent'); | |
| expect(enableAgent).toHaveBeenCalledWith( | |
| mockContext.services.settings, | |
| 'test-agent', | |
| ); | |
| expect(reloadSpy).toHaveBeenCalled(); | |
| expect(mockContext.ui.addItem).toHaveBeenCalledWith( | |
| expect.objectContaining({ | |
| type: MessageType.INFO, | |
| text: 'Enabling test-agent...', | |
| }), | |
| ); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'info', | |
| content: 'Enabled test-agent.', | |
| }); | |
| }); | |
| it('should handle no-op when enabling an agent', async () => { | |
| mockConfig | |
| .getAgentRegistry() | |
| .getAllAgentNames.mockReturnValue(['test-agent']); | |
| const enableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'enable', | |
| ); | |
| const result = await enableCommand!.action!(mockContext, 'test-agent'); | |
| expect(enableAgent).not.toHaveBeenCalled(); | |
| expect(mockContext.ui.addItem).not.toHaveBeenCalled(); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'info', | |
| content: "Agent 'test-agent' is already enabled.", | |
| }); | |
| }); | |
| it('should show usage error if no agent name provided for enable', async () => { | |
| const enableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'enable', | |
| ); | |
| const result = await enableCommand!.action!(mockContext, ' '); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Usage: /agents enable <agent-name>', | |
| }); | |
| }); | |
| it('should show an error if config is not available for enable', async () => { | |
| const contextWithoutConfig = createMockCommandContext({ | |
| services: { agentContext: null }, | |
| }); | |
| const enableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'enable', | |
| ); | |
| const result = await enableCommand!.action!(contextWithoutConfig, 'test'); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Config not loaded.', | |
| }); | |
| }); | |
| it('should disable an agent successfully', async () => { | |
| const reloadSpy = vi.fn().mockResolvedValue(undefined); | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue({ | |
| getAllAgentNames: vi.fn().mockReturnValue(['test-agent']), | |
| reload: reloadSpy, | |
| }); | |
| vi.mocked(disableAgent).mockReturnValue({ | |
| status: 'success', | |
| agentName: 'test-agent', | |
| action: 'disable', | |
| modifiedScopes: [], | |
| alreadyInStateScopes: [], | |
| }); | |
| vi.mocked(renderAgentActionFeedback).mockReturnValue( | |
| 'Disabled test-agent.', | |
| ); | |
| const disableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'disable', | |
| ); | |
| expect(disableCommand).toBeDefined(); | |
| const result = await disableCommand!.action!(mockContext, 'test-agent'); | |
| expect(disableAgent).toHaveBeenCalledWith( | |
| mockContext.services.settings, | |
| 'test-agent', | |
| expect.anything(), // Scope is derived in the command | |
| ); | |
| expect(reloadSpy).toHaveBeenCalled(); | |
| expect(mockContext.ui.addItem).toHaveBeenCalledWith( | |
| expect.objectContaining({ | |
| type: MessageType.INFO, | |
| text: 'Disabling test-agent...', | |
| }), | |
| ); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'info', | |
| content: 'Disabled test-agent.', | |
| }); | |
| }); | |
| it('should show info message if agent is already disabled', async () => { | |
| mockConfig.getAgentRegistry().getAllAgentNames.mockReturnValue([]); | |
| mockContext.services.settings.merged.agents.overrides['test-agent'] = { | |
| enabled: false, | |
| }; | |
| const disableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'disable', | |
| ); | |
| const result = await disableCommand!.action!(mockContext, 'test-agent'); | |
| expect(disableAgent).not.toHaveBeenCalled(); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'info', | |
| content: "Agent 'test-agent' is already disabled.", | |
| }); | |
| }); | |
| it('should show error if agent is not found when disabling', async () => { | |
| mockConfig.getAgentRegistry().getAllAgentNames.mockReturnValue([]); | |
| const disableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'disable', | |
| ); | |
| const result = await disableCommand!.action!(mockContext, 'test-agent'); | |
| expect(disableAgent).not.toHaveBeenCalled(); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: "Agent 'test-agent' not found.", | |
| }); | |
| }); | |
| it('should show usage error if no agent name provided for disable', async () => { | |
| const disableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'disable', | |
| ); | |
| const result = await disableCommand!.action!(mockContext, ''); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Usage: /agents disable <agent-name>', | |
| }); | |
| }); | |
| it('should show an error if config is not available for disable', async () => { | |
| const contextWithoutConfig = createMockCommandContext({ | |
| services: { agentContext: null }, | |
| }); | |
| const disableCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'disable', | |
| ); | |
| const result = await disableCommand!.action!(contextWithoutConfig, 'test'); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Config not loaded.', | |
| }); | |
| }); | |
| describe('config sub-command', () => { | |
| it('should return dialog action for a valid agent', async () => { | |
| const mockDefinition = { | |
| name: 'test-agent', | |
| displayName: 'Test Agent', | |
| description: 'test desc', | |
| kind: 'local', | |
| }; | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue({ | |
| getDiscoveredDefinition: vi.fn().mockReturnValue(mockDefinition), | |
| }); | |
| const configCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'config', | |
| ); | |
| expect(configCommand).toBeDefined(); | |
| const result = await configCommand!.action!(mockContext, 'test-agent'); | |
| expect(result).toEqual({ | |
| type: 'dialog', | |
| dialog: 'agentConfig', | |
| props: { | |
| name: 'test-agent', | |
| displayName: 'Test Agent', | |
| definition: mockDefinition, | |
| }, | |
| }); | |
| }); | |
| it('should use name as displayName if displayName is missing', async () => { | |
| const mockDefinition = { | |
| name: 'test-agent', | |
| description: 'test desc', | |
| kind: 'local', | |
| }; | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue({ | |
| getDiscoveredDefinition: vi.fn().mockReturnValue(mockDefinition), | |
| }); | |
| const configCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'config', | |
| ); | |
| const result = await configCommand!.action!(mockContext, 'test-agent'); | |
| expect(result).toEqual({ | |
| type: 'dialog', | |
| dialog: 'agentConfig', | |
| props: { | |
| name: 'test-agent', | |
| displayName: 'test-agent', // Falls back to name | |
| definition: mockDefinition, | |
| }, | |
| }); | |
| }); | |
| it('should show error if agent is not found', async () => { | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue({ | |
| getDiscoveredDefinition: vi.fn().mockReturnValue(undefined), | |
| }); | |
| const configCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'config', | |
| ); | |
| const result = await configCommand!.action!(mockContext, 'non-existent'); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: "Agent 'non-existent' not found.", | |
| }); | |
| }); | |
| it('should show usage error if no agent name provided', async () => { | |
| const configCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'config', | |
| ); | |
| const result = await configCommand!.action!(mockContext, ' '); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Usage: /agents config <agent-name>', | |
| }); | |
| }); | |
| it('should show an error if config is not available', async () => { | |
| const contextWithoutConfig = createMockCommandContext({ | |
| services: { agentContext: null }, | |
| }); | |
| const configCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'config', | |
| ); | |
| const result = await configCommand!.action!(contextWithoutConfig, 'test'); | |
| expect(result).toEqual({ | |
| type: 'message', | |
| messageType: 'error', | |
| content: 'Config not loaded.', | |
| }); | |
| }); | |
| it('should provide completions for discovered agents', async () => { | |
| mockConfig.getAgentRegistry = vi.fn().mockReturnValue({ | |
| getAllDiscoveredAgentNames: vi | |
| .fn() | |
| .mockReturnValue(['agent1', 'agent2', 'other']), | |
| }); | |
| const configCommand = agentsCommand.subCommands?.find( | |
| (cmd) => cmd.name === 'config', | |
| ); | |
| expect(configCommand?.completion).toBeDefined(); | |
| const completions = await configCommand!.completion!(mockContext, 'age'); | |
| expect(completions).toEqual(['agent1', 'agent2']); | |
| }); | |
| }); | |
| }); | |