@juspay/neurolink 1.6.0 → 1.10.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 +200 -7
- package/README.md +101 -18
- package/dist/agent/direct-tools.d.ts +1203 -0
- package/dist/agent/direct-tools.js +387 -0
- package/dist/cli/commands/agent-generate.d.ts +2 -0
- package/dist/cli/commands/agent-generate.js +70 -0
- package/dist/cli/commands/config.d.ts +6 -6
- package/dist/cli/commands/config.js +326 -273
- package/dist/cli/commands/mcp.d.ts +2 -1
- package/dist/cli/commands/mcp.js +874 -146
- package/dist/cli/commands/ollama.d.ts +1 -1
- package/dist/cli/commands/ollama.js +153 -143
- package/dist/cli/index.js +687 -325
- package/dist/cli/utils/complete-setup.d.ts +19 -0
- package/dist/cli/utils/complete-setup.js +81 -0
- package/dist/cli/utils/env-manager.d.ts +44 -0
- package/dist/cli/utils/env-manager.js +226 -0
- package/dist/cli/utils/interactive-setup.d.ts +48 -0
- package/dist/cli/utils/interactive-setup.js +302 -0
- package/dist/core/dynamic-models.d.ts +208 -0
- package/dist/core/dynamic-models.js +250 -0
- package/dist/core/factory.d.ts +13 -6
- package/dist/core/factory.js +177 -62
- package/dist/core/types.d.ts +4 -2
- package/dist/core/types.js +4 -4
- package/dist/index.d.ts +16 -16
- package/dist/index.js +16 -16
- package/dist/lib/agent/direct-tools.d.ts +1203 -0
- package/dist/lib/agent/direct-tools.js +387 -0
- package/dist/lib/core/dynamic-models.d.ts +208 -0
- package/dist/lib/core/dynamic-models.js +250 -0
- package/dist/lib/core/factory.d.ts +13 -6
- package/dist/lib/core/factory.js +177 -62
- package/dist/lib/core/types.d.ts +4 -2
- package/dist/lib/core/types.js +4 -4
- package/dist/lib/index.d.ts +16 -16
- package/dist/lib/index.js +16 -16
- package/dist/lib/mcp/auto-discovery.d.ts +120 -0
- package/dist/lib/mcp/auto-discovery.js +793 -0
- package/dist/lib/mcp/client.d.ts +66 -0
- package/dist/lib/mcp/client.js +245 -0
- package/dist/lib/mcp/config.d.ts +31 -0
- package/dist/lib/mcp/config.js +74 -0
- package/dist/lib/mcp/context-manager.d.ts +4 -4
- package/dist/lib/mcp/context-manager.js +24 -18
- package/dist/lib/mcp/factory.d.ts +28 -11
- package/dist/lib/mcp/factory.js +36 -29
- package/dist/lib/mcp/function-calling.d.ts +51 -0
- package/dist/lib/mcp/function-calling.js +510 -0
- package/dist/lib/mcp/index.d.ts +190 -0
- package/dist/lib/mcp/index.js +156 -0
- package/dist/lib/mcp/initialize-tools.d.ts +28 -0
- package/dist/lib/mcp/initialize-tools.js +209 -0
- package/dist/lib/mcp/initialize.d.ts +17 -0
- package/dist/lib/mcp/initialize.js +51 -0
- package/dist/lib/mcp/logging.d.ts +71 -0
- package/dist/lib/mcp/logging.js +183 -0
- package/dist/lib/mcp/manager.d.ts +67 -0
- package/dist/lib/mcp/manager.js +176 -0
- package/dist/lib/mcp/neurolink-mcp-client.d.ts +96 -0
- package/dist/lib/mcp/neurolink-mcp-client.js +417 -0
- package/dist/lib/mcp/orchestrator.d.ts +3 -3
- package/dist/lib/mcp/orchestrator.js +46 -43
- package/dist/lib/mcp/registry.d.ts +12 -4
- package/dist/lib/mcp/registry.js +64 -37
- package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
- package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +204 -65
- package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +142 -102
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +197 -142
- package/dist/lib/mcp/servers/utilities/utility-server.d.ts +8 -0
- package/dist/lib/mcp/servers/utilities/utility-server.js +326 -0
- package/dist/lib/mcp/tool-integration.d.ts +67 -0
- package/dist/lib/mcp/tool-integration.js +179 -0
- package/dist/lib/mcp/unified-registry.d.ts +269 -0
- package/dist/lib/mcp/unified-registry.js +1411 -0
- package/dist/lib/neurolink.d.ts +68 -6
- package/dist/lib/neurolink.js +304 -42
- package/dist/lib/providers/agent-enhanced-provider.d.ts +59 -0
- package/dist/lib/providers/agent-enhanced-provider.js +242 -0
- package/dist/lib/providers/amazonBedrock.d.ts +3 -3
- package/dist/lib/providers/amazonBedrock.js +54 -50
- package/dist/lib/providers/anthropic.d.ts +2 -2
- package/dist/lib/providers/anthropic.js +92 -84
- package/dist/lib/providers/azureOpenAI.d.ts +2 -2
- package/dist/lib/providers/azureOpenAI.js +97 -86
- package/dist/lib/providers/function-calling-provider.d.ts +70 -0
- package/dist/lib/providers/function-calling-provider.js +359 -0
- package/dist/lib/providers/googleAIStudio.d.ts +10 -5
- package/dist/lib/providers/googleAIStudio.js +60 -38
- package/dist/lib/providers/googleVertexAI.d.ts +3 -3
- package/dist/lib/providers/googleVertexAI.js +96 -86
- package/dist/lib/providers/huggingFace.d.ts +3 -3
- package/dist/lib/providers/huggingFace.js +70 -63
- package/dist/lib/providers/index.d.ts +11 -11
- package/dist/lib/providers/index.js +18 -18
- package/dist/lib/providers/mcp-provider.d.ts +62 -0
- package/dist/lib/providers/mcp-provider.js +183 -0
- package/dist/lib/providers/mistralAI.d.ts +3 -3
- package/dist/lib/providers/mistralAI.js +42 -36
- package/dist/lib/providers/ollama.d.ts +4 -4
- package/dist/lib/providers/ollama.js +128 -98
- package/dist/lib/providers/openAI.d.ts +7 -3
- package/dist/lib/providers/openAI.js +45 -33
- package/dist/lib/utils/logger.js +2 -2
- package/dist/lib/utils/providerUtils-fixed.d.ts +8 -0
- package/dist/lib/utils/providerUtils-fixed.js +75 -0
- package/dist/lib/utils/providerUtils.d.ts +8 -1
- package/dist/lib/utils/providerUtils.js +63 -32
- package/dist/mcp/auto-discovery.d.ts +120 -0
- package/dist/mcp/auto-discovery.js +794 -0
- package/dist/mcp/client.d.ts +66 -0
- package/dist/mcp/client.js +245 -0
- package/dist/mcp/config.d.ts +31 -0
- package/dist/mcp/config.js +74 -0
- package/dist/mcp/context-manager.d.ts +4 -4
- package/dist/mcp/context-manager.js +24 -18
- package/dist/mcp/factory.d.ts +28 -11
- package/dist/mcp/factory.js +36 -29
- package/dist/mcp/function-calling.d.ts +51 -0
- package/dist/mcp/function-calling.js +510 -0
- package/dist/mcp/index.d.ts +190 -0
- package/dist/mcp/index.js +156 -0
- package/dist/mcp/initialize-tools.d.ts +28 -0
- package/dist/mcp/initialize-tools.js +210 -0
- package/dist/mcp/initialize.d.ts +17 -0
- package/dist/mcp/initialize.js +51 -0
- package/dist/mcp/logging.d.ts +71 -0
- package/dist/mcp/logging.js +183 -0
- package/dist/mcp/manager.d.ts +67 -0
- package/dist/mcp/manager.js +176 -0
- package/dist/mcp/neurolink-mcp-client.d.ts +96 -0
- package/dist/mcp/neurolink-mcp-client.js +417 -0
- package/dist/mcp/orchestrator.d.ts +3 -3
- package/dist/mcp/orchestrator.js +46 -43
- package/dist/mcp/registry.d.ts +12 -4
- package/dist/mcp/registry.js +64 -37
- package/dist/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
- package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +204 -65
- package/dist/mcp/servers/ai-providers/ai-core-server.js +142 -102
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +197 -142
- package/dist/mcp/servers/utilities/utility-server.d.ts +8 -0
- package/dist/mcp/servers/utilities/utility-server.js +326 -0
- package/dist/mcp/tool-integration.d.ts +67 -0
- package/dist/mcp/tool-integration.js +179 -0
- package/dist/mcp/unified-registry.d.ts +269 -0
- package/dist/mcp/unified-registry.js +1411 -0
- package/dist/neurolink.d.ts +68 -6
- package/dist/neurolink.js +304 -42
- package/dist/providers/agent-enhanced-provider.d.ts +59 -0
- package/dist/providers/agent-enhanced-provider.js +242 -0
- package/dist/providers/amazonBedrock.d.ts +3 -3
- package/dist/providers/amazonBedrock.js +54 -50
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +92 -84
- package/dist/providers/azureOpenAI.d.ts +2 -2
- package/dist/providers/azureOpenAI.js +97 -86
- package/dist/providers/function-calling-provider.d.ts +70 -0
- package/dist/providers/function-calling-provider.js +359 -0
- package/dist/providers/googleAIStudio.d.ts +10 -5
- package/dist/providers/googleAIStudio.js +60 -38
- package/dist/providers/googleVertexAI.d.ts +3 -3
- package/dist/providers/googleVertexAI.js +96 -86
- package/dist/providers/huggingFace.d.ts +3 -3
- package/dist/providers/huggingFace.js +70 -63
- package/dist/providers/index.d.ts +11 -11
- package/dist/providers/index.js +18 -18
- package/dist/providers/mcp-provider.d.ts +62 -0
- package/dist/providers/mcp-provider.js +183 -0
- package/dist/providers/mistralAI.d.ts +3 -3
- package/dist/providers/mistralAI.js +42 -36
- package/dist/providers/ollama.d.ts +4 -4
- package/dist/providers/ollama.js +128 -98
- package/dist/providers/openAI.d.ts +7 -3
- package/dist/providers/openAI.js +45 -33
- package/dist/utils/logger.js +2 -2
- package/dist/utils/providerUtils-fixed.d.ts +8 -0
- package/dist/utils/providerUtils-fixed.js +75 -0
- package/dist/utils/providerUtils.d.ts +8 -1
- package/dist/utils/providerUtils.js +63 -32
- package/package.json +182 -160
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NeuroLink MCP Client with Automatic Tool Detection
|
|
3
|
+
* Implements automatic tool execution based on prompt analysis
|
|
4
|
+
* Following Lighthouse's pattern of prompt-based tool invocation
|
|
5
|
+
*/
|
|
6
|
+
import { EventEmitter } from "events";
|
|
7
|
+
import { logger } from "../utils/logger.js";
|
|
8
|
+
import { v4 as uuidv4 } from "uuid";
|
|
9
|
+
/**
|
|
10
|
+
* NeuroLink MCP Client with Automatic Tool Detection
|
|
11
|
+
*/
|
|
12
|
+
export class NeuroLinkMCPClient extends EventEmitter {
|
|
13
|
+
provider;
|
|
14
|
+
tools = new Map();
|
|
15
|
+
toolPatterns = [];
|
|
16
|
+
config;
|
|
17
|
+
sessionId;
|
|
18
|
+
executionCount = 0;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
super();
|
|
21
|
+
this.provider = config.provider;
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.sessionId = config.sessionId || uuidv4();
|
|
24
|
+
this.initializeDefaultPatterns();
|
|
25
|
+
logger.info(`[NeuroLink MCP Client] Initialized with automatic tool detection`, {
|
|
26
|
+
sessionId: this.sessionId,
|
|
27
|
+
provider: config.providerName,
|
|
28
|
+
model: config.modelName,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Initialize default tool detection patterns
|
|
33
|
+
*/
|
|
34
|
+
initializeDefaultPatterns() {
|
|
35
|
+
// NO HARDCODED PATTERNS! Let AI decide which tools to use
|
|
36
|
+
// This is TRUE automatic tool detection
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Register a tool with automatic detection patterns
|
|
40
|
+
*/
|
|
41
|
+
registerTool(tool, patterns) {
|
|
42
|
+
this.tools.set(tool.name, tool);
|
|
43
|
+
// Add custom patterns if provided
|
|
44
|
+
if (patterns) {
|
|
45
|
+
this.toolPatterns.push(patterns);
|
|
46
|
+
}
|
|
47
|
+
logger.debug(`[NeuroLink MCP Client] Registered tool: ${tool.name}`, {
|
|
48
|
+
hasPatterns: !!patterns,
|
|
49
|
+
sessionId: this.sessionId,
|
|
50
|
+
});
|
|
51
|
+
this.emit("tool:registered", { toolName: tool.name });
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extract tool parameters using AI
|
|
55
|
+
* No hardcoded patterns - let AI figure out the parameters
|
|
56
|
+
*/
|
|
57
|
+
async extractToolParameters(toolName, tool, prompt) {
|
|
58
|
+
// If the tool has no input schema, no parameters needed
|
|
59
|
+
if (!tool.inputSchema) {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
// Get the schema information
|
|
63
|
+
let schemaDescription = "";
|
|
64
|
+
try {
|
|
65
|
+
// Convert schema to a readable format
|
|
66
|
+
if (typeof tool.inputSchema === "object" && tool.inputSchema !== null) {
|
|
67
|
+
schemaDescription = JSON.stringify(tool.inputSchema, null, 2);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
logger.warn(`[NeuroLink MCP Client] Could not serialize schema for ${toolName}`);
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
// Ask AI to extract parameters
|
|
75
|
+
const extractionPrompt = `Extract the parameters needed for the tool "${toolName}" from the user prompt.
|
|
76
|
+
|
|
77
|
+
Tool: ${toolName}
|
|
78
|
+
Description: ${tool.description}
|
|
79
|
+
Input Schema: ${schemaDescription}
|
|
80
|
+
|
|
81
|
+
User prompt: "${prompt}"
|
|
82
|
+
|
|
83
|
+
Instructions:
|
|
84
|
+
1. Analyze the user prompt to extract values for the tool parameters
|
|
85
|
+
2. Return ONLY a JSON object with the extracted parameters
|
|
86
|
+
3. If a parameter cannot be extracted from the prompt, omit it or use a reasonable default
|
|
87
|
+
4. Make sure the JSON is valid and matches the schema
|
|
88
|
+
|
|
89
|
+
Examples:
|
|
90
|
+
- Prompt: "What's the weather in New York?" → {"location": "New York"}
|
|
91
|
+
- Prompt: "Calculate 5 + 3" → {"expression": "5 + 3"}
|
|
92
|
+
- Prompt: "What time is it?" → {} (no parameters needed)
|
|
93
|
+
|
|
94
|
+
Response (JSON object only):`;
|
|
95
|
+
try {
|
|
96
|
+
const response = await this.provider.generateText({
|
|
97
|
+
prompt: extractionPrompt,
|
|
98
|
+
temperature: 0,
|
|
99
|
+
maxTokens: 200,
|
|
100
|
+
});
|
|
101
|
+
if (response?.text) {
|
|
102
|
+
// Extract JSON object from response
|
|
103
|
+
const match = response.text.match(/\{([^}]*)\}/);
|
|
104
|
+
if (match) {
|
|
105
|
+
try {
|
|
106
|
+
const params = JSON.parse(match[0]);
|
|
107
|
+
logger.debug(`[NeuroLink MCP Client] Extracted parameters for ${toolName}`, params);
|
|
108
|
+
return params;
|
|
109
|
+
}
|
|
110
|
+
catch (parseError) {
|
|
111
|
+
logger.error(`[NeuroLink MCP Client] Failed to parse parameters`, parseError);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
logger.error(`[NeuroLink MCP Client] Failed to extract parameters with AI`, error);
|
|
118
|
+
}
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Analyze prompt to detect required tools
|
|
123
|
+
* TRUE AUTOMATIC DETECTION - AI decides which tools to use
|
|
124
|
+
*/
|
|
125
|
+
async analyzePrompt(prompt) {
|
|
126
|
+
const detectedTools = [];
|
|
127
|
+
// No patterns! Always use AI to detect tools
|
|
128
|
+
if (this.tools.size > 0) {
|
|
129
|
+
const toolList = Array.from(this.tools.values()).map((tool) => ({
|
|
130
|
+
name: tool.name,
|
|
131
|
+
description: tool.description,
|
|
132
|
+
}));
|
|
133
|
+
const analysisPrompt = `Analyze this user prompt and determine which tools should be used to answer it properly.
|
|
134
|
+
|
|
135
|
+
User prompt: "${prompt}"
|
|
136
|
+
|
|
137
|
+
Available tools:
|
|
138
|
+
${toolList.map((t) => `- ${t.name}: ${t.description}`).join("\n")}
|
|
139
|
+
|
|
140
|
+
Instructions:
|
|
141
|
+
1. Analyze what the user is asking for
|
|
142
|
+
2. Determine which tools would be helpful to answer the question
|
|
143
|
+
3. Return ONLY a JSON array of tool names that should be used
|
|
144
|
+
4. If no tools are needed, return an empty array []
|
|
145
|
+
5. Be selective - only choose tools that are directly relevant
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
- "What time is it?" → ["neurolink-utility_get-current-time"]
|
|
149
|
+
- "Calculate 5 + 3" → ["neurolink-utility_calculator"]
|
|
150
|
+
- "What is the capital of France?" → []
|
|
151
|
+
- "What's the weather in NYC?" → ["neurolink-utility_get-weather"]
|
|
152
|
+
|
|
153
|
+
Response (JSON array only):`;
|
|
154
|
+
try {
|
|
155
|
+
const response = await this.provider.generateText({
|
|
156
|
+
prompt: analysisPrompt,
|
|
157
|
+
temperature: 0,
|
|
158
|
+
maxTokens: 200,
|
|
159
|
+
});
|
|
160
|
+
if (response?.text) {
|
|
161
|
+
// Extract JSON array from response
|
|
162
|
+
const match = response.text.match(/\[([^\]]*)\]/);
|
|
163
|
+
if (match) {
|
|
164
|
+
try {
|
|
165
|
+
const toolNames = JSON.parse(match[0]);
|
|
166
|
+
// Filter to only include tools that actually exist
|
|
167
|
+
const validTools = toolNames.filter((name) => {
|
|
168
|
+
// Check exact match first
|
|
169
|
+
if (this.tools.has(name)) {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
// Check for partial matches (e.g., "get-current-time" matches "neurolink-utility_get-current-time")
|
|
173
|
+
for (const [registeredName] of this.tools) {
|
|
174
|
+
if (registeredName.endsWith(`_${name}`) ||
|
|
175
|
+
registeredName.includes(name)) {
|
|
176
|
+
// Replace with the full registered name
|
|
177
|
+
const index = toolNames.indexOf(name);
|
|
178
|
+
if (index !== -1) {
|
|
179
|
+
toolNames[index] = registeredName;
|
|
180
|
+
}
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
});
|
|
186
|
+
detectedTools.push(...validTools);
|
|
187
|
+
}
|
|
188
|
+
catch (parseError) {
|
|
189
|
+
logger.error(`[NeuroLink MCP Client] Failed to parse tool names`, parseError);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
logger.error(`[NeuroLink MCP Client] Failed to analyze prompt with AI`, error);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
logger.info(`[NeuroLink MCP Client] AI detected tools for prompt`, {
|
|
199
|
+
prompt: prompt.substring(0, 50),
|
|
200
|
+
detectedTools,
|
|
201
|
+
sessionId: this.sessionId,
|
|
202
|
+
});
|
|
203
|
+
return detectedTools;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Execute detected tools
|
|
207
|
+
*/
|
|
208
|
+
async executeTools(toolNames, prompt) {
|
|
209
|
+
const results = [];
|
|
210
|
+
for (const toolName of toolNames) {
|
|
211
|
+
const tool = this.tools.get(toolName);
|
|
212
|
+
if (!tool) {
|
|
213
|
+
logger.warn(`[NeuroLink MCP Client] Tool not found: ${toolName}`);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
// Extract parameters for the tool using AI
|
|
217
|
+
const params = await this.extractToolParameters(toolName, tool, prompt);
|
|
218
|
+
// Create execution context
|
|
219
|
+
const context = {
|
|
220
|
+
sessionId: this.sessionId,
|
|
221
|
+
userId: this.config.userId,
|
|
222
|
+
organizationId: this.config.organizationId,
|
|
223
|
+
aiProvider: this.config.providerName,
|
|
224
|
+
modelId: this.config.modelName,
|
|
225
|
+
timestamp: Date.now(),
|
|
226
|
+
};
|
|
227
|
+
// Emit tool start event
|
|
228
|
+
this.executionCount++;
|
|
229
|
+
const executionId = `exec-${this.executionCount}`;
|
|
230
|
+
this.emit("tool:start", {
|
|
231
|
+
executionId,
|
|
232
|
+
toolName,
|
|
233
|
+
params,
|
|
234
|
+
});
|
|
235
|
+
const startTime = Date.now();
|
|
236
|
+
try {
|
|
237
|
+
// Execute the tool
|
|
238
|
+
const result = await tool.execute(params, context);
|
|
239
|
+
const executionTime = Date.now() - startTime;
|
|
240
|
+
results.push({
|
|
241
|
+
toolName,
|
|
242
|
+
result,
|
|
243
|
+
executionTime,
|
|
244
|
+
});
|
|
245
|
+
// Emit tool end event
|
|
246
|
+
this.emit("tool:end", {
|
|
247
|
+
executionId,
|
|
248
|
+
toolName,
|
|
249
|
+
result,
|
|
250
|
+
executionTime,
|
|
251
|
+
});
|
|
252
|
+
logger.info(`[NeuroLink MCP Client] Tool executed successfully`, {
|
|
253
|
+
toolName,
|
|
254
|
+
executionTime,
|
|
255
|
+
success: result.success,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
const executionTime = Date.now() - startTime;
|
|
260
|
+
const errorResult = {
|
|
261
|
+
success: false,
|
|
262
|
+
error: error instanceof Error ? error.message : String(error),
|
|
263
|
+
};
|
|
264
|
+
results.push({
|
|
265
|
+
toolName,
|
|
266
|
+
result: errorResult,
|
|
267
|
+
executionTime,
|
|
268
|
+
});
|
|
269
|
+
// Emit tool error event
|
|
270
|
+
this.emit("tool:error", {
|
|
271
|
+
executionId,
|
|
272
|
+
toolName,
|
|
273
|
+
error: errorResult.error,
|
|
274
|
+
executionTime,
|
|
275
|
+
});
|
|
276
|
+
logger.error(`[NeuroLink MCP Client] Tool execution failed`, {
|
|
277
|
+
toolName,
|
|
278
|
+
error: errorResult.error,
|
|
279
|
+
executionTime,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return results;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Generate response with tool results incorporated
|
|
287
|
+
*/
|
|
288
|
+
async generateResponse(prompt, toolResults) {
|
|
289
|
+
// If no tools were used, generate regular response
|
|
290
|
+
if (toolResults.length === 0) {
|
|
291
|
+
const response = await this.provider.generateText({ prompt });
|
|
292
|
+
return response?.text || "";
|
|
293
|
+
}
|
|
294
|
+
// Extract human-readable results from tool executions
|
|
295
|
+
const toolResultsText = toolResults
|
|
296
|
+
.map((tr) => {
|
|
297
|
+
if (tr.result.success && tr.result.data) {
|
|
298
|
+
// Check if tool result has a displayString or other human-readable format
|
|
299
|
+
const data = tr.result.data;
|
|
300
|
+
// For time tool, use the displayString
|
|
301
|
+
if (data.displayString) {
|
|
302
|
+
return data.displayString;
|
|
303
|
+
}
|
|
304
|
+
// For other tools, try to extract meaningful text
|
|
305
|
+
if (data.formatted) {
|
|
306
|
+
return data.formatted;
|
|
307
|
+
}
|
|
308
|
+
// For complex results, create a summary
|
|
309
|
+
if (typeof data === "object") {
|
|
310
|
+
// Try to find the most relevant field
|
|
311
|
+
if (data.result) {
|
|
312
|
+
return String(data.result);
|
|
313
|
+
}
|
|
314
|
+
if (data.output) {
|
|
315
|
+
return String(data.output);
|
|
316
|
+
}
|
|
317
|
+
if (data.text) {
|
|
318
|
+
return String(data.text);
|
|
319
|
+
}
|
|
320
|
+
if (data.value) {
|
|
321
|
+
return String(data.value);
|
|
322
|
+
}
|
|
323
|
+
// For time-specific fields
|
|
324
|
+
if (data.localTime) {
|
|
325
|
+
return `The current time is ${data.localTime} in ${data.actualTimezone || data.requestedTimezone}`;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Fallback to stringified result
|
|
329
|
+
return JSON.stringify(data);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
return `Tool ${tr.toolName} failed: ${tr.result.error}`;
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
.join("\n");
|
|
336
|
+
// For single tool results with displayString, return directly
|
|
337
|
+
if (toolResults.length === 1) {
|
|
338
|
+
const toolResult = toolResults[0];
|
|
339
|
+
if (toolResult.result.success && toolResult.result.data) {
|
|
340
|
+
const data = toolResult.result.data;
|
|
341
|
+
if (data.displayString) {
|
|
342
|
+
return data.displayString;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
// For more complex queries, let the AI incorporate the results
|
|
347
|
+
const enhancedPrompt = `User question: ${prompt}
|
|
348
|
+
|
|
349
|
+
Tool results: ${toolResultsText}
|
|
350
|
+
|
|
351
|
+
Please provide a natural response based on the tool results.`;
|
|
352
|
+
// Generate final response
|
|
353
|
+
const response = await this.provider.generateText({
|
|
354
|
+
prompt: enhancedPrompt,
|
|
355
|
+
temperature: 0.7,
|
|
356
|
+
maxTokens: 1000,
|
|
357
|
+
});
|
|
358
|
+
return response?.text || toolResultsText;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Send a prompt and automatically execute any needed tools
|
|
362
|
+
*/
|
|
363
|
+
async sendPrompt(prompt) {
|
|
364
|
+
logger.info(`[NeuroLink MCP Client] Processing prompt with automatic tool detection`, {
|
|
365
|
+
prompt: prompt.substring(0, 100),
|
|
366
|
+
sessionId: this.sessionId,
|
|
367
|
+
});
|
|
368
|
+
// Step 1: Analyze prompt for tool needs
|
|
369
|
+
const toolsNeeded = await this.analyzePrompt(prompt);
|
|
370
|
+
// Step 2: Execute tools if needed
|
|
371
|
+
const toolResults = await this.executeTools(toolsNeeded, prompt);
|
|
372
|
+
// Step 3: Generate response with tool results
|
|
373
|
+
const response = await this.generateResponse(prompt, toolResults);
|
|
374
|
+
return response;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Get registered tools
|
|
378
|
+
*/
|
|
379
|
+
getTools() {
|
|
380
|
+
const tools = {};
|
|
381
|
+
for (const [name, tool] of this.tools) {
|
|
382
|
+
tools[name] = {
|
|
383
|
+
description: tool.description,
|
|
384
|
+
inputSchema: tool.inputSchema,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return tools;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Get session statistics
|
|
391
|
+
*/
|
|
392
|
+
getStats() {
|
|
393
|
+
return {
|
|
394
|
+
sessionId: this.sessionId,
|
|
395
|
+
toolCount: this.tools.size,
|
|
396
|
+
patternCount: this.toolPatterns.length,
|
|
397
|
+
executionCount: this.executionCount,
|
|
398
|
+
provider: this.config.providerName,
|
|
399
|
+
model: this.config.modelName,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Clean up resources
|
|
404
|
+
*/
|
|
405
|
+
async cleanup() {
|
|
406
|
+
this.tools.clear();
|
|
407
|
+
this.toolPatterns = [];
|
|
408
|
+
this.removeAllListeners();
|
|
409
|
+
logger.info(`[NeuroLink MCP Client] Cleaned up session ${this.sessionId}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Create a new NeuroLink MCP Client instance
|
|
414
|
+
*/
|
|
415
|
+
export function createNeuroLinkMCPClient(config) {
|
|
416
|
+
return new NeuroLinkMCPClient(config);
|
|
417
|
+
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Central orchestrator for coordinated tool execution with pipeline management
|
|
4
4
|
* Coordinates factory, registry, context, and AI tools for seamless operation
|
|
5
5
|
*/
|
|
6
|
-
import type { ToolResult } from
|
|
7
|
-
import { MCPToolRegistry, type ToolExecutionOptions } from
|
|
8
|
-
import { ContextManager, type ContextRequest } from
|
|
6
|
+
import type { ToolResult } from "./factory.js";
|
|
7
|
+
import { MCPToolRegistry, type ToolExecutionOptions } from "./registry.js";
|
|
8
|
+
import { ContextManager, type ContextRequest } from "./context-manager.js";
|
|
9
9
|
/**
|
|
10
10
|
* Pipeline execution options
|
|
11
11
|
*/
|
package/dist/mcp/orchestrator.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Central orchestrator for coordinated tool execution with pipeline management
|
|
4
4
|
* Coordinates factory, registry, context, and AI tools for seamless operation
|
|
5
5
|
*/
|
|
6
|
-
import { MCPToolRegistry, defaultToolRegistry } from
|
|
7
|
-
import { ContextManager, defaultContextManager, createExecutionContext } from
|
|
8
|
-
import { aiCoreServer } from
|
|
6
|
+
import { MCPToolRegistry, defaultToolRegistry, } from "./registry.js";
|
|
7
|
+
import { ContextManager, defaultContextManager, createExecutionContext, } from "./context-manager.js";
|
|
8
|
+
import { aiCoreServer } from "./servers/ai-providers/ai-core-server.js";
|
|
9
9
|
/**
|
|
10
10
|
* NeuroLink MCP Tool Orchestrator
|
|
11
11
|
* Central coordination engine for tool execution, pipelines, and AI operations
|
|
@@ -26,10 +26,10 @@ export class MCPOrchestrator {
|
|
|
26
26
|
async initializeDefaultServers() {
|
|
27
27
|
try {
|
|
28
28
|
await this.registry.registerServer(aiCoreServer);
|
|
29
|
-
console.log(
|
|
29
|
+
console.log("[Orchestrator] Initialized with AI Core Server");
|
|
30
30
|
}
|
|
31
31
|
catch (error) {
|
|
32
|
-
console.warn(
|
|
32
|
+
console.warn("[Orchestrator] Failed to register AI Core Server:", error);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
@@ -47,7 +47,7 @@ export class MCPOrchestrator {
|
|
|
47
47
|
console.log(`[Orchestrator] Executing tool '${toolName}' in session ${context.sessionId}`);
|
|
48
48
|
// Execute tool through registry
|
|
49
49
|
const result = await this.registry.executeTool(toolName, params, context, options);
|
|
50
|
-
console.log(`[Orchestrator] Tool '${toolName}' execution ${result.success ?
|
|
50
|
+
console.log(`[Orchestrator] Tool '${toolName}' execution ${result.success ? "completed" : "failed"}`);
|
|
51
51
|
return result;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
@@ -61,11 +61,11 @@ export class MCPOrchestrator {
|
|
|
61
61
|
async executePipeline(steps, contextRequest = {}, options = {}) {
|
|
62
62
|
const startTime = Date.now();
|
|
63
63
|
const pipelineId = this.generatePipelineId();
|
|
64
|
-
const { stopOnError = true, parallel = false, timeout = 60000, trackMetrics = true, validateInputs = true } = options;
|
|
64
|
+
const { stopOnError = true, parallel = false, timeout = 60000, trackMetrics = true, validateInputs = true, } = options;
|
|
65
65
|
// Create shared execution context
|
|
66
66
|
const context = this.contextManager.createContext({
|
|
67
67
|
...contextRequest,
|
|
68
|
-
sessionId: contextRequest.sessionId || pipelineId
|
|
68
|
+
sessionId: contextRequest.sessionId || pipelineId,
|
|
69
69
|
});
|
|
70
70
|
const results = new Map();
|
|
71
71
|
const errors = new Map();
|
|
@@ -79,7 +79,7 @@ export class MCPOrchestrator {
|
|
|
79
79
|
timeout,
|
|
80
80
|
trackMetrics,
|
|
81
81
|
validateInputs,
|
|
82
|
-
stopOnError
|
|
82
|
+
stopOnError,
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
else {
|
|
@@ -92,12 +92,12 @@ export class MCPOrchestrator {
|
|
|
92
92
|
...step.options,
|
|
93
93
|
validateInput: validateInputs,
|
|
94
94
|
trackMetrics,
|
|
95
|
-
timeoutMs: timeout / steps.length // Distribute timeout across steps
|
|
95
|
+
timeoutMs: timeout / steps.length, // Distribute timeout across steps
|
|
96
96
|
});
|
|
97
97
|
results.set(stepId, stepResult);
|
|
98
98
|
stepsExecuted++;
|
|
99
99
|
if (!stepResult.success) {
|
|
100
|
-
errors.set(stepId, stepResult.error ||
|
|
100
|
+
errors.set(stepId, stepResult.error || "Unknown error");
|
|
101
101
|
if (stopOnError) {
|
|
102
102
|
console.error(`[Orchestrator] Pipeline ${pipelineId} stopped due to error in step ${stepId}`);
|
|
103
103
|
break;
|
|
@@ -117,7 +117,7 @@ export class MCPOrchestrator {
|
|
|
117
117
|
}
|
|
118
118
|
const executionTime = Date.now() - startTime;
|
|
119
119
|
const success = errors.size === 0 || !stopOnError;
|
|
120
|
-
console.log(`[Orchestrator] Pipeline ${pipelineId} completed in ${executionTime}ms - ${success ?
|
|
120
|
+
console.log(`[Orchestrator] Pipeline ${pipelineId} completed in ${executionTime}ms - ${success ? "SUCCESS" : "FAILED"}`);
|
|
121
121
|
return {
|
|
122
122
|
success,
|
|
123
123
|
results,
|
|
@@ -129,8 +129,8 @@ export class MCPOrchestrator {
|
|
|
129
129
|
pipelineId,
|
|
130
130
|
sessionId: context.sessionId,
|
|
131
131
|
timestamp: Date.now(),
|
|
132
|
-
parallel
|
|
133
|
-
}
|
|
132
|
+
parallel,
|
|
133
|
+
},
|
|
134
134
|
};
|
|
135
135
|
}
|
|
136
136
|
catch (error) {
|
|
@@ -140,7 +140,7 @@ export class MCPOrchestrator {
|
|
|
140
140
|
return {
|
|
141
141
|
success: false,
|
|
142
142
|
results,
|
|
143
|
-
errors: new Map([[
|
|
143
|
+
errors: new Map([["pipeline", errorMessage]]),
|
|
144
144
|
executionTime,
|
|
145
145
|
stepsExecuted,
|
|
146
146
|
stepsSkipped,
|
|
@@ -148,8 +148,8 @@ export class MCPOrchestrator {
|
|
|
148
148
|
pipelineId,
|
|
149
149
|
sessionId: context.sessionId,
|
|
150
150
|
timestamp: Date.now(),
|
|
151
|
-
parallel
|
|
152
|
-
}
|
|
151
|
+
parallel,
|
|
152
|
+
},
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
155
|
}
|
|
@@ -172,29 +172,29 @@ export class MCPOrchestrator {
|
|
|
172
172
|
// Step 1: Provider selection (if not specified)
|
|
173
173
|
if (!options.provider) {
|
|
174
174
|
steps.push({
|
|
175
|
-
stepId:
|
|
176
|
-
toolName:
|
|
175
|
+
stepId: "select-provider",
|
|
176
|
+
toolName: "select-provider",
|
|
177
177
|
params: {
|
|
178
178
|
requirements: {
|
|
179
179
|
maxTokens: options.maxTokens,
|
|
180
|
-
costEfficient: true
|
|
181
|
-
}
|
|
182
|
-
}
|
|
180
|
+
costEfficient: true,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
183
|
});
|
|
184
184
|
}
|
|
185
185
|
// Step 2: Text generation
|
|
186
186
|
steps.push({
|
|
187
|
-
stepId:
|
|
188
|
-
toolName:
|
|
187
|
+
stepId: "generate-text",
|
|
188
|
+
toolName: "generate-text",
|
|
189
189
|
params: {
|
|
190
190
|
prompt,
|
|
191
191
|
provider: options.provider,
|
|
192
192
|
model: options.model,
|
|
193
193
|
temperature: options.temperature,
|
|
194
194
|
maxTokens: options.maxTokens,
|
|
195
|
-
systemPrompt: options.systemPrompt
|
|
195
|
+
systemPrompt: options.systemPrompt,
|
|
196
196
|
},
|
|
197
|
-
dependsOn: options.provider ? [] : [
|
|
197
|
+
dependsOn: options.provider ? [] : ["select-provider"],
|
|
198
198
|
});
|
|
199
199
|
// Step 3: Custom tools (if specified)
|
|
200
200
|
if (options.customTools && options.customTools.length > 0) {
|
|
@@ -202,8 +202,10 @@ export class MCPOrchestrator {
|
|
|
202
202
|
steps.push({
|
|
203
203
|
stepId: `custom-${toolName}`,
|
|
204
204
|
toolName,
|
|
205
|
-
params: {
|
|
206
|
-
|
|
205
|
+
params: {
|
|
206
|
+
/* tool-specific params */
|
|
207
|
+
},
|
|
208
|
+
dependsOn: ["generate-text"],
|
|
207
209
|
});
|
|
208
210
|
}
|
|
209
211
|
}
|
|
@@ -211,14 +213,14 @@ export class MCPOrchestrator {
|
|
|
211
213
|
const pipelineResult = await this.executePipeline(steps, contextRequest, {
|
|
212
214
|
stopOnError: true,
|
|
213
215
|
parallel: false,
|
|
214
|
-
trackMetrics: true
|
|
216
|
+
trackMetrics: true,
|
|
215
217
|
});
|
|
216
218
|
const executionTime = Date.now() - startTime;
|
|
217
219
|
// Extract text generation result
|
|
218
|
-
const textResult = pipelineResult.results.get(
|
|
219
|
-
const providerResult = pipelineResult.results.get(
|
|
220
|
+
const textResult = pipelineResult.results.get("generate-text");
|
|
221
|
+
const providerResult = pipelineResult.results.get("select-provider");
|
|
220
222
|
if (!textResult || !textResult.success) {
|
|
221
|
-
throw new Error(
|
|
223
|
+
throw new Error("Text generation failed");
|
|
222
224
|
}
|
|
223
225
|
const toolsUsed = Array.from(pipelineResult.results.keys());
|
|
224
226
|
console.log(`[Orchestrator] Text pipeline completed in ${executionTime}ms`);
|
|
@@ -232,8 +234,8 @@ export class MCPOrchestrator {
|
|
|
232
234
|
metadata: {
|
|
233
235
|
sessionId: context.sessionId,
|
|
234
236
|
timestamp: Date.now(),
|
|
235
|
-
toolsUsed
|
|
236
|
-
}
|
|
237
|
+
toolsUsed,
|
|
238
|
+
},
|
|
237
239
|
};
|
|
238
240
|
}
|
|
239
241
|
catch (error) {
|
|
@@ -246,8 +248,8 @@ export class MCPOrchestrator {
|
|
|
246
248
|
metadata: {
|
|
247
249
|
sessionId: context.sessionId,
|
|
248
250
|
timestamp: Date.now(),
|
|
249
|
-
toolsUsed: []
|
|
250
|
-
}
|
|
251
|
+
toolsUsed: [],
|
|
252
|
+
},
|
|
251
253
|
};
|
|
252
254
|
}
|
|
253
255
|
}
|
|
@@ -261,8 +263,8 @@ export class MCPOrchestrator {
|
|
|
261
263
|
registry: this.registry.getStats(),
|
|
262
264
|
context: this.contextManager.getStats(),
|
|
263
265
|
orchestrator: {
|
|
264
|
-
pipelinesExecuted: this.pipelineCounter
|
|
265
|
-
}
|
|
266
|
+
pipelinesExecuted: this.pipelineCounter,
|
|
267
|
+
},
|
|
266
268
|
};
|
|
267
269
|
}
|
|
268
270
|
/**
|
|
@@ -283,14 +285,15 @@ export class MCPOrchestrator {
|
|
|
283
285
|
const completed = new Set();
|
|
284
286
|
const executing = new Set();
|
|
285
287
|
while (completed.size < steps.length) {
|
|
286
|
-
const readySteps = Array.from(stepMap.keys()).filter(stepId => {
|
|
287
|
-
if (completed.has(stepId) || executing.has(stepId))
|
|
288
|
+
const readySteps = Array.from(stepMap.keys()).filter((stepId) => {
|
|
289
|
+
if (completed.has(stepId) || executing.has(stepId)) {
|
|
288
290
|
return false;
|
|
291
|
+
}
|
|
289
292
|
const dependencies = dependencyGraph.get(stepId) || [];
|
|
290
|
-
return dependencies.every(dep => completed.has(dep));
|
|
293
|
+
return dependencies.every((dep) => completed.has(dep));
|
|
291
294
|
});
|
|
292
295
|
if (readySteps.length === 0) {
|
|
293
|
-
throw new Error(
|
|
296
|
+
throw new Error("Circular dependency detected in pipeline");
|
|
294
297
|
}
|
|
295
298
|
// Execute ready steps in parallel
|
|
296
299
|
const executePromises = readySteps.map(async (stepId) => {
|
|
@@ -300,7 +303,7 @@ export class MCPOrchestrator {
|
|
|
300
303
|
const result = await this.registry.executeTool(step.toolName, step.params, context, { ...step.options, ...options });
|
|
301
304
|
results.set(stepId, result);
|
|
302
305
|
if (!result.success) {
|
|
303
|
-
errors.set(stepId, result.error ||
|
|
306
|
+
errors.set(stepId, result.error || "Unknown error");
|
|
304
307
|
}
|
|
305
308
|
}
|
|
306
309
|
catch (error) {
|