@google/gemini-cli-core 0.1.9-nightly.250709.c8cf954e → 0.1.9-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -17
- package/dist/google-gemini-cli-core-0.1.9-rc.1.tgz +0 -0
- package/dist/src/code_assist/codeAssist.js +2 -3
- package/dist/src/code_assist/codeAssist.js.map +1 -1
- package/dist/src/code_assist/converter.js.map +1 -1
- package/dist/src/code_assist/oauth2.d.ts +2 -3
- package/dist/src/code_assist/oauth2.js +25 -56
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +7 -83
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/code_assist/server.js +1 -0
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/setup.js +1 -1
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/config/config.d.ts +2 -19
- package/dist/src/config/config.js +56 -78
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +0 -25
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/core/client.d.ts +3 -18
- package/dist/src/core/client.js +14 -55
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +4 -209
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +4 -3
- package/dist/src/core/contentGenerator.js +13 -14
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +3 -49
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +2 -9
- package/dist/src/core/coreToolScheduler.js +2 -28
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +0 -78
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/logger.d.ts +4 -3
- package/dist/src/core/logger.js +11 -7
- package/dist/src/core/logger.js.map +1 -1
- package/dist/src/core/logger.test.js +15 -6
- package/dist/src/core/logger.test.js.map +1 -1
- package/dist/src/core/modelCheck.js +1 -1
- package/dist/src/core/modelCheck.js.map +1 -1
- package/dist/src/services/fileDiscoveryService.d.ts +0 -4
- package/dist/src/services/fileDiscoveryService.js +0 -13
- package/dist/src/services/fileDiscoveryService.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +11 -34
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/tools/edit.d.ts +2 -1
- package/dist/src/tools/edit.js +12 -11
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +9 -7
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/glob.d.ts +1 -5
- package/dist/src/tools/glob.js +9 -14
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/glob.test.js +3 -3
- package/dist/src/tools/glob.test.js.map +1 -1
- package/dist/src/tools/grep.js +7 -8
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/grep.test.js +3 -3
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/ls.js +8 -9
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +2 -0
- package/dist/src/tools/mcp-client.js +30 -31
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +4 -85
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.d.ts +3 -3
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/memoryTool.js +2 -3
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/read-file.js +8 -8
- package/dist/src/tools/read-file.js.map +1 -1
- package/dist/src/tools/read-file.test.js +4 -4
- package/dist/src/tools/read-file.test.js.map +1 -1
- package/dist/src/tools/read-many-files.js +38 -24
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +4 -4
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/shell.d.ts +1 -20
- package/dist/src/tools/shell.js +16 -53
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +65 -85
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +2 -16
- package/dist/src/tools/tool-registry.js +19 -150
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +75 -186
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +4 -7
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/web-fetch.js +5 -6
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-search.d.ts +0 -5
- package/dist/src/tools/web-search.js +6 -12
- package/dist/src/tools/web-search.js.map +1 -1
- package/dist/src/tools/write-file.d.ts +1 -7
- package/dist/src/tools/write-file.js +11 -17
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +4 -4
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/utils/editCorrector.d.ts +1 -1
- package/dist/src/utils/editCorrector.js +2 -106
- package/dist/src/utils/editCorrector.js.map +1 -1
- package/dist/src/utils/editCorrector.test.js +19 -65
- package/dist/src/utils/editCorrector.test.js.map +1 -1
- package/dist/src/utils/editor.d.ts +1 -1
- package/dist/src/utils/editor.js +1 -1
- package/dist/src/utils/fileUtils.d.ts +1 -1
- package/dist/src/utils/fileUtils.js +0 -17
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +0 -17
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/messageInspectors.d.ts +0 -1
- package/dist/src/utils/messageInspectors.js +0 -5
- package/dist/src/utils/messageInspectors.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.js +1 -1
- package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
- package/dist/src/utils/schemaValidator.d.ts +5 -10
- package/dist/src/utils/schemaValidator.js +32 -44
- package/dist/src/utils/schemaValidator.js.map +1 -1
- package/dist/src/utils/user_id.d.ts +1 -1
- package/dist/src/utils/user_id.js +5 -5
- package/dist/src/utils/user_id.js.map +1 -1
- package/dist/src/utils/user_id.test.js +11 -15
- package/dist/src/utils/user_id.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -11
- package/dist/google-gemini-cli-core-0.1.9.tgz +0 -0
- package/dist/src/code_assist/setup.test.d.ts +0 -6
- package/dist/src/code_assist/setup.test.js +0 -62
- package/dist/src/code_assist/setup.test.js.map +0 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { FunctionDeclaration
|
|
6
|
+
import { FunctionDeclaration } from '@google/genai';
|
|
7
7
|
import { Tool, ToolResult, BaseTool } from './tools.js';
|
|
8
8
|
import { Config } from '../config/config.js';
|
|
9
9
|
type ToolParams = Record<string, unknown>;
|
|
@@ -17,6 +17,7 @@ export declare class DiscoveredTool extends BaseTool<ToolParams, ToolResult> {
|
|
|
17
17
|
}
|
|
18
18
|
export declare class ToolRegistry {
|
|
19
19
|
private tools;
|
|
20
|
+
private discovery;
|
|
20
21
|
private config;
|
|
21
22
|
constructor(config: Config);
|
|
22
23
|
/**
|
|
@@ -29,7 +30,6 @@ export declare class ToolRegistry {
|
|
|
29
30
|
* Can be called multiple times to update discovered tools.
|
|
30
31
|
*/
|
|
31
32
|
discoverTools(): Promise<void>;
|
|
32
|
-
private discoverAndRegisterToolsFromCommand;
|
|
33
33
|
/**
|
|
34
34
|
* Retrieves the list of tool schemas (FunctionDeclaration array).
|
|
35
35
|
* Extracts the declarations from the ToolListUnion structure.
|
|
@@ -50,18 +50,4 @@ export declare class ToolRegistry {
|
|
|
50
50
|
*/
|
|
51
51
|
getTool(name: string): Tool | undefined;
|
|
52
52
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Sanitizes a schema object in-place to ensure compatibility with the Gemini API.
|
|
55
|
-
*
|
|
56
|
-
* NOTE: This function mutates the passed schema object.
|
|
57
|
-
*
|
|
58
|
-
* It performs the following actions:
|
|
59
|
-
* - Removes the `default` property when `anyOf` is present.
|
|
60
|
-
* - Removes unsupported `format` values from string properties, keeping only 'enum' and 'date-time'.
|
|
61
|
-
* - Recursively sanitizes nested schemas within `anyOf`, `items`, and `properties`.
|
|
62
|
-
* - Handles circular references within the schema to prevent infinite loops.
|
|
63
|
-
*
|
|
64
|
-
* @param schema The schema object to sanitize. It will be modified directly.
|
|
65
|
-
*/
|
|
66
|
-
export declare function sanitizeParameters(schema?: Schema): void;
|
|
67
53
|
export {};
|
|
@@ -3,13 +3,10 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { Type } from '@google/genai';
|
|
7
6
|
import { BaseTool } from './tools.js';
|
|
8
|
-
import { spawn } from 'node:child_process';
|
|
9
|
-
import { StringDecoder } from 'node:string_decoder';
|
|
7
|
+
import { spawn, execSync } from 'node:child_process';
|
|
10
8
|
import { discoverMcpTools } from './mcp-client.js';
|
|
11
9
|
import { DiscoveredMCPTool } from './mcp-tool.js';
|
|
12
|
-
import { parse } from 'shell-quote';
|
|
13
10
|
export class DiscoveredTool extends BaseTool {
|
|
14
11
|
config;
|
|
15
12
|
name;
|
|
@@ -103,6 +100,7 @@ Signal: Signal number or \`(none)\` if no signal was received.
|
|
|
103
100
|
}
|
|
104
101
|
export class ToolRegistry {
|
|
105
102
|
tools = new Map();
|
|
103
|
+
discovery = null;
|
|
106
104
|
config;
|
|
107
105
|
constructor(config) {
|
|
108
106
|
this.config = config;
|
|
@@ -128,108 +126,33 @@ export class ToolRegistry {
|
|
|
128
126
|
if (tool instanceof DiscoveredTool || tool instanceof DiscoveredMCPTool) {
|
|
129
127
|
this.tools.delete(tool.name);
|
|
130
128
|
}
|
|
129
|
+
else {
|
|
130
|
+
// Keep manually registered tools
|
|
131
|
+
}
|
|
131
132
|
}
|
|
132
|
-
|
|
133
|
-
// discover tools using MCP servers, if configured
|
|
134
|
-
await discoverMcpTools(this.config.getMcpServers() ?? {}, this.config.getMcpServerCommand(), this);
|
|
135
|
-
}
|
|
136
|
-
async discoverAndRegisterToolsFromCommand() {
|
|
133
|
+
// discover tools using discovery command, if configured
|
|
137
134
|
const discoveryCmd = this.config.getToolDiscoveryCommand();
|
|
138
|
-
if (
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
try {
|
|
142
|
-
const cmdParts = parse(discoveryCmd);
|
|
143
|
-
if (cmdParts.length === 0) {
|
|
144
|
-
throw new Error('Tool discovery command is empty or contains only whitespace.');
|
|
145
|
-
}
|
|
146
|
-
const proc = spawn(cmdParts[0], cmdParts.slice(1));
|
|
147
|
-
let stdout = '';
|
|
148
|
-
const stdoutDecoder = new StringDecoder('utf8');
|
|
149
|
-
let stderr = '';
|
|
150
|
-
const stderrDecoder = new StringDecoder('utf8');
|
|
151
|
-
let sizeLimitExceeded = false;
|
|
152
|
-
const MAX_STDOUT_SIZE = 10 * 1024 * 1024; // 10MB limit
|
|
153
|
-
const MAX_STDERR_SIZE = 10 * 1024 * 1024; // 10MB limit
|
|
154
|
-
let stdoutByteLength = 0;
|
|
155
|
-
let stderrByteLength = 0;
|
|
156
|
-
proc.stdout.on('data', (data) => {
|
|
157
|
-
if (sizeLimitExceeded)
|
|
158
|
-
return;
|
|
159
|
-
if (stdoutByteLength + data.length > MAX_STDOUT_SIZE) {
|
|
160
|
-
sizeLimitExceeded = true;
|
|
161
|
-
proc.kill();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
stdoutByteLength += data.length;
|
|
165
|
-
stdout += stdoutDecoder.write(data);
|
|
166
|
-
});
|
|
167
|
-
proc.stderr.on('data', (data) => {
|
|
168
|
-
if (sizeLimitExceeded)
|
|
169
|
-
return;
|
|
170
|
-
if (stderrByteLength + data.length > MAX_STDERR_SIZE) {
|
|
171
|
-
sizeLimitExceeded = true;
|
|
172
|
-
proc.kill();
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
stderrByteLength += data.length;
|
|
176
|
-
stderr += stderrDecoder.write(data);
|
|
177
|
-
});
|
|
178
|
-
await new Promise((resolve, reject) => {
|
|
179
|
-
proc.on('error', reject);
|
|
180
|
-
proc.on('close', (code) => {
|
|
181
|
-
stdout += stdoutDecoder.end();
|
|
182
|
-
stderr += stderrDecoder.end();
|
|
183
|
-
if (sizeLimitExceeded) {
|
|
184
|
-
return reject(new Error(`Tool discovery command output exceeded size limit of ${MAX_STDOUT_SIZE} bytes.`));
|
|
185
|
-
}
|
|
186
|
-
if (code !== 0) {
|
|
187
|
-
console.error(`Command failed with code ${code}`);
|
|
188
|
-
console.error(stderr);
|
|
189
|
-
return reject(new Error(`Tool discovery command failed with exit code ${code}`));
|
|
190
|
-
}
|
|
191
|
-
resolve();
|
|
192
|
-
});
|
|
193
|
-
});
|
|
135
|
+
if (discoveryCmd) {
|
|
194
136
|
// execute discovery command and extract function declarations (w/ or w/o "tool" wrappers)
|
|
195
137
|
const functions = [];
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
else if (Array.isArray(tool['functionDeclarations'])) {
|
|
206
|
-
functions.push(...tool['functionDeclarations']);
|
|
207
|
-
}
|
|
208
|
-
else if (tool['name']) {
|
|
209
|
-
functions.push(tool);
|
|
210
|
-
}
|
|
138
|
+
for (const tool of JSON.parse(execSync(discoveryCmd).toString().trim())) {
|
|
139
|
+
if (tool['function_declarations']) {
|
|
140
|
+
functions.push(...tool['function_declarations']);
|
|
141
|
+
}
|
|
142
|
+
else if (tool['functionDeclarations']) {
|
|
143
|
+
functions.push(...tool['functionDeclarations']);
|
|
144
|
+
}
|
|
145
|
+
else if (tool['name']) {
|
|
146
|
+
functions.push(tool);
|
|
211
147
|
}
|
|
212
148
|
}
|
|
213
149
|
// register each function as a tool
|
|
214
150
|
for (const func of functions) {
|
|
215
|
-
|
|
216
|
-
console.warn('Discovered a tool with no name. Skipping.');
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
// Sanitize the parameters before registering the tool.
|
|
220
|
-
const parameters = func.parameters &&
|
|
221
|
-
typeof func.parameters === 'object' &&
|
|
222
|
-
!Array.isArray(func.parameters)
|
|
223
|
-
? func.parameters
|
|
224
|
-
: {};
|
|
225
|
-
sanitizeParameters(parameters);
|
|
226
|
-
this.registerTool(new DiscoveredTool(this.config, func.name, func.description ?? '', parameters));
|
|
151
|
+
this.registerTool(new DiscoveredTool(this.config, func.name, func.description, func.parameters));
|
|
227
152
|
}
|
|
228
153
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
throw e;
|
|
232
|
-
}
|
|
154
|
+
// discover tools using MCP servers, if configured
|
|
155
|
+
await discoverMcpTools(this.config.getMcpServers() ?? {}, this.config.getMcpServerCommand(), this);
|
|
233
156
|
}
|
|
234
157
|
/**
|
|
235
158
|
* Retrieves the list of tool schemas (FunctionDeclaration array).
|
|
@@ -269,58 +192,4 @@ export class ToolRegistry {
|
|
|
269
192
|
return this.tools.get(name);
|
|
270
193
|
}
|
|
271
194
|
}
|
|
272
|
-
/**
|
|
273
|
-
* Sanitizes a schema object in-place to ensure compatibility with the Gemini API.
|
|
274
|
-
*
|
|
275
|
-
* NOTE: This function mutates the passed schema object.
|
|
276
|
-
*
|
|
277
|
-
* It performs the following actions:
|
|
278
|
-
* - Removes the `default` property when `anyOf` is present.
|
|
279
|
-
* - Removes unsupported `format` values from string properties, keeping only 'enum' and 'date-time'.
|
|
280
|
-
* - Recursively sanitizes nested schemas within `anyOf`, `items`, and `properties`.
|
|
281
|
-
* - Handles circular references within the schema to prevent infinite loops.
|
|
282
|
-
*
|
|
283
|
-
* @param schema The schema object to sanitize. It will be modified directly.
|
|
284
|
-
*/
|
|
285
|
-
export function sanitizeParameters(schema) {
|
|
286
|
-
_sanitizeParameters(schema, new Set());
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Internal recursive implementation for sanitizeParameters.
|
|
290
|
-
* @param schema The schema object to sanitize.
|
|
291
|
-
* @param visited A set used to track visited schema objects during recursion.
|
|
292
|
-
*/
|
|
293
|
-
function _sanitizeParameters(schema, visited) {
|
|
294
|
-
if (!schema || visited.has(schema)) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
visited.add(schema);
|
|
298
|
-
if (schema.anyOf) {
|
|
299
|
-
// Vertex AI gets confused if both anyOf and default are set.
|
|
300
|
-
schema.default = undefined;
|
|
301
|
-
for (const item of schema.anyOf) {
|
|
302
|
-
if (typeof item !== 'boolean') {
|
|
303
|
-
_sanitizeParameters(item, visited);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
if (schema.items && typeof schema.items !== 'boolean') {
|
|
308
|
-
_sanitizeParameters(schema.items, visited);
|
|
309
|
-
}
|
|
310
|
-
if (schema.properties) {
|
|
311
|
-
for (const item of Object.values(schema.properties)) {
|
|
312
|
-
if (typeof item !== 'boolean') {
|
|
313
|
-
_sanitizeParameters(item, visited);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
// Vertex AI only supports 'enum' and 'date-time' for STRING format.
|
|
318
|
-
if (schema.type === Type.STRING) {
|
|
319
|
-
if (schema.format &&
|
|
320
|
-
schema.format !== 'enum' &&
|
|
321
|
-
schema.format !== 'date-time') {
|
|
322
|
-
schema.format = undefined;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
195
|
//# sourceMappingURL=tool-registry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-registry.js","sourceRoot":"","sources":["../../../src/tools/tool-registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"tool-registry.js","sourceRoot":"","sources":["../../../src/tools/tool-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
7
7
|
import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
|
|
8
|
-
import { ToolRegistry,
|
|
8
|
+
import { ToolRegistry, DiscoveredTool } from './tool-registry.js';
|
|
9
9
|
import { DiscoveredMCPTool } from './mcp-tool.js';
|
|
10
|
-
import { Config, ApprovalMode } from '../config/config.js';
|
|
10
|
+
import { Config, ApprovalMode, } from '../config/config.js';
|
|
11
11
|
import { BaseTool } from './tools.js';
|
|
12
12
|
import { mcpToTool, Type, } from '@google/genai';
|
|
13
|
-
import {
|
|
13
|
+
import { execSync } from 'node:child_process';
|
|
14
14
|
// Use vi.hoisted to define the mock function so it can be used in the vi.mock factory
|
|
15
15
|
const mockDiscoverMcpTools = vi.hoisted(() => vi.fn());
|
|
16
16
|
// Mock ./mcp-client.js to control its behavior within tool-registry tests
|
|
@@ -37,6 +37,7 @@ vi.mock('@modelcontextprotocol/sdk/client/index.js', () => {
|
|
|
37
37
|
set onerror(handler) {
|
|
38
38
|
mockMcpClientOnError(handler);
|
|
39
39
|
},
|
|
40
|
+
// listTools and callTool are no longer directly used by ToolRegistry/discoverMcpTools
|
|
40
41
|
}));
|
|
41
42
|
return { Client: MockClient };
|
|
42
43
|
});
|
|
@@ -61,6 +62,7 @@ vi.mock('@google/genai', async () => {
|
|
|
61
62
|
return {
|
|
62
63
|
...actualGenai,
|
|
63
64
|
mcpToTool: vi.fn().mockImplementation(() => ({
|
|
65
|
+
// Default mock implementation
|
|
64
66
|
tool: vi.fn().mockResolvedValue({ functionDeclarations: [] }),
|
|
65
67
|
callTool: vi.fn(),
|
|
66
68
|
})),
|
|
@@ -74,9 +76,9 @@ const createMockCallableTool = (toolDeclarations) => ({
|
|
|
74
76
|
class MockTool extends BaseTool {
|
|
75
77
|
constructor(name = 'mock-tool', description = 'A mock tool') {
|
|
76
78
|
super(name, name, description, {
|
|
77
|
-
type:
|
|
79
|
+
type: 'object',
|
|
78
80
|
properties: {
|
|
79
|
-
param: { type:
|
|
81
|
+
param: { type: 'string' },
|
|
80
82
|
},
|
|
81
83
|
required: ['param'],
|
|
82
84
|
});
|
|
@@ -103,7 +105,6 @@ const baseConfigParams = {
|
|
|
103
105
|
describe('ToolRegistry', () => {
|
|
104
106
|
let config;
|
|
105
107
|
let toolRegistry;
|
|
106
|
-
let mockConfigGetToolDiscoveryCommand;
|
|
107
108
|
beforeEach(() => {
|
|
108
109
|
config = new Config(baseConfigParams);
|
|
109
110
|
toolRegistry = new ToolRegistry(config);
|
|
@@ -111,15 +112,13 @@ describe('ToolRegistry', () => {
|
|
|
111
112
|
vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
112
113
|
vi.spyOn(console, 'debug').mockImplementation(() => { });
|
|
113
114
|
vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
114
|
-
|
|
115
|
+
// Reset mocks for MCP parts
|
|
116
|
+
mockMcpClientConnect.mockReset().mockResolvedValue(undefined); // Default connect success
|
|
115
117
|
mockStdioTransportClose.mockReset();
|
|
116
118
|
mockSseTransportClose.mockReset();
|
|
117
119
|
vi.mocked(mcpToTool).mockClear();
|
|
120
|
+
// Default mcpToTool to return a callable tool that returns no functions
|
|
118
121
|
vi.mocked(mcpToTool).mockReturnValue(createMockCallableTool([]));
|
|
119
|
-
mockConfigGetToolDiscoveryCommand = vi.spyOn(config, 'getToolDiscoveryCommand');
|
|
120
|
-
vi.spyOn(config, 'getMcpServers');
|
|
121
|
-
vi.spyOn(config, 'getMcpServerCommand');
|
|
122
|
-
mockDiscoverMcpTools.mockReset().mockResolvedValue(undefined);
|
|
123
122
|
});
|
|
124
123
|
afterEach(() => {
|
|
125
124
|
vi.restoreAllMocks();
|
|
@@ -130,16 +129,18 @@ describe('ToolRegistry', () => {
|
|
|
130
129
|
toolRegistry.registerTool(tool);
|
|
131
130
|
expect(toolRegistry.getTool('mock-tool')).toBe(tool);
|
|
132
131
|
});
|
|
132
|
+
// ... other registerTool tests
|
|
133
133
|
});
|
|
134
134
|
describe('getToolsByServer', () => {
|
|
135
135
|
it('should return an empty array if no tools match the server name', () => {
|
|
136
|
-
toolRegistry.registerTool(new MockTool());
|
|
136
|
+
toolRegistry.registerTool(new MockTool()); // A non-MCP tool
|
|
137
137
|
expect(toolRegistry.getToolsByServer('any-mcp-server')).toEqual([]);
|
|
138
138
|
});
|
|
139
139
|
it('should return only tools matching the server name', async () => {
|
|
140
140
|
const server1Name = 'mcp-server-uno';
|
|
141
141
|
const server2Name = 'mcp-server-dos';
|
|
142
|
-
|
|
142
|
+
// Manually register mock MCP tools for this test
|
|
143
|
+
const mockCallable = {}; // Minimal mock callable
|
|
143
144
|
const mcpTool1 = new DiscoveredMCPTool(mockCallable, server1Name, 'server1Name__tool-on-server1', 'd1', {}, 'tool-on-server1');
|
|
144
145
|
const mcpTool2 = new DiscoveredMCPTool(mockCallable, server2Name, 'server2Name__tool-on-server2', 'd2', {}, 'tool-on-server2');
|
|
145
146
|
const nonMcpTool = new MockTool('regular-tool');
|
|
@@ -149,62 +150,48 @@ describe('ToolRegistry', () => {
|
|
|
149
150
|
const toolsFromServer1 = toolRegistry.getToolsByServer(server1Name);
|
|
150
151
|
expect(toolsFromServer1).toHaveLength(1);
|
|
151
152
|
expect(toolsFromServer1[0].name).toBe(mcpTool1.name);
|
|
153
|
+
expect(toolsFromServer1[0].serverName).toBe(server1Name);
|
|
152
154
|
const toolsFromServer2 = toolRegistry.getToolsByServer(server2Name);
|
|
153
155
|
expect(toolsFromServer2).toHaveLength(1);
|
|
154
156
|
expect(toolsFromServer2[0].name).toBe(mcpTool2.name);
|
|
157
|
+
expect(toolsFromServer2[0].serverName).toBe(server2Name);
|
|
158
|
+
expect(toolRegistry.getToolsByServer('non-existent-server')).toEqual([]);
|
|
155
159
|
});
|
|
156
160
|
});
|
|
157
161
|
describe('discoverTools', () => {
|
|
158
|
-
|
|
162
|
+
let mockConfigGetToolDiscoveryCommand;
|
|
163
|
+
let mockConfigGetMcpServers;
|
|
164
|
+
let mockConfigGetMcpServerCommand;
|
|
165
|
+
let mockExecSync;
|
|
166
|
+
beforeEach(() => {
|
|
167
|
+
mockConfigGetToolDiscoveryCommand = vi.spyOn(config, 'getToolDiscoveryCommand');
|
|
168
|
+
mockConfigGetMcpServers = vi.spyOn(config, 'getMcpServers');
|
|
169
|
+
mockConfigGetMcpServerCommand = vi.spyOn(config, 'getMcpServerCommand');
|
|
170
|
+
mockExecSync = vi.mocked(execSync);
|
|
171
|
+
toolRegistry = new ToolRegistry(config); // Reset registry
|
|
172
|
+
// Reset the mock for discoverMcpTools before each test in this suite
|
|
173
|
+
mockDiscoverMcpTools.mockReset().mockResolvedValue(undefined);
|
|
174
|
+
});
|
|
175
|
+
it('should discover tools using discovery command', async () => {
|
|
176
|
+
// ... this test remains largely the same
|
|
159
177
|
const discoveryCommand = 'my-discovery-command';
|
|
160
178
|
mockConfigGetToolDiscoveryCommand.mockReturnValue(discoveryCommand);
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
type: Type.OBJECT,
|
|
166
|
-
properties: {
|
|
167
|
-
some_string: {
|
|
168
|
-
type: Type.STRING,
|
|
169
|
-
format: 'uuid', // This is an unsupported format
|
|
170
|
-
},
|
|
171
|
-
},
|
|
179
|
+
const mockToolDeclarations = [
|
|
180
|
+
{
|
|
181
|
+
name: 'discovered-tool-1',
|
|
182
|
+
description: 'A discovered tool',
|
|
183
|
+
parameters: { type: Type.OBJECT, properties: {} },
|
|
172
184
|
},
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const mockChildProcess = {
|
|
176
|
-
stdout: { on: vi.fn() },
|
|
177
|
-
stderr: { on: vi.fn() },
|
|
178
|
-
on: vi.fn(),
|
|
179
|
-
};
|
|
180
|
-
mockSpawn.mockReturnValue(mockChildProcess);
|
|
181
|
-
// Simulate stdout data
|
|
182
|
-
mockChildProcess.stdout.on.mockImplementation((event, callback) => {
|
|
183
|
-
if (event === 'data') {
|
|
184
|
-
callback(Buffer.from(JSON.stringify([
|
|
185
|
-
{ function_declarations: [unsanitizedToolDeclaration] },
|
|
186
|
-
])));
|
|
187
|
-
}
|
|
188
|
-
return mockChildProcess;
|
|
189
|
-
});
|
|
190
|
-
// Simulate process close
|
|
191
|
-
mockChildProcess.on.mockImplementation((event, callback) => {
|
|
192
|
-
if (event === 'close') {
|
|
193
|
-
callback(0);
|
|
194
|
-
}
|
|
195
|
-
return mockChildProcess;
|
|
196
|
-
});
|
|
185
|
+
];
|
|
186
|
+
mockExecSync.mockReturnValue(Buffer.from(JSON.stringify([{ function_declarations: mockToolDeclarations }])));
|
|
197
187
|
await toolRegistry.discoverTools();
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
.parameters;
|
|
202
|
-
expect(registeredParams.properties?.['some_string']).toBeDefined();
|
|
203
|
-
expect(registeredParams.properties?.['some_string']).toHaveProperty('format', undefined);
|
|
188
|
+
expect(execSync).toHaveBeenCalledWith(discoveryCommand);
|
|
189
|
+
const discoveredTool = toolRegistry.getTool('discovered-tool-1');
|
|
190
|
+
expect(discoveredTool).toBeInstanceOf(DiscoveredTool);
|
|
204
191
|
});
|
|
205
192
|
it('should discover tools using MCP servers defined in getMcpServers', async () => {
|
|
206
193
|
mockConfigGetToolDiscoveryCommand.mockReturnValue(undefined);
|
|
207
|
-
|
|
194
|
+
mockConfigGetMcpServerCommand.mockReturnValue(undefined);
|
|
208
195
|
const mcpServerConfigVal = {
|
|
209
196
|
'my-mcp-server': {
|
|
210
197
|
command: 'mcp-server-cmd',
|
|
@@ -212,142 +199,44 @@ describe('ToolRegistry', () => {
|
|
|
212
199
|
trust: true,
|
|
213
200
|
},
|
|
214
201
|
};
|
|
215
|
-
|
|
202
|
+
mockConfigGetMcpServers.mockReturnValue(mcpServerConfigVal);
|
|
216
203
|
await toolRegistry.discoverTools();
|
|
217
204
|
expect(mockDiscoverMcpTools).toHaveBeenCalledWith(mcpServerConfigVal, undefined, toolRegistry);
|
|
205
|
+
// We no longer check these as discoverMcpTools is mocked
|
|
206
|
+
// expect(vi.mocked(mcpToTool)).toHaveBeenCalledTimes(1);
|
|
207
|
+
// expect(Client).toHaveBeenCalledTimes(1);
|
|
208
|
+
// expect(StdioClientTransport).toHaveBeenCalledWith({
|
|
209
|
+
// command: 'mcp-server-cmd',
|
|
210
|
+
// args: ['--port', '1234'],
|
|
211
|
+
// env: expect.any(Object),
|
|
212
|
+
// stderr: 'pipe',
|
|
213
|
+
// });
|
|
214
|
+
// expect(mockMcpClientConnect).toHaveBeenCalled();
|
|
215
|
+
// To verify that tools *would* have been registered, we'd need mockDiscoverMcpTools
|
|
216
|
+
// to call toolRegistry.registerTool, or we test that separately.
|
|
217
|
+
// For now, we just check that the delegation happened.
|
|
218
218
|
});
|
|
219
|
-
it('should discover tools using MCP
|
|
219
|
+
it('should discover tools using MCP server command from getMcpServerCommand', async () => {
|
|
220
220
|
mockConfigGetToolDiscoveryCommand.mockReturnValue(undefined);
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
'my-mcp-server': {
|
|
224
|
-
command: 'mcp-server-cmd',
|
|
225
|
-
args: ['--port', '1234'],
|
|
226
|
-
trust: true,
|
|
227
|
-
},
|
|
228
|
-
};
|
|
229
|
-
vi.spyOn(config, 'getMcpServers').mockReturnValue(mcpServerConfigVal);
|
|
221
|
+
mockConfigGetMcpServers.mockReturnValue({});
|
|
222
|
+
mockConfigGetMcpServerCommand.mockReturnValue('mcp-server-start-command --param');
|
|
230
223
|
await toolRegistry.discoverTools();
|
|
231
|
-
expect(mockDiscoverMcpTools).toHaveBeenCalledWith(
|
|
224
|
+
expect(mockDiscoverMcpTools).toHaveBeenCalledWith({}, 'mcp-server-start-command --param', toolRegistry);
|
|
225
|
+
});
|
|
226
|
+
it('should handle errors during MCP client connection gracefully and close transport', async () => {
|
|
227
|
+
mockConfigGetToolDiscoveryCommand.mockReturnValue(undefined);
|
|
228
|
+
mockConfigGetMcpServers.mockReturnValue({
|
|
229
|
+
'failing-mcp': { command: 'fail-cmd' },
|
|
230
|
+
});
|
|
231
|
+
mockMcpClientConnect.mockRejectedValue(new Error('Connection failed'));
|
|
232
|
+
await toolRegistry.discoverTools();
|
|
233
|
+
expect(mockDiscoverMcpTools).toHaveBeenCalledWith({
|
|
234
|
+
'failing-mcp': { command: 'fail-cmd' },
|
|
235
|
+
}, undefined, toolRegistry);
|
|
236
|
+
expect(toolRegistry.getAllTools()).toHaveLength(0);
|
|
232
237
|
});
|
|
233
238
|
});
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
it('should remove unsupported format from a simple string property', () => {
|
|
237
|
-
const schema = {
|
|
238
|
-
type: Type.OBJECT,
|
|
239
|
-
properties: {
|
|
240
|
-
name: { type: Type.STRING },
|
|
241
|
-
id: { type: Type.STRING, format: 'uuid' },
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
sanitizeParameters(schema);
|
|
245
|
-
expect(schema.properties?.['id']).toHaveProperty('format', undefined);
|
|
246
|
-
expect(schema.properties?.['name']).not.toHaveProperty('format');
|
|
247
|
-
});
|
|
248
|
-
it('should NOT remove supported format values', () => {
|
|
249
|
-
const schema = {
|
|
250
|
-
type: Type.OBJECT,
|
|
251
|
-
properties: {
|
|
252
|
-
date: { type: Type.STRING, format: 'date-time' },
|
|
253
|
-
role: {
|
|
254
|
-
type: Type.STRING,
|
|
255
|
-
format: 'enum',
|
|
256
|
-
enum: ['admin', 'user'],
|
|
257
|
-
},
|
|
258
|
-
},
|
|
259
|
-
};
|
|
260
|
-
const originalSchema = JSON.parse(JSON.stringify(schema));
|
|
261
|
-
sanitizeParameters(schema);
|
|
262
|
-
expect(schema).toEqual(originalSchema);
|
|
263
|
-
});
|
|
264
|
-
it('should handle nested objects recursively', () => {
|
|
265
|
-
const schema = {
|
|
266
|
-
type: Type.OBJECT,
|
|
267
|
-
properties: {
|
|
268
|
-
user: {
|
|
269
|
-
type: Type.OBJECT,
|
|
270
|
-
properties: {
|
|
271
|
-
email: { type: Type.STRING, format: 'email' },
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
sanitizeParameters(schema);
|
|
277
|
-
expect(schema.properties?.['user']?.properties?.['email']).toHaveProperty('format', undefined);
|
|
278
|
-
});
|
|
279
|
-
it('should handle arrays of objects', () => {
|
|
280
|
-
const schema = {
|
|
281
|
-
type: Type.OBJECT,
|
|
282
|
-
properties: {
|
|
283
|
-
items: {
|
|
284
|
-
type: Type.ARRAY,
|
|
285
|
-
items: {
|
|
286
|
-
type: Type.OBJECT,
|
|
287
|
-
properties: {
|
|
288
|
-
itemId: { type: Type.STRING, format: 'uuid' },
|
|
289
|
-
},
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
};
|
|
294
|
-
sanitizeParameters(schema);
|
|
295
|
-
expect(schema.properties?.['items']?.items?.properties?.['itemId']).toHaveProperty('format', undefined);
|
|
296
|
-
});
|
|
297
|
-
it('should handle schemas with no properties to sanitize', () => {
|
|
298
|
-
const schema = {
|
|
299
|
-
type: Type.OBJECT,
|
|
300
|
-
properties: {
|
|
301
|
-
count: { type: Type.NUMBER },
|
|
302
|
-
isActive: { type: Type.BOOLEAN },
|
|
303
|
-
},
|
|
304
|
-
};
|
|
305
|
-
const originalSchema = JSON.parse(JSON.stringify(schema));
|
|
306
|
-
sanitizeParameters(schema);
|
|
307
|
-
expect(schema).toEqual(originalSchema);
|
|
308
|
-
});
|
|
309
|
-
it('should not crash on an empty or undefined schema', () => {
|
|
310
|
-
expect(() => sanitizeParameters({})).not.toThrow();
|
|
311
|
-
expect(() => sanitizeParameters(undefined)).not.toThrow();
|
|
312
|
-
});
|
|
313
|
-
it('should handle cyclic schemas without crashing', () => {
|
|
314
|
-
const schema = {
|
|
315
|
-
type: Type.OBJECT,
|
|
316
|
-
properties: {
|
|
317
|
-
name: { type: Type.STRING, format: 'hostname' },
|
|
318
|
-
},
|
|
319
|
-
};
|
|
320
|
-
schema.properties.self = schema;
|
|
321
|
-
expect(() => sanitizeParameters(schema)).not.toThrow();
|
|
322
|
-
expect(schema.properties.name).toHaveProperty('format', undefined);
|
|
323
|
-
});
|
|
324
|
-
it('should handle complex nested schemas with cycles', () => {
|
|
325
|
-
const userNode = {
|
|
326
|
-
type: Type.OBJECT,
|
|
327
|
-
properties: {
|
|
328
|
-
id: { type: Type.STRING, format: 'uuid' },
|
|
329
|
-
name: { type: Type.STRING },
|
|
330
|
-
manager: {
|
|
331
|
-
type: Type.OBJECT,
|
|
332
|
-
properties: {
|
|
333
|
-
id: { type: Type.STRING, format: 'uuid' },
|
|
334
|
-
},
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
};
|
|
338
|
-
userNode.properties.reports = {
|
|
339
|
-
type: Type.ARRAY,
|
|
340
|
-
items: userNode,
|
|
341
|
-
};
|
|
342
|
-
const schema = {
|
|
343
|
-
type: Type.OBJECT,
|
|
344
|
-
properties: {
|
|
345
|
-
ceo: userNode,
|
|
346
|
-
},
|
|
347
|
-
};
|
|
348
|
-
expect(() => sanitizeParameters(schema)).not.toThrow();
|
|
349
|
-
expect(schema.properties?.['ceo']?.properties?.['id']).toHaveProperty('format', undefined);
|
|
350
|
-
expect(schema.properties?.['ceo']?.properties?.['manager']?.properties?.['id']).toHaveProperty('format', undefined);
|
|
351
|
-
});
|
|
239
|
+
// Other tests for DiscoveredTool and DiscoveredMCPTool can be simplified or removed
|
|
240
|
+
// if their core logic is now tested in their respective dedicated test files (mcp-tool.test.ts)
|
|
352
241
|
});
|
|
353
242
|
//# sourceMappingURL=tool-registry.test.js.map
|