Files
gemini-cli/packages/core/src/utils/tool-utils.test.ts

133 lines
3.9 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { expect, describe, it } from 'vitest';
import { doesToolInvocationMatch, getToolSuggestion } from './tool-utils.js';
import type { AnyToolInvocation, Config } from '../index.js';
import { ReadFileTool } from '../tools/read-file.js';
import { createMockMessageBus } from '../test-utils/mock-message-bus.js';
describe('getToolSuggestion', () => {
it('should suggest the top N closest tool names for a typo', () => {
const allToolNames = ['list_files', 'read_file', 'write_file'];
// Test that the right tool is selected, with only 1 result, for typos
const misspelledTool = getToolSuggestion('list_fils', allToolNames, 1);
expect(misspelledTool).toBe(' Did you mean "list_files"?');
// Test that the right tool is selected, with only 1 result, for prefixes
const prefixedTool = getToolSuggestion(
'github.list_files',
allToolNames,
1,
);
expect(prefixedTool).toBe(' Did you mean "list_files"?');
// Test that the right tool is first
const suggestionMultiple = getToolSuggestion('list_fils', allToolNames);
expect(suggestionMultiple).toBe(
' Did you mean one of: "list_files", "read_file", "write_file"?',
);
});
});
describe('doesToolInvocationMatch', () => {
it('should not match a partial command prefix', () => {
const invocation = {
params: { command: 'git commitsomething' },
} as AnyToolInvocation;
const patterns = ['ShellTool(git commit)'];
const result = doesToolInvocationMatch(
'run_shell_command',
invocation,
patterns,
);
expect(result).toBe(false);
});
it('should match an exact command', () => {
const invocation = {
params: { command: 'git status' },
} as AnyToolInvocation;
const patterns = ['ShellTool(git status)'];
const result = doesToolInvocationMatch(
'run_shell_command',
invocation,
patterns,
);
expect(result).toBe(true);
});
it('should match a command with an alias', () => {
const invocation = {
params: { command: 'wc -l' },
} as AnyToolInvocation;
const patterns = ['ShellTool(wc)'];
const result = doesToolInvocationMatch('ShellTool', invocation, patterns);
expect(result).toBe(true);
});
it('should match a command that is a prefix', () => {
const invocation = {
params: { command: 'git status -v' },
} as AnyToolInvocation;
const patterns = ['ShellTool(git status)'];
const result = doesToolInvocationMatch(
'run_shell_command',
invocation,
patterns,
);
expect(result).toBe(true);
});
describe('for non-shell tools', () => {
const mockConfig = {
getTargetDir: () => '/tmp',
getFileFilteringOptions: () => ({}),
} as unknown as Config;
const readFileTool = new ReadFileTool(mockConfig, createMockMessageBus());
const invocation = {
params: { file: 'test.txt' },
} as AnyToolInvocation;
it('should match by tool name', () => {
const patterns = ['read_file'];
const result = doesToolInvocationMatch(
readFileTool,
invocation,
patterns,
);
expect(result).toBe(true);
});
it('should match by tool class name', () => {
const patterns = ['ReadFileTool'];
const result = doesToolInvocationMatch(
readFileTool,
invocation,
patterns,
);
expect(result).toBe(true);
});
it('should not match if neither name is in the patterns', () => {
const patterns = ['some_other_tool', 'AnotherToolClass'];
const result = doesToolInvocationMatch(
readFileTool,
invocation,
patterns,
);
expect(result).toBe(false);
});
it('should match by tool name when passed as a string', () => {
const patterns = ['read_file'];
const result = doesToolInvocationMatch('read_file', invocation, patterns);
expect(result).toBe(true);
});
});
});