@juspay/neurolink 7.29.0 → 7.29.2
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 +3 -3
- package/dist/cli/commands/mcp.js +25 -0
- package/dist/cli/factories/commandFactory.d.ts +1 -0
- package/dist/cli/factories/commandFactory.js +115 -21
- package/dist/cli/index.js +8 -0
- package/dist/core/factory.js +77 -4
- package/dist/factories/providerFactory.js +3 -0
- package/dist/factories/providerRegistry.js +2 -2
- package/dist/lib/core/factory.js +77 -4
- package/dist/lib/factories/providerFactory.js +3 -0
- package/dist/lib/factories/providerRegistry.js +2 -2
- package/dist/lib/mcp/externalServerManager.js +13 -14
- package/dist/lib/mcp/flexibleToolValidator.d.ts +50 -0
- package/dist/lib/mcp/flexibleToolValidator.js +161 -0
- package/dist/lib/mcp/toolRegistry.d.ts +2 -2
- package/dist/lib/mcp/toolRegistry.js +25 -50
- package/dist/lib/neurolink.d.ts +299 -4
- package/dist/lib/neurolink.js +434 -73
- package/dist/lib/providers/amazonBedrock.d.ts +47 -6
- package/dist/lib/providers/amazonBedrock.js +282 -23
- 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/googleVertex.js +13 -4
- 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/types/providers.d.ts +43 -0
- package/dist/lib/utils/providerConfig.d.ts +1 -0
- package/dist/lib/utils/providerConfig.js +2 -1
- package/dist/lib/utils/providerHealth.js +123 -5
- package/dist/mcp/externalServerManager.js +13 -14
- package/dist/mcp/flexibleToolValidator.d.ts +50 -0
- package/dist/mcp/flexibleToolValidator.js +161 -0
- package/dist/mcp/toolRegistry.d.ts +2 -2
- package/dist/mcp/toolRegistry.js +25 -50
- package/dist/neurolink.d.ts +299 -4
- package/dist/neurolink.js +434 -73
- package/dist/providers/amazonBedrock.d.ts +47 -6
- package/dist/providers/amazonBedrock.js +282 -23
- 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/googleVertex.js +13 -4
- 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/types/providers.d.ts +43 -0
- package/dist/utils/providerConfig.d.ts +1 -0
- package/dist/utils/providerConfig.js +2 -1
- package/dist/utils/providerHealth.js +123 -5
- package/package.json +5 -1
package/dist/neurolink.js
CHANGED
|
@@ -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,17 +55,52 @@ 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;
|
|
76
|
+
/**
|
|
77
|
+
* Creates a new NeuroLink instance for AI text generation with MCP tool integration.
|
|
78
|
+
*
|
|
79
|
+
* @param config - Optional configuration object
|
|
80
|
+
* @param config.conversationMemory - Configuration for conversation memory features
|
|
81
|
+
* @param config.conversationMemory.enabled - Whether to enable conversation memory (default: false)
|
|
82
|
+
* @param config.conversationMemory.maxSessions - Maximum number of concurrent sessions (default: 100)
|
|
83
|
+
* @param config.conversationMemory.maxTurnsPerSession - Maximum conversation turns per session (default: 50)
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* // Basic usage
|
|
88
|
+
* const neurolink = new NeuroLink();
|
|
89
|
+
*
|
|
90
|
+
* // With conversation memory
|
|
91
|
+
* const neurolink = new NeuroLink({
|
|
92
|
+
* conversationMemory: {
|
|
93
|
+
* enabled: true,
|
|
94
|
+
* maxSessions: 50,
|
|
95
|
+
* maxTurnsPerSession: 20
|
|
96
|
+
* }
|
|
97
|
+
* });
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @throws {Error} When provider registry setup fails
|
|
101
|
+
* @throws {Error} When conversation memory initialization fails (if enabled)
|
|
102
|
+
* @throws {Error} When external server manager initialization fails
|
|
103
|
+
*/
|
|
68
104
|
constructor(config) {
|
|
69
105
|
// 🚀 EXHAUSTIVE LOGGING POINT C001: CONSTRUCTOR ENTRY
|
|
70
106
|
const constructorStartTime = Date.now();
|
|
@@ -724,6 +760,54 @@ export class NeuroLink {
|
|
|
724
760
|
this.contextManager = new ContextManager(this.generateTextInternal.bind(this), contextConfig);
|
|
725
761
|
logger.info("[NeuroLink] Automatic context summarization enabled.");
|
|
726
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* Generate AI content using the best available provider with MCP tool integration.
|
|
765
|
+
* This is the primary method for text generation with full feature support.
|
|
766
|
+
*
|
|
767
|
+
* @param optionsOrPrompt - Either a string prompt or a comprehensive GenerateOptions object
|
|
768
|
+
* @param optionsOrPrompt.input - Input configuration object
|
|
769
|
+
* @param optionsOrPrompt.input.text - The text prompt to send to the AI (required)
|
|
770
|
+
* @param optionsOrPrompt.provider - AI provider to use ('auto', 'openai', 'anthropic', etc.)
|
|
771
|
+
* @param optionsOrPrompt.model - Specific model to use (e.g., 'gpt-4', 'claude-3-opus')
|
|
772
|
+
* @param optionsOrPrompt.temperature - Randomness in response (0.0 = deterministic, 2.0 = very random)
|
|
773
|
+
* @param optionsOrPrompt.maxTokens - Maximum tokens in response
|
|
774
|
+
* @param optionsOrPrompt.systemPrompt - System message to set AI behavior
|
|
775
|
+
* @param optionsOrPrompt.disableTools - Whether to disable MCP tool usage
|
|
776
|
+
* @param optionsOrPrompt.enableAnalytics - Whether to include usage analytics
|
|
777
|
+
* @param optionsOrPrompt.enableEvaluation - Whether to include response quality evaluation
|
|
778
|
+
* @param optionsOrPrompt.context - Additional context for the request
|
|
779
|
+
* @param optionsOrPrompt.evaluationDomain - Domain for specialized evaluation
|
|
780
|
+
* @param optionsOrPrompt.toolUsageContext - Context for tool usage decisions
|
|
781
|
+
*
|
|
782
|
+
* @returns Promise resolving to GenerateResult with content, usage data, and optional analytics
|
|
783
|
+
*
|
|
784
|
+
* @example
|
|
785
|
+
* ```typescript
|
|
786
|
+
* // Simple usage with string prompt
|
|
787
|
+
* const result = await neurolink.generate("What is artificial intelligence?");
|
|
788
|
+
* console.log(result.content);
|
|
789
|
+
*
|
|
790
|
+
* // Advanced usage with options
|
|
791
|
+
* const result = await neurolink.generate({
|
|
792
|
+
* input: { text: "Explain quantum computing" },
|
|
793
|
+
* provider: "openai",
|
|
794
|
+
* model: "gpt-4",
|
|
795
|
+
* temperature: 0.7,
|
|
796
|
+
* maxTokens: 500,
|
|
797
|
+
* enableAnalytics: true,
|
|
798
|
+
* enableEvaluation: true,
|
|
799
|
+
* context: { domain: "science", level: "intermediate" }
|
|
800
|
+
* });
|
|
801
|
+
*
|
|
802
|
+
* // Access analytics and evaluation data
|
|
803
|
+
* console.log(result.analytics?.usage);
|
|
804
|
+
* console.log(result.evaluation?.relevance);
|
|
805
|
+
* ```
|
|
806
|
+
*
|
|
807
|
+
* @throws {Error} When input text is missing or invalid
|
|
808
|
+
* @throws {Error} When all providers fail to generate content
|
|
809
|
+
* @throws {Error} When conversation memory operations fail (if enabled)
|
|
810
|
+
*/
|
|
727
811
|
async generate(optionsOrPrompt) {
|
|
728
812
|
const originalPrompt = this._extractOriginalPrompt(optionsOrPrompt);
|
|
729
813
|
// Convert string prompt to full options
|
|
@@ -740,11 +824,15 @@ export class NeuroLink {
|
|
|
740
824
|
options.input.text = this.contextManager.getContextForPrompt("user", options.input.text);
|
|
741
825
|
}
|
|
742
826
|
const startTime = Date.now();
|
|
743
|
-
// Emit generation start event
|
|
827
|
+
// Emit generation start event (NeuroLink format - keep existing)
|
|
744
828
|
this.emitter.emit("generation:start", {
|
|
745
829
|
provider: options.provider || "auto",
|
|
746
830
|
timestamp: startTime,
|
|
747
831
|
});
|
|
832
|
+
// ADD: Bedrock-compatible response:start event
|
|
833
|
+
this.emitter.emit("response:start");
|
|
834
|
+
// ADD: Bedrock-compatible message event
|
|
835
|
+
this.emitter.emit("message", `Starting ${options.provider || "auto"} text generation...`);
|
|
748
836
|
// Process factory configuration
|
|
749
837
|
const factoryResult = processFactoryOptions(options);
|
|
750
838
|
// Validate factory configuration if present
|
|
@@ -787,13 +875,18 @@ export class NeuroLink {
|
|
|
787
875
|
}
|
|
788
876
|
// Use redesigned generation logic
|
|
789
877
|
const textResult = await this.generateTextInternal(textOptions);
|
|
790
|
-
// Emit generation completion event
|
|
878
|
+
// Emit generation completion event (NeuroLink format - enhanced with content)
|
|
791
879
|
this.emitter.emit("generation:end", {
|
|
792
880
|
provider: textResult.provider,
|
|
793
881
|
responseTime: Date.now() - startTime,
|
|
794
882
|
toolsUsed: textResult.toolsUsed,
|
|
795
883
|
timestamp: Date.now(),
|
|
884
|
+
result: textResult, // Enhanced: include full result
|
|
796
885
|
});
|
|
886
|
+
// ADD: Bedrock-compatible response:end event with content
|
|
887
|
+
this.emitter.emit("response:end", textResult.content || "");
|
|
888
|
+
// ADD: Bedrock-compatible message event
|
|
889
|
+
this.emitter.emit("message", `Generation completed in ${Date.now() - startTime}ms`);
|
|
797
890
|
// Convert back to GenerateResult
|
|
798
891
|
const generateResult = {
|
|
799
892
|
content: textResult.content,
|
|
@@ -926,6 +1019,10 @@ export class NeuroLink {
|
|
|
926
1019
|
promptLength: options.prompt?.length || 0,
|
|
927
1020
|
hasConversationMemory: !!this.conversationMemory,
|
|
928
1021
|
});
|
|
1022
|
+
// ADD: Bedrock-compatible response:start event for generateTextInternal
|
|
1023
|
+
this.emitter.emit("response:start");
|
|
1024
|
+
// ADD: Bedrock-compatible message event for generateTextInternal
|
|
1025
|
+
this.emitter.emit("message", `Starting ${options.provider || "auto"} text generation (internal)...`);
|
|
929
1026
|
try {
|
|
930
1027
|
// 🚀 EXHAUSTIVE LOGGING POINT G002: CONVERSATION MEMORY INITIALIZATION
|
|
931
1028
|
const conversationMemoryStartTime = process.hrtime.bigint();
|
|
@@ -1072,6 +1169,8 @@ export class NeuroLink {
|
|
|
1072
1169
|
});
|
|
1073
1170
|
// Store conversation turn
|
|
1074
1171
|
await storeConversationTurn(this.conversationMemory, options, mcpResult);
|
|
1172
|
+
// ADD: Bedrock-compatible response:end event for MCP success path
|
|
1173
|
+
this.emitter.emit("response:end", mcpResult.content || "");
|
|
1075
1174
|
return mcpResult;
|
|
1076
1175
|
}
|
|
1077
1176
|
else {
|
|
@@ -1088,6 +1187,8 @@ export class NeuroLink {
|
|
|
1088
1187
|
logger.debug(`[${functionTag}] Found tool executions but no content, continuing with result`);
|
|
1089
1188
|
// Store conversation turn even with empty content if tools executed
|
|
1090
1189
|
await storeConversationTurn(this.conversationMemory, options, mcpResult);
|
|
1190
|
+
// ADD: Bedrock-compatible response:end event for MCP tool execution success path
|
|
1191
|
+
this.emitter.emit("response:end", mcpResult.content || "");
|
|
1091
1192
|
return mcpResult;
|
|
1092
1193
|
}
|
|
1093
1194
|
}
|
|
@@ -1112,12 +1213,20 @@ export class NeuroLink {
|
|
|
1112
1213
|
logger.debug(`[${functionTag}] Direct generation successful`);
|
|
1113
1214
|
// Store conversation turn
|
|
1114
1215
|
await storeConversationTurn(this.conversationMemory, options, directResult);
|
|
1216
|
+
// ADD: Bedrock-compatible response:end event for generateTextInternal
|
|
1217
|
+
this.emitter.emit("response:end", directResult.content || "");
|
|
1218
|
+
// ADD: Bedrock-compatible message event for generateTextInternal completion
|
|
1219
|
+
this.emitter.emit("message", `Text generation completed successfully`);
|
|
1115
1220
|
return directResult;
|
|
1116
1221
|
}
|
|
1117
1222
|
catch (error) {
|
|
1118
1223
|
logger.error(`[${functionTag}] All generation methods failed`, {
|
|
1119
1224
|
error: error instanceof Error ? error.message : String(error),
|
|
1120
1225
|
});
|
|
1226
|
+
// ADD: Bedrock-compatible response:end event for error path (empty content)
|
|
1227
|
+
this.emitter.emit("response:end", "");
|
|
1228
|
+
// ADD: Centralized error event emission
|
|
1229
|
+
this.emitter.emit("error", error instanceof Error ? error : new Error(String(error)));
|
|
1121
1230
|
throw error;
|
|
1122
1231
|
}
|
|
1123
1232
|
}
|
|
@@ -1223,6 +1332,9 @@ export class NeuroLink {
|
|
|
1223
1332
|
// Create provider and generate
|
|
1224
1333
|
const provider = await AIProviderFactory.createProvider(providerName, options.model, !options.disableTools, // Pass disableTools as inverse of enableMCP
|
|
1225
1334
|
this);
|
|
1335
|
+
// ADD: Emit connection events for all providers (Bedrock-compatible)
|
|
1336
|
+
this.emitter.emit("connected");
|
|
1337
|
+
this.emitter.emit("message", `${providerName} provider initialized successfully`);
|
|
1226
1338
|
// Enable tool execution for the provider using BaseProvider method
|
|
1227
1339
|
provider.setupToolExecutor({
|
|
1228
1340
|
customTools: this.getCustomTools(),
|
|
@@ -1317,6 +1429,9 @@ export class NeuroLink {
|
|
|
1317
1429
|
const conversationMessages = await getConversationMessages(this.conversationMemory, options);
|
|
1318
1430
|
const provider = await AIProviderFactory.createProvider(providerName, options.model, !options.disableTools, // Pass disableTools as inverse of enableMCP
|
|
1319
1431
|
this);
|
|
1432
|
+
// ADD: Emit connection events for successful provider creation (Bedrock-compatible)
|
|
1433
|
+
this.emitter.emit("connected");
|
|
1434
|
+
this.emitter.emit("message", `${providerName} provider initialized successfully`);
|
|
1320
1435
|
// Enable tool execution for direct provider generation using BaseProvider method
|
|
1321
1436
|
provider.setupToolExecutor({
|
|
1322
1437
|
customTools: this.getCustomTools(),
|
|
@@ -1378,7 +1493,7 @@ export class NeuroLink {
|
|
|
1378
1493
|
* Execute tools if available through centralized registry
|
|
1379
1494
|
* Simplified approach without domain detection - relies on tool registry
|
|
1380
1495
|
*/
|
|
1381
|
-
async detectAndExecuteTools(prompt,
|
|
1496
|
+
async detectAndExecuteTools(prompt, _domainType) {
|
|
1382
1497
|
const functionTag = "NeuroLink.detectAndExecuteTools";
|
|
1383
1498
|
try {
|
|
1384
1499
|
// Simplified: Just return original prompt without complex detection
|
|
@@ -1439,8 +1554,55 @@ export class NeuroLink {
|
|
|
1439
1554
|
return stringStream();
|
|
1440
1555
|
}
|
|
1441
1556
|
/**
|
|
1442
|
-
*
|
|
1443
|
-
*
|
|
1557
|
+
* Stream AI-generated content in real-time using the best available provider.
|
|
1558
|
+
* This method provides real-time streaming of AI responses with full MCP tool integration.
|
|
1559
|
+
*
|
|
1560
|
+
* @param options - Stream configuration options
|
|
1561
|
+
* @param options.input - Input configuration object
|
|
1562
|
+
* @param options.input.text - The text prompt to send to the AI (required)
|
|
1563
|
+
* @param options.provider - AI provider to use ('auto', 'openai', 'anthropic', etc.)
|
|
1564
|
+
* @param options.model - Specific model to use (e.g., 'gpt-4', 'claude-3-opus')
|
|
1565
|
+
* @param options.temperature - Randomness in response (0.0 = deterministic, 2.0 = very random)
|
|
1566
|
+
* @param options.maxTokens - Maximum tokens in response
|
|
1567
|
+
* @param options.systemPrompt - System message to set AI behavior
|
|
1568
|
+
* @param options.disableTools - Whether to disable MCP tool usage
|
|
1569
|
+
* @param options.enableAnalytics - Whether to include usage analytics
|
|
1570
|
+
* @param options.enableEvaluation - Whether to include response quality evaluation
|
|
1571
|
+
* @param options.context - Additional context for the request
|
|
1572
|
+
* @param options.evaluationDomain - Domain for specialized evaluation
|
|
1573
|
+
*
|
|
1574
|
+
* @returns Promise resolving to StreamResult with an async iterable stream
|
|
1575
|
+
*
|
|
1576
|
+
* @example
|
|
1577
|
+
* ```typescript
|
|
1578
|
+
* // Basic streaming usage
|
|
1579
|
+
* const result = await neurolink.stream({
|
|
1580
|
+
* input: { text: "Tell me a story about space exploration" }
|
|
1581
|
+
* });
|
|
1582
|
+
*
|
|
1583
|
+
* // Consume the stream
|
|
1584
|
+
* for await (const chunk of result.stream) {
|
|
1585
|
+
* process.stdout.write(chunk.content);
|
|
1586
|
+
* }
|
|
1587
|
+
*
|
|
1588
|
+
* // Advanced streaming with options
|
|
1589
|
+
* const result = await neurolink.stream({
|
|
1590
|
+
* input: { text: "Explain machine learning" },
|
|
1591
|
+
* provider: "openai",
|
|
1592
|
+
* model: "gpt-4",
|
|
1593
|
+
* temperature: 0.7,
|
|
1594
|
+
* enableAnalytics: true,
|
|
1595
|
+
* context: { domain: "education", audience: "beginners" }
|
|
1596
|
+
* });
|
|
1597
|
+
*
|
|
1598
|
+
* // Access metadata and analytics
|
|
1599
|
+
* console.log(result.provider);
|
|
1600
|
+
* console.log(result.analytics?.usage);
|
|
1601
|
+
* ```
|
|
1602
|
+
*
|
|
1603
|
+
* @throws {Error} When input text is missing or invalid
|
|
1604
|
+
* @throws {Error} When all providers fail to generate content
|
|
1605
|
+
* @throws {Error} When conversation memory operations fail (if enabled)
|
|
1444
1606
|
*/
|
|
1445
1607
|
async stream(options) {
|
|
1446
1608
|
const startTime = Date.now();
|
|
@@ -1546,7 +1708,7 @@ export class NeuroLink {
|
|
|
1546
1708
|
global.gc();
|
|
1547
1709
|
return process.memoryUsage();
|
|
1548
1710
|
}
|
|
1549
|
-
catch (
|
|
1711
|
+
catch (_e) {
|
|
1550
1712
|
return null;
|
|
1551
1713
|
}
|
|
1552
1714
|
})()
|
|
@@ -1684,11 +1846,15 @@ export class NeuroLink {
|
|
|
1684
1846
|
cpuAfterValidation: process.cpuUsage(),
|
|
1685
1847
|
message: "EXHAUSTIVE validation success - proceeding with stream processing",
|
|
1686
1848
|
});
|
|
1687
|
-
// Emit stream start event
|
|
1849
|
+
// Emit stream start event (NeuroLink format - keep existing)
|
|
1688
1850
|
this.emitter.emit("stream:start", {
|
|
1689
1851
|
provider: options.provider || "auto",
|
|
1690
1852
|
timestamp: startTime,
|
|
1691
1853
|
});
|
|
1854
|
+
// ADD: Bedrock-compatible response:start event
|
|
1855
|
+
this.emitter.emit("response:start");
|
|
1856
|
+
// ADD: Bedrock-compatible message event
|
|
1857
|
+
this.emitter.emit("message", `Starting ${options.provider || "auto"} stream generation...`);
|
|
1692
1858
|
// Process factory configuration for streaming
|
|
1693
1859
|
const factoryResult = processFactoryOptions(options);
|
|
1694
1860
|
const streamingResult = processStreamingFactoryOptions(options);
|
|
@@ -1780,6 +1946,8 @@ export class NeuroLink {
|
|
|
1780
1946
|
// Ensure chunk has content property and it's a string
|
|
1781
1947
|
if (typeof chunk.content === "string") {
|
|
1782
1948
|
accumulatedContent += chunk.content;
|
|
1949
|
+
// ADD: Bedrock-compatible response:chunk event
|
|
1950
|
+
self.emitter.emit("response:chunk", chunk.content);
|
|
1783
1951
|
}
|
|
1784
1952
|
else if (chunk.content === undefined ||
|
|
1785
1953
|
chunk.content === null) {
|
|
@@ -1791,6 +1959,8 @@ export class NeuroLink {
|
|
|
1791
1959
|
const stringContent = String(chunk.content || "");
|
|
1792
1960
|
processedChunk = { ...chunk, content: stringContent };
|
|
1793
1961
|
accumulatedContent += stringContent;
|
|
1962
|
+
// ADD: Bedrock-compatible response:chunk event
|
|
1963
|
+
self.emitter.emit("response:chunk", stringContent);
|
|
1794
1964
|
}
|
|
1795
1965
|
}
|
|
1796
1966
|
else if (chunk === null || chunk === undefined) {
|
|
@@ -1827,11 +1997,16 @@ export class NeuroLink {
|
|
|
1827
1997
|
responseTime,
|
|
1828
1998
|
provider: providerName,
|
|
1829
1999
|
});
|
|
1830
|
-
// Emit stream completion event
|
|
2000
|
+
// Emit stream completion event (NeuroLink format - enhanced with content)
|
|
1831
2001
|
this.emitter.emit("stream:end", {
|
|
1832
2002
|
provider: providerName,
|
|
1833
2003
|
responseTime,
|
|
2004
|
+
result: { content: accumulatedContent }, // Enhanced: include accumulated content
|
|
1834
2005
|
});
|
|
2006
|
+
// ADD: Bedrock-compatible response:end event with full response
|
|
2007
|
+
this.emitter.emit("response:end", accumulatedContent);
|
|
2008
|
+
// ADD: Bedrock-compatible message event
|
|
2009
|
+
this.emitter.emit("message", `Stream completed in ${responseTime}ms (${accumulatedContent.length} chars)`);
|
|
1835
2010
|
// Convert to StreamResult format - Include analytics and evaluation from provider
|
|
1836
2011
|
return {
|
|
1837
2012
|
stream: processedStream,
|
|
@@ -1860,6 +2035,8 @@ export class NeuroLink {
|
|
|
1860
2035
|
};
|
|
1861
2036
|
}
|
|
1862
2037
|
catch (error) {
|
|
2038
|
+
// ADD: Error event emission for MCP streaming failure
|
|
2039
|
+
this.emitter.emit("error", error instanceof Error ? error : new Error(String(error)));
|
|
1863
2040
|
// Fall back to regular streaming if MCP fails
|
|
1864
2041
|
mcpLogger.warn(`[${functionTag}] MCP streaming failed, falling back to regular`, {
|
|
1865
2042
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -1895,6 +2072,8 @@ export class NeuroLink {
|
|
|
1895
2072
|
for await (const chunk of streamResult.stream) {
|
|
1896
2073
|
if (chunk && typeof chunk.content === "string") {
|
|
1897
2074
|
fallbackAccumulatedContent += chunk.content;
|
|
2075
|
+
// ADD: Bedrock-compatible response:chunk event for fallback
|
|
2076
|
+
self.emitter.emit("response:chunk", chunk.content);
|
|
1898
2077
|
}
|
|
1899
2078
|
yield chunk; // Preserve original streaming behavior
|
|
1900
2079
|
}
|
|
@@ -1922,12 +2101,17 @@ export class NeuroLink {
|
|
|
1922
2101
|
}
|
|
1923
2102
|
})(this);
|
|
1924
2103
|
const responseTime = Date.now() - startTime;
|
|
1925
|
-
// Emit stream completion event for fallback
|
|
2104
|
+
// Emit stream completion event for fallback (NeuroLink format - enhanced with content)
|
|
1926
2105
|
this.emitter.emit("stream:end", {
|
|
1927
2106
|
provider: providerName,
|
|
1928
2107
|
responseTime,
|
|
1929
2108
|
fallback: true,
|
|
2109
|
+
result: { content: fallbackAccumulatedContent }, // Enhanced: include accumulated content
|
|
1930
2110
|
});
|
|
2111
|
+
// ADD: Bedrock-compatible response:end event with full response
|
|
2112
|
+
this.emitter.emit("response:end", fallbackAccumulatedContent);
|
|
2113
|
+
// ADD: Bedrock-compatible message event
|
|
2114
|
+
this.emitter.emit("message", `Fallback stream completed in ${responseTime}ms (${fallbackAccumulatedContent.length} chars)`);
|
|
1931
2115
|
return {
|
|
1932
2116
|
stream: fallbackProcessedStream,
|
|
1933
2117
|
provider: providerName,
|
|
@@ -1957,8 +2141,178 @@ export class NeuroLink {
|
|
|
1957
2141
|
}
|
|
1958
2142
|
}
|
|
1959
2143
|
/**
|
|
1960
|
-
* Get the EventEmitter to listen to NeuroLink events
|
|
1961
|
-
*
|
|
2144
|
+
* Get the EventEmitter instance to listen to NeuroLink events for real-time monitoring and debugging.
|
|
2145
|
+
* This method provides access to the internal event system that emits events during AI generation,
|
|
2146
|
+
* tool execution, streaming, and other operations for comprehensive observability.
|
|
2147
|
+
*
|
|
2148
|
+
* @returns EventEmitter instance that emits various NeuroLink operation events
|
|
2149
|
+
*
|
|
2150
|
+
* @example
|
|
2151
|
+
* ```typescript
|
|
2152
|
+
* // Basic event listening setup
|
|
2153
|
+
* const neurolink = new NeuroLink();
|
|
2154
|
+
* const emitter = neurolink.getEventEmitter();
|
|
2155
|
+
*
|
|
2156
|
+
* // Listen to generation events
|
|
2157
|
+
* emitter.on('generation:start', (event) => {
|
|
2158
|
+
* console.log(`Generation started with provider: ${event.provider}`);
|
|
2159
|
+
* console.log(`Started at: ${new Date(event.timestamp)}`);
|
|
2160
|
+
* });
|
|
2161
|
+
*
|
|
2162
|
+
* emitter.on('generation:end', (event) => {
|
|
2163
|
+
* console.log(`Generation completed in ${event.responseTime}ms`);
|
|
2164
|
+
* console.log(`Tools used: ${event.toolsUsed?.length || 0}`);
|
|
2165
|
+
* });
|
|
2166
|
+
*
|
|
2167
|
+
* // Listen to streaming events
|
|
2168
|
+
* emitter.on('stream:start', (event) => {
|
|
2169
|
+
* console.log(`Streaming started with provider: ${event.provider}`);
|
|
2170
|
+
* });
|
|
2171
|
+
*
|
|
2172
|
+
* emitter.on('stream:end', (event) => {
|
|
2173
|
+
* console.log(`Streaming completed in ${event.responseTime}ms`);
|
|
2174
|
+
* if (event.fallback) console.log('Used fallback streaming');
|
|
2175
|
+
* });
|
|
2176
|
+
*
|
|
2177
|
+
* // Listen to tool execution events
|
|
2178
|
+
* emitter.on('tool:start', (event) => {
|
|
2179
|
+
* console.log(`Tool execution started: ${event.toolName}`);
|
|
2180
|
+
* });
|
|
2181
|
+
*
|
|
2182
|
+
* emitter.on('tool:end', (event) => {
|
|
2183
|
+
* console.log(`Tool ${event.toolName} ${event.success ? 'succeeded' : 'failed'}`);
|
|
2184
|
+
* console.log(`Execution time: ${event.responseTime}ms`);
|
|
2185
|
+
* });
|
|
2186
|
+
*
|
|
2187
|
+
* // Listen to tool registration events
|
|
2188
|
+
* emitter.on('tools-register:start', (event) => {
|
|
2189
|
+
* console.log(`Registering tool: ${event.toolName}`);
|
|
2190
|
+
* });
|
|
2191
|
+
*
|
|
2192
|
+
* emitter.on('tools-register:end', (event) => {
|
|
2193
|
+
* console.log(`Tool registration ${event.success ? 'succeeded' : 'failed'}: ${event.toolName}`);
|
|
2194
|
+
* });
|
|
2195
|
+
*
|
|
2196
|
+
* // Listen to external MCP server events
|
|
2197
|
+
* emitter.on('externalMCP:serverConnected', (event) => {
|
|
2198
|
+
* console.log(`External MCP server connected: ${event.serverId}`);
|
|
2199
|
+
* console.log(`Tools available: ${event.toolCount || 0}`);
|
|
2200
|
+
* });
|
|
2201
|
+
*
|
|
2202
|
+
* emitter.on('externalMCP:serverDisconnected', (event) => {
|
|
2203
|
+
* console.log(`External MCP server disconnected: ${event.serverId}`);
|
|
2204
|
+
* console.log(`Reason: ${event.reason || 'Unknown'}`);
|
|
2205
|
+
* });
|
|
2206
|
+
*
|
|
2207
|
+
* emitter.on('externalMCP:toolDiscovered', (event) => {
|
|
2208
|
+
* console.log(`New tool discovered: ${event.toolName} from ${event.serverId}`);
|
|
2209
|
+
* });
|
|
2210
|
+
*
|
|
2211
|
+
* // Advanced usage with error handling
|
|
2212
|
+
* emitter.on('error', (error) => {
|
|
2213
|
+
* console.error('NeuroLink error:', error);
|
|
2214
|
+
* });
|
|
2215
|
+
*
|
|
2216
|
+
* // Clean up event listeners when done
|
|
2217
|
+
* function cleanup() {
|
|
2218
|
+
* emitter.removeAllListeners();
|
|
2219
|
+
* }
|
|
2220
|
+
*
|
|
2221
|
+
* process.on('SIGINT', cleanup);
|
|
2222
|
+
* process.on('SIGTERM', cleanup);
|
|
2223
|
+
* ```
|
|
2224
|
+
*
|
|
2225
|
+
* @example
|
|
2226
|
+
* ```typescript
|
|
2227
|
+
* // Advanced monitoring with metrics collection
|
|
2228
|
+
* const neurolink = new NeuroLink();
|
|
2229
|
+
* const emitter = neurolink.getEventEmitter();
|
|
2230
|
+
* const metrics = {
|
|
2231
|
+
* generations: 0,
|
|
2232
|
+
* totalResponseTime: 0,
|
|
2233
|
+
* toolExecutions: 0,
|
|
2234
|
+
* failures: 0
|
|
2235
|
+
* };
|
|
2236
|
+
*
|
|
2237
|
+
* // Collect performance metrics
|
|
2238
|
+
* emitter.on('generation:end', (event) => {
|
|
2239
|
+
* metrics.generations++;
|
|
2240
|
+
* metrics.totalResponseTime += event.responseTime;
|
|
2241
|
+
* metrics.toolExecutions += event.toolsUsed?.length || 0;
|
|
2242
|
+
* });
|
|
2243
|
+
*
|
|
2244
|
+
* emitter.on('tool:end', (event) => {
|
|
2245
|
+
* if (!event.success) {
|
|
2246
|
+
* metrics.failures++;
|
|
2247
|
+
* }
|
|
2248
|
+
* });
|
|
2249
|
+
*
|
|
2250
|
+
* // Log metrics every 10 seconds
|
|
2251
|
+
* setInterval(() => {
|
|
2252
|
+
* const avgResponseTime = metrics.generations > 0
|
|
2253
|
+
* ? metrics.totalResponseTime / metrics.generations
|
|
2254
|
+
* : 0;
|
|
2255
|
+
*
|
|
2256
|
+
* console.log('NeuroLink Metrics:', {
|
|
2257
|
+
* totalGenerations: metrics.generations,
|
|
2258
|
+
* averageResponseTime: `${avgResponseTime.toFixed(2)}ms`,
|
|
2259
|
+
* totalToolExecutions: metrics.toolExecutions,
|
|
2260
|
+
* failureRate: `${((metrics.failures / (metrics.toolExecutions || 1)) * 100).toFixed(2)}%`
|
|
2261
|
+
* });
|
|
2262
|
+
* }, 10000);
|
|
2263
|
+
* ```
|
|
2264
|
+
*
|
|
2265
|
+
* **Available Events:**
|
|
2266
|
+
*
|
|
2267
|
+
* **Generation Events:**
|
|
2268
|
+
* - `generation:start` - Fired when text generation begins
|
|
2269
|
+
* - `{ provider: string, timestamp: number }`
|
|
2270
|
+
* - `generation:end` - Fired when text generation completes
|
|
2271
|
+
* - `{ provider: string, responseTime: number, toolsUsed?: string[], timestamp: number }`
|
|
2272
|
+
*
|
|
2273
|
+
* **Streaming Events:**
|
|
2274
|
+
* - `stream:start` - Fired when streaming begins
|
|
2275
|
+
* - `{ provider: string, timestamp: number }`
|
|
2276
|
+
* - `stream:end` - Fired when streaming completes
|
|
2277
|
+
* - `{ provider: string, responseTime: number, fallback?: boolean }`
|
|
2278
|
+
*
|
|
2279
|
+
* **Tool Events:**
|
|
2280
|
+
* - `tool:start` - Fired when tool execution begins
|
|
2281
|
+
* - `{ toolName: string, timestamp: number }`
|
|
2282
|
+
* - `tool:end` - Fired when tool execution completes
|
|
2283
|
+
* - `{ toolName: string, responseTime: number, success: boolean, timestamp: number }`
|
|
2284
|
+
* - `tools-register:start` - Fired when tool registration begins
|
|
2285
|
+
* - `{ toolName: string, timestamp: number }`
|
|
2286
|
+
* - `tools-register:end` - Fired when tool registration completes
|
|
2287
|
+
* - `{ toolName: string, success: boolean, timestamp: number }`
|
|
2288
|
+
*
|
|
2289
|
+
* **External MCP Events:**
|
|
2290
|
+
* - `externalMCP:serverConnected` - Fired when external MCP server connects
|
|
2291
|
+
* - `{ serverId: string, toolCount?: number, timestamp: number }`
|
|
2292
|
+
* - `externalMCP:serverDisconnected` - Fired when external MCP server disconnects
|
|
2293
|
+
* - `{ serverId: string, reason?: string, timestamp: number }`
|
|
2294
|
+
* - `externalMCP:serverFailed` - Fired when external MCP server fails
|
|
2295
|
+
* - `{ serverId: string, error: string, timestamp: number }`
|
|
2296
|
+
* - `externalMCP:toolDiscovered` - Fired when external MCP tool is discovered
|
|
2297
|
+
* - `{ toolName: string, serverId: string, timestamp: number }`
|
|
2298
|
+
* - `externalMCP:toolRemoved` - Fired when external MCP tool is removed
|
|
2299
|
+
* - `{ toolName: string, serverId: string, timestamp: number }`
|
|
2300
|
+
* - `externalMCP:serverAdded` - Fired when external MCP server is added
|
|
2301
|
+
* - `{ serverId: string, config: MCPServerInfo, toolCount: number, timestamp: number }`
|
|
2302
|
+
* - `externalMCP:serverRemoved` - Fired when external MCP server is removed
|
|
2303
|
+
* - `{ serverId: string, timestamp: number }`
|
|
2304
|
+
*
|
|
2305
|
+
* **Error Events:**
|
|
2306
|
+
* - `error` - Fired when an error occurs
|
|
2307
|
+
* - `{ error: Error, context?: object }`
|
|
2308
|
+
*
|
|
2309
|
+
* @throws {Error} This method does not throw errors as it returns the internal EventEmitter
|
|
2310
|
+
*
|
|
2311
|
+
* @since 1.0.0
|
|
2312
|
+
* @see {@link https://nodejs.org/api/events.html} Node.js EventEmitter documentation
|
|
2313
|
+
* @see {@link NeuroLink.generate} for events related to text generation
|
|
2314
|
+
* @see {@link NeuroLink.stream} for events related to streaming
|
|
2315
|
+
* @see {@link NeuroLink.executeTool} for events related to tool execution
|
|
1962
2316
|
*/
|
|
1963
2317
|
getEventEmitter() {
|
|
1964
2318
|
return this.emitter;
|
|
@@ -1978,7 +2332,7 @@ export class NeuroLink {
|
|
|
1978
2332
|
timestamp: Date.now(),
|
|
1979
2333
|
});
|
|
1980
2334
|
try {
|
|
1981
|
-
// --- Start:
|
|
2335
|
+
// --- Start: Enhanced Validation Logic with FlexibleToolValidator ---
|
|
1982
2336
|
if (!name || typeof name !== "string") {
|
|
1983
2337
|
throw new Error("Invalid tool name");
|
|
1984
2338
|
}
|
|
@@ -1988,55 +2342,36 @@ export class NeuroLink {
|
|
|
1988
2342
|
if (typeof tool.execute !== "function") {
|
|
1989
2343
|
throw new Error(`Tool '${name}' must have an execute method.`);
|
|
1990
2344
|
}
|
|
1991
|
-
//
|
|
1992
|
-
// Import validation functions synchronously - they are pure functions
|
|
1993
|
-
let validateTool;
|
|
1994
|
-
let isToolNameAvailable;
|
|
1995
|
-
let suggestToolNames;
|
|
2345
|
+
// Use FlexibleToolValidator for consistent validation across SDK and toolRegistry
|
|
1996
2346
|
try {
|
|
1997
|
-
|
|
1998
|
-
const
|
|
1999
|
-
|
|
2000
|
-
|
|
2347
|
+
const flexibleValidatorModule = require("./mcp/flexibleToolValidator.js");
|
|
2348
|
+
const FlexibleToolValidator = flexibleValidatorModule.FlexibleToolValidator;
|
|
2349
|
+
// Use the same validation logic as toolRegistry (static method)
|
|
2350
|
+
const validationResult = FlexibleToolValidator.validateToolName(name);
|
|
2351
|
+
if (!validationResult.isValid) {
|
|
2352
|
+
throw new Error(`Tool validation failed: ${validationResult.error}`);
|
|
2353
|
+
}
|
|
2001
2354
|
}
|
|
2002
2355
|
catch (error) {
|
|
2003
|
-
//
|
|
2004
|
-
logger.warn("
|
|
2356
|
+
// If FlexibleToolValidator import fails, use basic safety checks
|
|
2357
|
+
logger.warn("FlexibleToolValidator not available, using basic validation", {
|
|
2005
2358
|
error: error instanceof Error ? error.message : String(error),
|
|
2006
2359
|
});
|
|
2007
|
-
//
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
// Create a simplified tool object for validation
|
|
2019
|
-
const toolForValidation = {
|
|
2020
|
-
description: tool.description || "",
|
|
2021
|
-
execute: async (params) => {
|
|
2022
|
-
if (tool.execute) {
|
|
2023
|
-
const result = await tool.execute(params);
|
|
2024
|
-
return result;
|
|
2025
|
-
}
|
|
2026
|
-
return "";
|
|
2027
|
-
},
|
|
2028
|
-
parameters: tool.inputSchema,
|
|
2029
|
-
metadata: {
|
|
2030
|
-
category: "custom",
|
|
2031
|
-
},
|
|
2032
|
-
};
|
|
2033
|
-
// Use comprehensive validation logic
|
|
2034
|
-
try {
|
|
2035
|
-
validateTool(name, toolForValidation);
|
|
2036
|
-
}
|
|
2037
|
-
catch (error) {
|
|
2038
|
-
throw new Error(`Tool registration failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2360
|
+
// Basic safety checks to prevent obvious issues
|
|
2361
|
+
if (name.trim() === "") {
|
|
2362
|
+
throw new Error("Tool name cannot be empty");
|
|
2363
|
+
}
|
|
2364
|
+
if (name.length > 100) {
|
|
2365
|
+
throw new Error("Tool name is too long (maximum 100 characters)");
|
|
2366
|
+
}
|
|
2367
|
+
// eslint-disable-next-line no-control-regex
|
|
2368
|
+
if (/[\x00-\x1F\x7F]/.test(name)) {
|
|
2369
|
+
throw new Error("Tool name contains invalid control characters");
|
|
2370
|
+
}
|
|
2039
2371
|
}
|
|
2372
|
+
// --- End: Enhanced Validation Logic ---
|
|
2373
|
+
// Tool object validation is now handled by FlexibleToolValidator above
|
|
2374
|
+
// Proceed with tool registration since validation passed
|
|
2040
2375
|
// SMART DEFAULTS: Use utility to eliminate boilerplate creation
|
|
2041
2376
|
const mcpServerInfo = createCustomToolServerInfo(name, tool);
|
|
2042
2377
|
// Register with toolRegistry using MCPServerInfo directly
|
|
@@ -2196,11 +2531,14 @@ export class NeuroLink {
|
|
|
2196
2531
|
: params,
|
|
2197
2532
|
hasExternalManager: !!this.externalServerManager,
|
|
2198
2533
|
});
|
|
2199
|
-
// Emit tool start event
|
|
2534
|
+
// Emit tool start event (NeuroLink format - keep existing)
|
|
2200
2535
|
this.emitter.emit("tool:start", {
|
|
2201
2536
|
toolName,
|
|
2202
2537
|
timestamp: executionStartTime,
|
|
2538
|
+
input: params, // Enhanced: add input parameters
|
|
2203
2539
|
});
|
|
2540
|
+
// ADD: Bedrock-compatible tool:start event (positional parameters)
|
|
2541
|
+
this.emitter.emit("tool:start", toolName, params);
|
|
2204
2542
|
// Set default options
|
|
2205
2543
|
const finalOptions = {
|
|
2206
2544
|
timeout: options?.timeout || 30000, // 30 second default timeout
|
|
@@ -2226,13 +2564,15 @@ export class NeuroLink {
|
|
|
2226
2564
|
});
|
|
2227
2565
|
}
|
|
2228
2566
|
const metrics = this.toolExecutionMetrics.get(toolName);
|
|
2229
|
-
metrics
|
|
2567
|
+
if (metrics) {
|
|
2568
|
+
metrics.totalExecutions++;
|
|
2569
|
+
}
|
|
2230
2570
|
try {
|
|
2231
2571
|
mcpLogger.debug(`[${functionTag}] Executing tool: ${toolName}`, {
|
|
2232
2572
|
toolName,
|
|
2233
2573
|
params,
|
|
2234
2574
|
options: finalOptions,
|
|
2235
|
-
circuitBreakerState: circuitBreaker
|
|
2575
|
+
circuitBreakerState: circuitBreaker?.getState(),
|
|
2236
2576
|
});
|
|
2237
2577
|
// Execute with circuit breaker, timeout, and retry logic
|
|
2238
2578
|
const result = await circuitBreaker.execute(async () => {
|
|
@@ -2253,12 +2593,14 @@ export class NeuroLink {
|
|
|
2253
2593
|
});
|
|
2254
2594
|
// Update success metrics
|
|
2255
2595
|
const executionTime = Date.now() - executionStartTime;
|
|
2256
|
-
metrics
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2596
|
+
if (metrics) {
|
|
2597
|
+
metrics.successfulExecutions++;
|
|
2598
|
+
metrics.lastExecutionTime = executionTime;
|
|
2599
|
+
metrics.averageExecutionTime =
|
|
2600
|
+
(metrics.averageExecutionTime * (metrics.successfulExecutions - 1) +
|
|
2601
|
+
executionTime) /
|
|
2602
|
+
metrics.successfulExecutions;
|
|
2603
|
+
}
|
|
2262
2604
|
// Track memory usage
|
|
2263
2605
|
const endMemory = MemoryManager.getMemoryUsageMB();
|
|
2264
2606
|
const memoryDelta = endMemory.heapUsed - startMemory.heapUsed;
|
|
@@ -2273,15 +2615,17 @@ export class NeuroLink {
|
|
|
2273
2615
|
toolName,
|
|
2274
2616
|
executionTime,
|
|
2275
2617
|
memoryDelta,
|
|
2276
|
-
circuitBreakerState: circuitBreaker
|
|
2618
|
+
circuitBreakerState: circuitBreaker?.getState(),
|
|
2277
2619
|
});
|
|
2278
2620
|
// Emit tool end event using the helper method
|
|
2279
|
-
this.emitToolEndEvent(toolName, executionStartTime, true);
|
|
2621
|
+
this.emitToolEndEvent(toolName, executionStartTime, true, result);
|
|
2280
2622
|
return result;
|
|
2281
2623
|
}
|
|
2282
2624
|
catch (error) {
|
|
2283
2625
|
// Update failure metrics
|
|
2284
|
-
metrics
|
|
2626
|
+
if (metrics) {
|
|
2627
|
+
metrics.failedExecutions++;
|
|
2628
|
+
}
|
|
2285
2629
|
const executionTime = Date.now() - executionStartTime;
|
|
2286
2630
|
// Create structured error
|
|
2287
2631
|
let structuredError;
|
|
@@ -2312,8 +2656,10 @@ export class NeuroLink {
|
|
|
2312
2656
|
else {
|
|
2313
2657
|
structuredError = ErrorFactory.toolExecutionFailed(toolName, new Error(String(error)));
|
|
2314
2658
|
}
|
|
2659
|
+
// ADD: Centralized error event emission
|
|
2660
|
+
this.emitter.emit("error", structuredError);
|
|
2315
2661
|
// Emit tool end event using the helper method
|
|
2316
|
-
this.emitToolEndEvent(toolName, executionStartTime, false);
|
|
2662
|
+
this.emitToolEndEvent(toolName, executionStartTime, false, undefined, structuredError);
|
|
2317
2663
|
// Add execution context to structured error
|
|
2318
2664
|
structuredError = new NeuroLinkError({
|
|
2319
2665
|
...structuredError,
|
|
@@ -2322,8 +2668,8 @@ export class NeuroLink {
|
|
|
2322
2668
|
executionTime,
|
|
2323
2669
|
params,
|
|
2324
2670
|
options: finalOptions,
|
|
2325
|
-
circuitBreakerState: circuitBreaker
|
|
2326
|
-
circuitBreakerFailures: circuitBreaker
|
|
2671
|
+
circuitBreakerState: circuitBreaker?.getState(),
|
|
2672
|
+
circuitBreakerFailures: circuitBreaker?.getFailureCount(),
|
|
2327
2673
|
metrics: { ...metrics },
|
|
2328
2674
|
},
|
|
2329
2675
|
});
|
|
@@ -2374,9 +2720,21 @@ export class NeuroLink {
|
|
|
2374
2720
|
userId: "neurolink-user",
|
|
2375
2721
|
};
|
|
2376
2722
|
const result = (await toolRegistry.executeTool(toolName, params, context));
|
|
2723
|
+
// ADD: Check if result indicates a failure and emit error event
|
|
2724
|
+
if (result &&
|
|
2725
|
+
typeof result === "object" &&
|
|
2726
|
+
"success" in result &&
|
|
2727
|
+
result.success === false) {
|
|
2728
|
+
const errorMessage = result.error || "Tool execution failed";
|
|
2729
|
+
const errorToEmit = new Error(errorMessage);
|
|
2730
|
+
this.emitter.emit("error", errorToEmit);
|
|
2731
|
+
}
|
|
2377
2732
|
return result;
|
|
2378
2733
|
}
|
|
2379
2734
|
catch (error) {
|
|
2735
|
+
// ADD: Emergency error event emission (fallback)
|
|
2736
|
+
const errorToEmit = error instanceof Error ? error : new Error(String(error));
|
|
2737
|
+
this.emitter.emit("error", errorToEmit);
|
|
2380
2738
|
// Check if tool was not found
|
|
2381
2739
|
if (error instanceof Error && error.message.includes("not found")) {
|
|
2382
2740
|
const availableTools = await this.getAllAvailableTools();
|
|
@@ -2548,6 +2906,9 @@ export class NeuroLink {
|
|
|
2548
2906
|
}
|
|
2549
2907
|
const { AIProviderFactory } = await import("./core/factory.js");
|
|
2550
2908
|
const { hasProviderEnvVars } = await import("./utils/providerUtils.js");
|
|
2909
|
+
// Keep references to prevent unused variable warnings
|
|
2910
|
+
void AIProviderFactory;
|
|
2911
|
+
void hasProviderEnvVars;
|
|
2551
2912
|
const providers = [
|
|
2552
2913
|
"openai",
|
|
2553
2914
|
"bedrock",
|
|
@@ -2810,7 +3171,7 @@ export class NeuroLink {
|
|
|
2810
3171
|
const inMemoryServers = this.getInMemoryServers();
|
|
2811
3172
|
if (inMemoryServers.has(serverId)) {
|
|
2812
3173
|
const serverInfo = inMemoryServers.get(serverId);
|
|
2813
|
-
return !!(serverInfo
|
|
3174
|
+
return !!(serverInfo?.tools && serverInfo.tools.length > 0);
|
|
2814
3175
|
}
|
|
2815
3176
|
// Test external MCP servers
|
|
2816
3177
|
const externalServer = this.externalServerManager.getServer(serverId);
|
|
@@ -3317,7 +3678,7 @@ export class NeuroLink {
|
|
|
3317
3678
|
* Convert JSON Schema to AI SDK compatible format
|
|
3318
3679
|
* For now, we'll skip schema validation and let the AI SDK handle parameters dynamically
|
|
3319
3680
|
*/
|
|
3320
|
-
convertJSONSchemaToAISDKFormat(
|
|
3681
|
+
convertJSONSchemaToAISDKFormat(_inputSchema) {
|
|
3321
3682
|
// The simplest approach: don't provide parameters schema
|
|
3322
3683
|
// This lets the AI SDK handle the tool without schema validation
|
|
3323
3684
|
// Tools will still work, they just won't have strict parameter validation
|