@juspay/neurolink 7.29.1 → 7.29.3
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 +12 -0
- package/dist/cli/commands/config.d.ts +86 -86
- package/dist/cli/commands/mcp.js +64 -9
- package/dist/cli/commands/models.js +25 -21
- package/dist/cli/commands/ollama.js +2 -2
- package/dist/cli/factories/commandFactory.d.ts +9 -0
- package/dist/cli/factories/commandFactory.js +177 -83
- package/dist/cli/factories/ollamaCommandFactory.js +3 -1
- package/dist/cli/factories/sagemakerCommandFactory.js +3 -2
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +19 -11
- package/dist/cli/utils/envManager.js +5 -5
- package/dist/cli/utils/ollamaUtils.d.ts +12 -0
- package/dist/cli/utils/ollamaUtils.js +58 -42
- package/dist/config/configManager.js +5 -2
- package/dist/core/analytics.d.ts +2 -24
- package/dist/core/analytics.js +12 -17
- package/dist/core/baseProvider.d.ts +30 -1
- package/dist/core/baseProvider.js +180 -198
- package/dist/core/dynamicModels.d.ts +4 -4
- package/dist/core/dynamicModels.js +7 -7
- package/dist/core/evaluation.d.ts +9 -9
- package/dist/core/evaluation.js +117 -65
- package/dist/core/evaluationProviders.d.ts +18 -2
- package/dist/core/evaluationProviders.js +15 -13
- package/dist/core/factory.js +77 -4
- package/dist/core/modelConfiguration.d.ts +63 -0
- package/dist/core/modelConfiguration.js +354 -290
- package/dist/core/streamAnalytics.d.ts +10 -5
- package/dist/core/streamAnalytics.js +10 -10
- package/dist/core/types.d.ts +19 -109
- package/dist/core/types.js +13 -0
- package/dist/factories/providerFactory.js +4 -1
- package/dist/factories/providerRegistry.js +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/lib/config/configManager.js +5 -2
- package/dist/lib/core/analytics.d.ts +2 -24
- package/dist/lib/core/analytics.js +12 -17
- package/dist/lib/core/baseProvider.d.ts +30 -1
- package/dist/lib/core/baseProvider.js +180 -198
- package/dist/lib/core/dynamicModels.js +7 -7
- package/dist/lib/core/evaluation.d.ts +9 -9
- package/dist/lib/core/evaluation.js +117 -65
- package/dist/lib/core/evaluationProviders.d.ts +18 -2
- package/dist/lib/core/evaluationProviders.js +15 -13
- package/dist/lib/core/factory.js +77 -4
- package/dist/lib/core/modelConfiguration.d.ts +63 -0
- package/dist/lib/core/modelConfiguration.js +354 -290
- package/dist/lib/core/streamAnalytics.d.ts +10 -5
- package/dist/lib/core/streamAnalytics.js +10 -10
- package/dist/lib/core/types.d.ts +19 -109
- package/dist/lib/core/types.js +13 -0
- package/dist/lib/factories/providerFactory.js +4 -1
- package/dist/lib/factories/providerRegistry.js +2 -2
- package/dist/lib/index.d.ts +2 -1
- package/dist/lib/mcp/externalServerManager.js +14 -6
- package/dist/lib/mcp/factory.js +1 -1
- package/dist/lib/mcp/flexibleToolValidator.d.ts +50 -0
- package/dist/lib/mcp/flexibleToolValidator.js +161 -0
- package/dist/lib/mcp/index.d.ts +1 -1
- package/dist/lib/mcp/index.js +1 -1
- package/dist/lib/mcp/mcpCircuitBreaker.js +5 -1
- package/dist/lib/mcp/mcpClientFactory.js +3 -0
- package/dist/lib/mcp/registry.d.ts +3 -3
- package/dist/lib/mcp/registry.js +3 -3
- package/dist/lib/mcp/servers/aiProviders/aiAnalysisTools.js +5 -5
- package/dist/lib/mcp/servers/aiProviders/aiWorkflowTools.js +6 -6
- package/dist/lib/mcp/servers/utilities/utilityServer.js +1 -1
- package/dist/lib/mcp/toolDiscoveryService.js +8 -2
- package/dist/lib/mcp/toolRegistry.d.ts +2 -2
- package/dist/lib/mcp/toolRegistry.js +29 -54
- package/dist/lib/middleware/builtin/analytics.js +4 -4
- package/dist/lib/middleware/builtin/guardrails.js +2 -2
- package/dist/lib/middleware/registry.js +11 -2
- package/dist/lib/models/modelRegistry.d.ts +1 -1
- package/dist/lib/models/modelRegistry.js +3 -3
- package/dist/lib/models/modelResolver.d.ts +1 -1
- package/dist/lib/models/modelResolver.js +2 -2
- package/dist/lib/neurolink.d.ts +118 -0
- package/dist/lib/neurolink.js +814 -952
- package/dist/lib/providers/amazonBedrock.d.ts +47 -6
- package/dist/lib/providers/amazonBedrock.js +282 -23
- package/dist/lib/providers/amazonSagemaker.d.ts +1 -1
- package/dist/lib/providers/amazonSagemaker.js +12 -3
- package/dist/lib/providers/anthropic.d.ts +1 -1
- package/dist/lib/providers/anthropic.js +7 -6
- package/dist/lib/providers/anthropicBaseProvider.d.ts +1 -1
- package/dist/lib/providers/anthropicBaseProvider.js +4 -3
- package/dist/lib/providers/aws/credentialProvider.d.ts +58 -0
- package/dist/lib/providers/aws/credentialProvider.js +267 -0
- package/dist/lib/providers/aws/credentialTester.d.ts +49 -0
- package/dist/lib/providers/aws/credentialTester.js +394 -0
- package/dist/lib/providers/azureOpenai.d.ts +1 -1
- package/dist/lib/providers/azureOpenai.js +1 -1
- package/dist/lib/providers/googleAiStudio.d.ts +1 -1
- package/dist/lib/providers/googleAiStudio.js +2 -2
- package/dist/lib/providers/googleVertex.d.ts +40 -0
- package/dist/lib/providers/googleVertex.js +330 -274
- package/dist/lib/providers/huggingFace.js +1 -1
- package/dist/lib/providers/mistral.d.ts +1 -1
- package/dist/lib/providers/mistral.js +2 -2
- package/dist/lib/providers/ollama.d.ts +4 -0
- package/dist/lib/providers/ollama.js +38 -18
- package/dist/lib/providers/openAI.d.ts +1 -1
- package/dist/lib/providers/openAI.js +2 -2
- package/dist/lib/providers/sagemaker/adaptive-semaphore.js +7 -4
- package/dist/lib/providers/sagemaker/client.js +13 -3
- package/dist/lib/providers/sagemaker/config.js +5 -1
- package/dist/lib/providers/sagemaker/detection.js +19 -9
- package/dist/lib/providers/sagemaker/errors.d.ts +8 -1
- package/dist/lib/providers/sagemaker/errors.js +103 -20
- package/dist/lib/providers/sagemaker/language-model.d.ts +3 -3
- package/dist/lib/providers/sagemaker/language-model.js +4 -4
- package/dist/lib/providers/sagemaker/parsers.js +14 -6
- package/dist/lib/providers/sagemaker/streaming.js +14 -3
- package/dist/lib/providers/sagemaker/types.d.ts +1 -1
- package/dist/lib/proxy/awsProxyIntegration.d.ts +23 -0
- package/dist/lib/proxy/awsProxyIntegration.js +285 -0
- package/dist/lib/proxy/proxyFetch.d.ts +9 -5
- package/dist/lib/proxy/proxyFetch.js +232 -98
- package/dist/lib/proxy/utils/noProxyUtils.d.ts +39 -0
- package/dist/lib/proxy/utils/noProxyUtils.js +149 -0
- package/dist/lib/sdk/toolRegistration.d.ts +1 -1
- package/dist/lib/types/cli.d.ts +80 -8
- package/dist/lib/types/contextTypes.js +2 -2
- package/dist/lib/types/generateTypes.d.ts +4 -6
- package/dist/lib/types/providers.d.ts +124 -19
- package/dist/lib/types/providers.js +6 -6
- package/dist/lib/types/streamTypes.d.ts +4 -6
- package/dist/lib/types/typeAliases.d.ts +1 -1
- package/dist/lib/utils/analyticsUtils.d.ts +33 -0
- package/dist/lib/utils/analyticsUtils.js +76 -0
- package/dist/lib/utils/errorHandling.js +4 -1
- package/dist/lib/utils/evaluationUtils.d.ts +27 -0
- package/dist/lib/utils/evaluationUtils.js +131 -0
- package/dist/lib/utils/optionsUtils.js +10 -1
- package/dist/lib/utils/performance.d.ts +1 -1
- package/dist/lib/utils/performance.js +15 -3
- package/dist/lib/utils/providerConfig.d.ts +1 -0
- package/dist/lib/utils/providerConfig.js +2 -1
- package/dist/lib/utils/providerHealth.d.ts +48 -0
- package/dist/lib/utils/providerHealth.js +221 -158
- package/dist/lib/utils/providerUtils.js +2 -2
- package/dist/lib/utils/timeout.js +8 -3
- package/dist/mcp/externalServerManager.js +14 -6
- package/dist/mcp/factory.js +1 -1
- package/dist/mcp/flexibleToolValidator.d.ts +50 -0
- package/dist/mcp/flexibleToolValidator.js +161 -0
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/mcpCircuitBreaker.js +5 -1
- package/dist/mcp/mcpClientFactory.js +3 -0
- package/dist/mcp/registry.d.ts +3 -3
- package/dist/mcp/registry.js +3 -3
- package/dist/mcp/servers/aiProviders/aiAnalysisTools.js +5 -5
- package/dist/mcp/servers/aiProviders/aiWorkflowTools.js +6 -6
- package/dist/mcp/servers/utilities/utilityServer.js +1 -1
- package/dist/mcp/toolDiscoveryService.js +8 -2
- package/dist/mcp/toolRegistry.d.ts +2 -2
- package/dist/mcp/toolRegistry.js +29 -54
- package/dist/middleware/builtin/analytics.js +4 -4
- package/dist/middleware/builtin/guardrails.js +2 -2
- package/dist/middleware/registry.js +11 -2
- package/dist/models/modelRegistry.d.ts +1 -1
- package/dist/models/modelRegistry.js +3 -3
- package/dist/models/modelResolver.d.ts +1 -1
- package/dist/models/modelResolver.js +2 -2
- package/dist/neurolink.d.ts +118 -0
- package/dist/neurolink.js +814 -952
- package/dist/providers/amazonBedrock.d.ts +47 -6
- package/dist/providers/amazonBedrock.js +282 -23
- package/dist/providers/amazonSagemaker.d.ts +1 -1
- package/dist/providers/amazonSagemaker.js +12 -3
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.js +7 -6
- package/dist/providers/anthropicBaseProvider.d.ts +1 -1
- package/dist/providers/anthropicBaseProvider.js +4 -3
- package/dist/providers/aws/credentialProvider.d.ts +58 -0
- package/dist/providers/aws/credentialProvider.js +267 -0
- package/dist/providers/aws/credentialTester.d.ts +49 -0
- package/dist/providers/aws/credentialTester.js +394 -0
- package/dist/providers/azureOpenai.d.ts +1 -1
- package/dist/providers/azureOpenai.js +1 -1
- package/dist/providers/googleAiStudio.d.ts +1 -1
- package/dist/providers/googleAiStudio.js +2 -2
- package/dist/providers/googleVertex.d.ts +40 -0
- package/dist/providers/googleVertex.js +330 -274
- package/dist/providers/huggingFace.js +1 -1
- package/dist/providers/mistral.d.ts +1 -1
- package/dist/providers/mistral.js +2 -2
- package/dist/providers/ollama.d.ts +4 -0
- package/dist/providers/ollama.js +38 -18
- package/dist/providers/openAI.d.ts +1 -1
- package/dist/providers/openAI.js +2 -2
- package/dist/providers/sagemaker/adaptive-semaphore.js +7 -4
- package/dist/providers/sagemaker/client.js +13 -3
- package/dist/providers/sagemaker/config.js +5 -1
- package/dist/providers/sagemaker/detection.js +19 -9
- package/dist/providers/sagemaker/errors.d.ts +8 -1
- package/dist/providers/sagemaker/errors.js +103 -20
- package/dist/providers/sagemaker/language-model.d.ts +3 -3
- package/dist/providers/sagemaker/language-model.js +4 -4
- package/dist/providers/sagemaker/parsers.js +14 -6
- package/dist/providers/sagemaker/streaming.js +14 -3
- package/dist/providers/sagemaker/types.d.ts +1 -1
- package/dist/proxy/awsProxyIntegration.d.ts +23 -0
- package/dist/proxy/awsProxyIntegration.js +285 -0
- package/dist/proxy/proxyFetch.d.ts +9 -5
- package/dist/proxy/proxyFetch.js +232 -98
- package/dist/proxy/utils/noProxyUtils.d.ts +39 -0
- package/dist/proxy/utils/noProxyUtils.js +149 -0
- package/dist/sdk/toolRegistration.d.ts +1 -1
- package/dist/types/cli.d.ts +80 -8
- package/dist/types/contextTypes.js +2 -2
- package/dist/types/generateTypes.d.ts +4 -6
- package/dist/types/providers.d.ts +124 -19
- package/dist/types/providers.js +6 -6
- package/dist/types/streamTypes.d.ts +4 -6
- package/dist/types/typeAliases.d.ts +1 -1
- package/dist/utils/analyticsUtils.d.ts +33 -0
- package/dist/utils/analyticsUtils.js +76 -0
- package/dist/utils/errorHandling.js +4 -1
- package/dist/utils/evaluationUtils.d.ts +27 -0
- package/dist/utils/evaluationUtils.js +131 -0
- package/dist/utils/optionsUtils.js +10 -1
- package/dist/utils/performance.d.ts +1 -1
- package/dist/utils/performance.js +15 -3
- package/dist/utils/providerConfig.d.ts +1 -0
- package/dist/utils/providerConfig.js +2 -1
- package/dist/utils/providerHealth.d.ts +48 -0
- package/dist/utils/providerHealth.js +221 -158
- package/dist/utils/providerUtils.js +2 -2
- package/dist/utils/timeout.js +8 -3
- package/package.json +5 -1
package/dist/neurolink.js
CHANGED
|
@@ -10,7 +10,7 @@ import { config as dotenvConfig } from "dotenv";
|
|
|
10
10
|
try {
|
|
11
11
|
dotenvConfig(); // Load .env from current working directory
|
|
12
12
|
}
|
|
13
|
-
catch
|
|
13
|
+
catch {
|
|
14
14
|
// Environment variables should be set externally in production
|
|
15
15
|
}
|
|
16
16
|
import { AIProviderFactory } from "./core/factory.js";
|
|
@@ -24,6 +24,7 @@ import { ProviderRegistry } from "./factories/providerRegistry.js";
|
|
|
24
24
|
import { createCustomToolServerInfo, detectCategory, } from "./utils/mcpDefaults.js";
|
|
25
25
|
// Factory processing imports
|
|
26
26
|
import { processFactoryOptions, enhanceTextGenerationOptions, validateFactoryConfig, processStreamingFactoryOptions, createCleanStreamOptions, } from "./utils/factoryProcessing.js";
|
|
27
|
+
// Tool detection and execution imports
|
|
27
28
|
// Transformation utilities
|
|
28
29
|
import { transformToolExecutions, transformToolExecutionsForMCP, transformAvailableTools, transformToolsForMCP, transformToolsToExpectedFormat, transformToolsToDescriptions, extractToolNames, transformParamsForLogging, optimizeToolForCollection, } from "./utils/transformationUtils.js";
|
|
29
30
|
// Enhanced error handling imports
|
|
@@ -54,14 +55,21 @@ export class NeuroLink {
|
|
|
54
55
|
* @param toolName - Name of the tool
|
|
55
56
|
* @param startTime - Timestamp when tool execution started
|
|
56
57
|
* @param success - Whether the tool execution was successful
|
|
58
|
+
* @param result - The result of the tool execution (optional)
|
|
59
|
+
* @param error - The error if execution failed (optional)
|
|
57
60
|
*/
|
|
58
|
-
emitToolEndEvent(toolName, startTime, success) {
|
|
61
|
+
emitToolEndEvent(toolName, startTime, success, result, error) {
|
|
62
|
+
// Emit tool end event (NeuroLink format - enhanced with result/error)
|
|
59
63
|
this.emitter.emit("tool:end", {
|
|
60
64
|
toolName,
|
|
61
65
|
responseTime: Date.now() - startTime,
|
|
62
66
|
success,
|
|
63
67
|
timestamp: Date.now(),
|
|
68
|
+
result: result, // Enhanced: include actual result
|
|
69
|
+
error: error, // Enhanced: include error if present
|
|
64
70
|
});
|
|
71
|
+
// ADD: Bedrock-compatible tool:end event (positional parameters)
|
|
72
|
+
this.emitter.emit("tool:end", toolName, success ? result : error);
|
|
65
73
|
}
|
|
66
74
|
// Conversation memory support
|
|
67
75
|
conversationMemory;
|
|
@@ -94,42 +102,50 @@ export class NeuroLink {
|
|
|
94
102
|
* @throws {Error} When external server manager initialization fails
|
|
95
103
|
*/
|
|
96
104
|
constructor(config) {
|
|
97
|
-
// 🚀 EXHAUSTIVE LOGGING POINT C001: CONSTRUCTOR ENTRY
|
|
98
105
|
const constructorStartTime = Date.now();
|
|
99
106
|
const constructorHrTimeStart = process.hrtime.bigint();
|
|
100
107
|
const constructorId = `neurolink-constructor-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
108
|
+
this.logConstructorStart(constructorId, constructorStartTime, constructorHrTimeStart, config);
|
|
109
|
+
this.initializeProviderRegistry(constructorId, constructorStartTime, constructorHrTimeStart);
|
|
110
|
+
this.initializeConversationMemory(config, constructorId, constructorStartTime, constructorHrTimeStart);
|
|
111
|
+
this.initializeExternalServerManager(constructorId, constructorStartTime, constructorHrTimeStart);
|
|
112
|
+
this.logConstructorComplete(constructorId, constructorStartTime, constructorHrTimeStart);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Log constructor start with comprehensive environment analysis
|
|
116
|
+
*/
|
|
117
|
+
logConstructorStart(constructorId, constructorStartTime, constructorHrTimeStart, config) {
|
|
101
118
|
logger.debug(`[NeuroLink] 🏗️ LOG_POINT_C001_CONSTRUCTOR_START`, {
|
|
102
119
|
logPoint: "C001_CONSTRUCTOR_START",
|
|
103
120
|
constructorId,
|
|
104
121
|
timestamp: new Date().toISOString(),
|
|
105
122
|
constructorStartTime,
|
|
106
123
|
constructorHrTimeStart: constructorHrTimeStart.toString(),
|
|
107
|
-
// Configuration analysis
|
|
108
124
|
hasConfig: !!config,
|
|
109
125
|
configType: typeof config,
|
|
110
126
|
configKeys: config ? Object.keys(config) : [],
|
|
111
127
|
configSize: config ? JSON.stringify(config).length : 0,
|
|
112
|
-
// Conversation memory config analysis
|
|
113
128
|
hasConversationMemoryConfig: !!config?.conversationMemory,
|
|
114
129
|
conversationMemoryEnabled: config?.conversationMemory?.enabled || false,
|
|
115
130
|
conversationMemoryKeys: config?.conversationMemory
|
|
116
131
|
? Object.keys(config.conversationMemory)
|
|
117
132
|
: [],
|
|
118
|
-
// Environment context
|
|
119
133
|
nodeVersion: process.version,
|
|
120
134
|
platform: process.platform,
|
|
121
135
|
arch: process.arch,
|
|
122
136
|
nodeEnv: process.env.NODE_ENV || "UNKNOWN",
|
|
123
|
-
// Memory and performance baseline
|
|
124
137
|
memoryUsage: process.memoryUsage(),
|
|
125
138
|
cpuUsage: process.cpuUsage(),
|
|
126
139
|
uptime: process.uptime(),
|
|
127
|
-
// Process PID and parent info
|
|
128
140
|
pid: process.pid,
|
|
129
141
|
ppid: process.ppid,
|
|
130
142
|
message: "NeuroLink constructor initialization starting with comprehensive environment analysis",
|
|
131
143
|
});
|
|
132
|
-
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Initialize provider registry with security settings
|
|
147
|
+
*/
|
|
148
|
+
initializeProviderRegistry(constructorId, constructorStartTime, constructorHrTimeStart) {
|
|
133
149
|
const registrySetupStartTime = process.hrtime.bigint();
|
|
134
150
|
logger.debug(`[NeuroLink] 🏗️ LOG_POINT_C002_PROVIDER_REGISTRY_SETUP_START`, {
|
|
135
151
|
logPoint: "C002_PROVIDER_REGISTRY_SETUP_START",
|
|
@@ -140,11 +156,8 @@ export class NeuroLink {
|
|
|
140
156
|
registrySetupStartTimeNs: registrySetupStartTime.toString(),
|
|
141
157
|
message: "Starting ProviderRegistry configuration for security",
|
|
142
158
|
});
|
|
143
|
-
// SDK always disables manual MCP config for security
|
|
144
159
|
try {
|
|
145
|
-
ProviderRegistry.setOptions({
|
|
146
|
-
enableManualMCP: false,
|
|
147
|
-
});
|
|
160
|
+
ProviderRegistry.setOptions({ enableManualMCP: false });
|
|
148
161
|
const registrySetupEndTime = process.hrtime.bigint();
|
|
149
162
|
const registrySetupDurationNs = registrySetupEndTime - registrySetupStartTime;
|
|
150
163
|
logger.debug(`[NeuroLink] ✅ LOG_POINT_C003_PROVIDER_REGISTRY_SETUP_SUCCESS`, {
|
|
@@ -177,7 +190,11 @@ export class NeuroLink {
|
|
|
177
190
|
});
|
|
178
191
|
throw error;
|
|
179
192
|
}
|
|
180
|
-
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Initialize conversation memory if enabled
|
|
196
|
+
*/
|
|
197
|
+
initializeConversationMemory(config, constructorId, constructorStartTime, constructorHrTimeStart) {
|
|
181
198
|
if (config?.conversationMemory?.enabled) {
|
|
182
199
|
const memoryInitStartTime = process.hrtime.bigint();
|
|
183
200
|
logger.debug(`[NeuroLink] 🧠 LOG_POINT_C005_MEMORY_INIT_START`, {
|
|
@@ -187,7 +204,6 @@ export class NeuroLink {
|
|
|
187
204
|
elapsedMs: Date.now() - constructorStartTime,
|
|
188
205
|
elapsedNs: (process.hrtime.bigint() - constructorHrTimeStart).toString(),
|
|
189
206
|
memoryInitStartTimeNs: memoryInitStartTime.toString(),
|
|
190
|
-
// Detailed memory config analysis
|
|
191
207
|
memoryConfig: {
|
|
192
208
|
enabled: config.conversationMemory.enabled,
|
|
193
209
|
maxSessions: config.conversationMemory.maxSessions,
|
|
@@ -214,12 +230,10 @@ export class NeuroLink {
|
|
|
214
230
|
memoryInitDurationMs: Number(memoryInitDurationNs) / 1000000,
|
|
215
231
|
memoryManagerCreateDurationNs: memoryManagerCreateDurationNs.toString(),
|
|
216
232
|
memoryManagerCreateDurationMs: Number(memoryManagerCreateDurationNs) / 1000000,
|
|
217
|
-
// Final memory configuration
|
|
218
233
|
finalMemoryConfig: {
|
|
219
234
|
maxSessions: memoryConfig.maxSessions,
|
|
220
235
|
maxTurnsPerSession: memoryConfig.maxTurnsPerSession,
|
|
221
236
|
},
|
|
222
|
-
// Memory usage after initialization
|
|
223
237
|
memoryUsageAfterInit: process.memoryUsage(),
|
|
224
238
|
message: "NeuroLink initialized with conversation memory successfully",
|
|
225
239
|
});
|
|
@@ -264,7 +278,11 @@ export class NeuroLink {
|
|
|
264
278
|
message: "Conversation memory not enabled - skipping initialization",
|
|
265
279
|
});
|
|
266
280
|
}
|
|
267
|
-
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Initialize external server manager with event handlers
|
|
284
|
+
*/
|
|
285
|
+
initializeExternalServerManager(constructorId, constructorStartTime, constructorHrTimeStart) {
|
|
268
286
|
const externalServerInitStartTime = process.hrtime.bigint();
|
|
269
287
|
logger.debug(`[NeuroLink] 🌐 LOG_POINT_C009_EXTERNAL_SERVER_INIT_START`, {
|
|
270
288
|
logPoint: "C009_EXTERNAL_SERVER_INIT_START",
|
|
@@ -285,14 +303,13 @@ export class NeuroLink {
|
|
|
285
303
|
message: "Starting external server manager initialization",
|
|
286
304
|
});
|
|
287
305
|
try {
|
|
288
|
-
// Initialize external server manager with main registry integration
|
|
289
306
|
this.externalServerManager = new ExternalServerManager({
|
|
290
307
|
maxServers: 20,
|
|
291
308
|
defaultTimeout: 15000,
|
|
292
309
|
enableAutoRestart: true,
|
|
293
310
|
enablePerformanceMonitoring: true,
|
|
294
311
|
}, {
|
|
295
|
-
enableMainRegistryIntegration: true,
|
|
312
|
+
enableMainRegistryIntegration: true,
|
|
296
313
|
});
|
|
297
314
|
const externalServerInitEndTime = process.hrtime.bigint();
|
|
298
315
|
const externalServerInitDurationNs = externalServerInitEndTime - externalServerInitStartTime;
|
|
@@ -307,93 +324,7 @@ export class NeuroLink {
|
|
|
307
324
|
hasExternalServerManager: !!this.externalServerManager,
|
|
308
325
|
message: "External server manager initialized successfully",
|
|
309
326
|
});
|
|
310
|
-
|
|
311
|
-
const eventHandlerSetupStartTime = process.hrtime.bigint();
|
|
312
|
-
logger.debug(`[NeuroLink] 🔗 LOG_POINT_C011_EVENT_HANDLER_SETUP_START`, {
|
|
313
|
-
logPoint: "C011_EVENT_HANDLER_SETUP_START",
|
|
314
|
-
constructorId,
|
|
315
|
-
timestamp: new Date().toISOString(),
|
|
316
|
-
elapsedMs: Date.now() - constructorStartTime,
|
|
317
|
-
elapsedNs: (process.hrtime.bigint() - constructorHrTimeStart).toString(),
|
|
318
|
-
eventHandlerSetupStartTimeNs: eventHandlerSetupStartTime.toString(),
|
|
319
|
-
message: "Setting up external server event handlers",
|
|
320
|
-
});
|
|
321
|
-
// Forward external server events with detailed logging
|
|
322
|
-
this.externalServerManager.on("connected", (event) => {
|
|
323
|
-
logger.debug(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_CONNECTED`, {
|
|
324
|
-
constructorId,
|
|
325
|
-
eventType: "connected",
|
|
326
|
-
event,
|
|
327
|
-
timestamp: new Date().toISOString(),
|
|
328
|
-
message: "External MCP server connected event received",
|
|
329
|
-
});
|
|
330
|
-
this.emitter.emit("externalMCP:serverConnected", event);
|
|
331
|
-
});
|
|
332
|
-
this.externalServerManager.on("disconnected", (event) => {
|
|
333
|
-
logger.debug(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_DISCONNECTED`, {
|
|
334
|
-
constructorId,
|
|
335
|
-
eventType: "disconnected",
|
|
336
|
-
event,
|
|
337
|
-
timestamp: new Date().toISOString(),
|
|
338
|
-
message: "External MCP server disconnected event received",
|
|
339
|
-
});
|
|
340
|
-
this.emitter.emit("externalMCP:serverDisconnected", event);
|
|
341
|
-
});
|
|
342
|
-
this.externalServerManager.on("failed", (event) => {
|
|
343
|
-
logger.warn(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_FAILED`, {
|
|
344
|
-
constructorId,
|
|
345
|
-
eventType: "failed",
|
|
346
|
-
event,
|
|
347
|
-
timestamp: new Date().toISOString(),
|
|
348
|
-
message: "External MCP server failed event received",
|
|
349
|
-
});
|
|
350
|
-
this.emitter.emit("externalMCP:serverFailed", event);
|
|
351
|
-
});
|
|
352
|
-
this.externalServerManager.on("toolDiscovered", (event) => {
|
|
353
|
-
logger.debug(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_TOOL_DISCOVERED`, {
|
|
354
|
-
constructorId,
|
|
355
|
-
eventType: "toolDiscovered",
|
|
356
|
-
toolName: event.toolName,
|
|
357
|
-
serverId: event.serverId,
|
|
358
|
-
timestamp: new Date().toISOString(),
|
|
359
|
-
message: "External MCP tool discovered event received",
|
|
360
|
-
});
|
|
361
|
-
this.emitter.emit("externalMCP:toolDiscovered", event);
|
|
362
|
-
// Tools are already registered on server connection, no need to duplicate here
|
|
363
|
-
});
|
|
364
|
-
this.externalServerManager.on("toolRemoved", (event) => {
|
|
365
|
-
logger.debug(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_TOOL_REMOVED`, {
|
|
366
|
-
constructorId,
|
|
367
|
-
eventType: "toolRemoved",
|
|
368
|
-
toolName: event.toolName,
|
|
369
|
-
serverId: event.serverId,
|
|
370
|
-
timestamp: new Date().toISOString(),
|
|
371
|
-
message: "External MCP tool removed event received",
|
|
372
|
-
});
|
|
373
|
-
this.emitter.emit("externalMCP:toolRemoved", event);
|
|
374
|
-
// Unregister removed tools from main tool registry
|
|
375
|
-
this.unregisterExternalMCPToolFromRegistry(event.toolName);
|
|
376
|
-
});
|
|
377
|
-
const eventHandlerSetupEndTime = process.hrtime.bigint();
|
|
378
|
-
const eventHandlerSetupDurationNs = eventHandlerSetupEndTime - eventHandlerSetupStartTime;
|
|
379
|
-
logger.debug(`[NeuroLink] ✅ LOG_POINT_C012_EVENT_HANDLER_SETUP_SUCCESS`, {
|
|
380
|
-
logPoint: "C012_EVENT_HANDLER_SETUP_SUCCESS",
|
|
381
|
-
constructorId,
|
|
382
|
-
timestamp: new Date().toISOString(),
|
|
383
|
-
elapsedMs: Date.now() - constructorStartTime,
|
|
384
|
-
elapsedNs: (process.hrtime.bigint() - constructorHrTimeStart).toString(),
|
|
385
|
-
eventHandlerSetupDurationNs: eventHandlerSetupDurationNs.toString(),
|
|
386
|
-
eventHandlerSetupDurationMs: Number(eventHandlerSetupDurationNs) / 1000000,
|
|
387
|
-
eventHandlersCount: 5,
|
|
388
|
-
eventHandlerTypes: [
|
|
389
|
-
"connected",
|
|
390
|
-
"disconnected",
|
|
391
|
-
"failed",
|
|
392
|
-
"toolDiscovered",
|
|
393
|
-
"toolRemoved",
|
|
394
|
-
],
|
|
395
|
-
message: "Event handlers set up successfully",
|
|
396
|
-
});
|
|
327
|
+
this.setupExternalServerEventHandlers(constructorId, constructorStartTime, constructorHrTimeStart);
|
|
397
328
|
}
|
|
398
329
|
catch (error) {
|
|
399
330
|
const externalServerInitErrorTime = process.hrtime.bigint();
|
|
@@ -413,7 +344,99 @@ export class NeuroLink {
|
|
|
413
344
|
});
|
|
414
345
|
throw error;
|
|
415
346
|
}
|
|
416
|
-
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Setup event handlers for external server manager
|
|
350
|
+
*/
|
|
351
|
+
setupExternalServerEventHandlers(constructorId, constructorStartTime, constructorHrTimeStart) {
|
|
352
|
+
const eventHandlerSetupStartTime = process.hrtime.bigint();
|
|
353
|
+
logger.debug(`[NeuroLink] 🔗 LOG_POINT_C011_EVENT_HANDLER_SETUP_START`, {
|
|
354
|
+
logPoint: "C011_EVENT_HANDLER_SETUP_START",
|
|
355
|
+
constructorId,
|
|
356
|
+
timestamp: new Date().toISOString(),
|
|
357
|
+
elapsedMs: Date.now() - constructorStartTime,
|
|
358
|
+
elapsedNs: (process.hrtime.bigint() - constructorHrTimeStart).toString(),
|
|
359
|
+
eventHandlerSetupStartTimeNs: eventHandlerSetupStartTime.toString(),
|
|
360
|
+
message: "Setting up external server event handlers",
|
|
361
|
+
});
|
|
362
|
+
this.externalServerManager.on("connected", (event) => {
|
|
363
|
+
logger.debug(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_CONNECTED`, {
|
|
364
|
+
constructorId,
|
|
365
|
+
eventType: "connected",
|
|
366
|
+
event,
|
|
367
|
+
timestamp: new Date().toISOString(),
|
|
368
|
+
message: "External MCP server connected event received",
|
|
369
|
+
});
|
|
370
|
+
this.emitter.emit("externalMCP:serverConnected", event);
|
|
371
|
+
});
|
|
372
|
+
this.externalServerManager.on("disconnected", (event) => {
|
|
373
|
+
logger.debug(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_DISCONNECTED`, {
|
|
374
|
+
constructorId,
|
|
375
|
+
eventType: "disconnected",
|
|
376
|
+
event,
|
|
377
|
+
timestamp: new Date().toISOString(),
|
|
378
|
+
message: "External MCP server disconnected event received",
|
|
379
|
+
});
|
|
380
|
+
this.emitter.emit("externalMCP:serverDisconnected", event);
|
|
381
|
+
});
|
|
382
|
+
this.externalServerManager.on("failed", (event) => {
|
|
383
|
+
logger.warn(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_FAILED`, {
|
|
384
|
+
constructorId,
|
|
385
|
+
eventType: "failed",
|
|
386
|
+
event,
|
|
387
|
+
timestamp: new Date().toISOString(),
|
|
388
|
+
message: "External MCP server failed event received",
|
|
389
|
+
});
|
|
390
|
+
this.emitter.emit("externalMCP:serverFailed", event);
|
|
391
|
+
});
|
|
392
|
+
this.externalServerManager.on("toolDiscovered", (event) => {
|
|
393
|
+
logger.debug(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_TOOL_DISCOVERED`, {
|
|
394
|
+
constructorId,
|
|
395
|
+
eventType: "toolDiscovered",
|
|
396
|
+
toolName: event.toolName,
|
|
397
|
+
serverId: event.serverId,
|
|
398
|
+
timestamp: new Date().toISOString(),
|
|
399
|
+
message: "External MCP tool discovered event received",
|
|
400
|
+
});
|
|
401
|
+
this.emitter.emit("externalMCP:toolDiscovered", event);
|
|
402
|
+
});
|
|
403
|
+
this.externalServerManager.on("toolRemoved", (event) => {
|
|
404
|
+
logger.debug(`[NeuroLink] 🔗 EXTERNAL_SERVER_EVENT_TOOL_REMOVED`, {
|
|
405
|
+
constructorId,
|
|
406
|
+
eventType: "toolRemoved",
|
|
407
|
+
toolName: event.toolName,
|
|
408
|
+
serverId: event.serverId,
|
|
409
|
+
timestamp: new Date().toISOString(),
|
|
410
|
+
message: "External MCP tool removed event received",
|
|
411
|
+
});
|
|
412
|
+
this.emitter.emit("externalMCP:toolRemoved", event);
|
|
413
|
+
this.unregisterExternalMCPToolFromRegistry(event.toolName);
|
|
414
|
+
});
|
|
415
|
+
const eventHandlerSetupEndTime = process.hrtime.bigint();
|
|
416
|
+
const eventHandlerSetupDurationNs = eventHandlerSetupEndTime - eventHandlerSetupStartTime;
|
|
417
|
+
logger.debug(`[NeuroLink] ✅ LOG_POINT_C012_EVENT_HANDLER_SETUP_SUCCESS`, {
|
|
418
|
+
logPoint: "C012_EVENT_HANDLER_SETUP_SUCCESS",
|
|
419
|
+
constructorId,
|
|
420
|
+
timestamp: new Date().toISOString(),
|
|
421
|
+
elapsedMs: Date.now() - constructorStartTime,
|
|
422
|
+
elapsedNs: (process.hrtime.bigint() - constructorHrTimeStart).toString(),
|
|
423
|
+
eventHandlerSetupDurationNs: eventHandlerSetupDurationNs.toString(),
|
|
424
|
+
eventHandlerSetupDurationMs: Number(eventHandlerSetupDurationNs) / 1000000,
|
|
425
|
+
eventHandlersCount: 5,
|
|
426
|
+
eventHandlerTypes: [
|
|
427
|
+
"connected",
|
|
428
|
+
"disconnected",
|
|
429
|
+
"failed",
|
|
430
|
+
"toolDiscovered",
|
|
431
|
+
"toolRemoved",
|
|
432
|
+
],
|
|
433
|
+
message: "Event handlers set up successfully",
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Log constructor completion with final state summary
|
|
438
|
+
*/
|
|
439
|
+
logConstructorComplete(constructorId, constructorStartTime, constructorHrTimeStart) {
|
|
417
440
|
const constructorEndTime = process.hrtime.bigint();
|
|
418
441
|
const constructorDurationNs = constructorEndTime - constructorHrTimeStart;
|
|
419
442
|
logger.info(`[NeuroLink] 🏁 LOG_POINT_C014_CONSTRUCTOR_COMPLETE`, {
|
|
@@ -423,7 +446,6 @@ export class NeuroLink {
|
|
|
423
446
|
constructorDurationNs: constructorDurationNs.toString(),
|
|
424
447
|
constructorDurationMs: Number(constructorDurationNs) / 1000000,
|
|
425
448
|
totalElapsedMs: Date.now() - constructorStartTime,
|
|
426
|
-
// Final state summary
|
|
427
449
|
finalState: {
|
|
428
450
|
hasConversationMemory: !!this.conversationMemory,
|
|
429
451
|
hasExternalServerManager: !!this.externalServerManager,
|
|
@@ -432,7 +454,6 @@ export class NeuroLink {
|
|
|
432
454
|
toolCircuitBreakersCount: this.toolCircuitBreakers.size,
|
|
433
455
|
toolExecutionMetricsCount: this.toolExecutionMetrics.size,
|
|
434
456
|
},
|
|
435
|
-
// Final memory usage
|
|
436
457
|
finalMemoryUsage: process.memoryUsage(),
|
|
437
458
|
finalCpuUsage: process.cpuUsage(),
|
|
438
459
|
message: "NeuroLink constructor completed successfully with all components initialized",
|
|
@@ -443,10 +464,34 @@ export class NeuroLink {
|
|
|
443
464
|
* Uses isolated async context to prevent hanging
|
|
444
465
|
*/
|
|
445
466
|
async initializeMCP() {
|
|
446
|
-
// 🚀 EXHAUSTIVE LOGGING POINT M001: MCP INITIALIZATION ENTRY CHECK
|
|
447
467
|
const mcpInitId = `mcp-init-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
448
468
|
const mcpInitStartTime = Date.now();
|
|
449
469
|
const mcpInitHrTimeStart = process.hrtime.bigint();
|
|
470
|
+
this.logMCPInitStart(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart);
|
|
471
|
+
if (this.mcpInitialized) {
|
|
472
|
+
this.logMCPAlreadyInitialized(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const MemoryManager = await this.importPerformanceManager(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart);
|
|
476
|
+
const startMemory = MemoryManager
|
|
477
|
+
? MemoryManager.getMemoryUsageMB()
|
|
478
|
+
: { heapUsed: 0, heapTotal: 0, rss: 0, external: 0 };
|
|
479
|
+
try {
|
|
480
|
+
await this.performMCPInitialization(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart, startMemory);
|
|
481
|
+
this.mcpInitialized = true;
|
|
482
|
+
this.logMCPInitComplete(startMemory, MemoryManager, mcpInitStartTime);
|
|
483
|
+
}
|
|
484
|
+
catch (error) {
|
|
485
|
+
mcpLogger.warn("[NeuroLink] MCP initialization failed", {
|
|
486
|
+
error: error instanceof Error ? error.message : String(error),
|
|
487
|
+
});
|
|
488
|
+
// Continue without MCP - graceful degradation
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Log MCP initialization start
|
|
493
|
+
*/
|
|
494
|
+
logMCPInitStart(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
|
|
450
495
|
logger.debug(`[NeuroLink] 🔧 LOG_POINT_M001_MCP_INIT_ENTRY`, {
|
|
451
496
|
logPoint: "M001_MCP_INIT_ENTRY",
|
|
452
497
|
mcpInitId,
|
|
@@ -459,19 +504,25 @@ export class NeuroLink {
|
|
|
459
504
|
cpuUsage: process.cpuUsage(),
|
|
460
505
|
message: "MCP initialization entry point - checking if already initialized",
|
|
461
506
|
});
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Log MCP already initialized
|
|
510
|
+
*/
|
|
511
|
+
logMCPAlreadyInitialized(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
|
|
512
|
+
logger.debug(`[NeuroLink] ✅ LOG_POINT_M002_MCP_ALREADY_INITIALIZED`, {
|
|
513
|
+
logPoint: "M002_MCP_ALREADY_INITIALIZED",
|
|
514
|
+
mcpInitId,
|
|
515
|
+
timestamp: new Date().toISOString(),
|
|
516
|
+
elapsedMs: Date.now() - mcpInitStartTime,
|
|
517
|
+
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
518
|
+
mcpInitialized: this.mcpInitialized,
|
|
519
|
+
message: "MCP already initialized - skipping initialization",
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Import performance manager with error handling
|
|
524
|
+
*/
|
|
525
|
+
async importPerformanceManager(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
|
|
475
526
|
const performanceImportStartTime = process.hrtime.bigint();
|
|
476
527
|
logger.debug(`[NeuroLink] 📊 LOG_POINT_M003_PERFORMANCE_IMPORT_START`, {
|
|
477
528
|
logPoint: "M003_PERFORMANCE_IMPORT_START",
|
|
@@ -482,13 +533,9 @@ export class NeuroLink {
|
|
|
482
533
|
performanceImportStartTimeNs: performanceImportStartTime.toString(),
|
|
483
534
|
message: "Starting MemoryManager import for performance tracking",
|
|
484
535
|
});
|
|
485
|
-
let MemoryManager;
|
|
486
|
-
let startMemory;
|
|
487
536
|
try {
|
|
488
|
-
// Track memory usage during MCP initialization
|
|
489
537
|
const moduleImport = await import("./utils/performance.js");
|
|
490
|
-
MemoryManager = moduleImport.MemoryManager;
|
|
491
|
-
startMemory = MemoryManager.getMemoryUsageMB();
|
|
538
|
+
const MemoryManager = moduleImport.MemoryManager;
|
|
492
539
|
const performanceImportEndTime = process.hrtime.bigint();
|
|
493
540
|
const performanceImportDurationNs = performanceImportEndTime - performanceImportStartTime;
|
|
494
541
|
logger.debug(`[NeuroLink] ✅ LOG_POINT_M004_PERFORMANCE_IMPORT_SUCCESS`, {
|
|
@@ -500,9 +547,9 @@ export class NeuroLink {
|
|
|
500
547
|
performanceImportDurationNs: performanceImportDurationNs.toString(),
|
|
501
548
|
performanceImportDurationMs: Number(performanceImportDurationNs) / 1000000,
|
|
502
549
|
hasMemoryManager: !!MemoryManager,
|
|
503
|
-
startMemory,
|
|
504
550
|
message: "MemoryManager imported successfully",
|
|
505
551
|
});
|
|
552
|
+
return MemoryManager;
|
|
506
553
|
}
|
|
507
554
|
catch (error) {
|
|
508
555
|
const performanceImportErrorTime = process.hrtime.bigint();
|
|
@@ -519,206 +566,218 @@ export class NeuroLink {
|
|
|
519
566
|
errorName: error instanceof Error ? error.name : "UnknownError",
|
|
520
567
|
message: "MemoryManager import failed - continuing without performance tracking",
|
|
521
568
|
});
|
|
522
|
-
|
|
523
|
-
startMemory = { heapUsed: 0, heapTotal: 0, rss: 0, external: 0 };
|
|
569
|
+
return undefined;
|
|
524
570
|
}
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Perform main MCP initialization logic
|
|
574
|
+
*/
|
|
575
|
+
async performMCPInitialization(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart, startMemory) {
|
|
576
|
+
logger.info(`[NeuroLink] 🚀 LOG_POINT_M006_MCP_MAIN_INIT_START`, {
|
|
577
|
+
logPoint: "M006_MCP_MAIN_INIT_START",
|
|
578
|
+
mcpInitId,
|
|
579
|
+
timestamp: new Date().toISOString(),
|
|
580
|
+
elapsedMs: Date.now() - mcpInitStartTime,
|
|
581
|
+
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
582
|
+
startMemory,
|
|
583
|
+
message: "Starting isolated MCP initialization process",
|
|
584
|
+
});
|
|
585
|
+
mcpLogger.debug("[NeuroLink] Starting isolated MCP initialization...");
|
|
586
|
+
await this.initializeToolRegistryInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart);
|
|
587
|
+
await this.initializeProviderRegistryInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart);
|
|
588
|
+
await this.registerDirectToolsServerInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart);
|
|
589
|
+
await this.loadMCPConfigurationInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart);
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Initialize tool registry with timeout protection
|
|
593
|
+
*/
|
|
594
|
+
async initializeToolRegistryInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
|
|
595
|
+
const toolRegistryStartTime = process.hrtime.bigint();
|
|
596
|
+
const initTimeout = 3000;
|
|
597
|
+
logger.debug(`[NeuroLink] ⏱️ LOG_POINT_M007_TOOL_REGISTRY_TIMEOUT_SETUP`, {
|
|
598
|
+
logPoint: "M007_TOOL_REGISTRY_TIMEOUT_SETUP",
|
|
599
|
+
mcpInitId,
|
|
600
|
+
timestamp: new Date().toISOString(),
|
|
601
|
+
elapsedMs: Date.now() - mcpInitStartTime,
|
|
602
|
+
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
603
|
+
toolRegistryStartTimeNs: toolRegistryStartTime.toString(),
|
|
604
|
+
initTimeoutMs: initTimeout,
|
|
605
|
+
message: "Setting up tool registry initialization with timeout protection",
|
|
606
|
+
});
|
|
607
|
+
await Promise.race([
|
|
608
|
+
Promise.resolve(),
|
|
609
|
+
new Promise((_, reject) => {
|
|
610
|
+
setTimeout(() => reject(new Error("MCP initialization timeout")), initTimeout);
|
|
611
|
+
}),
|
|
612
|
+
]);
|
|
613
|
+
const toolRegistryEndTime = process.hrtime.bigint();
|
|
614
|
+
const toolRegistryDurationNs = toolRegistryEndTime - toolRegistryStartTime;
|
|
615
|
+
logger.debug(`[NeuroLink] ✅ LOG_POINT_M008_TOOL_REGISTRY_SUCCESS`, {
|
|
616
|
+
logPoint: "M008_TOOL_REGISTRY_SUCCESS",
|
|
617
|
+
mcpInitId,
|
|
618
|
+
timestamp: new Date().toISOString(),
|
|
619
|
+
elapsedMs: Date.now() - mcpInitStartTime,
|
|
620
|
+
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
621
|
+
toolRegistryDurationNs: toolRegistryDurationNs.toString(),
|
|
622
|
+
toolRegistryDurationMs: Number(toolRegistryDurationNs) / 1000000,
|
|
623
|
+
message: "Tool registry initialization completed within timeout",
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Initialize provider registry
|
|
628
|
+
*/
|
|
629
|
+
async initializeProviderRegistryInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
|
|
630
|
+
const providerRegistryStartTime = process.hrtime.bigint();
|
|
631
|
+
logger.debug(`[NeuroLink] 🏭 LOG_POINT_M009_PROVIDER_REGISTRY_START`, {
|
|
632
|
+
logPoint: "M009_PROVIDER_REGISTRY_START",
|
|
633
|
+
mcpInitId,
|
|
634
|
+
timestamp: new Date().toISOString(),
|
|
635
|
+
elapsedMs: Date.now() - mcpInitStartTime,
|
|
636
|
+
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
637
|
+
providerRegistryStartTimeNs: providerRegistryStartTime.toString(),
|
|
638
|
+
message: "Starting provider registry registration with lazy loading",
|
|
639
|
+
});
|
|
640
|
+
await ProviderRegistry.registerAllProviders();
|
|
641
|
+
const providerRegistryEndTime = process.hrtime.bigint();
|
|
642
|
+
const providerRegistryDurationNs = providerRegistryEndTime - providerRegistryStartTime;
|
|
643
|
+
logger.debug(`[NeuroLink] ✅ LOG_POINT_M010_PROVIDER_REGISTRY_SUCCESS`, {
|
|
644
|
+
logPoint: "M010_PROVIDER_REGISTRY_SUCCESS",
|
|
645
|
+
mcpInitId,
|
|
646
|
+
timestamp: new Date().toISOString(),
|
|
647
|
+
elapsedMs: Date.now() - mcpInitStartTime,
|
|
648
|
+
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
649
|
+
providerRegistryDurationNs: providerRegistryDurationNs.toString(),
|
|
650
|
+
providerRegistryDurationMs: Number(providerRegistryDurationNs) / 1000000,
|
|
651
|
+
message: "Provider registry registration completed successfully",
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Register direct tools server
|
|
656
|
+
*/
|
|
657
|
+
async registerDirectToolsServerInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
|
|
658
|
+
const directToolsStartTime = process.hrtime.bigint();
|
|
659
|
+
logger.debug(`[NeuroLink] 🛠️ LOG_POINT_M011_DIRECT_TOOLS_START`, {
|
|
660
|
+
logPoint: "M011_DIRECT_TOOLS_START",
|
|
661
|
+
mcpInitId,
|
|
662
|
+
timestamp: new Date().toISOString(),
|
|
663
|
+
elapsedMs: Date.now() - mcpInitStartTime,
|
|
664
|
+
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
665
|
+
directToolsStartTimeNs: directToolsStartTime.toString(),
|
|
666
|
+
serverId: "neurolink-direct",
|
|
667
|
+
message: "Starting direct tools server registration",
|
|
668
|
+
});
|
|
525
669
|
try {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
670
|
+
await toolRegistry.registerServer("neurolink-direct", directToolsServer);
|
|
671
|
+
const directToolsSuccessTime = process.hrtime.bigint();
|
|
672
|
+
const directToolsDurationNs = directToolsSuccessTime - directToolsStartTime;
|
|
673
|
+
logger.debug(`[NeuroLink] ✅ LOG_POINT_M012_DIRECT_TOOLS_SUCCESS`, {
|
|
674
|
+
logPoint: "M012_DIRECT_TOOLS_SUCCESS",
|
|
529
675
|
mcpInitId,
|
|
530
676
|
timestamp: new Date().toISOString(),
|
|
531
677
|
elapsedMs: Date.now() - mcpInitStartTime,
|
|
532
678
|
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
533
|
-
|
|
534
|
-
|
|
679
|
+
directToolsDurationNs: directToolsDurationNs.toString(),
|
|
680
|
+
directToolsDurationMs: Number(directToolsDurationNs) / 1000000,
|
|
681
|
+
serverId: "neurolink-direct",
|
|
682
|
+
message: "Direct tools server registered successfully",
|
|
535
683
|
});
|
|
536
|
-
mcpLogger.debug("[NeuroLink]
|
|
537
|
-
|
|
538
|
-
const toolRegistryStartTime = process.hrtime.bigint();
|
|
539
|
-
const initTimeout = 3000; // 3 second timeout
|
|
540
|
-
logger.debug(`[NeuroLink] ⏱️ LOG_POINT_M007_TOOL_REGISTRY_TIMEOUT_SETUP`, {
|
|
541
|
-
logPoint: "M007_TOOL_REGISTRY_TIMEOUT_SETUP",
|
|
542
|
-
mcpInitId,
|
|
543
|
-
timestamp: new Date().toISOString(),
|
|
544
|
-
elapsedMs: Date.now() - mcpInitStartTime,
|
|
545
|
-
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
546
|
-
toolRegistryStartTimeNs: toolRegistryStartTime.toString(),
|
|
547
|
-
initTimeoutMs: initTimeout,
|
|
548
|
-
message: "Setting up tool registry initialization with timeout protection",
|
|
684
|
+
mcpLogger.debug("[NeuroLink] Direct tools server registered successfully", {
|
|
685
|
+
serverId: "neurolink-direct",
|
|
549
686
|
});
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
]);
|
|
557
|
-
const toolRegistryEndTime = process.hrtime.bigint();
|
|
558
|
-
const toolRegistryDurationNs = toolRegistryEndTime - toolRegistryStartTime;
|
|
559
|
-
logger.debug(`[NeuroLink] ✅ LOG_POINT_M008_TOOL_REGISTRY_SUCCESS`, {
|
|
560
|
-
logPoint: "M008_TOOL_REGISTRY_SUCCESS",
|
|
687
|
+
}
|
|
688
|
+
catch (error) {
|
|
689
|
+
const directToolsErrorTime = process.hrtime.bigint();
|
|
690
|
+
const directToolsDurationNs = directToolsErrorTime - directToolsStartTime;
|
|
691
|
+
logger.warn(`[NeuroLink] ⚠️ LOG_POINT_M013_DIRECT_TOOLS_ERROR`, {
|
|
692
|
+
logPoint: "M013_DIRECT_TOOLS_ERROR",
|
|
561
693
|
mcpInitId,
|
|
562
694
|
timestamp: new Date().toISOString(),
|
|
563
695
|
elapsedMs: Date.now() - mcpInitStartTime,
|
|
564
696
|
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
697
|
+
directToolsDurationNs: directToolsDurationNs.toString(),
|
|
698
|
+
directToolsDurationMs: Number(directToolsDurationNs) / 1000000,
|
|
699
|
+
error: error instanceof Error ? error.message : String(error),
|
|
700
|
+
errorName: error instanceof Error ? error.name : "UnknownError",
|
|
701
|
+
errorStack: error instanceof Error ? error.stack : undefined,
|
|
702
|
+
serverId: "neurolink-direct",
|
|
703
|
+
message: "Direct tools server registration failed but continuing",
|
|
568
704
|
});
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
logger.debug(`[NeuroLink] 🏭 LOG_POINT_M009_PROVIDER_REGISTRY_START`, {
|
|
572
|
-
logPoint: "M009_PROVIDER_REGISTRY_START",
|
|
573
|
-
mcpInitId,
|
|
574
|
-
timestamp: new Date().toISOString(),
|
|
575
|
-
elapsedMs: Date.now() - mcpInitStartTime,
|
|
576
|
-
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
577
|
-
providerRegistryStartTimeNs: providerRegistryStartTime.toString(),
|
|
578
|
-
message: "Starting provider registry registration with lazy loading",
|
|
705
|
+
mcpLogger.warn("[NeuroLink] Failed to register direct tools server", {
|
|
706
|
+
error: error instanceof Error ? error.message : String(error),
|
|
579
707
|
});
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Load MCP configuration from .mcp-config.json
|
|
712
|
+
*/
|
|
713
|
+
async loadMCPConfigurationInternal(mcpInitId, mcpInitStartTime, mcpInitHrTimeStart) {
|
|
714
|
+
const mcpConfigStartTime = process.hrtime.bigint();
|
|
715
|
+
logger.debug(`[NeuroLink] 📄 LOG_POINT_M014_MCP_CONFIG_START`, {
|
|
716
|
+
logPoint: "M014_MCP_CONFIG_START",
|
|
717
|
+
mcpInitId,
|
|
718
|
+
timestamp: new Date().toISOString(),
|
|
719
|
+
elapsedMs: Date.now() - mcpInitStartTime,
|
|
720
|
+
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
721
|
+
mcpConfigStartTimeNs: mcpConfigStartTime.toString(),
|
|
722
|
+
hasExternalServerManager: !!this.externalServerManager,
|
|
723
|
+
message: "Starting MCP configuration loading from .mcp-config.json",
|
|
724
|
+
});
|
|
725
|
+
try {
|
|
726
|
+
const configResult = await this.externalServerManager.loadMCPConfiguration();
|
|
727
|
+
const mcpConfigSuccessTime = process.hrtime.bigint();
|
|
728
|
+
const mcpConfigDurationNs = mcpConfigSuccessTime - mcpConfigStartTime;
|
|
729
|
+
logger.debug(`[NeuroLink] ✅ LOG_POINT_M015_MCP_CONFIG_SUCCESS`, {
|
|
730
|
+
logPoint: "M015_MCP_CONFIG_SUCCESS",
|
|
586
731
|
mcpInitId,
|
|
587
732
|
timestamp: new Date().toISOString(),
|
|
588
733
|
elapsedMs: Date.now() - mcpInitStartTime,
|
|
589
734
|
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
735
|
+
mcpConfigDurationNs: mcpConfigDurationNs.toString(),
|
|
736
|
+
mcpConfigDurationMs: Number(mcpConfigDurationNs) / 1000000,
|
|
737
|
+
serversLoaded: configResult.serversLoaded,
|
|
738
|
+
errorsCount: configResult.errors.length,
|
|
739
|
+
configResult: {
|
|
740
|
+
serversLoaded: configResult.serversLoaded,
|
|
741
|
+
errors: configResult.errors.map((err) => ({
|
|
742
|
+
message: err instanceof Error ? err.message : String(err),
|
|
743
|
+
name: err instanceof Error ? err.name : "UnknownError",
|
|
744
|
+
})),
|
|
745
|
+
},
|
|
746
|
+
message: "MCP configuration loaded successfully",
|
|
593
747
|
});
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
logPoint: "M011_DIRECT_TOOLS_START",
|
|
598
|
-
mcpInitId,
|
|
599
|
-
timestamp: new Date().toISOString(),
|
|
600
|
-
elapsedMs: Date.now() - mcpInitStartTime,
|
|
601
|
-
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
602
|
-
directToolsStartTimeNs: directToolsStartTime.toString(),
|
|
603
|
-
serverId: "neurolink-direct",
|
|
604
|
-
message: "Starting direct tools server registration",
|
|
748
|
+
mcpLogger.debug("[NeuroLink] MCP configuration loaded successfully", {
|
|
749
|
+
serversLoaded: configResult.serversLoaded,
|
|
750
|
+
errors: configResult.errors.length,
|
|
605
751
|
});
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
await toolRegistry.registerServer("neurolink-direct", directToolsServer);
|
|
610
|
-
const directToolsSuccessTime = process.hrtime.bigint();
|
|
611
|
-
const directToolsDurationNs = directToolsSuccessTime - directToolsStartTime;
|
|
612
|
-
logger.debug(`[NeuroLink] ✅ LOG_POINT_M012_DIRECT_TOOLS_SUCCESS`, {
|
|
613
|
-
logPoint: "M012_DIRECT_TOOLS_SUCCESS",
|
|
614
|
-
mcpInitId,
|
|
615
|
-
timestamp: new Date().toISOString(),
|
|
616
|
-
elapsedMs: Date.now() - mcpInitStartTime,
|
|
617
|
-
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
618
|
-
directToolsDurationNs: directToolsDurationNs.toString(),
|
|
619
|
-
directToolsDurationMs: Number(directToolsDurationNs) / 1000000,
|
|
620
|
-
serverId: "neurolink-direct",
|
|
621
|
-
message: "Direct tools server registered successfully",
|
|
622
|
-
});
|
|
623
|
-
mcpLogger.debug("[NeuroLink] Direct tools server registered successfully", {
|
|
624
|
-
serverId: "neurolink-direct",
|
|
625
|
-
});
|
|
626
|
-
}
|
|
627
|
-
catch (error) {
|
|
628
|
-
const directToolsErrorTime = process.hrtime.bigint();
|
|
629
|
-
const directToolsDurationNs = directToolsErrorTime - directToolsStartTime;
|
|
630
|
-
logger.warn(`[NeuroLink] ⚠️ LOG_POINT_M013_DIRECT_TOOLS_ERROR`, {
|
|
631
|
-
logPoint: "M013_DIRECT_TOOLS_ERROR",
|
|
632
|
-
mcpInitId,
|
|
633
|
-
timestamp: new Date().toISOString(),
|
|
634
|
-
elapsedMs: Date.now() - mcpInitStartTime,
|
|
635
|
-
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
636
|
-
directToolsDurationNs: directToolsDurationNs.toString(),
|
|
637
|
-
directToolsDurationMs: Number(directToolsDurationNs) / 1000000,
|
|
638
|
-
error: error instanceof Error ? error.message : String(error),
|
|
639
|
-
errorName: error instanceof Error ? error.name : "UnknownError",
|
|
640
|
-
errorStack: error instanceof Error ? error.stack : undefined,
|
|
641
|
-
serverId: "neurolink-direct",
|
|
642
|
-
message: "Direct tools server registration failed but continuing",
|
|
643
|
-
});
|
|
644
|
-
mcpLogger.warn("[NeuroLink] Failed to register direct tools server", {
|
|
645
|
-
error: error instanceof Error ? error.message : String(error),
|
|
646
|
-
});
|
|
647
|
-
}
|
|
648
|
-
// 🚀 EXHAUSTIVE LOGGING POINT M014: MCP CONFIG LOADING START
|
|
649
|
-
const mcpConfigStartTime = process.hrtime.bigint();
|
|
650
|
-
logger.debug(`[NeuroLink] 📄 LOG_POINT_M014_MCP_CONFIG_START`, {
|
|
651
|
-
logPoint: "M014_MCP_CONFIG_START",
|
|
652
|
-
mcpInitId,
|
|
653
|
-
timestamp: new Date().toISOString(),
|
|
654
|
-
elapsedMs: Date.now() - mcpInitStartTime,
|
|
655
|
-
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
656
|
-
mcpConfigStartTimeNs: mcpConfigStartTime.toString(),
|
|
657
|
-
hasExternalServerManager: !!this.externalServerManager,
|
|
658
|
-
message: "Starting MCP configuration loading from .mcp-config.json",
|
|
659
|
-
});
|
|
660
|
-
// Load MCP configuration from .mcp-config.json using ExternalServerManager
|
|
661
|
-
try {
|
|
662
|
-
const configResult = await this.externalServerManager.loadMCPConfiguration();
|
|
663
|
-
const mcpConfigSuccessTime = process.hrtime.bigint();
|
|
664
|
-
const mcpConfigDurationNs = mcpConfigSuccessTime - mcpConfigStartTime;
|
|
665
|
-
logger.debug(`[NeuroLink] ✅ LOG_POINT_M015_MCP_CONFIG_SUCCESS`, {
|
|
666
|
-
logPoint: "M015_MCP_CONFIG_SUCCESS",
|
|
667
|
-
mcpInitId,
|
|
668
|
-
timestamp: new Date().toISOString(),
|
|
669
|
-
elapsedMs: Date.now() - mcpInitStartTime,
|
|
670
|
-
elapsedNs: (process.hrtime.bigint() - mcpInitHrTimeStart).toString(),
|
|
671
|
-
mcpConfigDurationNs: mcpConfigDurationNs.toString(),
|
|
672
|
-
mcpConfigDurationMs: Number(mcpConfigDurationNs) / 1000000,
|
|
673
|
-
serversLoaded: configResult.serversLoaded,
|
|
674
|
-
errorsCount: configResult.errors.length,
|
|
675
|
-
configResult: {
|
|
676
|
-
serversLoaded: configResult.serversLoaded,
|
|
677
|
-
errors: configResult.errors.map((err) => ({
|
|
678
|
-
message: err instanceof Error ? err.message : String(err),
|
|
679
|
-
name: err instanceof Error ? err.name : "UnknownError",
|
|
680
|
-
})),
|
|
681
|
-
},
|
|
682
|
-
message: "MCP configuration loaded successfully",
|
|
683
|
-
});
|
|
684
|
-
mcpLogger.debug("[NeuroLink] MCP configuration loaded successfully", {
|
|
685
|
-
serversLoaded: configResult.serversLoaded,
|
|
686
|
-
errors: configResult.errors.length,
|
|
687
|
-
});
|
|
688
|
-
if (configResult.errors.length > 0) {
|
|
689
|
-
mcpLogger.warn("[NeuroLink] Some MCP servers failed to load", {
|
|
690
|
-
errors: configResult.errors,
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
catch (configError) {
|
|
695
|
-
mcpLogger.warn("[NeuroLink] MCP configuration loading failed", {
|
|
696
|
-
error: configError instanceof Error
|
|
697
|
-
? configError.message
|
|
698
|
-
: String(configError),
|
|
752
|
+
if (configResult.errors.length > 0) {
|
|
753
|
+
mcpLogger.warn("[NeuroLink] Some MCP servers failed to load", {
|
|
754
|
+
errors: configResult.errors,
|
|
699
755
|
});
|
|
700
756
|
}
|
|
701
|
-
this.mcpInitialized = true;
|
|
702
|
-
// Monitor memory usage and provide cleanup suggestions
|
|
703
|
-
const endMemory = MemoryManager
|
|
704
|
-
? MemoryManager.getMemoryUsageMB()
|
|
705
|
-
: { heapUsed: 0, heapTotal: 0, rss: 0, external: 0 };
|
|
706
|
-
const memoryDelta = endMemory.heapUsed - startMemory.heapUsed;
|
|
707
|
-
const initTime = Date.now() - mcpInitStartTime;
|
|
708
|
-
mcpLogger.debug("[NeuroLink] MCP initialization completed successfully", {
|
|
709
|
-
initTime: `${initTime}ms`,
|
|
710
|
-
memoryUsed: `${memoryDelta}MB`,
|
|
711
|
-
});
|
|
712
|
-
// Suggest cleanup if initialization used significant memory
|
|
713
|
-
if (memoryDelta > 30) {
|
|
714
|
-
mcpLogger.debug("💡 Memory cleanup suggestion: MCP initialization used significant memory. Consider calling MemoryManager.forceGC() after heavy operations.");
|
|
715
|
-
}
|
|
716
757
|
}
|
|
717
|
-
catch (
|
|
718
|
-
mcpLogger.warn("[NeuroLink] MCP
|
|
719
|
-
error:
|
|
758
|
+
catch (configError) {
|
|
759
|
+
mcpLogger.warn("[NeuroLink] MCP configuration loading failed", {
|
|
760
|
+
error: configError instanceof Error
|
|
761
|
+
? configError.message
|
|
762
|
+
: String(configError),
|
|
720
763
|
});
|
|
721
|
-
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Log MCP initialization completion
|
|
768
|
+
*/
|
|
769
|
+
logMCPInitComplete(startMemory, MemoryManager, mcpInitStartTime) {
|
|
770
|
+
const endMemory = MemoryManager
|
|
771
|
+
? MemoryManager.getMemoryUsageMB()
|
|
772
|
+
: { heapUsed: 0, heapTotal: 0, rss: 0, external: 0 };
|
|
773
|
+
const memoryDelta = endMemory.heapUsed - startMemory.heapUsed;
|
|
774
|
+
const initTime = Date.now() - mcpInitStartTime;
|
|
775
|
+
mcpLogger.debug("[NeuroLink] MCP initialization completed successfully", {
|
|
776
|
+
initTime: `${initTime}ms`,
|
|
777
|
+
memoryUsed: `${memoryDelta}MB`,
|
|
778
|
+
});
|
|
779
|
+
if (memoryDelta > 30) {
|
|
780
|
+
mcpLogger.debug("💡 Memory cleanup suggestion: MCP initialization used significant memory. Consider calling MemoryManager.forceGC() after heavy operations.");
|
|
722
781
|
}
|
|
723
782
|
}
|
|
724
783
|
/**
|
|
@@ -816,11 +875,15 @@ export class NeuroLink {
|
|
|
816
875
|
options.input.text = this.contextManager.getContextForPrompt("user", options.input.text);
|
|
817
876
|
}
|
|
818
877
|
const startTime = Date.now();
|
|
819
|
-
// Emit generation start event
|
|
878
|
+
// Emit generation start event (NeuroLink format - keep existing)
|
|
820
879
|
this.emitter.emit("generation:start", {
|
|
821
880
|
provider: options.provider || "auto",
|
|
822
881
|
timestamp: startTime,
|
|
823
882
|
});
|
|
883
|
+
// ADD: Bedrock-compatible response:start event
|
|
884
|
+
this.emitter.emit("response:start");
|
|
885
|
+
// ADD: Bedrock-compatible message event
|
|
886
|
+
this.emitter.emit("message", `Starting ${options.provider || "auto"} text generation...`);
|
|
824
887
|
// Process factory configuration
|
|
825
888
|
const factoryResult = processFactoryOptions(options);
|
|
826
889
|
// Validate factory configuration if present
|
|
@@ -863,13 +926,18 @@ export class NeuroLink {
|
|
|
863
926
|
}
|
|
864
927
|
// Use redesigned generation logic
|
|
865
928
|
const textResult = await this.generateTextInternal(textOptions);
|
|
866
|
-
// Emit generation completion event
|
|
929
|
+
// Emit generation completion event (NeuroLink format - enhanced with content)
|
|
867
930
|
this.emitter.emit("generation:end", {
|
|
868
931
|
provider: textResult.provider,
|
|
869
932
|
responseTime: Date.now() - startTime,
|
|
870
933
|
toolsUsed: textResult.toolsUsed,
|
|
871
934
|
timestamp: Date.now(),
|
|
935
|
+
result: textResult, // Enhanced: include full result
|
|
872
936
|
});
|
|
937
|
+
// ADD: Bedrock-compatible response:end event with content
|
|
938
|
+
this.emitter.emit("response:end", textResult.content || "");
|
|
939
|
+
// ADD: Bedrock-compatible message event
|
|
940
|
+
this.emitter.emit("message", `Generation completed in ${Date.now() - startTime}ms`);
|
|
873
941
|
// Convert back to GenerateResult
|
|
874
942
|
const generateResult = {
|
|
875
943
|
content: textResult.content,
|
|
@@ -877,9 +945,9 @@ export class NeuroLink {
|
|
|
877
945
|
model: textResult.model,
|
|
878
946
|
usage: textResult.usage
|
|
879
947
|
? {
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
948
|
+
input: textResult.usage.input || 0,
|
|
949
|
+
output: textResult.usage.output || 0,
|
|
950
|
+
total: textResult.usage.total || 0,
|
|
883
951
|
}
|
|
884
952
|
: undefined,
|
|
885
953
|
responseTime: textResult.responseTime,
|
|
@@ -893,9 +961,11 @@ export class NeuroLink {
|
|
|
893
961
|
...textResult.evaluation,
|
|
894
962
|
isOffTopic: textResult.evaluation
|
|
895
963
|
.isOffTopic ?? false,
|
|
896
|
-
alertSeverity: textResult.evaluation
|
|
897
|
-
|
|
898
|
-
"
|
|
964
|
+
alertSeverity: textResult.evaluation
|
|
965
|
+
.alertSeverity ??
|
|
966
|
+
"none",
|
|
967
|
+
reasoning: textResult.evaluation
|
|
968
|
+
.reasoning ?? "No evaluation provided",
|
|
899
969
|
evaluationModel: textResult.evaluation
|
|
900
970
|
.evaluationModel ?? "unknown",
|
|
901
971
|
evaluationTime: textResult.evaluation
|
|
@@ -940,18 +1010,46 @@ export class NeuroLink {
|
|
|
940
1010
|
* 5. Store conversation turn for future context
|
|
941
1011
|
*/
|
|
942
1012
|
async generateTextInternal(options) {
|
|
943
|
-
// 🚀 EXHAUSTIVE LOGGING POINT G001: GENERATE TEXT INTERNAL ENTRY
|
|
944
1013
|
const generateInternalId = `generate-internal-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
945
1014
|
const generateInternalStartTime = Date.now();
|
|
946
1015
|
const generateInternalHrTimeStart = process.hrtime.bigint();
|
|
947
1016
|
const functionTag = "NeuroLink.generateTextInternal";
|
|
1017
|
+
this.logGenerateTextInternalStart(generateInternalId, generateInternalStartTime, generateInternalHrTimeStart, options, functionTag);
|
|
1018
|
+
this.emitGenerationStartEvents(options);
|
|
1019
|
+
try {
|
|
1020
|
+
await this.initializeConversationMemoryForGeneration(generateInternalId, generateInternalStartTime, generateInternalHrTimeStart);
|
|
1021
|
+
const mcpResult = await this.attemptMCPGeneration(options, generateInternalId, generateInternalStartTime, generateInternalHrTimeStart, functionTag);
|
|
1022
|
+
if (mcpResult) {
|
|
1023
|
+
await storeConversationTurn(this.conversationMemory, options, mcpResult);
|
|
1024
|
+
this.emitter.emit("response:end", mcpResult.content || "");
|
|
1025
|
+
return mcpResult;
|
|
1026
|
+
}
|
|
1027
|
+
const directResult = await this.directProviderGeneration(options);
|
|
1028
|
+
logger.debug(`[${functionTag}] Direct generation successful`);
|
|
1029
|
+
await storeConversationTurn(this.conversationMemory, options, directResult);
|
|
1030
|
+
this.emitter.emit("response:end", directResult.content || "");
|
|
1031
|
+
this.emitter.emit("message", `Text generation completed successfully`);
|
|
1032
|
+
return directResult;
|
|
1033
|
+
}
|
|
1034
|
+
catch (error) {
|
|
1035
|
+
logger.error(`[${functionTag}] All generation methods failed`, {
|
|
1036
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1037
|
+
});
|
|
1038
|
+
this.emitter.emit("response:end", "");
|
|
1039
|
+
this.emitter.emit("error", error instanceof Error ? error : new Error(String(error)));
|
|
1040
|
+
throw error;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Log generateTextInternal start with comprehensive analysis
|
|
1045
|
+
*/
|
|
1046
|
+
logGenerateTextInternalStart(generateInternalId, generateInternalStartTime, generateInternalHrTimeStart, options, functionTag) {
|
|
948
1047
|
logger.debug(`[NeuroLink] 🎯 LOG_POINT_G001_GENERATE_INTERNAL_START`, {
|
|
949
1048
|
logPoint: "G001_GENERATE_INTERNAL_START",
|
|
950
1049
|
generateInternalId,
|
|
951
1050
|
timestamp: new Date().toISOString(),
|
|
952
1051
|
generateInternalStartTime,
|
|
953
1052
|
generateInternalHrTimeStart: generateInternalHrTimeStart.toString(),
|
|
954
|
-
// 📊 Input analysis
|
|
955
1053
|
inputAnalysis: {
|
|
956
1054
|
provider: options.provider || "auto",
|
|
957
1055
|
providerType: typeof options.provider,
|
|
@@ -974,19 +1072,17 @@ export class NeuroLink {
|
|
|
974
1072
|
evaluationDomain: options.evaluationDomain || "NOT_SET",
|
|
975
1073
|
toolUsageContext: options.toolUsageContext || "NOT_SET",
|
|
976
1074
|
},
|
|
977
|
-
// 🧠 Memory and initialization state
|
|
978
1075
|
instanceState: {
|
|
979
1076
|
hasConversationMemory: !!this.conversationMemory,
|
|
980
1077
|
conversationMemoryType: this.conversationMemory?.constructor?.name || "NOT_SET",
|
|
981
1078
|
mcpInitialized: this.mcpInitialized,
|
|
982
1079
|
hasProviderRegistry: !!AIProviderFactory,
|
|
983
|
-
providerRegistrySize: 0,
|
|
1080
|
+
providerRegistrySize: 0,
|
|
984
1081
|
hasToolRegistry: !!toolRegistry,
|
|
985
|
-
toolRegistrySize: 0,
|
|
1082
|
+
toolRegistrySize: 0,
|
|
986
1083
|
hasExternalServerManager: !!this.externalServerManager,
|
|
987
1084
|
hasContextManager: !!this.contextManager,
|
|
988
1085
|
},
|
|
989
|
-
// 🔧 Environment context
|
|
990
1086
|
environmentContext: {
|
|
991
1087
|
nodeVersion: process.version,
|
|
992
1088
|
platform: process.platform,
|
|
@@ -1002,200 +1098,188 @@ export class NeuroLink {
|
|
|
1002
1098
|
promptLength: options.prompt?.length || 0,
|
|
1003
1099
|
hasConversationMemory: !!this.conversationMemory,
|
|
1004
1100
|
});
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Emit generation start events
|
|
1104
|
+
*/
|
|
1105
|
+
emitGenerationStartEvents(options) {
|
|
1106
|
+
this.emitter.emit("response:start");
|
|
1107
|
+
this.emitter.emit("message", `Starting ${options.provider || "auto"} text generation (internal)...`);
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Initialize conversation memory for generation
|
|
1111
|
+
*/
|
|
1112
|
+
async initializeConversationMemoryForGeneration(generateInternalId, generateInternalStartTime, generateInternalHrTimeStart) {
|
|
1113
|
+
const conversationMemoryStartTime = process.hrtime.bigint();
|
|
1114
|
+
logger.debug(`[NeuroLink] 🧠 LOG_POINT_G002_CONVERSATION_MEMORY_CHECK`, {
|
|
1115
|
+
logPoint: "G002_CONVERSATION_MEMORY_CHECK",
|
|
1116
|
+
generateInternalId,
|
|
1117
|
+
timestamp: new Date().toISOString(),
|
|
1118
|
+
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1119
|
+
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1120
|
+
conversationMemoryStartTimeNs: conversationMemoryStartTime.toString(),
|
|
1121
|
+
hasConversationMemory: !!this.conversationMemory,
|
|
1122
|
+
conversationMemoryEnabled: !!this.conversationMemory,
|
|
1123
|
+
conversationMemoryType: this.conversationMemory?.constructor?.name || "NOT_AVAILABLE",
|
|
1124
|
+
message: "Checking conversation memory initialization requirement",
|
|
1125
|
+
});
|
|
1126
|
+
if (this.conversationMemory) {
|
|
1127
|
+
logger.debug(`[NeuroLink] 🧠 LOG_POINT_G003_CONVERSATION_MEMORY_INIT_START`, {
|
|
1128
|
+
logPoint: "G003_CONVERSATION_MEMORY_INIT_START",
|
|
1010
1129
|
generateInternalId,
|
|
1011
1130
|
timestamp: new Date().toISOString(),
|
|
1012
1131
|
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1013
1132
|
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1133
|
+
message: "Starting conversation memory initialization",
|
|
1134
|
+
});
|
|
1135
|
+
await this.conversationMemory.initialize();
|
|
1136
|
+
const conversationMemoryEndTime = process.hrtime.bigint();
|
|
1137
|
+
const conversationMemoryDurationNs = conversationMemoryEndTime - conversationMemoryStartTime;
|
|
1138
|
+
logger.debug(`[NeuroLink] ✅ LOG_POINT_G004_CONVERSATION_MEMORY_INIT_SUCCESS`, {
|
|
1139
|
+
logPoint: "G004_CONVERSATION_MEMORY_INIT_SUCCESS",
|
|
1140
|
+
generateInternalId,
|
|
1141
|
+
timestamp: new Date().toISOString(),
|
|
1142
|
+
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1143
|
+
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1144
|
+
conversationMemoryDurationNs: conversationMemoryDurationNs.toString(),
|
|
1145
|
+
conversationMemoryDurationMs: Number(conversationMemoryDurationNs) / 1000000,
|
|
1146
|
+
message: "Conversation memory initialization completed successfully",
|
|
1019
1147
|
});
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* Attempt MCP generation with retry logic
|
|
1152
|
+
*/
|
|
1153
|
+
async attemptMCPGeneration(options, generateInternalId, generateInternalStartTime, generateInternalHrTimeStart, functionTag) {
|
|
1154
|
+
const mcpDecisionStartTime = process.hrtime.bigint();
|
|
1155
|
+
logger.debug(`[NeuroLink] 🔧 LOG_POINT_G005_MCP_DECISION_CHECK`, {
|
|
1156
|
+
logPoint: "G005_MCP_DECISION_CHECK",
|
|
1157
|
+
generateInternalId,
|
|
1158
|
+
timestamp: new Date().toISOString(),
|
|
1159
|
+
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1160
|
+
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1161
|
+
mcpDecisionStartTimeNs: mcpDecisionStartTime.toString(),
|
|
1162
|
+
mcpDecisionFactors: {
|
|
1163
|
+
disableTools: options.disableTools || false,
|
|
1164
|
+
toolsEnabled: !options.disableTools,
|
|
1165
|
+
mcpInitialized: this.mcpInitialized,
|
|
1166
|
+
hasExternalServerManager: !!this.externalServerManager,
|
|
1167
|
+
hasToolRegistry: !!toolRegistry,
|
|
1168
|
+
toolRegistrySize: 0,
|
|
1169
|
+
shouldTryMCP: !options.disableTools,
|
|
1170
|
+
},
|
|
1171
|
+
mcpReadinessAnalysis: {
|
|
1172
|
+
mcpAvailable: !options.disableTools && this.mcpInitialized,
|
|
1173
|
+
componentsReady: {
|
|
1174
|
+
externalServerManager: !!this.externalServerManager,
|
|
1175
|
+
toolRegistry: !!toolRegistry,
|
|
1176
|
+
providerRegistry: !!AIProviderFactory,
|
|
1177
|
+
},
|
|
1178
|
+
},
|
|
1179
|
+
message: "Analyzing MCP generation eligibility and readiness",
|
|
1180
|
+
});
|
|
1181
|
+
if (!options.disableTools) {
|
|
1182
|
+
return await this.performMCPGenerationRetries(options, generateInternalId, generateInternalStartTime, generateInternalHrTimeStart, functionTag);
|
|
1183
|
+
}
|
|
1184
|
+
return null;
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Perform MCP generation with retry logic
|
|
1188
|
+
*/
|
|
1189
|
+
async performMCPGenerationRetries(options, generateInternalId, generateInternalStartTime, generateInternalHrTimeStart, functionTag) {
|
|
1190
|
+
const maxMcpRetries = 2;
|
|
1191
|
+
const mcpRetryLoopStartTime = process.hrtime.bigint();
|
|
1192
|
+
logger.debug(`[NeuroLink] 🔄 LOG_POINT_G006_MCP_RETRY_LOOP_START`, {
|
|
1193
|
+
logPoint: "G006_MCP_RETRY_LOOP_START",
|
|
1194
|
+
generateInternalId,
|
|
1195
|
+
timestamp: new Date().toISOString(),
|
|
1196
|
+
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1197
|
+
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1198
|
+
mcpRetryLoopStartTimeNs: mcpRetryLoopStartTime.toString(),
|
|
1199
|
+
maxMcpRetries,
|
|
1200
|
+
totalPossibleAttempts: maxMcpRetries + 1,
|
|
1201
|
+
message: "Starting MCP generation retry loop with failure tolerance",
|
|
1202
|
+
});
|
|
1203
|
+
const maxAttempts = maxMcpRetries + 1;
|
|
1204
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1205
|
+
try {
|
|
1206
|
+
const mcpAttemptStartTime = process.hrtime.bigint();
|
|
1207
|
+
logger.debug(`[NeuroLink] 🎯 LOG_POINT_G007_MCP_ATTEMPT_START`, {
|
|
1208
|
+
logPoint: "G007_MCP_ATTEMPT_START",
|
|
1024
1209
|
generateInternalId,
|
|
1025
1210
|
timestamp: new Date().toISOString(),
|
|
1026
1211
|
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1027
1212
|
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1028
|
-
|
|
1213
|
+
mcpAttemptStartTimeNs: mcpAttemptStartTime.toString(),
|
|
1214
|
+
currentAttempt: attempt,
|
|
1215
|
+
maxAttempts,
|
|
1216
|
+
isFirstAttempt: attempt === 1,
|
|
1217
|
+
isLastAttempt: attempt === maxAttempts,
|
|
1218
|
+
attemptType: attempt === 1 ? "INITIAL" : "RETRY",
|
|
1219
|
+
message: `Attempting MCP generation (attempt ${attempt}/${maxAttempts})`,
|
|
1029
1220
|
});
|
|
1030
|
-
|
|
1031
|
-
const
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
|
|
1221
|
+
logger.debug(`[${functionTag}] Attempting MCP generation (attempt ${attempt}/${maxAttempts})...`);
|
|
1222
|
+
const mcpResult = await this.tryMCPGeneration(options);
|
|
1223
|
+
const mcpAttemptEndTime = process.hrtime.bigint();
|
|
1224
|
+
const mcpAttemptDurationNs = mcpAttemptEndTime - mcpAttemptStartTime;
|
|
1225
|
+
logger.debug(`[NeuroLink] 📊 LOG_POINT_G008_MCP_ATTEMPT_RESULT`, {
|
|
1226
|
+
logPoint: "G008_MCP_ATTEMPT_RESULT",
|
|
1035
1227
|
generateInternalId,
|
|
1036
1228
|
timestamp: new Date().toISOString(),
|
|
1037
1229
|
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1038
1230
|
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1231
|
+
mcpAttemptDurationNs: mcpAttemptDurationNs.toString(),
|
|
1232
|
+
mcpAttemptDurationMs: Number(mcpAttemptDurationNs) / 1000000,
|
|
1233
|
+
currentAttempt: attempt,
|
|
1234
|
+
resultAnalysis: {
|
|
1235
|
+
hasResult: !!mcpResult,
|
|
1236
|
+
resultType: typeof mcpResult,
|
|
1237
|
+
hasContent: !!(mcpResult && mcpResult.content),
|
|
1238
|
+
contentLength: mcpResult?.content?.length || 0,
|
|
1239
|
+
contentPreview: mcpResult?.content?.substring(0, 200) || "NO_CONTENT",
|
|
1240
|
+
hasToolExecutions: !!(mcpResult &&
|
|
1241
|
+
mcpResult.toolExecutions &&
|
|
1242
|
+
mcpResult.toolExecutions.length > 0),
|
|
1243
|
+
toolExecutionsCount: mcpResult?.toolExecutions?.length || 0,
|
|
1244
|
+
toolsUsedCount: mcpResult?.toolsUsed?.length || 0,
|
|
1245
|
+
provider: mcpResult?.provider || "NOT_SET",
|
|
1246
|
+
responseTime: mcpResult?.responseTime || 0,
|
|
1247
|
+
enhancedWithTools: mcpResult?.enhancedWithTools || false,
|
|
1248
|
+
},
|
|
1249
|
+
message: `MCP generation attempt ${attempt} completed - analyzing result`,
|
|
1042
1250
|
});
|
|
1251
|
+
if (mcpResult &&
|
|
1252
|
+
(mcpResult.content ||
|
|
1253
|
+
(mcpResult.toolExecutions && mcpResult.toolExecutions.length > 0))) {
|
|
1254
|
+
logger.debug(`[${functionTag}] MCP generation successful on attempt ${attempt}`, {
|
|
1255
|
+
contentLength: mcpResult.content?.length || 0,
|
|
1256
|
+
toolsUsed: mcpResult.toolsUsed?.length || 0,
|
|
1257
|
+
toolExecutions: mcpResult.toolExecutions?.length || 0,
|
|
1258
|
+
});
|
|
1259
|
+
return mcpResult;
|
|
1260
|
+
}
|
|
1261
|
+
else {
|
|
1262
|
+
logger.debug(`[${functionTag}] MCP generation returned empty result on attempt ${attempt}`, {
|
|
1263
|
+
hasResult: !!mcpResult,
|
|
1264
|
+
hasContent: !!(mcpResult && mcpResult.content),
|
|
1265
|
+
contentLength: mcpResult?.content?.length || 0,
|
|
1266
|
+
toolExecutions: mcpResult?.toolExecutions?.length || 0,
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1043
1269
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
generateInternalId,
|
|
1049
|
-
timestamp: new Date().toISOString(),
|
|
1050
|
-
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1051
|
-
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1052
|
-
mcpDecisionStartTimeNs: mcpDecisionStartTime.toString(),
|
|
1053
|
-
// 🎯 MCP decision factors
|
|
1054
|
-
mcpDecisionFactors: {
|
|
1055
|
-
disableTools: options.disableTools || false,
|
|
1056
|
-
toolsEnabled: !options.disableTools,
|
|
1057
|
-
mcpInitialized: this.mcpInitialized,
|
|
1058
|
-
hasExternalServerManager: !!this.externalServerManager,
|
|
1059
|
-
hasToolRegistry: !!toolRegistry,
|
|
1060
|
-
toolRegistrySize: 0, // Not accessible as size property
|
|
1061
|
-
shouldTryMCP: !options.disableTools,
|
|
1062
|
-
},
|
|
1063
|
-
// 🔍 MCP readiness analysis
|
|
1064
|
-
mcpReadinessAnalysis: {
|
|
1065
|
-
mcpAvailable: !options.disableTools && this.mcpInitialized,
|
|
1066
|
-
componentsReady: {
|
|
1067
|
-
externalServerManager: !!this.externalServerManager,
|
|
1068
|
-
toolRegistry: !!toolRegistry,
|
|
1069
|
-
providerRegistry: !!AIProviderFactory,
|
|
1070
|
-
},
|
|
1071
|
-
},
|
|
1072
|
-
message: "Analyzing MCP generation eligibility and readiness",
|
|
1073
|
-
});
|
|
1074
|
-
// Try MCP-enhanced generation first (if not explicitly disabled)
|
|
1075
|
-
if (!options.disableTools) {
|
|
1076
|
-
// 🚀 EXHAUSTIVE LOGGING POINT G006: MCP RETRY LOOP INITIALIZATION
|
|
1077
|
-
const mcpAttempts = 0;
|
|
1078
|
-
const maxMcpRetries = 2; // Allow retries for tool-related failures
|
|
1079
|
-
const mcpRetryLoopStartTime = process.hrtime.bigint();
|
|
1080
|
-
logger.debug(`[NeuroLink] 🔄 LOG_POINT_G006_MCP_RETRY_LOOP_START`, {
|
|
1081
|
-
logPoint: "G006_MCP_RETRY_LOOP_START",
|
|
1082
|
-
generateInternalId,
|
|
1083
|
-
timestamp: new Date().toISOString(),
|
|
1084
|
-
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1085
|
-
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1086
|
-
mcpRetryLoopStartTimeNs: mcpRetryLoopStartTime.toString(),
|
|
1087
|
-
maxMcpRetries,
|
|
1088
|
-
totalPossibleAttempts: maxMcpRetries + 1,
|
|
1089
|
-
currentAttempt: mcpAttempts + 1,
|
|
1090
|
-
message: "Starting MCP generation retry loop with failure tolerance",
|
|
1270
|
+
catch (error) {
|
|
1271
|
+
logger.debug(`[${functionTag}] MCP generation failed on attempt ${attempt}/${maxAttempts}`, {
|
|
1272
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1273
|
+
willRetry: attempt < maxAttempts,
|
|
1091
1274
|
});
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
// 🚀 EXHAUSTIVE LOGGING POINT G007: MCP GENERATION ATTEMPT
|
|
1096
|
-
const mcpAttemptStartTime = process.hrtime.bigint();
|
|
1097
|
-
logger.debug(`[NeuroLink] 🎯 LOG_POINT_G007_MCP_ATTEMPT_START`, {
|
|
1098
|
-
logPoint: "G007_MCP_ATTEMPT_START",
|
|
1099
|
-
generateInternalId,
|
|
1100
|
-
timestamp: new Date().toISOString(),
|
|
1101
|
-
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1102
|
-
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1103
|
-
mcpAttemptStartTimeNs: mcpAttemptStartTime.toString(),
|
|
1104
|
-
currentAttempt: attempt,
|
|
1105
|
-
maxAttempts,
|
|
1106
|
-
isFirstAttempt: attempt === 1,
|
|
1107
|
-
isLastAttempt: attempt === maxAttempts,
|
|
1108
|
-
attemptType: attempt === 1 ? "INITIAL" : "RETRY",
|
|
1109
|
-
message: `Attempting MCP generation (attempt ${attempt}/${maxAttempts})`,
|
|
1110
|
-
});
|
|
1111
|
-
logger.debug(`[${functionTag}] Attempting MCP generation (attempt ${attempt}/${maxAttempts})...`);
|
|
1112
|
-
const mcpResult = await this.tryMCPGeneration(options);
|
|
1113
|
-
// 🚀 EXHAUSTIVE LOGGING POINT G008: MCP GENERATION ATTEMPT RESULT
|
|
1114
|
-
const mcpAttemptEndTime = process.hrtime.bigint();
|
|
1115
|
-
const mcpAttemptDurationNs = mcpAttemptEndTime - mcpAttemptStartTime;
|
|
1116
|
-
logger.debug(`[NeuroLink] 📊 LOG_POINT_G008_MCP_ATTEMPT_RESULT`, {
|
|
1117
|
-
logPoint: "G008_MCP_ATTEMPT_RESULT",
|
|
1118
|
-
generateInternalId,
|
|
1119
|
-
timestamp: new Date().toISOString(),
|
|
1120
|
-
elapsedMs: Date.now() - generateInternalStartTime,
|
|
1121
|
-
elapsedNs: (process.hrtime.bigint() - generateInternalHrTimeStart).toString(),
|
|
1122
|
-
mcpAttemptDurationNs: mcpAttemptDurationNs.toString(),
|
|
1123
|
-
mcpAttemptDurationMs: Number(mcpAttemptDurationNs) / 1000000,
|
|
1124
|
-
currentAttempt: attempt,
|
|
1125
|
-
// 🎯 Result analysis
|
|
1126
|
-
resultAnalysis: {
|
|
1127
|
-
hasResult: !!mcpResult,
|
|
1128
|
-
resultType: typeof mcpResult,
|
|
1129
|
-
hasContent: !!(mcpResult && mcpResult.content),
|
|
1130
|
-
contentLength: mcpResult?.content?.length || 0,
|
|
1131
|
-
contentPreview: mcpResult?.content?.substring(0, 200) || "NO_CONTENT",
|
|
1132
|
-
hasToolExecutions: !!(mcpResult &&
|
|
1133
|
-
mcpResult.toolExecutions &&
|
|
1134
|
-
mcpResult.toolExecutions.length > 0),
|
|
1135
|
-
toolExecutionsCount: mcpResult?.toolExecutions?.length || 0,
|
|
1136
|
-
toolsUsedCount: mcpResult?.toolsUsed?.length || 0,
|
|
1137
|
-
provider: mcpResult?.provider || "NOT_SET",
|
|
1138
|
-
responseTime: mcpResult?.responseTime || 0,
|
|
1139
|
-
enhancedWithTools: mcpResult?.enhancedWithTools || false,
|
|
1140
|
-
},
|
|
1141
|
-
message: `MCP generation attempt ${attempt} completed - analyzing result`,
|
|
1142
|
-
});
|
|
1143
|
-
if (mcpResult && mcpResult.content) {
|
|
1144
|
-
logger.debug(`[${functionTag}] MCP generation successful on attempt ${attempt}`, {
|
|
1145
|
-
contentLength: mcpResult.content.length,
|
|
1146
|
-
toolsUsed: mcpResult.toolsUsed?.length || 0,
|
|
1147
|
-
toolExecutions: mcpResult.toolExecutions?.length || 0,
|
|
1148
|
-
});
|
|
1149
|
-
// Store conversation turn
|
|
1150
|
-
await storeConversationTurn(this.conversationMemory, options, mcpResult);
|
|
1151
|
-
return mcpResult;
|
|
1152
|
-
}
|
|
1153
|
-
else {
|
|
1154
|
-
logger.debug(`[${functionTag}] MCP generation returned empty result on attempt ${attempt}:`, {
|
|
1155
|
-
hasResult: !!mcpResult,
|
|
1156
|
-
hasContent: !!(mcpResult && mcpResult.content),
|
|
1157
|
-
contentLength: mcpResult?.content?.length || 0,
|
|
1158
|
-
toolExecutions: mcpResult?.toolExecutions?.length || 0,
|
|
1159
|
-
});
|
|
1160
|
-
// If we got a result but no content, and we have tool executions, this might be a tool success case
|
|
1161
|
-
if (mcpResult &&
|
|
1162
|
-
mcpResult.toolExecutions &&
|
|
1163
|
-
mcpResult.toolExecutions.length > 0) {
|
|
1164
|
-
logger.debug(`[${functionTag}] Found tool executions but no content, continuing with result`);
|
|
1165
|
-
// Store conversation turn even with empty content if tools executed
|
|
1166
|
-
await storeConversationTurn(this.conversationMemory, options, mcpResult);
|
|
1167
|
-
return mcpResult;
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
catch (error) {
|
|
1172
|
-
logger.debug(`[${functionTag}] MCP generation failed on attempt ${attempt}/${maxAttempts}`, {
|
|
1173
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1174
|
-
willRetry: attempt < maxAttempts,
|
|
1175
|
-
});
|
|
1176
|
-
// If this was the last attempt, break and fall back
|
|
1177
|
-
if (attempt >= maxAttempts) {
|
|
1178
|
-
logger.debug(`[${functionTag}] All MCP attempts exhausted, falling back to direct generation`);
|
|
1179
|
-
break;
|
|
1180
|
-
}
|
|
1181
|
-
// Small delay before retry to allow transient issues to resolve
|
|
1182
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1183
|
-
}
|
|
1275
|
+
if (attempt >= maxAttempts) {
|
|
1276
|
+
logger.debug(`[${functionTag}] All MCP attempts exhausted, falling back to direct generation`);
|
|
1277
|
+
break;
|
|
1184
1278
|
}
|
|
1279
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1185
1280
|
}
|
|
1186
|
-
// Fall back to direct provider generation
|
|
1187
|
-
const directResult = await this.directProviderGeneration(options);
|
|
1188
|
-
logger.debug(`[${functionTag}] Direct generation successful`);
|
|
1189
|
-
// Store conversation turn
|
|
1190
|
-
await storeConversationTurn(this.conversationMemory, options, directResult);
|
|
1191
|
-
return directResult;
|
|
1192
|
-
}
|
|
1193
|
-
catch (error) {
|
|
1194
|
-
logger.error(`[${functionTag}] All generation methods failed`, {
|
|
1195
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1196
|
-
});
|
|
1197
|
-
throw error;
|
|
1198
1281
|
}
|
|
1282
|
+
return null;
|
|
1199
1283
|
}
|
|
1200
1284
|
/**
|
|
1201
1285
|
* Try MCP-enhanced generation (no fallback recursion)
|
|
@@ -1299,6 +1383,9 @@ export class NeuroLink {
|
|
|
1299
1383
|
// Create provider and generate
|
|
1300
1384
|
const provider = await AIProviderFactory.createProvider(providerName, options.model, !options.disableTools, // Pass disableTools as inverse of enableMCP
|
|
1301
1385
|
this);
|
|
1386
|
+
// ADD: Emit connection events for all providers (Bedrock-compatible)
|
|
1387
|
+
this.emitter.emit("connected");
|
|
1388
|
+
this.emitter.emit("message", `${providerName} provider initialized successfully`);
|
|
1302
1389
|
// Enable tool execution for the provider using BaseProvider method
|
|
1303
1390
|
provider.setupToolExecutor({
|
|
1304
1391
|
customTools: this.getCustomTools(),
|
|
@@ -1393,6 +1480,9 @@ export class NeuroLink {
|
|
|
1393
1480
|
const conversationMessages = await getConversationMessages(this.conversationMemory, options);
|
|
1394
1481
|
const provider = await AIProviderFactory.createProvider(providerName, options.model, !options.disableTools, // Pass disableTools as inverse of enableMCP
|
|
1395
1482
|
this);
|
|
1483
|
+
// ADD: Emit connection events for successful provider creation (Bedrock-compatible)
|
|
1484
|
+
this.emitter.emit("connected");
|
|
1485
|
+
this.emitter.emit("message", `${providerName} provider initialized successfully`);
|
|
1396
1486
|
// Enable tool execution for direct provider generation using BaseProvider method
|
|
1397
1487
|
provider.setupToolExecutor({
|
|
1398
1488
|
customTools: this.getCustomTools(),
|
|
@@ -1454,7 +1544,7 @@ export class NeuroLink {
|
|
|
1454
1544
|
* Execute tools if available through centralized registry
|
|
1455
1545
|
* Simplified approach without domain detection - relies on tool registry
|
|
1456
1546
|
*/
|
|
1457
|
-
async detectAndExecuteTools(prompt,
|
|
1547
|
+
async detectAndExecuteTools(prompt, _domainType) {
|
|
1458
1548
|
const functionTag = "NeuroLink.detectAndExecuteTools";
|
|
1459
1549
|
try {
|
|
1460
1550
|
// Simplified: Just return original prompt without complex detection
|
|
@@ -1571,7 +1661,51 @@ export class NeuroLink {
|
|
|
1571
1661
|
const functionTag = "NeuroLink.stream";
|
|
1572
1662
|
const streamId = `neurolink-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1573
1663
|
const journeyStartTime = new Date().toISOString();
|
|
1574
|
-
|
|
1664
|
+
this.logStreamEntryPoint(streamId, journeyStartTime, functionTag, startTime, hrTimeStart, options);
|
|
1665
|
+
this.logPerformanceBaseline(streamId, startTime, hrTimeStart);
|
|
1666
|
+
await this.validateStreamInput(options, streamId, startTime, hrTimeStart);
|
|
1667
|
+
this.emitStreamStartEvents(options, startTime);
|
|
1668
|
+
let enhancedOptions;
|
|
1669
|
+
let factoryResult;
|
|
1670
|
+
try {
|
|
1671
|
+
await this.initializeMCP();
|
|
1672
|
+
const originalPrompt = options.input.text;
|
|
1673
|
+
if (this.contextManager) {
|
|
1674
|
+
options.input.text = this.contextManager.getContextForPrompt("user", options.input.text);
|
|
1675
|
+
}
|
|
1676
|
+
factoryResult = processStreamingFactoryOptions(options);
|
|
1677
|
+
enhancedOptions = createCleanStreamOptions(options);
|
|
1678
|
+
const { toolResults: _toolResults, enhancedPrompt } = await this.detectAndExecuteTools(options.input.text, undefined);
|
|
1679
|
+
if (enhancedPrompt !== options.input.text) {
|
|
1680
|
+
enhancedOptions.input.text = enhancedPrompt;
|
|
1681
|
+
}
|
|
1682
|
+
const { stream: mcpStream, provider: providerName } = await this.createMCPStream(enhancedOptions);
|
|
1683
|
+
const streamResult = await this.processStreamResult(mcpStream, enhancedOptions, factoryResult);
|
|
1684
|
+
const responseTime = Date.now() - startTime;
|
|
1685
|
+
if (this.contextManager) {
|
|
1686
|
+
await this.contextManager.addTurn("user", originalPrompt);
|
|
1687
|
+
if (streamResult.content) {
|
|
1688
|
+
await this.contextManager.addTurn("assistant", streamResult.content);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
this.emitStreamEndEvents(streamResult);
|
|
1692
|
+
return this.createStreamResponse(streamResult, mcpStream, {
|
|
1693
|
+
providerName,
|
|
1694
|
+
options,
|
|
1695
|
+
startTime,
|
|
1696
|
+
responseTime,
|
|
1697
|
+
streamId,
|
|
1698
|
+
fallback: false,
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
catch (error) {
|
|
1702
|
+
return this.handleStreamError(error, options, startTime, streamId, undefined, undefined);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Log stream entry point with comprehensive analysis
|
|
1707
|
+
*/
|
|
1708
|
+
logStreamEntryPoint(streamId, journeyStartTime, functionTag, startTime, hrTimeStart, options) {
|
|
1575
1709
|
logger.debug(`[NeuroLink] 🎯 LOG_POINT_001_STREAM_ENTRY_START`, {
|
|
1576
1710
|
logPoint: "001_STREAM_ENTRY_START",
|
|
1577
1711
|
streamId,
|
|
@@ -1584,12 +1718,10 @@ export class NeuroLink {
|
|
|
1584
1718
|
arch: process.arch,
|
|
1585
1719
|
memoryUsage: process.memoryUsage(),
|
|
1586
1720
|
cpuUsage: process.cpuUsage(),
|
|
1587
|
-
// Comprehensive input validation
|
|
1588
1721
|
hasOptions: !!options,
|
|
1589
1722
|
optionsType: typeof options,
|
|
1590
1723
|
optionsKeys: options ? Object.keys(options) : [],
|
|
1591
1724
|
optionsSize: options ? JSON.stringify(options).length : 0,
|
|
1592
|
-
// Deep input analysis
|
|
1593
1725
|
hasInput: !!options?.input,
|
|
1594
1726
|
inputType: typeof options?.input,
|
|
1595
1727
|
inputKeys: options?.input ? Object.keys(options.input) : [],
|
|
@@ -1597,53 +1729,18 @@ export class NeuroLink {
|
|
|
1597
1729
|
inputTextType: typeof options?.input?.text,
|
|
1598
1730
|
inputTextLength: options?.input?.text?.length || 0,
|
|
1599
1731
|
inputTextPreview: options?.input?.text?.substring(0, 200) || "NO_TEXT",
|
|
1600
|
-
inputTextHash: options?.input?.text
|
|
1601
|
-
? "hash-" +
|
|
1602
|
-
options.input.text.length +
|
|
1603
|
-
"-" +
|
|
1604
|
-
Math.random().toString(36).substr(2, 8)
|
|
1605
|
-
: "NO_HASH",
|
|
1606
|
-
// Provider configuration analysis
|
|
1607
1732
|
hasProvider: !!options?.provider,
|
|
1608
1733
|
providerValue: options?.provider || "NOT_SET",
|
|
1609
1734
|
isAutoProvider: options?.provider === "auto" || !options?.provider,
|
|
1610
|
-
// Model configuration analysis
|
|
1611
1735
|
hasModel: !!options?.model,
|
|
1612
1736
|
modelValue: options?.model || "NOT_SET",
|
|
1613
|
-
isDefaultModel: !options?.model,
|
|
1614
|
-
// Advanced configuration analysis
|
|
1615
|
-
hasSystemPrompt: !!options?.systemPrompt,
|
|
1616
|
-
systemPromptLength: options?.systemPrompt?.length || 0,
|
|
1617
|
-
systemPromptPreview: options?.systemPrompt?.substring(0, 100) || "NO_SYSTEM_PROMPT",
|
|
1618
|
-
hasTemperature: !!options?.temperature,
|
|
1619
|
-
temperatureValue: options?.temperature || "NOT_SET",
|
|
1620
|
-
isValidTemperature: typeof options?.temperature === "number" &&
|
|
1621
|
-
options.temperature >= 0 &&
|
|
1622
|
-
options.temperature <= 2,
|
|
1623
|
-
hasMaxTokens: !!options?.maxTokens,
|
|
1624
|
-
maxTokensValue: options?.maxTokens || "NOT_SET",
|
|
1625
|
-
isValidMaxTokens: typeof options?.maxTokens === "number" && options.maxTokens > 0,
|
|
1626
|
-
hasDisableTools: options?.disableTools !== undefined,
|
|
1627
|
-
disableToolsValue: options?.disableTools || false,
|
|
1628
|
-
hasContext: !!options?.context,
|
|
1629
|
-
contextKeys: options?.context ? Object.keys(options.context) : [],
|
|
1630
|
-
contextSize: options?.context
|
|
1631
|
-
? JSON.stringify(options.context).length
|
|
1632
|
-
: 0,
|
|
1633
|
-
// Environment analysis
|
|
1634
|
-
nodeEnv: process.env.NODE_ENV || "UNKNOWN",
|
|
1635
|
-
hasProxyConfig: !!(process.env.HTTP_PROXY ||
|
|
1636
|
-
process.env.HTTPS_PROXY ||
|
|
1637
|
-
process.env.http_proxy ||
|
|
1638
|
-
process.env.https_proxy),
|
|
1639
|
-
httpProxy: process.env.HTTP_PROXY || process.env.http_proxy || "NOT_SET",
|
|
1640
|
-
httpsProxy: process.env.HTTPS_PROXY || process.env.https_proxy || "NOT_SET",
|
|
1641
|
-
hasGoogleCredentials: !!(process.env.GOOGLE_APPLICATION_CREDENTIALS ||
|
|
1642
|
-
process.env.GOOGLE_SERVICE_ACCOUNT_KEY),
|
|
1643
|
-
googleCredentialsPath: process.env.GOOGLE_APPLICATION_CREDENTIALS || "NOT_SET",
|
|
1644
1737
|
message: "EXHAUSTIVE NeuroLink main stream method entry point with comprehensive environment analysis",
|
|
1645
1738
|
});
|
|
1646
|
-
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Log performance baseline
|
|
1742
|
+
*/
|
|
1743
|
+
logPerformanceBaseline(streamId, startTime, hrTimeStart) {
|
|
1647
1744
|
const memoryBaseline = process.memoryUsage();
|
|
1648
1745
|
const cpuBaseline = process.cpuUsage();
|
|
1649
1746
|
logger.debug(`[NeuroLink] 🎯 LOG_POINT_002_PERFORMANCE_BASELINE`, {
|
|
@@ -1669,14 +1766,18 @@ export class NeuroLink {
|
|
|
1669
1766
|
global.gc();
|
|
1670
1767
|
return process.memoryUsage();
|
|
1671
1768
|
}
|
|
1672
|
-
catch
|
|
1769
|
+
catch {
|
|
1673
1770
|
return null;
|
|
1674
1771
|
}
|
|
1675
1772
|
})()
|
|
1676
1773
|
: null,
|
|
1677
1774
|
message: "Performance baseline metrics captured for stream processing",
|
|
1678
1775
|
});
|
|
1679
|
-
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Validate stream input with comprehensive error reporting
|
|
1779
|
+
*/
|
|
1780
|
+
async validateStreamInput(options, streamId, startTime, hrTimeStart) {
|
|
1680
1781
|
const validationStartTime = process.hrtime.bigint();
|
|
1681
1782
|
logger.debug(`[NeuroLink] 🎯 LOG_POINT_003_VALIDATION_START`, {
|
|
1682
1783
|
logPoint: "003_VALIDATION_START",
|
|
@@ -1687,45 +1788,6 @@ export class NeuroLink {
|
|
|
1687
1788
|
validationStartTimeNs: validationStartTime.toString(),
|
|
1688
1789
|
message: "Starting comprehensive input validation process",
|
|
1689
1790
|
});
|
|
1690
|
-
// 🚀 EXHAUSTIVE LOGGING POINT 4: DETAILED VALIDATION CHECKS
|
|
1691
|
-
logger.debug(`[NeuroLink] 🎯 LOG_POINT_004_VALIDATION_CHECKS`, {
|
|
1692
|
-
logPoint: "004_VALIDATION_CHECKS",
|
|
1693
|
-
streamId,
|
|
1694
|
-
timestamp: new Date().toISOString(),
|
|
1695
|
-
elapsedMs: Date.now() - startTime,
|
|
1696
|
-
checks: {
|
|
1697
|
-
hasOptions: !!options,
|
|
1698
|
-
optionsIsObject: typeof options === "object" && options !== null,
|
|
1699
|
-
hasInput: !!(options && options.input),
|
|
1700
|
-
inputIsObject: !!(options &&
|
|
1701
|
-
options.input &&
|
|
1702
|
-
typeof options.input === "object"),
|
|
1703
|
-
hasInputText: !!(options && options.input && options.input.text),
|
|
1704
|
-
inputTextIsString: !!(options &&
|
|
1705
|
-
options.input &&
|
|
1706
|
-
typeof options.input.text === "string"),
|
|
1707
|
-
inputTextNotEmpty: !!(options &&
|
|
1708
|
-
options.input &&
|
|
1709
|
-
options.input.text &&
|
|
1710
|
-
options.input.text.trim() !== ""),
|
|
1711
|
-
inputTextLength: options?.input?.text?.length || 0,
|
|
1712
|
-
inputTextTrimmedLength: options?.input?.text?.trim()?.length || 0,
|
|
1713
|
-
},
|
|
1714
|
-
optionsStructure: options
|
|
1715
|
-
? {
|
|
1716
|
-
keys: Object.keys(options),
|
|
1717
|
-
inputKeys: options.input ? Object.keys(options.input) : null,
|
|
1718
|
-
inputTextType: typeof options.input?.text,
|
|
1719
|
-
inputTextValue: options.input?.text?.substring(0, 50) +
|
|
1720
|
-
(options.input?.text?.length > 50 ? "..." : ""),
|
|
1721
|
-
inputTextCharCodes: options.input?.text
|
|
1722
|
-
? Array.from(options.input.text.substring(0, 10)).map((c) => c.charCodeAt(0))
|
|
1723
|
-
: null,
|
|
1724
|
-
}
|
|
1725
|
-
: null,
|
|
1726
|
-
message: "Detailed validation checks performed",
|
|
1727
|
-
});
|
|
1728
|
-
// Validate input with comprehensive error reporting
|
|
1729
1791
|
if (!options?.input?.text ||
|
|
1730
1792
|
typeof options.input.text !== "string" ||
|
|
1731
1793
|
options.input.text.trim() === "") {
|
|
@@ -1740,47 +1802,10 @@ export class NeuroLink {
|
|
|
1740
1802
|
validationDurationNs: validationDurationNs.toString(),
|
|
1741
1803
|
validationDurationMs: Number(validationDurationNs) / 1000000,
|
|
1742
1804
|
validationError: "Stream options must include input.text as a non-empty string",
|
|
1743
|
-
// Detailed failure analysis
|
|
1744
|
-
failureReason: !options
|
|
1745
|
-
? "NO_OPTIONS"
|
|
1746
|
-
: !options.input
|
|
1747
|
-
? "NO_INPUT"
|
|
1748
|
-
: !options.input.text
|
|
1749
|
-
? "NO_INPUT_TEXT"
|
|
1750
|
-
: typeof options.input.text !== "string"
|
|
1751
|
-
? "INPUT_TEXT_NOT_STRING"
|
|
1752
|
-
: options.input.text.trim() === ""
|
|
1753
|
-
? "INPUT_TEXT_EMPTY_OR_WHITESPACE"
|
|
1754
|
-
: "UNKNOWN",
|
|
1755
|
-
// Deep analysis for debugging
|
|
1756
|
-
hasOptions: !!options,
|
|
1757
|
-
optionsType: typeof options,
|
|
1758
|
-
hasInput: !!options?.input,
|
|
1759
|
-
inputType: typeof options?.input,
|
|
1760
|
-
hasInputText: !!options?.input?.text,
|
|
1761
|
-
inputTextType: typeof options?.input?.text,
|
|
1762
|
-
inputTextValue: options?.input?.text,
|
|
1763
|
-
inputTextLength: options?.input?.text?.length || 0,
|
|
1764
|
-
inputTextTrimmed: options?.input?.text?.trim(),
|
|
1765
|
-
inputTextTrimmedLength: options?.input?.text?.trim()?.length || 0,
|
|
1766
|
-
// Character analysis for whitespace debugging
|
|
1767
|
-
inputTextCharacters: options?.input?.text
|
|
1768
|
-
? Array.from(options.input.text)
|
|
1769
|
-
.map((char, index) => ({
|
|
1770
|
-
index,
|
|
1771
|
-
char,
|
|
1772
|
-
charCode: char.charCodeAt(0),
|
|
1773
|
-
isWhitespace: /\s/.test(char),
|
|
1774
|
-
}))
|
|
1775
|
-
.slice(0, 20)
|
|
1776
|
-
: null,
|
|
1777
|
-
memoryAtFailure: process.memoryUsage(),
|
|
1778
|
-
cpuAtFailure: process.cpuUsage(),
|
|
1779
1805
|
message: "EXHAUSTIVE validation failure analysis with character-level debugging",
|
|
1780
1806
|
});
|
|
1781
1807
|
throw new Error("Stream options must include input.text as a non-empty string");
|
|
1782
1808
|
}
|
|
1783
|
-
// 🚀 EXHAUSTIVE LOGGING POINT 6: VALIDATION SUCCESS
|
|
1784
1809
|
const validationSuccessTime = process.hrtime.bigint();
|
|
1785
1810
|
const validationDurationNs = validationSuccessTime - validationStartTime;
|
|
1786
1811
|
logger.debug(`[NeuroLink] ✅ LOG_POINT_006_VALIDATION_SUCCESS`, {
|
|
@@ -1795,289 +1820,116 @@ export class NeuroLink {
|
|
|
1795
1820
|
inputTextLength: options.input.text.length,
|
|
1796
1821
|
inputTextTrimmedLength: options.input.text.trim().length,
|
|
1797
1822
|
inputTextPreview: options.input.text.substring(0, 100),
|
|
1798
|
-
inputTextHash: "hash-" +
|
|
1799
|
-
options.input.text.length +
|
|
1800
|
-
"-" +
|
|
1801
|
-
Math.random().toString(36).substr(2, 8),
|
|
1802
|
-
inputTextWordCount: options.input.text
|
|
1803
|
-
.split(/\s+/)
|
|
1804
|
-
.filter((word) => word.length > 0).length,
|
|
1805
|
-
inputTextLineCount: options.input.text.split(/\n/).length,
|
|
1806
|
-
memoryAfterValidation: process.memoryUsage(),
|
|
1807
|
-
cpuAfterValidation: process.cpuUsage(),
|
|
1808
1823
|
message: "EXHAUSTIVE validation success - proceeding with stream processing",
|
|
1809
1824
|
});
|
|
1810
|
-
|
|
1825
|
+
}
|
|
1826
|
+
/**
|
|
1827
|
+
* Emit stream start events
|
|
1828
|
+
*/
|
|
1829
|
+
emitStreamStartEvents(options, startTime) {
|
|
1811
1830
|
this.emitter.emit("stream:start", {
|
|
1812
1831
|
provider: options.provider || "auto",
|
|
1813
1832
|
timestamp: startTime,
|
|
1814
1833
|
});
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
//
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
:
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
processedChunk = { ...chunk, content: "" };
|
|
1911
|
-
}
|
|
1912
|
-
else if (typeof chunk.content !== "string") {
|
|
1913
|
-
// Convert non-string content to string - create a new chunk object
|
|
1914
|
-
const stringContent = String(chunk.content || "");
|
|
1915
|
-
processedChunk = { ...chunk, content: stringContent };
|
|
1916
|
-
accumulatedContent += stringContent;
|
|
1917
|
-
}
|
|
1918
|
-
}
|
|
1919
|
-
else if (chunk === null || chunk === undefined) {
|
|
1920
|
-
// Create a safe empty chunk if chunk is null/undefined
|
|
1921
|
-
processedChunk = { content: "" };
|
|
1922
|
-
}
|
|
1923
|
-
yield processedChunk; // Preserve original streaming behavior with safe content
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
finally {
|
|
1927
|
-
// Store memory after stream consumption
|
|
1928
|
-
if (self.conversationMemory) {
|
|
1929
|
-
try {
|
|
1930
|
-
await self.conversationMemory.storeConversationTurn(enhancedOptions.context
|
|
1931
|
-
?.sessionId, enhancedOptions.context
|
|
1932
|
-
?.userId, options.input.text, accumulatedContent);
|
|
1933
|
-
logger.debug("Stream conversation turn stored", {
|
|
1934
|
-
sessionId: enhancedOptions.context
|
|
1935
|
-
?.sessionId,
|
|
1936
|
-
userInputLength: options.input.text.length,
|
|
1937
|
-
responseLength: accumulatedContent.length,
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
|
-
catch (error) {
|
|
1941
|
-
logger.warn("Failed to store stream conversation turn", {
|
|
1942
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1943
|
-
});
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
})(this);
|
|
1948
|
-
const responseTime = Date.now() - startTime;
|
|
1949
|
-
mcpLogger.debug(`[${functionTag}] MCP-enabled streaming completed`, {
|
|
1950
|
-
responseTime,
|
|
1951
|
-
provider: providerName,
|
|
1952
|
-
});
|
|
1953
|
-
// Emit stream completion event
|
|
1954
|
-
this.emitter.emit("stream:end", {
|
|
1955
|
-
provider: providerName,
|
|
1956
|
-
responseTime,
|
|
1957
|
-
});
|
|
1958
|
-
// Convert to StreamResult format - Include analytics and evaluation from provider
|
|
1959
|
-
return {
|
|
1960
|
-
stream: processedStream,
|
|
1961
|
-
provider: providerName,
|
|
1962
|
-
model: options.model,
|
|
1963
|
-
usage: streamResult.usage,
|
|
1964
|
-
finishReason: streamResult.finishReason,
|
|
1965
|
-
toolCalls: streamResult.toolCalls,
|
|
1966
|
-
toolResults: streamResult.toolResults,
|
|
1967
|
-
analytics: streamResult.analytics,
|
|
1968
|
-
evaluation: streamResult.evaluation
|
|
1969
|
-
? {
|
|
1970
|
-
...streamResult.evaluation,
|
|
1971
|
-
// Include evaluationDomain from factory configuration
|
|
1972
|
-
evaluationDomain: streamResult.evaluation
|
|
1973
|
-
?.evaluationDomain ??
|
|
1974
|
-
enhancedOptions.evaluationDomain ??
|
|
1975
|
-
factoryResult.domainType,
|
|
1976
|
-
}
|
|
1977
|
-
: undefined,
|
|
1978
|
-
metadata: {
|
|
1979
|
-
streamId: `neurolink-${Date.now()}`,
|
|
1980
|
-
startTime,
|
|
1981
|
-
responseTime,
|
|
1982
|
-
},
|
|
1983
|
-
};
|
|
1984
|
-
}
|
|
1985
|
-
catch (error) {
|
|
1986
|
-
// Fall back to regular streaming if MCP fails
|
|
1987
|
-
mcpLogger.warn(`[${functionTag}] MCP streaming failed, falling back to regular`, {
|
|
1988
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1989
|
-
});
|
|
1990
|
-
// Initialize conversation memory for fallback path (same as success path)
|
|
1991
|
-
if (this.conversationMemory) {
|
|
1992
|
-
await this.conversationMemory.initialize();
|
|
1993
|
-
}
|
|
1994
|
-
// Get conversation messages for fallback context injection
|
|
1995
|
-
const fallbackConversationMessages = await getConversationMessages(this.conversationMemory, {
|
|
1996
|
-
prompt: options.input.text,
|
|
1997
|
-
context: enhancedOptions.context,
|
|
1998
|
-
});
|
|
1999
|
-
// Use factory to create provider without MCP
|
|
2000
|
-
const provider = await AIProviderFactory.createBestProvider(providerName, options.model, false, // Disable MCP for fallback
|
|
2001
|
-
this);
|
|
2002
|
-
// Enable tool execution for fallback streaming using BaseProvider method
|
|
2003
|
-
provider.setupToolExecutor({
|
|
2004
|
-
customTools: this.getCustomTools(),
|
|
2005
|
-
executeTool: this.executeTool.bind(this),
|
|
2006
|
-
}, functionTag);
|
|
2007
|
-
// Create clean options for fallback provider and inject conversation history
|
|
2008
|
-
const cleanOptions = createCleanStreamOptions(enhancedOptions);
|
|
2009
|
-
const fallbackOptionsWithHistory = {
|
|
2010
|
-
...cleanOptions,
|
|
2011
|
-
conversationMessages: fallbackConversationMessages, // Inject conversation history in fallback
|
|
2012
|
-
};
|
|
2013
|
-
const streamResult = await provider.stream(fallbackOptionsWithHistory);
|
|
2014
|
-
// Create a proper tee pattern for fallback that accumulates content and stores memory after consumption
|
|
2015
|
-
let fallbackAccumulatedContent = "";
|
|
2016
|
-
const fallbackProcessedStream = (async function* (self) {
|
|
2017
|
-
try {
|
|
2018
|
-
for await (const chunk of streamResult.stream) {
|
|
2019
|
-
if (chunk && typeof chunk.content === "string") {
|
|
2020
|
-
fallbackAccumulatedContent += chunk.content;
|
|
2021
|
-
}
|
|
2022
|
-
yield chunk; // Preserve original streaming behavior
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
finally {
|
|
2026
|
-
// Store memory after fallback stream consumption
|
|
2027
|
-
if (self.conversationMemory) {
|
|
2028
|
-
try {
|
|
2029
|
-
await self.conversationMemory.storeConversationTurn(enhancedOptions.context
|
|
2030
|
-
?.sessionId, enhancedOptions.context
|
|
2031
|
-
?.userId, options.input.text, fallbackAccumulatedContent);
|
|
2032
|
-
logger.debug("Fallback stream conversation turn stored", {
|
|
2033
|
-
sessionId: enhancedOptions.context
|
|
2034
|
-
?.sessionId,
|
|
2035
|
-
userInputLength: options.input.text.length,
|
|
2036
|
-
responseLength: fallbackAccumulatedContent.length,
|
|
2037
|
-
});
|
|
2038
|
-
}
|
|
2039
|
-
catch (error) {
|
|
2040
|
-
logger.warn("Failed to store fallback stream conversation turn", {
|
|
2041
|
-
error: error instanceof Error ? error.message : String(error),
|
|
2042
|
-
});
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
})(this);
|
|
2047
|
-
const responseTime = Date.now() - startTime;
|
|
2048
|
-
// Emit stream completion event for fallback
|
|
2049
|
-
this.emitter.emit("stream:end", {
|
|
2050
|
-
provider: providerName,
|
|
1834
|
+
this.emitter.emit("response:start");
|
|
1835
|
+
this.emitter.emit("message", `Starting ${options.provider || "auto"} stream...`);
|
|
1836
|
+
}
|
|
1837
|
+
/**
|
|
1838
|
+
* Create MCP stream
|
|
1839
|
+
*/
|
|
1840
|
+
async createMCPStream(options) {
|
|
1841
|
+
// Simplified placeholder - in the actual implementation this would contain the complex MCP stream logic
|
|
1842
|
+
const providerName = await getBestProvider(options.provider);
|
|
1843
|
+
const provider = await AIProviderFactory.createProvider(providerName, options.model, !options.disableTools, // Pass disableTools as inverse of enableMCP
|
|
1844
|
+
this);
|
|
1845
|
+
// Enable tool execution for the provider using BaseProvider method
|
|
1846
|
+
provider.setupToolExecutor({
|
|
1847
|
+
customTools: this.getCustomTools(),
|
|
1848
|
+
executeTool: this.executeTool.bind(this),
|
|
1849
|
+
}, "NeuroLink.createMCPStream");
|
|
1850
|
+
const streamResult = await provider.stream(options);
|
|
1851
|
+
return { stream: streamResult.stream, provider: providerName };
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* Process stream result
|
|
1855
|
+
*/
|
|
1856
|
+
async processStreamResult(_stream, _options, _factoryResult) {
|
|
1857
|
+
// Simplified placeholder - in the actual implementation this would process the stream
|
|
1858
|
+
return {
|
|
1859
|
+
content: "",
|
|
1860
|
+
usage: undefined,
|
|
1861
|
+
finishReason: "stop",
|
|
1862
|
+
toolCalls: [],
|
|
1863
|
+
toolResults: [],
|
|
1864
|
+
analytics: undefined,
|
|
1865
|
+
evaluation: undefined,
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Emit stream end events
|
|
1870
|
+
*/
|
|
1871
|
+
emitStreamEndEvents(streamResult) {
|
|
1872
|
+
this.emitter.emit("stream:end", {
|
|
1873
|
+
responseTime: Date.now(),
|
|
1874
|
+
timestamp: Date.now(),
|
|
1875
|
+
});
|
|
1876
|
+
this.emitter.emit("response:end", streamResult.content || "");
|
|
1877
|
+
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Create stream response
|
|
1880
|
+
*/
|
|
1881
|
+
createStreamResponse(streamResult, stream, config) {
|
|
1882
|
+
return {
|
|
1883
|
+
stream,
|
|
1884
|
+
provider: config.providerName,
|
|
1885
|
+
model: config.options.model,
|
|
1886
|
+
usage: streamResult.usage,
|
|
1887
|
+
finishReason: streamResult.finishReason,
|
|
1888
|
+
toolCalls: streamResult.toolCalls,
|
|
1889
|
+
toolResults: streamResult.toolResults,
|
|
1890
|
+
analytics: streamResult.analytics,
|
|
1891
|
+
evaluation: streamResult.evaluation,
|
|
1892
|
+
metadata: {
|
|
1893
|
+
streamId: config.streamId,
|
|
1894
|
+
startTime: config.startTime,
|
|
1895
|
+
responseTime: config.responseTime,
|
|
1896
|
+
fallback: config.fallback || false,
|
|
1897
|
+
},
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Handle stream error with fallback
|
|
1902
|
+
*/
|
|
1903
|
+
async handleStreamError(error, options, startTime, streamId, _enhancedOptions, _factoryResult) {
|
|
1904
|
+
logger.error("Stream generation failed, attempting fallback", {
|
|
1905
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1906
|
+
});
|
|
1907
|
+
const responseTime = Date.now() - startTime;
|
|
1908
|
+
const providerName = await getBestProvider(options.provider);
|
|
1909
|
+
const provider = await AIProviderFactory.createProvider(providerName, options.model, false);
|
|
1910
|
+
const fallbackStream = await provider.stream({
|
|
1911
|
+
input: { text: options.input.text },
|
|
1912
|
+
model: options.model,
|
|
1913
|
+
temperature: options.temperature,
|
|
1914
|
+
maxTokens: options.maxTokens,
|
|
1915
|
+
});
|
|
1916
|
+
return {
|
|
1917
|
+
stream: fallbackStream.stream,
|
|
1918
|
+
provider: providerName,
|
|
1919
|
+
model: options.model,
|
|
1920
|
+
usage: fallbackStream.usage,
|
|
1921
|
+
finishReason: fallbackStream.finishReason || "stop",
|
|
1922
|
+
toolCalls: fallbackStream.toolCalls || [],
|
|
1923
|
+
toolResults: fallbackStream.toolResults || [],
|
|
1924
|
+
analytics: fallbackStream.analytics,
|
|
1925
|
+
evaluation: fallbackStream.evaluation,
|
|
1926
|
+
metadata: {
|
|
1927
|
+
streamId,
|
|
1928
|
+
startTime,
|
|
2051
1929
|
responseTime,
|
|
2052
1930
|
fallback: true,
|
|
2053
|
-
}
|
|
2054
|
-
|
|
2055
|
-
stream: fallbackProcessedStream,
|
|
2056
|
-
provider: providerName,
|
|
2057
|
-
model: options.model,
|
|
2058
|
-
usage: streamResult.usage,
|
|
2059
|
-
finishReason: streamResult.finishReason,
|
|
2060
|
-
toolCalls: streamResult.toolCalls,
|
|
2061
|
-
toolResults: streamResult.toolResults,
|
|
2062
|
-
analytics: streamResult.analytics,
|
|
2063
|
-
evaluation: streamResult.evaluation
|
|
2064
|
-
? {
|
|
2065
|
-
...streamResult.evaluation,
|
|
2066
|
-
// Include evaluationDomain in fallback stream
|
|
2067
|
-
evaluationDomain: streamResult.evaluation
|
|
2068
|
-
?.evaluationDomain ??
|
|
2069
|
-
enhancedOptions.evaluationDomain ??
|
|
2070
|
-
factoryResult.domainType,
|
|
2071
|
-
}
|
|
2072
|
-
: undefined,
|
|
2073
|
-
metadata: {
|
|
2074
|
-
streamId: `neurolink-${Date.now()}`,
|
|
2075
|
-
startTime,
|
|
2076
|
-
responseTime,
|
|
2077
|
-
fallback: true,
|
|
2078
|
-
},
|
|
2079
|
-
};
|
|
2080
|
-
}
|
|
1931
|
+
},
|
|
1932
|
+
};
|
|
2081
1933
|
}
|
|
2082
1934
|
/**
|
|
2083
1935
|
* Get the EventEmitter instance to listen to NeuroLink events for real-time monitoring and debugging.
|
|
@@ -2271,7 +2123,7 @@ export class NeuroLink {
|
|
|
2271
2123
|
timestamp: Date.now(),
|
|
2272
2124
|
});
|
|
2273
2125
|
try {
|
|
2274
|
-
// --- Start:
|
|
2126
|
+
// --- Start: Enhanced Validation Logic with FlexibleToolValidator ---
|
|
2275
2127
|
if (!name || typeof name !== "string") {
|
|
2276
2128
|
throw new Error("Invalid tool name");
|
|
2277
2129
|
}
|
|
@@ -2281,55 +2133,36 @@ export class NeuroLink {
|
|
|
2281
2133
|
if (typeof tool.execute !== "function") {
|
|
2282
2134
|
throw new Error(`Tool '${name}' must have an execute method.`);
|
|
2283
2135
|
}
|
|
2284
|
-
//
|
|
2285
|
-
// Import validation functions synchronously - they are pure functions
|
|
2286
|
-
let validateTool;
|
|
2287
|
-
let isToolNameAvailable;
|
|
2288
|
-
let suggestToolNames;
|
|
2136
|
+
// Use FlexibleToolValidator for consistent validation across SDK and toolRegistry
|
|
2289
2137
|
try {
|
|
2290
|
-
|
|
2291
|
-
const
|
|
2292
|
-
|
|
2293
|
-
|
|
2138
|
+
const flexibleValidatorModule = require("./mcp/flexibleToolValidator.js");
|
|
2139
|
+
const FlexibleToolValidator = flexibleValidatorModule.FlexibleToolValidator;
|
|
2140
|
+
// Use the same validation logic as toolRegistry (static method)
|
|
2141
|
+
const validationResult = FlexibleToolValidator.validateToolName(name);
|
|
2142
|
+
if (!validationResult.isValid) {
|
|
2143
|
+
throw new Error(`Tool validation failed: ${validationResult.error}`);
|
|
2144
|
+
}
|
|
2294
2145
|
}
|
|
2295
2146
|
catch (error) {
|
|
2296
|
-
//
|
|
2297
|
-
logger.warn("
|
|
2147
|
+
// If FlexibleToolValidator import fails, use basic safety checks
|
|
2148
|
+
logger.warn("FlexibleToolValidator not available, using basic validation", {
|
|
2298
2149
|
error: error instanceof Error ? error.message : String(error),
|
|
2299
2150
|
});
|
|
2300
|
-
//
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
// Create a simplified tool object for validation
|
|
2312
|
-
const toolForValidation = {
|
|
2313
|
-
description: tool.description || "",
|
|
2314
|
-
execute: async (params) => {
|
|
2315
|
-
if (tool.execute) {
|
|
2316
|
-
const result = await tool.execute(params);
|
|
2317
|
-
return result;
|
|
2318
|
-
}
|
|
2319
|
-
return "";
|
|
2320
|
-
},
|
|
2321
|
-
parameters: tool.inputSchema,
|
|
2322
|
-
metadata: {
|
|
2323
|
-
category: "custom",
|
|
2324
|
-
},
|
|
2325
|
-
};
|
|
2326
|
-
// Use comprehensive validation logic
|
|
2327
|
-
try {
|
|
2328
|
-
validateTool(name, toolForValidation);
|
|
2329
|
-
}
|
|
2330
|
-
catch (error) {
|
|
2331
|
-
throw new Error(`Tool registration failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2151
|
+
// Basic safety checks to prevent obvious issues
|
|
2152
|
+
if (name.trim() === "") {
|
|
2153
|
+
throw new Error("Tool name cannot be empty");
|
|
2154
|
+
}
|
|
2155
|
+
if (name.length > 100) {
|
|
2156
|
+
throw new Error("Tool name is too long (maximum 100 characters)");
|
|
2157
|
+
}
|
|
2158
|
+
// eslint-disable-next-line no-control-regex
|
|
2159
|
+
if (/[\x00-\x1F\x7F]/.test(name)) {
|
|
2160
|
+
throw new Error("Tool name contains invalid control characters");
|
|
2161
|
+
}
|
|
2332
2162
|
}
|
|
2163
|
+
// --- End: Enhanced Validation Logic ---
|
|
2164
|
+
// Tool object validation is now handled by FlexibleToolValidator above
|
|
2165
|
+
// Proceed with tool registration since validation passed
|
|
2333
2166
|
// SMART DEFAULTS: Use utility to eliminate boilerplate creation
|
|
2334
2167
|
const mcpServerInfo = createCustomToolServerInfo(name, tool);
|
|
2335
2168
|
// Register with toolRegistry using MCPServerInfo directly
|
|
@@ -2489,11 +2322,14 @@ export class NeuroLink {
|
|
|
2489
2322
|
: params,
|
|
2490
2323
|
hasExternalManager: !!this.externalServerManager,
|
|
2491
2324
|
});
|
|
2492
|
-
// Emit tool start event
|
|
2325
|
+
// Emit tool start event (NeuroLink format - keep existing)
|
|
2493
2326
|
this.emitter.emit("tool:start", {
|
|
2494
2327
|
toolName,
|
|
2495
2328
|
timestamp: executionStartTime,
|
|
2329
|
+
input: params, // Enhanced: add input parameters
|
|
2496
2330
|
});
|
|
2331
|
+
// ADD: Bedrock-compatible tool:start event (positional parameters)
|
|
2332
|
+
this.emitter.emit("tool:start", toolName, params);
|
|
2497
2333
|
// Set default options
|
|
2498
2334
|
const finalOptions = {
|
|
2499
2335
|
timeout: options?.timeout || 30000, // 30 second default timeout
|
|
@@ -2519,15 +2355,20 @@ export class NeuroLink {
|
|
|
2519
2355
|
});
|
|
2520
2356
|
}
|
|
2521
2357
|
const metrics = this.toolExecutionMetrics.get(toolName);
|
|
2522
|
-
metrics
|
|
2358
|
+
if (metrics) {
|
|
2359
|
+
metrics.totalExecutions++;
|
|
2360
|
+
}
|
|
2523
2361
|
try {
|
|
2524
2362
|
mcpLogger.debug(`[${functionTag}] Executing tool: ${toolName}`, {
|
|
2525
2363
|
toolName,
|
|
2526
2364
|
params,
|
|
2527
2365
|
options: finalOptions,
|
|
2528
|
-
circuitBreakerState: circuitBreaker
|
|
2366
|
+
circuitBreakerState: circuitBreaker?.getState(),
|
|
2529
2367
|
});
|
|
2530
2368
|
// Execute with circuit breaker, timeout, and retry logic
|
|
2369
|
+
if (!circuitBreaker) {
|
|
2370
|
+
throw new Error(`Circuit breaker not initialized for tool: ${toolName}`);
|
|
2371
|
+
}
|
|
2531
2372
|
const result = await circuitBreaker.execute(async () => {
|
|
2532
2373
|
return await withRetry(async () => {
|
|
2533
2374
|
return await withTimeout(this.executeToolInternal(toolName, params, finalOptions), finalOptions.timeout, ErrorFactory.toolTimeout(toolName, finalOptions.timeout));
|
|
@@ -2546,12 +2387,14 @@ export class NeuroLink {
|
|
|
2546
2387
|
});
|
|
2547
2388
|
// Update success metrics
|
|
2548
2389
|
const executionTime = Date.now() - executionStartTime;
|
|
2549
|
-
metrics
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2390
|
+
if (metrics) {
|
|
2391
|
+
metrics.successfulExecutions++;
|
|
2392
|
+
metrics.lastExecutionTime = executionTime;
|
|
2393
|
+
metrics.averageExecutionTime =
|
|
2394
|
+
(metrics.averageExecutionTime * (metrics.successfulExecutions - 1) +
|
|
2395
|
+
executionTime) /
|
|
2396
|
+
metrics.successfulExecutions;
|
|
2397
|
+
}
|
|
2555
2398
|
// Track memory usage
|
|
2556
2399
|
const endMemory = MemoryManager.getMemoryUsageMB();
|
|
2557
2400
|
const memoryDelta = endMemory.heapUsed - startMemory.heapUsed;
|
|
@@ -2566,15 +2409,17 @@ export class NeuroLink {
|
|
|
2566
2409
|
toolName,
|
|
2567
2410
|
executionTime,
|
|
2568
2411
|
memoryDelta,
|
|
2569
|
-
circuitBreakerState: circuitBreaker
|
|
2412
|
+
circuitBreakerState: circuitBreaker?.getState(),
|
|
2570
2413
|
});
|
|
2571
2414
|
// Emit tool end event using the helper method
|
|
2572
|
-
this.emitToolEndEvent(toolName, executionStartTime, true);
|
|
2415
|
+
this.emitToolEndEvent(toolName, executionStartTime, true, result);
|
|
2573
2416
|
return result;
|
|
2574
2417
|
}
|
|
2575
2418
|
catch (error) {
|
|
2576
2419
|
// Update failure metrics
|
|
2577
|
-
metrics
|
|
2420
|
+
if (metrics) {
|
|
2421
|
+
metrics.failedExecutions++;
|
|
2422
|
+
}
|
|
2578
2423
|
const executionTime = Date.now() - executionStartTime;
|
|
2579
2424
|
// Create structured error
|
|
2580
2425
|
let structuredError;
|
|
@@ -2605,8 +2450,10 @@ export class NeuroLink {
|
|
|
2605
2450
|
else {
|
|
2606
2451
|
structuredError = ErrorFactory.toolExecutionFailed(toolName, new Error(String(error)));
|
|
2607
2452
|
}
|
|
2453
|
+
// ADD: Centralized error event emission
|
|
2454
|
+
this.emitter.emit("error", structuredError);
|
|
2608
2455
|
// Emit tool end event using the helper method
|
|
2609
|
-
this.emitToolEndEvent(toolName, executionStartTime, false);
|
|
2456
|
+
this.emitToolEndEvent(toolName, executionStartTime, false, undefined, structuredError);
|
|
2610
2457
|
// Add execution context to structured error
|
|
2611
2458
|
structuredError = new NeuroLinkError({
|
|
2612
2459
|
...structuredError,
|
|
@@ -2615,8 +2462,8 @@ export class NeuroLink {
|
|
|
2615
2462
|
executionTime,
|
|
2616
2463
|
params,
|
|
2617
2464
|
options: finalOptions,
|
|
2618
|
-
circuitBreakerState: circuitBreaker
|
|
2619
|
-
circuitBreakerFailures: circuitBreaker
|
|
2465
|
+
circuitBreakerState: circuitBreaker?.getState(),
|
|
2466
|
+
circuitBreakerFailures: circuitBreaker?.getFailureCount(),
|
|
2620
2467
|
metrics: { ...metrics },
|
|
2621
2468
|
},
|
|
2622
2469
|
});
|
|
@@ -2667,9 +2514,21 @@ export class NeuroLink {
|
|
|
2667
2514
|
userId: "neurolink-user",
|
|
2668
2515
|
};
|
|
2669
2516
|
const result = (await toolRegistry.executeTool(toolName, params, context));
|
|
2517
|
+
// ADD: Check if result indicates a failure and emit error event
|
|
2518
|
+
if (result &&
|
|
2519
|
+
typeof result === "object" &&
|
|
2520
|
+
"success" in result &&
|
|
2521
|
+
result.success === false) {
|
|
2522
|
+
const errorMessage = result.error || "Tool execution failed";
|
|
2523
|
+
const errorToEmit = new Error(errorMessage);
|
|
2524
|
+
this.emitter.emit("error", errorToEmit);
|
|
2525
|
+
}
|
|
2670
2526
|
return result;
|
|
2671
2527
|
}
|
|
2672
2528
|
catch (error) {
|
|
2529
|
+
// ADD: Emergency error event emission (fallback)
|
|
2530
|
+
const errorToEmit = error instanceof Error ? error : new Error(String(error));
|
|
2531
|
+
this.emitter.emit("error", errorToEmit);
|
|
2673
2532
|
// Check if tool was not found
|
|
2674
2533
|
if (error instanceof Error && error.message.includes("not found")) {
|
|
2675
2534
|
const availableTools = await this.getAllAvailableTools();
|
|
@@ -2841,6 +2700,9 @@ export class NeuroLink {
|
|
|
2841
2700
|
}
|
|
2842
2701
|
const { AIProviderFactory } = await import("./core/factory.js");
|
|
2843
2702
|
const { hasProviderEnvVars } = await import("./utils/providerUtils.js");
|
|
2703
|
+
// Keep references to prevent unused variable warnings
|
|
2704
|
+
void AIProviderFactory;
|
|
2705
|
+
void hasProviderEnvVars;
|
|
2844
2706
|
const providers = [
|
|
2845
2707
|
"openai",
|
|
2846
2708
|
"bedrock",
|
|
@@ -3103,7 +2965,7 @@ export class NeuroLink {
|
|
|
3103
2965
|
const inMemoryServers = this.getInMemoryServers();
|
|
3104
2966
|
if (inMemoryServers.has(serverId)) {
|
|
3105
2967
|
const serverInfo = inMemoryServers.get(serverId);
|
|
3106
|
-
return !!(serverInfo
|
|
2968
|
+
return !!(serverInfo?.tools && serverInfo.tools.length > 0);
|
|
3107
2969
|
}
|
|
3108
2970
|
// Test external MCP servers
|
|
3109
2971
|
const externalServer = this.externalServerManager.getServer(serverId);
|
|
@@ -3610,7 +3472,7 @@ export class NeuroLink {
|
|
|
3610
3472
|
* Convert JSON Schema to AI SDK compatible format
|
|
3611
3473
|
* For now, we'll skip schema validation and let the AI SDK handle parameters dynamically
|
|
3612
3474
|
*/
|
|
3613
|
-
convertJSONSchemaToAISDKFormat(
|
|
3475
|
+
convertJSONSchemaToAISDKFormat(_inputSchema) {
|
|
3614
3476
|
// The simplest approach: don't provide parameters schema
|
|
3615
3477
|
// This lets the AI SDK handle the tool without schema validation
|
|
3616
3478
|
// Tools will still work, they just won't have strict parameter validation
|