@juspay/neurolink 5.2.0 → 5.3.0
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/CHANGELOG.md +8 -2
- package/dist/cli/factories/command-factory.js +6 -5
- package/dist/core/base-provider.js +24 -13
- package/dist/core/constants.d.ts +1 -0
- package/dist/core/constants.js +1 -0
- package/dist/lib/core/base-provider.js +24 -13
- package/dist/lib/core/constants.d.ts +1 -0
- package/dist/lib/core/constants.js +1 -0
- package/dist/lib/mcp/client.d.ts +1 -0
- package/dist/lib/mcp/client.js +1 -0
- package/dist/lib/mcp/context-manager.d.ts +1 -0
- package/dist/lib/mcp/context-manager.js +8 -4
- package/dist/lib/mcp/function-calling.d.ts +13 -0
- package/dist/lib/mcp/function-calling.js +133 -34
- package/dist/lib/mcp/neurolink-mcp-client.d.ts +1 -0
- package/dist/lib/mcp/neurolink-mcp-client.js +21 -5
- package/dist/lib/providers/function-calling-provider.d.ts +64 -2
- package/dist/lib/providers/function-calling-provider.js +208 -9
- package/dist/lib/providers/mcp-provider.js +20 -5
- package/dist/lib/services/streaming/streaming-manager.js +11 -10
- package/dist/lib/services/websocket/websocket-server.js +12 -11
- package/dist/lib/telemetry/telemetry-service.js +8 -7
- package/dist/mcp/client.d.ts +1 -0
- package/dist/mcp/client.js +1 -0
- package/dist/mcp/context-manager.d.ts +1 -0
- package/dist/mcp/context-manager.js +8 -4
- package/dist/mcp/function-calling.d.ts +13 -0
- package/dist/mcp/function-calling.js +133 -34
- package/dist/mcp/neurolink-mcp-client.d.ts +1 -0
- package/dist/mcp/neurolink-mcp-client.js +21 -5
- package/dist/providers/function-calling-provider.d.ts +64 -2
- package/dist/providers/function-calling-provider.js +208 -9
- package/dist/providers/mcp-provider.js +20 -5
- package/dist/services/streaming/streaming-manager.js +11 -10
- package/dist/services/websocket/websocket-server.js +12 -11
- package/dist/telemetry/telemetry-service.js +8 -7
- package/package.json +12 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
# [5.
|
|
1
|
+
# [5.3.0](https://github.com/juspay/neurolink/compare/v5.2.0...v5.3.0) (2025-07-23)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **mcp:** enhance MCP integration with comprehensive testing infrastructure and tool ecosystem improvements ([a38d845](https://github.com/juspay/neurolink/commit/a38d845032133eee098de10b966cbdd3a329fdfd))
|
|
2
7
|
|
|
8
|
+
# [5.2.0](https://github.com/juspay/neurolink/compare/v5.1.0...v5.2.0) (2025-07-22)
|
|
3
9
|
|
|
4
10
|
### Features
|
|
5
11
|
|
|
6
|
-
|
|
12
|
+
- **core:** implement comprehensive factory pattern architecture with full MCP integration and provider unification ([b13963a](https://github.com/juspay/neurolink/commit/b13963aaf6f95233be8b1e9bdc69ce1b65604cdf))
|
|
7
13
|
|
|
8
14
|
# [5.1.0](https://github.com/juspay/neurolink/compare/v5.0.0...v5.1.0) (2025-07-13)
|
|
9
15
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NeuroLink } from "../../lib/neurolink.js";
|
|
2
2
|
import ora from "ora";
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
+
import { logger } from "../../lib/utils/logger.js";
|
|
4
5
|
/**
|
|
5
6
|
* CLI Command Factory for generate commands
|
|
6
7
|
*/
|
|
@@ -161,14 +162,14 @@ export class CLICommandFactory {
|
|
|
161
162
|
console.log(result.content);
|
|
162
163
|
}
|
|
163
164
|
if (argv.debug) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
logger.debug("\n" + chalk.yellow("Debug Information:"));
|
|
166
|
+
logger.debug("Provider:", result.provider);
|
|
167
|
+
logger.debug("Model:", result.model);
|
|
167
168
|
if (result.analytics) {
|
|
168
|
-
|
|
169
|
+
logger.debug("Analytics:", JSON.stringify(result.analytics, null, 2));
|
|
169
170
|
}
|
|
170
171
|
if (result.evaluation) {
|
|
171
|
-
|
|
172
|
+
logger.debug("Evaluation:", JSON.stringify(result.evaluation, null, 2));
|
|
172
173
|
}
|
|
173
174
|
}
|
|
174
175
|
// Exit successfully
|
|
@@ -4,6 +4,18 @@ import { directAgentTools } from "../agent/direct-tools.js";
|
|
|
4
4
|
// import { evaluateResponse } from "../core/evaluation.js";
|
|
5
5
|
// import { getAvailableFunctionTools } from "../mcp/function-calling.js";
|
|
6
6
|
// Analytics helper will be dynamically imported when needed
|
|
7
|
+
/**
|
|
8
|
+
* Validates if a result contains a valid toolsObject structure
|
|
9
|
+
* @param result - The result object to validate
|
|
10
|
+
* @returns true if the result contains a valid toolsObject, false otherwise
|
|
11
|
+
*/
|
|
12
|
+
function isValidToolsObject(result) {
|
|
13
|
+
return (result &&
|
|
14
|
+
typeof result === "object" &&
|
|
15
|
+
result.toolsObject &&
|
|
16
|
+
typeof result.toolsObject === "object" &&
|
|
17
|
+
Object.keys(result.toolsObject).length > 0);
|
|
18
|
+
}
|
|
7
19
|
/**
|
|
8
20
|
* Abstract base class for all AI providers
|
|
9
21
|
* Tools are integrated as first-class citizens - always available by default
|
|
@@ -170,16 +182,16 @@ export class BaseProvider {
|
|
|
170
182
|
const tools = {
|
|
171
183
|
...this.directTools, // Always include direct tools
|
|
172
184
|
};
|
|
173
|
-
logger.
|
|
174
|
-
|
|
185
|
+
logger.debug(`[BaseProvider] getAllTools called, SDK available: ${!!this.sdk}, type: ${typeof this.sdk}`);
|
|
186
|
+
logger.debug(`[BaseProvider] Direct tools: ${Object.keys(this.directTools).join(", ")}`);
|
|
175
187
|
// Add custom tools from SDK if available
|
|
176
|
-
|
|
188
|
+
logger.debug(`[BaseProvider] Checking SDK: ${!!this.sdk}, has getInMemoryServers: ${this.sdk && typeof this.sdk.getInMemoryServers}`);
|
|
177
189
|
if (this.sdk &&
|
|
178
190
|
typeof this.sdk.getInMemoryServers === "function") {
|
|
179
|
-
|
|
191
|
+
logger.debug(`[BaseProvider] SDK check passed, loading custom tools`);
|
|
180
192
|
try {
|
|
181
193
|
const inMemoryServers = this.sdk.getInMemoryServers();
|
|
182
|
-
|
|
194
|
+
logger.debug(`[BaseProvider] Got servers:`, inMemoryServers.size);
|
|
183
195
|
logger.debug(`[BaseProvider] Loading custom tools from SDK, found ${inMemoryServers.size} servers`);
|
|
184
196
|
if (inMemoryServers && inMemoryServers.size > 0) {
|
|
185
197
|
// Convert in-memory server tools to AI SDK format
|
|
@@ -192,7 +204,7 @@ export class BaseProvider {
|
|
|
192
204
|
: Object.entries(server.tools || {});
|
|
193
205
|
for (const [toolName, toolInfo] of toolEntries) {
|
|
194
206
|
if (toolInfo && typeof toolInfo.execute === "function") {
|
|
195
|
-
|
|
207
|
+
logger.debug(`[BaseProvider] Converting custom tool: ${toolName}`);
|
|
196
208
|
// Convert to AI SDK tool format
|
|
197
209
|
const { tool: createAISDKTool } = await import("ai");
|
|
198
210
|
const { z } = await import("zod");
|
|
@@ -233,12 +245,11 @@ export class BaseProvider {
|
|
|
233
245
|
try {
|
|
234
246
|
const { getAvailableFunctionTools } = await import("../mcp/function-calling.js");
|
|
235
247
|
const result = await getAvailableFunctionTools();
|
|
236
|
-
if (result
|
|
237
|
-
this.mcpTools =
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
248
|
+
if (isValidToolsObject(result)) {
|
|
249
|
+
this.mcpTools = result.toolsObject;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
logger.debug(`Invalid or empty toolsObject for ${this.providerName}: Expected an object with at least one key, but got ${typeof result.toolsObject} with ${result.toolsObject ? Object.keys(result.toolsObject).length : 0} keys. Full result:`, result);
|
|
242
253
|
}
|
|
243
254
|
}
|
|
244
255
|
catch (error) {
|
|
@@ -250,7 +261,7 @@ export class BaseProvider {
|
|
|
250
261
|
if (this.mcpTools) {
|
|
251
262
|
Object.assign(tools, this.mcpTools);
|
|
252
263
|
}
|
|
253
|
-
|
|
264
|
+
logger.debug(`[BaseProvider] getAllTools returning tools: ${Object.keys(tools).join(", ")}`);
|
|
254
265
|
return tools;
|
|
255
266
|
}
|
|
256
267
|
/**
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export declare const DEFAULT_MAX_TOKENS = 8192;
|
|
6
6
|
export declare const DEFAULT_TEMPERATURE = 0.7;
|
|
7
7
|
export declare const DEFAULT_TIMEOUT = 30000;
|
|
8
|
+
export declare const DEFAULT_MAX_STEPS = 5;
|
|
8
9
|
export declare const DEFAULT_EVALUATION_MAX_TOKENS = 500;
|
|
9
10
|
export declare const DEFAULT_ANALYSIS_MAX_TOKENS = 800;
|
|
10
11
|
export declare const DEFAULT_DOCUMENTATION_MAX_TOKENS = 12000;
|
package/dist/core/constants.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export const DEFAULT_MAX_TOKENS = 8192; // Changed from 10000 to fix Anthropic error
|
|
7
7
|
export const DEFAULT_TEMPERATURE = 0.7;
|
|
8
8
|
export const DEFAULT_TIMEOUT = 30000;
|
|
9
|
+
export const DEFAULT_MAX_STEPS = 5; // Default multi-turn tool execution steps
|
|
9
10
|
// Specialized Use Case Defaults
|
|
10
11
|
export const DEFAULT_EVALUATION_MAX_TOKENS = 500; // Keep evaluation fast
|
|
11
12
|
export const DEFAULT_ANALYSIS_MAX_TOKENS = 800; // For analysis tools
|
|
@@ -4,6 +4,18 @@ import { directAgentTools } from "../agent/direct-tools.js";
|
|
|
4
4
|
// import { evaluateResponse } from "../core/evaluation.js";
|
|
5
5
|
// import { getAvailableFunctionTools } from "../mcp/function-calling.js";
|
|
6
6
|
// Analytics helper will be dynamically imported when needed
|
|
7
|
+
/**
|
|
8
|
+
* Validates if a result contains a valid toolsObject structure
|
|
9
|
+
* @param result - The result object to validate
|
|
10
|
+
* @returns true if the result contains a valid toolsObject, false otherwise
|
|
11
|
+
*/
|
|
12
|
+
function isValidToolsObject(result) {
|
|
13
|
+
return (result &&
|
|
14
|
+
typeof result === "object" &&
|
|
15
|
+
result.toolsObject &&
|
|
16
|
+
typeof result.toolsObject === "object" &&
|
|
17
|
+
Object.keys(result.toolsObject).length > 0);
|
|
18
|
+
}
|
|
7
19
|
/**
|
|
8
20
|
* Abstract base class for all AI providers
|
|
9
21
|
* Tools are integrated as first-class citizens - always available by default
|
|
@@ -170,16 +182,16 @@ export class BaseProvider {
|
|
|
170
182
|
const tools = {
|
|
171
183
|
...this.directTools, // Always include direct tools
|
|
172
184
|
};
|
|
173
|
-
logger.
|
|
174
|
-
|
|
185
|
+
logger.debug(`[BaseProvider] getAllTools called, SDK available: ${!!this.sdk}, type: ${typeof this.sdk}`);
|
|
186
|
+
logger.debug(`[BaseProvider] Direct tools: ${Object.keys(this.directTools).join(", ")}`);
|
|
175
187
|
// Add custom tools from SDK if available
|
|
176
|
-
|
|
188
|
+
logger.debug(`[BaseProvider] Checking SDK: ${!!this.sdk}, has getInMemoryServers: ${this.sdk && typeof this.sdk.getInMemoryServers}`);
|
|
177
189
|
if (this.sdk &&
|
|
178
190
|
typeof this.sdk.getInMemoryServers === "function") {
|
|
179
|
-
|
|
191
|
+
logger.debug(`[BaseProvider] SDK check passed, loading custom tools`);
|
|
180
192
|
try {
|
|
181
193
|
const inMemoryServers = this.sdk.getInMemoryServers();
|
|
182
|
-
|
|
194
|
+
logger.debug(`[BaseProvider] Got servers:`, inMemoryServers.size);
|
|
183
195
|
logger.debug(`[BaseProvider] Loading custom tools from SDK, found ${inMemoryServers.size} servers`);
|
|
184
196
|
if (inMemoryServers && inMemoryServers.size > 0) {
|
|
185
197
|
// Convert in-memory server tools to AI SDK format
|
|
@@ -192,7 +204,7 @@ export class BaseProvider {
|
|
|
192
204
|
: Object.entries(server.tools || {});
|
|
193
205
|
for (const [toolName, toolInfo] of toolEntries) {
|
|
194
206
|
if (toolInfo && typeof toolInfo.execute === "function") {
|
|
195
|
-
|
|
207
|
+
logger.debug(`[BaseProvider] Converting custom tool: ${toolName}`);
|
|
196
208
|
// Convert to AI SDK tool format
|
|
197
209
|
const { tool: createAISDKTool } = await import("ai");
|
|
198
210
|
const { z } = await import("zod");
|
|
@@ -233,12 +245,11 @@ export class BaseProvider {
|
|
|
233
245
|
try {
|
|
234
246
|
const { getAvailableFunctionTools } = await import("../mcp/function-calling.js");
|
|
235
247
|
const result = await getAvailableFunctionTools();
|
|
236
|
-
if (result
|
|
237
|
-
this.mcpTools =
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
248
|
+
if (isValidToolsObject(result)) {
|
|
249
|
+
this.mcpTools = result.toolsObject;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
logger.debug(`Invalid or empty toolsObject for ${this.providerName}: Expected an object with at least one key, but got ${typeof result.toolsObject} with ${result.toolsObject ? Object.keys(result.toolsObject).length : 0} keys. Full result:`, result);
|
|
242
253
|
}
|
|
243
254
|
}
|
|
244
255
|
catch (error) {
|
|
@@ -250,7 +261,7 @@ export class BaseProvider {
|
|
|
250
261
|
if (this.mcpTools) {
|
|
251
262
|
Object.assign(tools, this.mcpTools);
|
|
252
263
|
}
|
|
253
|
-
|
|
264
|
+
logger.debug(`[BaseProvider] getAllTools returning tools: ${Object.keys(tools).join(", ")}`);
|
|
254
265
|
return tools;
|
|
255
266
|
}
|
|
256
267
|
/**
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export declare const DEFAULT_MAX_TOKENS = 8192;
|
|
6
6
|
export declare const DEFAULT_TEMPERATURE = 0.7;
|
|
7
7
|
export declare const DEFAULT_TIMEOUT = 30000;
|
|
8
|
+
export declare const DEFAULT_MAX_STEPS = 5;
|
|
8
9
|
export declare const DEFAULT_EVALUATION_MAX_TOKENS = 500;
|
|
9
10
|
export declare const DEFAULT_ANALYSIS_MAX_TOKENS = 800;
|
|
10
11
|
export declare const DEFAULT_DOCUMENTATION_MAX_TOKENS = 12000;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export const DEFAULT_MAX_TOKENS = 8192; // Changed from 10000 to fix Anthropic error
|
|
7
7
|
export const DEFAULT_TEMPERATURE = 0.7;
|
|
8
8
|
export const DEFAULT_TIMEOUT = 30000;
|
|
9
|
+
export const DEFAULT_MAX_STEPS = 5; // Default multi-turn tool execution steps
|
|
9
10
|
// Specialized Use Case Defaults
|
|
10
11
|
export const DEFAULT_EVALUATION_MAX_TOKENS = 500; // Keep evaluation fast
|
|
11
12
|
export const DEFAULT_ANALYSIS_MAX_TOKENS = 800; // For analysis tools
|
package/dist/lib/mcp/client.d.ts
CHANGED
package/dist/lib/mcp/client.js
CHANGED
|
@@ -130,6 +130,7 @@ export class NeuroLinkMCPClient extends EventEmitter {
|
|
|
130
130
|
const tools = {};
|
|
131
131
|
for (const [name, tool] of this.tools) {
|
|
132
132
|
tools[name] = {
|
|
133
|
+
name: name, // Include the tool name as a property
|
|
133
134
|
description: tool.description,
|
|
134
135
|
inputSchema: tool.inputSchema,
|
|
135
136
|
};
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
export class ContextManager {
|
|
11
11
|
sessionCounter = 0;
|
|
12
12
|
activeContexts = new Map();
|
|
13
|
+
static cachedLogger = null;
|
|
13
14
|
/**
|
|
14
15
|
* Create a new execution context with rich information
|
|
15
16
|
*
|
|
@@ -64,6 +65,7 @@ export class ContextManager {
|
|
|
64
65
|
},
|
|
65
66
|
path: {
|
|
66
67
|
join: (...paths) => {
|
|
68
|
+
// Use dynamic require for synchronous path operations
|
|
67
69
|
const path = require("path");
|
|
68
70
|
return path.join(...paths);
|
|
69
71
|
},
|
|
@@ -85,11 +87,13 @@ export class ContextManager {
|
|
|
85
87
|
},
|
|
86
88
|
},
|
|
87
89
|
grantedPermissions: request.permissions || [],
|
|
88
|
-
log: (level, message, data) => {
|
|
89
|
-
// Use logger if available, otherwise
|
|
90
|
+
log: async (level, message, data) => {
|
|
91
|
+
// Use cached logger if available, otherwise import and cache
|
|
90
92
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
if (!ContextManager.cachedLogger) {
|
|
94
|
+
ContextManager.cachedLogger = await import("../utils/logger.js").then(({ logger }) => logger);
|
|
95
|
+
}
|
|
96
|
+
ContextManager.cachedLogger[level](message, data);
|
|
93
97
|
}
|
|
94
98
|
catch {
|
|
95
99
|
console[level === "debug" ? "log" : level](message, data);
|
|
@@ -14,6 +14,7 @@ export declare function mcpToolToAISDKTool(tool: NeuroLinkMCPTool, serverId: str
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function getAvailableFunctionTools(): Promise<{
|
|
16
16
|
tools: Tool[];
|
|
17
|
+
toolsObject: Record<string, Tool>;
|
|
17
18
|
toolMap: Map<string, {
|
|
18
19
|
serverId: string;
|
|
19
20
|
toolName: string;
|
|
@@ -49,3 +50,15 @@ export declare function getFunctionToolsForCategory(category?: string, maxTools?
|
|
|
49
50
|
* Check if function calling is available
|
|
50
51
|
*/
|
|
51
52
|
export declare function isFunctionCallingAvailable(): Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Utility function to create a named tool object for debugging
|
|
55
|
+
*/
|
|
56
|
+
export declare function createNamedTool(name: string, toolDef: any): any & {
|
|
57
|
+
name: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Get tools with proper name properties for debugging
|
|
61
|
+
*/
|
|
62
|
+
export declare function getToolsWithNames(): Promise<Record<string, any & {
|
|
63
|
+
name: string;
|
|
64
|
+
}>>;
|
|
@@ -8,6 +8,100 @@ import { z } from "zod";
|
|
|
8
8
|
import { unifiedRegistry } from "./unified-registry.js";
|
|
9
9
|
import { createExecutionContext } from "./context-manager.js";
|
|
10
10
|
import { mcpLogger } from "./logging.js";
|
|
11
|
+
/**
|
|
12
|
+
* Parses neurolink-specific function name patterns to extract the server ID and tool name.
|
|
13
|
+
*
|
|
14
|
+
* @param {string[]} parts - An array of strings representing parts of a function name,
|
|
15
|
+
* typically obtained by splitting the function name on underscores.
|
|
16
|
+
* @returns {{ serverId: string; toolName: string } | null} An object containing the `serverId`
|
|
17
|
+
* and `toolName` if the input matches a neurolink-specific pattern, or `null` if no match is found.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Returns { serverId: "neurolink_ai_core", toolName: "generate" }
|
|
21
|
+
* parseNeuroLinkPattern(["neurolink", "ai", "core", "generate"]);
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // Returns { serverId: "neurolink_utility", toolName: "format_number" }
|
|
25
|
+
* parseNeuroLinkPattern(["neurolink", "utility", "format_number"]);
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Returns null
|
|
29
|
+
* parseNeuroLinkPattern(["other", "pattern"]);
|
|
30
|
+
*/
|
|
31
|
+
function parseNeuroLinkPattern(parts) {
|
|
32
|
+
if (parts.length >= 3 &&
|
|
33
|
+
parts[0] === "neurolink" &&
|
|
34
|
+
(parts[1] === "ai" || parts[1] === "utility")) {
|
|
35
|
+
// neurolink_ai_core_generate -> serverId: "neurolink_ai_core", toolName: "generate"
|
|
36
|
+
// neurolink_utility_format_number -> serverId: "neurolink_utility", toolName: "format_number"
|
|
37
|
+
if (parts[1] === "ai" && parts[2] === "core") {
|
|
38
|
+
return {
|
|
39
|
+
serverId: "neurolink_ai_core",
|
|
40
|
+
toolName: parts.slice(3).join("_"),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
else if (parts[1] === "utility") {
|
|
44
|
+
return {
|
|
45
|
+
serverId: "neurolink_utility",
|
|
46
|
+
toolName: parts.slice(2).join("_"),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parse underscore-separated function name format
|
|
54
|
+
*/
|
|
55
|
+
function parseUnderscoreFormat(functionName) {
|
|
56
|
+
const parts = functionName.split("_");
|
|
57
|
+
if (parts.length >= 2) {
|
|
58
|
+
// Try neurolink-specific patterns first
|
|
59
|
+
const neurolinkResult = parseNeuroLinkPattern(parts);
|
|
60
|
+
if (neurolinkResult) {
|
|
61
|
+
return neurolinkResult;
|
|
62
|
+
}
|
|
63
|
+
// Default underscore parsing
|
|
64
|
+
return {
|
|
65
|
+
serverId: parts[0],
|
|
66
|
+
toolName: parts.slice(1).join("_"),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Parse dot-separated function name format (legacy support)
|
|
73
|
+
*/
|
|
74
|
+
function parseDotFormat(functionName) {
|
|
75
|
+
const parts = functionName.split(".");
|
|
76
|
+
if (parts.length >= 2) {
|
|
77
|
+
return {
|
|
78
|
+
serverId: parts[0],
|
|
79
|
+
toolName: parts.slice(1).join("."),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse function name to extract server ID and tool name
|
|
86
|
+
* Handles various naming patterns including neurolink server patterns
|
|
87
|
+
*/
|
|
88
|
+
function parseFunctionName(functionName) {
|
|
89
|
+
// Try underscore format first (most common)
|
|
90
|
+
const underscoreResult = parseUnderscoreFormat(functionName);
|
|
91
|
+
if (underscoreResult) {
|
|
92
|
+
return underscoreResult;
|
|
93
|
+
}
|
|
94
|
+
// Fallback to dot format for backward compatibility
|
|
95
|
+
const dotResult = parseDotFormat(functionName);
|
|
96
|
+
if (dotResult) {
|
|
97
|
+
return dotResult;
|
|
98
|
+
}
|
|
99
|
+
// Final fallback - return as-is with unknown server
|
|
100
|
+
return {
|
|
101
|
+
serverId: "unknown",
|
|
102
|
+
toolName: functionName,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
11
105
|
/**
|
|
12
106
|
* Convert MCP tool to AI SDK function definition
|
|
13
107
|
*/
|
|
@@ -55,6 +149,7 @@ export function mcpToolToAISDKTool(tool, serverId) {
|
|
|
55
149
|
export async function getAvailableFunctionTools() {
|
|
56
150
|
const functionTag = "getAvailableFunctionTools";
|
|
57
151
|
const tools = [];
|
|
152
|
+
const toolsObject = {};
|
|
58
153
|
const toolMap = new Map();
|
|
59
154
|
try {
|
|
60
155
|
// Add overall timeout for the entire function
|
|
@@ -281,6 +376,8 @@ export async function getAvailableFunctionTools() {
|
|
|
281
376
|
},
|
|
282
377
|
});
|
|
283
378
|
tools.push(aiTool);
|
|
379
|
+
// Store tool with proper name association
|
|
380
|
+
toolsObject[functionName] = aiTool;
|
|
284
381
|
// Store mapping for execution - CRITICAL: Use sanitized functionName as key
|
|
285
382
|
toolMap.set(functionName, {
|
|
286
383
|
serverId: typeof toolInfo.serverId === "string"
|
|
@@ -302,7 +399,7 @@ export async function getAvailableFunctionTools() {
|
|
|
302
399
|
if (overallTimeoutId) {
|
|
303
400
|
clearTimeout(overallTimeoutId);
|
|
304
401
|
}
|
|
305
|
-
return { tools, toolMap };
|
|
402
|
+
return { tools, toolsObject, toolMap };
|
|
306
403
|
}
|
|
307
404
|
catch (error) {
|
|
308
405
|
if (overallTimeoutId) {
|
|
@@ -315,7 +412,7 @@ export async function getAvailableFunctionTools() {
|
|
|
315
412
|
}
|
|
316
413
|
catch (error) {
|
|
317
414
|
mcpLogger.error(`[${functionTag}] Error getting function tools:`, error);
|
|
318
|
-
return { tools: [], toolMap: new Map() };
|
|
415
|
+
return { tools: [], toolsObject: {}, toolMap: new Map() };
|
|
319
416
|
}
|
|
320
417
|
}
|
|
321
418
|
/**
|
|
@@ -345,38 +442,12 @@ export async function executeFunctionCall(functionName, parameters, context) {
|
|
|
345
442
|
});
|
|
346
443
|
}
|
|
347
444
|
// Parse server and tool name from function name
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const firstPart = parts[0];
|
|
355
|
-
if (firstPart && typeof firstPart === "string" && firstPart.length > 0) {
|
|
356
|
-
serverId = firstPart;
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
serverId = "unknown";
|
|
360
|
-
}
|
|
361
|
-
toolName = parts.slice(1).join("_"); // Rejoin in case tool name had underscores
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
// Fallback to dot format for backward compatibility
|
|
365
|
-
parts = functionName.split(".");
|
|
366
|
-
if (parts.length === 2) {
|
|
367
|
-
const parsedServerId = parts[0];
|
|
368
|
-
const parsedToolName = parts[1];
|
|
369
|
-
if (parsedServerId && parsedToolName) {
|
|
370
|
-
serverId = parsedServerId;
|
|
371
|
-
toolName = parsedToolName;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
// Can't parse - try executing as-is through unified registry
|
|
376
|
-
mcpLogger.debug(`[${functionTag}] Cannot parse function name format: ${functionName}, trying unified registry`);
|
|
377
|
-
const result = await unifiedRegistry.executeTool(functionName, actualParameters, finalContext);
|
|
378
|
-
return result;
|
|
379
|
-
}
|
|
445
|
+
const { serverId, toolName } = parseFunctionName(functionName);
|
|
446
|
+
if (serverId === "unknown") {
|
|
447
|
+
// Can't parse - try executing as-is through unified registry
|
|
448
|
+
mcpLogger.debug(`[${functionTag}] Cannot parse function name format: ${functionName}, trying unified registry`);
|
|
449
|
+
const result = await unifiedRegistry.executeTool(functionName, actualParameters, finalContext);
|
|
450
|
+
return result;
|
|
380
451
|
}
|
|
381
452
|
// Handle built-in NeuroLink servers directly
|
|
382
453
|
if (serverId === "neurolink-utility" ||
|
|
@@ -541,3 +612,31 @@ export async function isFunctionCallingAvailable() {
|
|
|
541
612
|
return false;
|
|
542
613
|
}
|
|
543
614
|
}
|
|
615
|
+
/**
|
|
616
|
+
* Utility function to create a named tool object for debugging
|
|
617
|
+
*/
|
|
618
|
+
export function createNamedTool(name, toolDef) {
|
|
619
|
+
return {
|
|
620
|
+
name,
|
|
621
|
+
description: toolDef.description,
|
|
622
|
+
parameters: toolDef.parameters,
|
|
623
|
+
execute: toolDef.execute,
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Get tools with proper name properties for debugging
|
|
628
|
+
*/
|
|
629
|
+
export async function getToolsWithNames() {
|
|
630
|
+
try {
|
|
631
|
+
const { toolsObject } = await getAvailableFunctionTools();
|
|
632
|
+
const namedTools = {};
|
|
633
|
+
for (const [name, tool] of Object.entries(toolsObject)) {
|
|
634
|
+
namedTools[name] = createNamedTool(name, tool);
|
|
635
|
+
}
|
|
636
|
+
return namedTools;
|
|
637
|
+
}
|
|
638
|
+
catch (error) {
|
|
639
|
+
mcpLogger.warn("[getToolsWithNames] Failed to get tools with names:", error);
|
|
640
|
+
return {};
|
|
641
|
+
}
|
|
642
|
+
}
|
|
@@ -244,11 +244,26 @@ Response (JSON array only):`;
|
|
|
244
244
|
exists: async () => false,
|
|
245
245
|
},
|
|
246
246
|
path: {
|
|
247
|
-
join: (...paths) =>
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
247
|
+
join: (...paths) => {
|
|
248
|
+
const pathModule = require("path");
|
|
249
|
+
return pathModule.join(...paths);
|
|
250
|
+
},
|
|
251
|
+
resolve: (...paths) => {
|
|
252
|
+
const pathModule = require("path");
|
|
253
|
+
return pathModule.resolve(...paths);
|
|
254
|
+
},
|
|
255
|
+
relative: (from, to) => {
|
|
256
|
+
const pathModule = require("path");
|
|
257
|
+
return pathModule.relative(from, to);
|
|
258
|
+
},
|
|
259
|
+
dirname: (pathArg) => {
|
|
260
|
+
const pathModule = require("path");
|
|
261
|
+
return pathModule.dirname(pathArg);
|
|
262
|
+
},
|
|
263
|
+
basename: (pathArg, ext) => {
|
|
264
|
+
const pathModule = require("path");
|
|
265
|
+
return pathModule.basename(pathArg, ext);
|
|
266
|
+
},
|
|
252
267
|
},
|
|
253
268
|
grantedPermissions: [],
|
|
254
269
|
log: console.log,
|
|
@@ -409,6 +424,7 @@ Please provide a natural response based on the tool results.`;
|
|
|
409
424
|
const tools = {};
|
|
410
425
|
for (const [name, tool] of this.tools) {
|
|
411
426
|
tools[name] = {
|
|
427
|
+
name: name, // Include the tool name as a property
|
|
412
428
|
description: tool.description,
|
|
413
429
|
inputSchema: tool.inputSchema,
|
|
414
430
|
};
|