ability to override core system prompt (via .gemini/system.md) and specify core tools via coreTools setting (e.g. coreTools:["ls", "GrepTool", ...]) ; added tests, but did not update docs for now (#413)

This commit is contained in:
Olcan 2025-05-17 19:45:16 -07:00 committed by GitHub
parent 76cf5e9fc1
commit 3bf0304e31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 227 additions and 42 deletions

View File

@ -399,6 +399,7 @@ export async function loadCliConfig(settings: Settings): Promise<Config> {
debugMode,
argv.prompt || '',
argv.all_files || false,
settings.coreTools || undefined,
settings.toolDiscoveryCommand,
settings.toolCallCommand,
settings.mcpServerCommand,

View File

@ -21,6 +21,7 @@ export enum SettingScope {
export interface Settings {
theme?: string;
sandbox?: boolean | string;
coreTools?: string[];
toolDiscoveryCommand?: string;
toolCallCommand?: string;
mcpServerCommand?: string;

View File

@ -56,6 +56,7 @@ describe('Server Config (config.ts)', () => {
DEBUG_MODE,
QUESTION,
FULL_CONTEXT,
undefined, // coreTools
undefined, // toolDiscoveryCommand
undefined, // toolCallCommand
undefined, // mcpServerCommand
@ -85,6 +86,7 @@ describe('Server Config (config.ts)', () => {
undefined,
undefined,
undefined,
undefined,
USER_AGENT,
// No userMemory argument
);
@ -101,10 +103,11 @@ describe('Server Config (config.ts)', () => {
DEBUG_MODE,
QUESTION,
FULL_CONTEXT,
undefined,
undefined,
undefined,
undefined,
undefined, // coreTools
undefined, // toolDiscoveryCommand
undefined, // toolCallCommand
undefined, // mcpServerCommand
undefined, // mcpServers
USER_AGENT,
USER_MEMORY, // Pass memory here
);
@ -125,10 +128,11 @@ describe('Server Config (config.ts)', () => {
DEBUG_MODE,
QUESTION,
FULL_CONTEXT,
undefined,
undefined,
undefined,
undefined,
undefined, // coreTools
undefined, // toolDiscoveryCommand
undefined, // toolCallCommand
undefined, // mcpServerCommand
undefined, // mcpServers
USER_AGENT,
// No userMemory argument
);
@ -148,10 +152,11 @@ describe('Server Config (config.ts)', () => {
DEBUG_MODE,
QUESTION,
FULL_CONTEXT,
undefined,
undefined,
undefined,
undefined,
undefined, // coreTools
undefined, // toolDiscoveryCommand
undefined, // toolCallCommand
undefined, // mcpServerCommand
undefined, // mcpServers
USER_AGENT,
USER_MEMORY,
);

View File

@ -19,7 +19,6 @@ import { ShellTool } from '../tools/shell.js';
import { WriteFileTool } from '../tools/write-file.js';
import { WebFetchTool } from '../tools/web-fetch.js';
import { ReadManyFilesTool } from '../tools/read-many-files.js';
import { BaseTool, ToolResult } from '../tools/tools.js';
import { MemoryTool } from '../tools/memoryTool.js';
export class MCPServerConfig {
@ -43,6 +42,7 @@ export class Config {
private readonly debugMode: boolean,
private readonly question: string | undefined, // Keep undefined possibility
private readonly fullContext: boolean = false, // Default value here
private readonly coreTools: string[] | undefined,
private readonly toolDiscoveryCommand: string | undefined,
private readonly toolCallCommand: string | undefined,
private readonly mcpServerCommand: string | undefined,
@ -87,6 +87,10 @@ export class Config {
return this.fullContext;
}
getCoreTools(): string[] | undefined {
return this.coreTools;
}
getToolDiscoveryCommand(): string | undefined {
return this.toolDiscoveryCommand;
}
@ -168,6 +172,7 @@ export function createServerConfig(
debugMode: boolean,
question: string,
fullContext?: boolean,
coreTools?: string[],
toolDiscoveryCommand?: string,
toolCallCommand?: string,
mcpServerCommand?: string,
@ -185,6 +190,7 @@ export function createServerConfig(
debugMode,
question,
fullContext,
coreTools,
toolDiscoveryCommand,
toolCallCommand,
mcpServerCommand,
@ -199,23 +205,30 @@ export function createServerConfig(
function createToolRegistry(config: Config): ToolRegistry {
const registry = new ToolRegistry(config);
const targetDir = config.getTargetDir();
const tools = config.getCoreTools()
? new Set(config.getCoreTools())
: undefined;
const tools: Array<BaseTool<unknown, ToolResult>> = [
new LSTool(targetDir),
new ReadFileTool(targetDir),
new GrepTool(targetDir),
new GlobTool(targetDir),
new EditTool(config),
new WriteFileTool(config),
new WebFetchTool(),
new ReadManyFilesTool(targetDir),
new ShellTool(config),
new MemoryTool(),
];
// helper to create & register core tools that are enabled
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const registerCoreTool = (ToolClass: any, ...args: unknown[]) => {
// check both the tool name (.Name) and the class name (.name)
if (!tools || tools.has(ToolClass.Name) || tools.has(ToolClass.name)) {
registry.registerTool(new ToolClass(...args));
}
};
registerCoreTool(LSTool, targetDir);
registerCoreTool(ReadFileTool, targetDir);
registerCoreTool(GrepTool, targetDir);
registerCoreTool(GlobTool, targetDir);
registerCoreTool(EditTool, config);
registerCoreTool(WriteFileTool, config);
registerCoreTool(WebFetchTool);
registerCoreTool(ReadManyFilesTool, targetDir);
registerCoreTool(ShellTool, config);
registerCoreTool(MemoryTool);
for (const tool of tools) {
registry.registerTool(tool);
}
registry.discoverTools();
return registry;
}

View File

@ -65,7 +65,7 @@ Rigorously adhere to existing project conventions when reading or modifying code
- **Command Execution:** Use the 'execute_bash_command' tool for running shell commands, remembering the safety rule to explain modifying commands first.
- **Background Processes:** Use background processes (via \`&\`) for commands that are unlikely to stop on their own, e.g. \`node server.js &\`. If unsure, ask the user.
- **Interactive Commands:** Try to avoid shell commands that are likely to require user interaction (e.g. \`git rebase -i\`). Use non-interactive versions of commands (e.g. \`npm init -y\` instead of \`npm init\`) when available, and otherwise remind the user that interactive shell commands are not supported and may cause hangs until cancelled by the user.
- **Remembering Facts:** Use the 'saveMemory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
## Interaction Details
- **Help Command:** The user can use '/help' to display help information.
@ -219,7 +219,7 @@ Rigorously adhere to existing project conventions when reading or modifying code
- **Command Execution:** Use the 'execute_bash_command' tool for running shell commands, remembering the safety rule to explain modifying commands first.
- **Background Processes:** Use background processes (via \`&\`) for commands that are unlikely to stop on their own, e.g. \`node server.js &\`. If unsure, ask the user.
- **Interactive Commands:** Try to avoid shell commands that are likely to require user interaction (e.g. \`git rebase -i\`). Use non-interactive versions of commands (e.g. \`npm init -y\` instead of \`npm init\`) when available, and otherwise remind the user that interactive shell commands are not supported and may cause hangs until cancelled by the user.
- **Remembering Facts:** Use the 'saveMemory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
## Interaction Details
- **Help Command:** The user can use '/help' to display help information.
@ -368,7 +368,7 @@ Rigorously adhere to existing project conventions when reading or modifying code
- **Command Execution:** Use the 'execute_bash_command' tool for running shell commands, remembering the safety rule to explain modifying commands first.
- **Background Processes:** Use background processes (via \`&\`) for commands that are unlikely to stop on their own, e.g. \`node server.js &\`. If unsure, ask the user.
- **Interactive Commands:** Try to avoid shell commands that are likely to require user interaction (e.g. \`git rebase -i\`). Use non-interactive versions of commands (e.g. \`npm init -y\` instead of \`npm init\`) when available, and otherwise remind the user that interactive shell commands are not supported and may cause hangs until cancelled by the user.
- **Remembering Facts:** Use the 'saveMemory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
## Interaction Details
- **Help Command:** The user can use '/help' to display help information.
@ -517,7 +517,7 @@ Rigorously adhere to existing project conventions when reading or modifying code
- **Command Execution:** Use the 'execute_bash_command' tool for running shell commands, remembering the safety rule to explain modifying commands first.
- **Background Processes:** Use background processes (via \`&\`) for commands that are unlikely to stop on their own, e.g. \`node server.js &\`. If unsure, ask the user.
- **Interactive Commands:** Try to avoid shell commands that are likely to require user interaction (e.g. \`git rebase -i\`). Use non-interactive versions of commands (e.g. \`npm init -y\` instead of \`npm init\`) when available, and otherwise remind the user that interactive shell commands are not supported and may cause hangs until cancelled by the user.
- **Remembering Facts:** Use the 'saveMemory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
## Interaction Details
- **Help Command:** The user can use '/help' to display help information.
@ -666,7 +666,7 @@ Rigorously adhere to existing project conventions when reading or modifying code
- **Command Execution:** Use the 'execute_bash_command' tool for running shell commands, remembering the safety rule to explain modifying commands first.
- **Background Processes:** Use background processes (via \`&\`) for commands that are unlikely to stop on their own, e.g. \`node server.js &\`. If unsure, ask the user.
- **Interactive Commands:** Try to avoid shell commands that are likely to require user interaction (e.g. \`git rebase -i\`). Use non-interactive versions of commands (e.g. \`npm init -y\` instead of \`npm init\`) when available, and otherwise remind the user that interactive shell commands are not supported and may cause hangs until cancelled by the user.
- **Remembering Facts:** Use the 'saveMemory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
## Interaction Details
- **Help Command:** The user can use '/help' to display help information.
@ -815,7 +815,7 @@ Rigorously adhere to existing project conventions when reading or modifying code
- **Command Execution:** Use the 'execute_bash_command' tool for running shell commands, remembering the safety rule to explain modifying commands first.
- **Background Processes:** Use background processes (via \`&\`) for commands that are unlikely to stop on their own, e.g. \`node server.js &\`. If unsure, ask the user.
- **Interactive Commands:** Try to avoid shell commands that are likely to require user interaction (e.g. \`git rebase -i\`). Use non-interactive versions of commands (e.g. \`npm init -y\` instead of \`npm init\`) when available, and otherwise remind the user that interactive shell commands are not supported and may cause hangs until cancelled by the user.
- **Remembering Facts:** Use the 'saveMemory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
## Interaction Details
- **Help Command:** The user can use '/help' to display help information.
@ -964,7 +964,7 @@ Rigorously adhere to existing project conventions when reading or modifying code
- **Command Execution:** Use the 'execute_bash_command' tool for running shell commands, remembering the safety rule to explain modifying commands first.
- **Background Processes:** Use background processes (via \`&\`) for commands that are unlikely to stop on their own, e.g. \`node server.js &\`. If unsure, ask the user.
- **Interactive Commands:** Try to avoid shell commands that are likely to require user interaction (e.g. \`git rebase -i\`). Use non-interactive versions of commands (e.g. \`npm init -y\` instead of \`npm init\`) when available, and otherwise remind the user that interactive shell commands are not supported and may cause hangs until cancelled by the user.
- **Remembering Facts:** Use the 'saveMemory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information that belongs in project-specific \`GEMINI.md\` files. If unsure whether to save something, you can ask the user, "Should I remember that for you?"
## Interaction Details
- **Help Command:** The user can use '/help' to display help information.

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import path from 'node:path';
import fs from 'node:fs';
import { LSTool } from '../tools/ls.js';
import { EditTool } from '../tools/edit.js';
import { GlobTool } from '../tools/glob.js';
@ -12,14 +14,18 @@ import { ReadFileTool } from '../tools/read-file.js';
import { ReadManyFilesTool } from '../tools/read-many-files.js';
import { ShellTool } from '../tools/shell.js';
import { WriteFileTool } from '../tools/write-file.js';
import process from 'node:process'; // Import process
import process from 'node:process';
import { execSync } from 'node:child_process';
import { MemoryTool } from '../tools/memoryTool.js';
import { MemoryTool, GEMINI_CONFIG_DIR } from '../tools/memoryTool.js';
const contactEmail = 'gemini-code-dev@google.com';
export function getCoreSystemPrompt(userMemory?: string): string {
const basePrompt = `
// replace base prompt with system.md if it exists under GEMINI_CONFIG_DIR
const systemMdPath = path.join(GEMINI_CONFIG_DIR, 'system.md');
const basePrompt = fs.existsSync(systemMdPath)
? fs.readFileSync(systemMdPath, 'utf8')
: `
You are an interactive CLI agent specializing in software engineering tasks. Your primary goal is to help users safely and efficiently, adhering strictly to the following instructions and utilizing your available tools.
# Primary Workflows

View File

@ -155,13 +155,13 @@ describe('MemoryTool', () => {
});
it('should have correct name, displayName, description, and schema', () => {
expect(memoryTool.name).toBe('saveMemory');
expect(memoryTool.name).toBe('save_memory');
expect(memoryTool.displayName).toBe('Save Memory');
expect(memoryTool.description).toContain(
'Saves a specific piece of information',
);
expect(memoryTool.schema).toBeDefined();
expect(memoryTool.schema.name).toBe('saveMemory');
expect(memoryTool.schema.name).toBe('save_memory');
expect(memoryTool.schema.parameters?.properties?.fact).toBeDefined();
});

View File

@ -10,7 +10,7 @@ import * as path from 'path';
import { homedir } from 'os';
const memoryToolSchemaData = {
name: 'saveMemory',
name: 'save_memory',
description:
'Saves a specific piece of information or fact to your long-term memory. Use this when the user explicitly asks you to remember something, or when they state a clear, concise fact that seems important to retain for future interactions.',
parameters: {
@ -180,7 +180,7 @@ export class MemoryTool extends BaseTool<SaveMemoryParams, ToolResult> {
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(
`[MemoryTool] Error executing saveMemory for fact "${fact}": ${errorMessage}`,
`[MemoryTool] Error executing save_memory for fact "${fact}": ${errorMessage}`,
);
return {
llmContent: JSON.stringify({

View File

@ -87,6 +87,7 @@ describe('ToolRegistry', () => {
false, // debugMode
undefined, // question
false, // fullContext
undefined, // coreTools
undefined, // toolDiscoveryCommand
undefined, // toolCallCommand
undefined, // mcpServerCommand
@ -170,6 +171,163 @@ describe('ToolRegistry', () => {
});
});
// New describe block for coreTools testing
describe('core tool registration based on config.coreTools', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const MOCK_TOOL_ALPHA_CLASS_NAME = 'MockCoreToolAlpha'; // Class.name
const MOCK_TOOL_ALPHA_STATIC_NAME = 'ToolAlphaFromStatic'; // Tool.Name and registration name
class MockCoreToolAlpha extends BaseTool<any, ToolResult> {
static readonly Name = MOCK_TOOL_ALPHA_STATIC_NAME;
constructor() {
super(
MockCoreToolAlpha.Name,
MockCoreToolAlpha.Name,
'Description for Alpha Tool',
{},
);
}
async execute(_params: any): Promise<ToolResult> {
return { llmContent: 'AlphaExecuted', returnDisplay: 'AlphaExecuted' };
}
}
const MOCK_TOOL_BETA_CLASS_NAME = 'MockCoreToolBeta'; // Class.name
const MOCK_TOOL_BETA_STATIC_NAME = 'ToolBetaFromStatic'; // Tool.Name and registration name
class MockCoreToolBeta extends BaseTool<any, ToolResult> {
static readonly Name = MOCK_TOOL_BETA_STATIC_NAME;
constructor() {
super(
MockCoreToolBeta.Name,
MockCoreToolBeta.Name,
'Description for Beta Tool',
{},
);
}
async execute(_params: any): Promise<ToolResult> {
return { llmContent: 'BetaExecuted', returnDisplay: 'BetaExecuted' };
}
}
const availableCoreToolClasses = [MockCoreToolAlpha, MockCoreToolBeta];
let currentConfig: Config;
let currentToolRegistry: ToolRegistry;
const mockTargetDir = '/test/dir'; // As used in outer scope
// Helper to set up Config, ToolRegistry, and simulate core tool registration
const setupRegistryAndSimulateRegistration = (
coreToolsValueInConfig: string[] | undefined,
) => {
currentConfig = new Config(
'test-api-key',
'test-model',
false, // sandbox
mockTargetDir, // targetDir
false, // debugMode
undefined, // question
false, // fullContext
coreToolsValueInConfig, // coreTools setting being tested
undefined, // toolDiscoveryCommand
undefined, // toolCallCommand
undefined, // mcpServerCommand
undefined, // mcpServers
'TestAgent/1.0', // userAgent
);
// We assume Config has a getter like getCoreTools() or stores it publicly.
// For this test, we'll directly use coreToolsValueInConfig for the simulation logic,
// as that's what Config would provide.
const coreToolsListFromConfig = coreToolsValueInConfig; // Simulating config.getCoreTools()
currentToolRegistry = new ToolRegistry(currentConfig);
// Simulate the external process that registers core tools based on config
if (coreToolsListFromConfig === undefined) {
// If coreTools is undefined, all available core tools are registered
availableCoreToolClasses.forEach((ToolClass) => {
currentToolRegistry.registerTool(new ToolClass());
});
} else {
// If coreTools is an array, register tools if their static Name or class name is in the list
availableCoreToolClasses.forEach((ToolClass) => {
if (
coreToolsListFromConfig.includes(ToolClass.Name) || // Check against static Name
coreToolsListFromConfig.includes(ToolClass.name) // Check against class name
) {
currentToolRegistry.registerTool(new ToolClass());
}
});
}
};
// beforeEach for this nested describe is not strictly needed if setup is per-test,
// but ensure console.warn is mocked if any registration overwrites occur (though unlikely with this setup).
beforeEach(() => {
vi.spyOn(console, 'warn').mockImplementation(() => {});
});
it('should register all core tools if coreTools config is undefined', () => {
setupRegistryAndSimulateRegistration(undefined);
expect(
currentToolRegistry.getTool(MOCK_TOOL_ALPHA_STATIC_NAME),
).toBeInstanceOf(MockCoreToolAlpha);
expect(
currentToolRegistry.getTool(MOCK_TOOL_BETA_STATIC_NAME),
).toBeInstanceOf(MockCoreToolBeta);
expect(currentToolRegistry.getAllTools()).toHaveLength(2);
});
it('should register no core tools if coreTools config is an empty array []', () => {
setupRegistryAndSimulateRegistration([]);
expect(currentToolRegistry.getAllTools()).toHaveLength(0);
expect(
currentToolRegistry.getTool(MOCK_TOOL_ALPHA_STATIC_NAME),
).toBeUndefined();
expect(
currentToolRegistry.getTool(MOCK_TOOL_BETA_STATIC_NAME),
).toBeUndefined();
});
it('should register only tools specified by their static Name (ToolClass.Name) in coreTools config', () => {
setupRegistryAndSimulateRegistration([MOCK_TOOL_ALPHA_STATIC_NAME]); // e.g., ["ToolAlphaFromStatic"]
expect(
currentToolRegistry.getTool(MOCK_TOOL_ALPHA_STATIC_NAME),
).toBeInstanceOf(MockCoreToolAlpha);
expect(
currentToolRegistry.getTool(MOCK_TOOL_BETA_STATIC_NAME),
).toBeUndefined();
expect(currentToolRegistry.getAllTools()).toHaveLength(1);
});
it('should register only tools specified by their class name (ToolClass.name) in coreTools config', () => {
// ToolBeta is registered under MOCK_TOOL_BETA_STATIC_NAME ('ToolBetaFromStatic')
// We configure coreTools with its class name: MOCK_TOOL_BETA_CLASS_NAME ('MockCoreToolBeta')
setupRegistryAndSimulateRegistration([MOCK_TOOL_BETA_CLASS_NAME]);
expect(
currentToolRegistry.getTool(MOCK_TOOL_BETA_STATIC_NAME),
).toBeInstanceOf(MockCoreToolBeta);
expect(
currentToolRegistry.getTool(MOCK_TOOL_ALPHA_STATIC_NAME),
).toBeUndefined();
expect(currentToolRegistry.getAllTools()).toHaveLength(1);
});
it('should register tools if specified by either static Name or class name in a mixed coreTools config', () => {
// Config: ["ToolAlphaFromStatic", "MockCoreToolBeta"]
// ToolAlpha matches by static Name. ToolBeta matches by class name.
setupRegistryAndSimulateRegistration([
MOCK_TOOL_ALPHA_STATIC_NAME, // Matches MockCoreToolAlpha.Name
MOCK_TOOL_BETA_CLASS_NAME, // Matches MockCoreToolBeta.name
]);
expect(
currentToolRegistry.getTool(MOCK_TOOL_ALPHA_STATIC_NAME),
).toBeInstanceOf(MockCoreToolAlpha);
expect(
currentToolRegistry.getTool(MOCK_TOOL_BETA_STATIC_NAME),
).toBeInstanceOf(MockCoreToolBeta); // Registered under its static Name
expect(currentToolRegistry.getAllTools()).toHaveLength(2);
});
});
describe('discoverTools', () => {
let mockConfigGetToolDiscoveryCommand: ReturnType<typeof vi.spyOn>;
let mockConfigGetMcpServers: ReturnType<typeof vi.spyOn>;
@ -417,6 +575,7 @@ describe('DiscoveredTool', () => {
false, // debugMode
undefined, // question
false, // fullContext
undefined, // coreTools
undefined, // toolDiscoveryCommand
undefined, // toolCallCommand
undefined, // mcpServerCommand