@juspay/neurolink 4.1.0 → 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.
Files changed (75) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/README.md +105 -116
  3. package/dist/cli/commands/mcp.d.ts +11 -0
  4. package/dist/cli/commands/mcp.js +332 -223
  5. package/dist/cli/index.js +69 -8
  6. package/dist/core/factory.js +2 -2
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/lib/core/factory.js +2 -2
  10. package/dist/lib/index.d.ts +1 -1
  11. package/dist/lib/index.js +1 -1
  12. package/dist/lib/mcp/context-manager.d.ts +6 -0
  13. package/dist/lib/mcp/context-manager.js +8 -0
  14. package/dist/lib/mcp/contracts/mcpContract.d.ts +1 -0
  15. package/dist/lib/mcp/external-client.js +6 -2
  16. package/dist/lib/mcp/initialize.d.ts +2 -1
  17. package/dist/lib/mcp/initialize.js +8 -7
  18. package/dist/lib/mcp/orchestrator.js +9 -0
  19. package/dist/lib/mcp/registry.d.ts +1 -1
  20. package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
  21. package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +3 -3
  22. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  23. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
  24. package/dist/lib/mcp/session-manager.js +1 -1
  25. package/dist/lib/mcp/session-persistence.js +1 -1
  26. package/dist/lib/mcp/tool-registry.d.ts +31 -11
  27. package/dist/lib/mcp/tool-registry.js +226 -38
  28. package/dist/lib/mcp/unified-mcp.d.ts +12 -2
  29. package/dist/lib/mcp/unified-registry.d.ts +21 -7
  30. package/dist/lib/mcp/unified-registry.js +179 -17
  31. package/dist/lib/neurolink.js +17 -25
  32. package/dist/lib/providers/googleVertexAI.js +19 -1
  33. package/dist/lib/providers/openAI.js +18 -1
  34. package/dist/lib/utils/provider-setup-messages.d.ts +8 -0
  35. package/dist/lib/utils/provider-setup-messages.js +120 -0
  36. package/dist/lib/utils/provider-validation.d.ts +35 -0
  37. package/dist/lib/utils/provider-validation.js +625 -0
  38. package/dist/lib/utils/providerUtils-fixed.js +20 -1
  39. package/dist/lib/utils/providerUtils.d.ts +2 -2
  40. package/dist/lib/utils/providerUtils.js +38 -7
  41. package/dist/lib/utils/timeout-manager.d.ts +75 -0
  42. package/dist/lib/utils/timeout-manager.js +244 -0
  43. package/dist/mcp/context-manager.d.ts +6 -0
  44. package/dist/mcp/context-manager.js +8 -0
  45. package/dist/mcp/contracts/mcpContract.d.ts +1 -0
  46. package/dist/mcp/external-client.js +6 -2
  47. package/dist/mcp/initialize.d.ts +2 -1
  48. package/dist/mcp/initialize.js +8 -7
  49. package/dist/mcp/orchestrator.js +9 -0
  50. package/dist/mcp/plugins/core/neurolink-mcp.json +15 -15
  51. package/dist/mcp/registry.d.ts +1 -1
  52. package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
  53. package/dist/mcp/servers/ai-providers/ai-core-server.js +3 -3
  54. package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  55. package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
  56. package/dist/mcp/session-manager.js +1 -1
  57. package/dist/mcp/session-persistence.js +1 -1
  58. package/dist/mcp/tool-registry.d.ts +31 -11
  59. package/dist/mcp/tool-registry.js +226 -38
  60. package/dist/mcp/unified-mcp.d.ts +12 -2
  61. package/dist/mcp/unified-registry.d.ts +21 -7
  62. package/dist/mcp/unified-registry.js +179 -17
  63. package/dist/neurolink.js +17 -25
  64. package/dist/providers/googleVertexAI.js +19 -1
  65. package/dist/providers/openAI.js +18 -1
  66. package/dist/utils/provider-setup-messages.d.ts +8 -0
  67. package/dist/utils/provider-setup-messages.js +120 -0
  68. package/dist/utils/provider-validation.d.ts +35 -0
  69. package/dist/utils/provider-validation.js +625 -0
  70. package/dist/utils/providerUtils-fixed.js +20 -1
  71. package/dist/utils/providerUtils.d.ts +2 -2
  72. package/dist/utils/providerUtils.js +38 -7
  73. package/dist/utils/timeout-manager.d.ts +75 -0
  74. package/dist/utils/timeout-manager.js +244 -0
  75. package/package.json +245 -245
@@ -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 getBestProviderSync(requestedProvider) {
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
- // Default fallback order - Google AI (Gemini) first as primary provider
16
- // Ollama last since it requires local setup
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
+ }