@juspay/neurolink 4.1.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -2
- package/README.md +1 -12
- package/dist/cli/commands/mcp.d.ts +11 -0
- package/dist/cli/commands/mcp.js +332 -223
- package/dist/cli/index.js +69 -8
- package/dist/core/factory.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/core/factory.js +2 -2
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/mcp/context-manager.d.ts +6 -0
- package/dist/lib/mcp/context-manager.js +8 -0
- package/dist/lib/mcp/contracts/mcpContract.d.ts +1 -0
- package/dist/lib/mcp/external-client.js +6 -2
- package/dist/lib/mcp/initialize.d.ts +2 -1
- package/dist/lib/mcp/initialize.js +8 -7
- package/dist/lib/mcp/orchestrator.js +9 -0
- package/dist/lib/mcp/registry.d.ts +1 -1
- package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
- package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +3 -3
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
- package/dist/lib/mcp/session-manager.js +1 -1
- package/dist/lib/mcp/session-persistence.js +1 -1
- package/dist/lib/mcp/tool-registry.d.ts +31 -11
- package/dist/lib/mcp/tool-registry.js +226 -38
- package/dist/lib/mcp/unified-mcp.d.ts +12 -2
- package/dist/lib/mcp/unified-registry.d.ts +21 -7
- package/dist/lib/mcp/unified-registry.js +179 -17
- package/dist/lib/neurolink.js +17 -25
- package/dist/lib/providers/googleVertexAI.js +19 -1
- package/dist/lib/providers/openAI.js +18 -1
- package/dist/lib/utils/provider-setup-messages.d.ts +8 -0
- package/dist/lib/utils/provider-setup-messages.js +120 -0
- package/dist/lib/utils/provider-validation.d.ts +35 -0
- package/dist/lib/utils/provider-validation.js +625 -0
- package/dist/lib/utils/providerUtils-fixed.js +20 -1
- package/dist/lib/utils/providerUtils.d.ts +2 -2
- package/dist/lib/utils/providerUtils.js +38 -7
- package/dist/lib/utils/timeout-manager.d.ts +75 -0
- package/dist/lib/utils/timeout-manager.js +244 -0
- package/dist/mcp/context-manager.d.ts +6 -0
- package/dist/mcp/context-manager.js +8 -0
- package/dist/mcp/contracts/mcpContract.d.ts +1 -0
- package/dist/mcp/external-client.js +6 -2
- package/dist/mcp/initialize.d.ts +2 -1
- package/dist/mcp/initialize.js +8 -7
- package/dist/mcp/orchestrator.js +9 -0
- package/dist/mcp/registry.d.ts +1 -1
- package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
- package/dist/mcp/servers/ai-providers/ai-core-server.js +3 -3
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
- package/dist/mcp/session-manager.js +1 -1
- package/dist/mcp/session-persistence.js +1 -1
- package/dist/mcp/tool-registry.d.ts +31 -11
- package/dist/mcp/tool-registry.js +226 -38
- package/dist/mcp/unified-mcp.d.ts +12 -2
- package/dist/mcp/unified-registry.d.ts +21 -7
- package/dist/mcp/unified-registry.js +179 -17
- package/dist/neurolink.js +17 -25
- package/dist/providers/googleVertexAI.js +19 -1
- package/dist/providers/openAI.js +18 -1
- package/dist/utils/provider-setup-messages.d.ts +8 -0
- package/dist/utils/provider-setup-messages.js +120 -0
- package/dist/utils/provider-validation.d.ts +35 -0
- package/dist/utils/provider-validation.js +625 -0
- package/dist/utils/providerUtils-fixed.js +20 -1
- package/dist/utils/providerUtils.d.ts +2 -2
- package/dist/utils/providerUtils.js +38 -7
- package/dist/utils/timeout-manager.d.ts +75 -0
- package/dist/utils/timeout-manager.js +244 -0
- package/package.json +1 -1
|
@@ -3,17 +3,48 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { logger } from "./logger.js";
|
|
5
5
|
/**
|
|
6
|
-
* Get the best available provider based on preferences and availability
|
|
6
|
+
* Get the best available provider based on preferences and availability (async)
|
|
7
7
|
* @param requestedProvider - Optional preferred provider name
|
|
8
8
|
* @returns The best provider name to use
|
|
9
9
|
*/
|
|
10
|
-
export function
|
|
11
|
-
// If a specific provider is requested, return it
|
|
12
|
-
if (requestedProvider) {
|
|
10
|
+
export async function getBestProvider(requestedProvider) {
|
|
11
|
+
// If a specific provider is requested, return it (existing logic)
|
|
12
|
+
if (requestedProvider && requestedProvider !== "auto") {
|
|
13
13
|
return requestedProvider;
|
|
14
14
|
}
|
|
15
|
-
//
|
|
16
|
-
|
|
15
|
+
// 🔧 FIX: Check for explicit default provider in env
|
|
16
|
+
if (process.env.DEFAULT_PROVIDER &&
|
|
17
|
+
isProviderConfigured(process.env.DEFAULT_PROVIDER)) {
|
|
18
|
+
return process.env.DEFAULT_PROVIDER;
|
|
19
|
+
}
|
|
20
|
+
// 🔧 FIX: Special case for Ollama when explicitly configured
|
|
21
|
+
if (process.env.OLLAMA_BASE_URL && process.env.OLLAMA_MODEL) {
|
|
22
|
+
// Quick connectivity check for Ollama (non-blocking)
|
|
23
|
+
try {
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
const timeout = setTimeout(() => controller.abort(), 2000);
|
|
26
|
+
let res;
|
|
27
|
+
try {
|
|
28
|
+
res = await fetch("http://localhost:11434/api/tags", {
|
|
29
|
+
method: "GET",
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
});
|
|
32
|
+
clearTimeout(timeout);
|
|
33
|
+
if (res.ok) {
|
|
34
|
+
return "ollama"; // Prioritize working local AI
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
clearTimeout(timeout);
|
|
39
|
+
// Fall through to cloud providers
|
|
40
|
+
}
|
|
41
|
+
// Removed redundant if (res.ok) block here
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Fall through to cloud providers
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Existing provider priority logic...
|
|
17
48
|
const providers = [
|
|
18
49
|
"google-ai",
|
|
19
50
|
"anthropic",
|
|
@@ -23,7 +54,7 @@ export function getBestProviderSync(requestedProvider) {
|
|
|
23
54
|
"azure",
|
|
24
55
|
"huggingface",
|
|
25
56
|
"bedrock",
|
|
26
|
-
"ollama",
|
|
57
|
+
"ollama", // Keep as fallback
|
|
27
58
|
];
|
|
28
59
|
// Check which providers have their required environment variables
|
|
29
60
|
for (const provider of providers) {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Timeout Manager for NeuroLink
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent timeout handling across all operations with proper cleanup,
|
|
5
|
+
* abort controller integration, and graceful degradation.
|
|
6
|
+
*/
|
|
7
|
+
export interface TimeoutConfig {
|
|
8
|
+
operation: string;
|
|
9
|
+
timeout?: number | string;
|
|
10
|
+
gracefulShutdown?: boolean;
|
|
11
|
+
retryOnTimeout?: boolean;
|
|
12
|
+
maxRetries?: number;
|
|
13
|
+
abortSignal?: AbortSignal;
|
|
14
|
+
}
|
|
15
|
+
export interface TimeoutResult<T> {
|
|
16
|
+
success: boolean;
|
|
17
|
+
data?: T;
|
|
18
|
+
error?: Error;
|
|
19
|
+
timedOut: boolean;
|
|
20
|
+
executionTime: number;
|
|
21
|
+
retriesUsed: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Enhanced timeout manager with proper cleanup and abort controller integration
|
|
25
|
+
*/
|
|
26
|
+
export declare class TimeoutManager {
|
|
27
|
+
private activeTimeouts;
|
|
28
|
+
/**
|
|
29
|
+
* Execute operation with timeout and proper cleanup
|
|
30
|
+
*/
|
|
31
|
+
executeWithTimeout<T>(operation: () => Promise<T>, config: TimeoutConfig): Promise<TimeoutResult<T>>;
|
|
32
|
+
/**
|
|
33
|
+
* Execute single operation with timeout
|
|
34
|
+
*/
|
|
35
|
+
private performSingleOperation;
|
|
36
|
+
/**
|
|
37
|
+
* Execute operation with abort signal support
|
|
38
|
+
*/
|
|
39
|
+
private executeWithAbortSignal;
|
|
40
|
+
/**
|
|
41
|
+
* Get timeout in milliseconds from config
|
|
42
|
+
*/
|
|
43
|
+
private getTimeoutMs;
|
|
44
|
+
/**
|
|
45
|
+
* Generate unique operation ID
|
|
46
|
+
*/
|
|
47
|
+
private generateOperationId;
|
|
48
|
+
/**
|
|
49
|
+
* Cleanup specific operation
|
|
50
|
+
*/
|
|
51
|
+
cleanup(operationId: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Cleanup all active timeouts (call on shutdown)
|
|
54
|
+
*/
|
|
55
|
+
cleanupAll(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Get current active timeout count (for debugging)
|
|
58
|
+
*/
|
|
59
|
+
getActiveTimeoutCount(): number;
|
|
60
|
+
/**
|
|
61
|
+
* Create a timeout wrapper for child process operations
|
|
62
|
+
*/
|
|
63
|
+
wrapChildProcess<T>(processFactory: () => Promise<T>, config: TimeoutConfig): Promise<TimeoutResult<T>>;
|
|
64
|
+
/**
|
|
65
|
+
* Create a timeout wrapper for MCP server operations
|
|
66
|
+
*/
|
|
67
|
+
wrapMCPOperation<T>(operation: () => Promise<T>, operationName: string, timeoutMs?: number): Promise<TimeoutResult<T>>;
|
|
68
|
+
/**
|
|
69
|
+
* Create a timeout wrapper for CLI operations
|
|
70
|
+
*/
|
|
71
|
+
wrapCLIOperation<T>(operation: () => Promise<T>, operationName: string, timeoutMs?: number): Promise<TimeoutResult<T>>;
|
|
72
|
+
}
|
|
73
|
+
export declare function createTimeoutManager(): TimeoutManager;
|
|
74
|
+
export declare function getDefaultTimeoutManager(): TimeoutManager;
|
|
75
|
+
export declare const defaultTimeoutManager: TimeoutManager;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Timeout Manager for NeuroLink
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent timeout handling across all operations with proper cleanup,
|
|
5
|
+
* abort controller integration, and graceful degradation.
|
|
6
|
+
*/
|
|
7
|
+
import { parseTimeout, TimeoutError, DEFAULT_TIMEOUTS } from "./timeout.js";
|
|
8
|
+
/**
|
|
9
|
+
* Enhanced timeout manager with proper cleanup and abort controller integration
|
|
10
|
+
*/
|
|
11
|
+
export class TimeoutManager {
|
|
12
|
+
activeTimeouts = new Map();
|
|
13
|
+
/**
|
|
14
|
+
* Execute operation with timeout and proper cleanup
|
|
15
|
+
*/
|
|
16
|
+
async executeWithTimeout(operation, config) {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
const operationId = this.generateOperationId(config.operation);
|
|
19
|
+
let retriesUsed = 0;
|
|
20
|
+
const maxRetries = config.retryOnTimeout ? (config.maxRetries ?? 1) : 0;
|
|
21
|
+
while (retriesUsed <= maxRetries) {
|
|
22
|
+
try {
|
|
23
|
+
const result = await this.performSingleOperation(operation, config, operationId);
|
|
24
|
+
return {
|
|
25
|
+
success: true,
|
|
26
|
+
data: result,
|
|
27
|
+
timedOut: false,
|
|
28
|
+
executionTime: Date.now() - startTime,
|
|
29
|
+
retriesUsed,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
// Clean up any active timeouts for this operation
|
|
34
|
+
this.cleanup(operationId);
|
|
35
|
+
if (error instanceof TimeoutError && retriesUsed < maxRetries) {
|
|
36
|
+
retriesUsed++;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
42
|
+
timedOut: error instanceof TimeoutError,
|
|
43
|
+
executionTime: Date.now() - startTime,
|
|
44
|
+
retriesUsed,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// This should never be reached, but TypeScript needs it
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
error: new Error("Maximum retries exceeded"),
|
|
52
|
+
timedOut: true,
|
|
53
|
+
executionTime: Date.now() - startTime,
|
|
54
|
+
retriesUsed,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Execute single operation with timeout
|
|
59
|
+
*/
|
|
60
|
+
async performSingleOperation(operation, config, operationId) {
|
|
61
|
+
const timeoutMs = this.getTimeoutMs(config);
|
|
62
|
+
if (!timeoutMs) {
|
|
63
|
+
// No timeout specified, execute directly
|
|
64
|
+
return await operation();
|
|
65
|
+
}
|
|
66
|
+
// Create abort controller for this operation
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
const existingSignal = config.abortSignal;
|
|
69
|
+
// Merge with existing abort signal if provided
|
|
70
|
+
if (existingSignal) {
|
|
71
|
+
existingSignal.addEventListener("abort", () => {
|
|
72
|
+
controller.abort(existingSignal.reason);
|
|
73
|
+
});
|
|
74
|
+
if (existingSignal.aborted) {
|
|
75
|
+
throw new Error("Operation aborted before execution");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Set up timeout
|
|
79
|
+
const timer = setTimeout(() => {
|
|
80
|
+
controller.abort(new TimeoutError(`Operation '${config.operation}' timed out after ${timeoutMs}ms`, timeoutMs, "timeout-manager", "generate"));
|
|
81
|
+
}, timeoutMs);
|
|
82
|
+
// Cleanup function
|
|
83
|
+
const cleanup = () => {
|
|
84
|
+
clearTimeout(timer);
|
|
85
|
+
this.activeTimeouts.delete(operationId);
|
|
86
|
+
};
|
|
87
|
+
// Store active timeout for potential cleanup
|
|
88
|
+
this.activeTimeouts.set(operationId, {
|
|
89
|
+
timer,
|
|
90
|
+
controller,
|
|
91
|
+
cleanup,
|
|
92
|
+
});
|
|
93
|
+
try {
|
|
94
|
+
// Execute operation with abort signal
|
|
95
|
+
const result = await this.executeWithAbortSignal(operation, controller.signal);
|
|
96
|
+
cleanup();
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
cleanup();
|
|
101
|
+
// Convert abort errors to timeout errors if appropriate
|
|
102
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
103
|
+
throw new TimeoutError(`Operation '${config.operation}' was aborted`, timeoutMs, "timeout-manager", "generate");
|
|
104
|
+
}
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Execute operation with abort signal support
|
|
110
|
+
*/
|
|
111
|
+
async executeWithAbortSignal(operation, signal) {
|
|
112
|
+
// Check if already aborted
|
|
113
|
+
if (signal.aborted) {
|
|
114
|
+
throw new Error("Operation aborted");
|
|
115
|
+
}
|
|
116
|
+
// Race between operation and abort signal
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
// Listen for abort
|
|
119
|
+
signal.addEventListener("abort", () => {
|
|
120
|
+
reject(signal.reason || new Error("Operation aborted"));
|
|
121
|
+
});
|
|
122
|
+
// Execute operation
|
|
123
|
+
operation().then(resolve).catch(reject);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get timeout in milliseconds from config
|
|
128
|
+
*/
|
|
129
|
+
getTimeoutMs(config) {
|
|
130
|
+
if (config.timeout !== undefined) {
|
|
131
|
+
return parseTimeout(config.timeout);
|
|
132
|
+
}
|
|
133
|
+
// Use default timeout based on operation type
|
|
134
|
+
const operation = config.operation.toLowerCase();
|
|
135
|
+
// MCP operations
|
|
136
|
+
if (operation.includes("mcp") || operation.includes("server")) {
|
|
137
|
+
return parseTimeout(DEFAULT_TIMEOUTS.tools.network);
|
|
138
|
+
}
|
|
139
|
+
// File operations
|
|
140
|
+
if (operation.includes("file") ||
|
|
141
|
+
operation.includes("read") ||
|
|
142
|
+
operation.includes("write")) {
|
|
143
|
+
return parseTimeout(DEFAULT_TIMEOUTS.tools.filesystem);
|
|
144
|
+
}
|
|
145
|
+
// Network operations
|
|
146
|
+
if (operation.includes("network") ||
|
|
147
|
+
operation.includes("http") ||
|
|
148
|
+
operation.includes("fetch")) {
|
|
149
|
+
return parseTimeout(DEFAULT_TIMEOUTS.tools.network);
|
|
150
|
+
}
|
|
151
|
+
// Default
|
|
152
|
+
return parseTimeout(DEFAULT_TIMEOUTS.tools.default);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Generate unique operation ID
|
|
156
|
+
*/
|
|
157
|
+
generateOperationId(operation) {
|
|
158
|
+
return `${operation}-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Cleanup specific operation
|
|
162
|
+
*/
|
|
163
|
+
cleanup(operationId) {
|
|
164
|
+
const timeout = this.activeTimeouts.get(operationId);
|
|
165
|
+
if (timeout) {
|
|
166
|
+
timeout.cleanup();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Cleanup all active timeouts (call on shutdown)
|
|
171
|
+
*/
|
|
172
|
+
cleanupAll() {
|
|
173
|
+
for (const [id, timeout] of this.activeTimeouts) {
|
|
174
|
+
timeout.cleanup();
|
|
175
|
+
}
|
|
176
|
+
this.activeTimeouts.clear();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get current active timeout count (for debugging)
|
|
180
|
+
*/
|
|
181
|
+
getActiveTimeoutCount() {
|
|
182
|
+
return this.activeTimeouts.size;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Create a timeout wrapper for child process operations
|
|
186
|
+
*/
|
|
187
|
+
wrapChildProcess(processFactory, config) {
|
|
188
|
+
return this.executeWithTimeout(processFactory, {
|
|
189
|
+
...config,
|
|
190
|
+
gracefulShutdown: true,
|
|
191
|
+
timeout: config.timeout || DEFAULT_TIMEOUTS.tools.network,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Create a timeout wrapper for MCP server operations
|
|
196
|
+
*/
|
|
197
|
+
wrapMCPOperation(operation, operationName, timeoutMs) {
|
|
198
|
+
return this.executeWithTimeout(operation, {
|
|
199
|
+
operation: `mcp-${operationName}`,
|
|
200
|
+
timeout: timeoutMs || parseTimeout(DEFAULT_TIMEOUTS.tools.network),
|
|
201
|
+
retryOnTimeout: false,
|
|
202
|
+
gracefulShutdown: true,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Create a timeout wrapper for CLI operations
|
|
207
|
+
*/
|
|
208
|
+
wrapCLIOperation(operation, operationName, timeoutMs) {
|
|
209
|
+
return this.executeWithTimeout(operation, {
|
|
210
|
+
operation: `cli-${operationName}`,
|
|
211
|
+
timeout: timeoutMs || 120000, // 2 minutes default for CLI
|
|
212
|
+
retryOnTimeout: false,
|
|
213
|
+
gracefulShutdown: true,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Factory function to create a new TimeoutManager instance
|
|
218
|
+
export function createTimeoutManager() {
|
|
219
|
+
return new TimeoutManager();
|
|
220
|
+
}
|
|
221
|
+
// Lazy-loaded default timeout manager instance
|
|
222
|
+
let _defaultTimeoutManager = null;
|
|
223
|
+
export function getDefaultTimeoutManager() {
|
|
224
|
+
if (!_defaultTimeoutManager) {
|
|
225
|
+
_defaultTimeoutManager = createTimeoutManager();
|
|
226
|
+
}
|
|
227
|
+
return _defaultTimeoutManager;
|
|
228
|
+
}
|
|
229
|
+
// Export default instance for backwards compatibility
|
|
230
|
+
export const defaultTimeoutManager = getDefaultTimeoutManager();
|
|
231
|
+
// Cleanup on process exit
|
|
232
|
+
if (typeof process !== "undefined") {
|
|
233
|
+
process.once("exit", () => {
|
|
234
|
+
getDefaultTimeoutManager().cleanupAll();
|
|
235
|
+
});
|
|
236
|
+
process.once("SIGINT", () => {
|
|
237
|
+
getDefaultTimeoutManager().cleanupAll();
|
|
238
|
+
process.exit(0);
|
|
239
|
+
});
|
|
240
|
+
process.once("SIGTERM", () => {
|
|
241
|
+
getDefaultTimeoutManager().cleanupAll();
|
|
242
|
+
process.exit(0);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
@@ -79,6 +79,12 @@ export declare class ContextManager {
|
|
|
79
79
|
* @param updates Partial context updates
|
|
80
80
|
*/
|
|
81
81
|
updateContext(sessionId: string, updates: Partial<NeuroLinkExecutionContext>): void;
|
|
82
|
+
/**
|
|
83
|
+
* Store context directly (used when session ID changes)
|
|
84
|
+
*
|
|
85
|
+
* @param context Complete execution context to store
|
|
86
|
+
*/
|
|
87
|
+
storeContext(context: NeuroLinkExecutionContext): void;
|
|
82
88
|
/**
|
|
83
89
|
* Remove context from active tracking
|
|
84
90
|
*
|
|
@@ -196,6 +196,14 @@ export class ContextManager {
|
|
|
196
196
|
this.activeContexts.set(sessionId, updatedContext);
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Store context directly (used when session ID changes)
|
|
201
|
+
*
|
|
202
|
+
* @param context Complete execution context to store
|
|
203
|
+
*/
|
|
204
|
+
storeContext(context) {
|
|
205
|
+
this.activeContexts.set(context.sessionId, context);
|
|
206
|
+
}
|
|
199
207
|
/**
|
|
200
208
|
* Remove context from active tracking
|
|
201
209
|
*
|
|
@@ -40,6 +40,10 @@ export class ExternalMCPClient extends EventEmitter {
|
|
|
40
40
|
stdio: ["pipe", "pipe", "pipe"],
|
|
41
41
|
env: { ...process.env, ...this.config.env },
|
|
42
42
|
});
|
|
43
|
+
// 🔧 FIX: Register for cleanup
|
|
44
|
+
process.once("beforeExit", () => this.disconnect());
|
|
45
|
+
process.once("SIGINT", () => this.disconnect());
|
|
46
|
+
process.once("SIGTERM", () => this.disconnect());
|
|
43
47
|
if (!this.process.stdout || !this.process.stdin || !this.process.stderr) {
|
|
44
48
|
throw new Error("Failed to create stdio pipes");
|
|
45
49
|
}
|
|
@@ -279,7 +283,7 @@ export class ExternalMCPClient extends EventEmitter {
|
|
|
279
283
|
pending.reject(new Error("Connection closed"));
|
|
280
284
|
}
|
|
281
285
|
this.pendingRequests.clear();
|
|
282
|
-
//
|
|
286
|
+
// 🔧 FIX: Enhanced process cleanup
|
|
283
287
|
if (this.process) {
|
|
284
288
|
this.process.kill("SIGTERM");
|
|
285
289
|
// Force kill after timeout
|
|
@@ -287,7 +291,7 @@ export class ExternalMCPClient extends EventEmitter {
|
|
|
287
291
|
if (this.process && !this.process.killed) {
|
|
288
292
|
this.process.kill("SIGKILL");
|
|
289
293
|
}
|
|
290
|
-
},
|
|
294
|
+
}, 1000); // Reduced from 5000ms to 1000ms
|
|
291
295
|
this.process = null;
|
|
292
296
|
}
|
|
293
297
|
this.isConnected = false;
|
package/dist/mcp/initialize.d.ts
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* Automatically registers built-in NeuroLink servers with the default registry
|
|
4
4
|
* Ensures built-in tools are always available without manual configuration
|
|
5
5
|
*/
|
|
6
|
+
import { type MCPToolRegistry } from "./tool-registry.js";
|
|
6
7
|
/**
|
|
7
8
|
* Initialize NeuroLink MCP system by registering built-in servers
|
|
8
9
|
*/
|
|
9
|
-
export declare function initializeNeuroLinkMCP(): Promise<void>;
|
|
10
|
+
export declare function initializeNeuroLinkMCP(targetRegistry?: MCPToolRegistry): Promise<void>;
|
|
10
11
|
/**
|
|
11
12
|
* Get initialization status
|
|
12
13
|
*/
|
package/dist/mcp/initialize.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* Automatically registers built-in NeuroLink servers with the default registry
|
|
4
4
|
* Ensures built-in tools are always available without manual configuration
|
|
5
5
|
*/
|
|
6
|
-
import { toolRegistry, defaultToolRegistry } from "./tool-registry.js";
|
|
6
|
+
import { toolRegistry, defaultToolRegistry, } from "./tool-registry.js";
|
|
7
7
|
import { mcpLogger } from "./logging.js";
|
|
8
8
|
let isInitialized = false;
|
|
9
9
|
/**
|
|
10
10
|
* Initialize NeuroLink MCP system by registering built-in servers
|
|
11
11
|
*/
|
|
12
|
-
export async function initializeNeuroLinkMCP() {
|
|
12
|
+
export async function initializeNeuroLinkMCP(targetRegistry) {
|
|
13
13
|
if (isInitialized) {
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
@@ -18,14 +18,15 @@ export async function initializeNeuroLinkMCP() {
|
|
|
18
18
|
// Import utility server dynamically to avoid circular dependencies
|
|
19
19
|
// Note: AI core server temporarily disabled due to circular dependency issues
|
|
20
20
|
const { utilityServer } = await import("./servers/utilities/utility-server.js");
|
|
21
|
-
// Register built-in NeuroLink servers with
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
// Register built-in NeuroLink servers with specified registry (or default)
|
|
22
|
+
const registry = targetRegistry || toolRegistry;
|
|
23
|
+
await registry.registerServer(utilityServer.id, utilityServer);
|
|
24
|
+
mcpLogger.debug(`Registered neurolink-utility server with built-in tools in ${targetRegistry ? "target" : "default"} registry`);
|
|
24
25
|
// TODO: Re-enable AI core server once circular dependencies are resolved
|
|
25
26
|
// const { aiCoreServer } = await import('./servers/ai-providers/ai-core-server.js');
|
|
26
|
-
// await
|
|
27
|
+
// await registry.registerServer(aiCoreServer.id, aiCoreServer);
|
|
27
28
|
// mcpLogger.debug('Registered neurolink-ai-core server with AI tools');
|
|
28
|
-
const stats = await
|
|
29
|
+
const stats = await registry.getStats();
|
|
29
30
|
mcpLogger.info(`Initialization complete: ${stats.totalServers} server, ${stats.totalTools} tools available`);
|
|
30
31
|
isInitialized = true;
|
|
31
32
|
}
|
package/dist/mcp/orchestrator.js
CHANGED
|
@@ -70,7 +70,14 @@ export class MCPOrchestrator {
|
|
|
70
70
|
// Create new session with options
|
|
71
71
|
session = await this.sessionManager.createSession(context, options.sessionOptions);
|
|
72
72
|
// Update context with new session ID
|
|
73
|
+
const oldSessionId = context.sessionId;
|
|
73
74
|
context.sessionId = session.id;
|
|
75
|
+
// Remove old context and store updated context in context manager
|
|
76
|
+
if (oldSessionId) {
|
|
77
|
+
this.contextManager.removeContext(oldSessionId);
|
|
78
|
+
}
|
|
79
|
+
// Store the updated context with the new session ID
|
|
80
|
+
this.contextManager.storeContext(context);
|
|
74
81
|
}
|
|
75
82
|
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
76
83
|
console.log(`[Orchestrator] Executing tool '${toolName}' in session ${context.sessionId}`);
|
|
@@ -80,6 +87,8 @@ export class MCPOrchestrator {
|
|
|
80
87
|
const semaphoreKey = `tool:${toolName}`;
|
|
81
88
|
const semaphoreResult = await this.semaphoreManager.acquire(semaphoreKey, async () => {
|
|
82
89
|
try {
|
|
90
|
+
// Add tool to the execution chain
|
|
91
|
+
this.contextManager.addToToolChain(context, toolName);
|
|
83
92
|
// Execute tool through registry
|
|
84
93
|
const result = await this.registry.executeTool(toolName, params, context);
|
|
85
94
|
if (process.env.NEUROLINK_DEBUG === "true") {
|
package/dist/mcp/registry.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface McpRegistry {
|
|
|
15
15
|
* Maintains backward compatibility with existing code
|
|
16
16
|
*/
|
|
17
17
|
export declare class MCPRegistry implements McpRegistry {
|
|
18
|
-
|
|
18
|
+
plugins: Map<string, DiscoveredMcp<Record<string, unknown>>>;
|
|
19
19
|
/**
|
|
20
20
|
* Register a plugin
|
|
21
21
|
*/
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { AIProviderFactory } from "../../../core/factory.js";
|
|
8
|
-
import {
|
|
8
|
+
import { getBestProvider, getAvailableProviders, } from "../../../utils/providerUtils.js";
|
|
9
9
|
/**
|
|
10
10
|
* Input Schemas for AI Analysis Tools
|
|
11
11
|
*/
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { createMCPServer } from "../../factory.js";
|
|
8
8
|
import { AIProviderFactory } from "../../../core/factory.js";
|
|
9
|
-
import {
|
|
9
|
+
import { getBestProvider, getAvailableProviders, } from "../../../utils/providerUtils.js";
|
|
10
10
|
import { logger } from "../../../utils/logger.js";
|
|
11
11
|
import { analyzeAIUsageTool, benchmarkProviderPerformanceTool, optimizePromptParametersTool, } from "./ai-analysis-tools.js";
|
|
12
12
|
import { generateTestCasesTool, refactorCodeTool, generateDocumentationTool, debugAIOutputTool, } from "./ai-workflow-tools.js";
|
|
@@ -85,7 +85,7 @@ aiCoreServer.registerTool({
|
|
|
85
85
|
try {
|
|
86
86
|
logger.debug(`[AI-Core] Starting text generation: "${params.prompt.substring(0, 50)}..."`);
|
|
87
87
|
// Use existing AIProviderFactory with best provider selection
|
|
88
|
-
const selectedProvider = params.provider || getBestProvider(params.provider);
|
|
88
|
+
const selectedProvider = params.provider || (await getBestProvider(params.provider));
|
|
89
89
|
const provider = await AIProviderFactory.createBestProvider(selectedProvider);
|
|
90
90
|
// Generate text using existing NeuroLink patterns
|
|
91
91
|
const result = await provider.generateText({
|
|
@@ -157,7 +157,7 @@ aiCoreServer.registerTool({
|
|
|
157
157
|
logger.debug(`[AI-Core] Selecting provider with requirements:`, params.requirements);
|
|
158
158
|
// Use existing provider selection logic
|
|
159
159
|
const availableProviders = getAvailableProviders();
|
|
160
|
-
const selectedProvider = getBestProvider(params.preferred);
|
|
160
|
+
const selectedProvider = await getBestProvider(params.preferred);
|
|
161
161
|
// Get provider capabilities
|
|
162
162
|
const getProviderCapabilities = (provider) => ({
|
|
163
163
|
multimodal: provider === "openai" ||
|
|
@@ -30,13 +30,13 @@ export declare const workflowToolSchemas: {
|
|
|
30
30
|
includeAsyncTests: z.ZodDefault<z.ZodBoolean>;
|
|
31
31
|
}, "strip", z.ZodTypeAny, {
|
|
32
32
|
codeFunction: string;
|
|
33
|
-
testTypes: ("integration" | "
|
|
33
|
+
testTypes: ("integration" | "performance" | "unit" | "edge-cases" | "security")[];
|
|
34
34
|
framework: "jest" | "mocha" | "vitest" | "pytest" | "unittest" | "rspec";
|
|
35
35
|
coverageTarget: number;
|
|
36
36
|
includeAsyncTests: boolean;
|
|
37
37
|
}, {
|
|
38
38
|
codeFunction: string;
|
|
39
|
-
testTypes?: ("integration" | "
|
|
39
|
+
testTypes?: ("integration" | "performance" | "unit" | "edge-cases" | "security")[] | undefined;
|
|
40
40
|
framework?: "jest" | "mocha" | "vitest" | "pytest" | "unittest" | "rspec" | undefined;
|
|
41
41
|
coverageTarget?: number | undefined;
|
|
42
42
|
includeAsyncTests?: boolean | undefined;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { AIProviderFactory } from "../../../core/factory.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getBestProvider } from "../../../utils/providerUtils.js";
|
|
8
8
|
import { DEFAULT_MAX_TOKENS } from "../../../core/constants.js";
|
|
9
9
|
// Tool-specific schemas with comprehensive validation
|
|
10
10
|
const generateTestCasesSchema = z.object({
|
|
@@ -94,7 +94,7 @@ export class SessionManager {
|
|
|
94
94
|
* @returns Session if found and not expired
|
|
95
95
|
*/
|
|
96
96
|
getSession(sessionId, extend = true) {
|
|
97
|
-
|
|
97
|
+
const session = this.sessions.get(sessionId) || null;
|
|
98
98
|
// For sync compatibility, skip disk loading in getSession
|
|
99
99
|
// Use async getSessionAsync() for full persistence features
|
|
100
100
|
if (!session) {
|