@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.
Files changed (61) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cli/commands/config.d.ts +3 -3
  3. package/dist/cli/commands/mcp.js +25 -0
  4. package/dist/cli/factories/commandFactory.d.ts +1 -0
  5. package/dist/cli/factories/commandFactory.js +115 -21
  6. package/dist/cli/index.js +8 -0
  7. package/dist/core/factory.js +77 -4
  8. package/dist/factories/providerFactory.js +3 -0
  9. package/dist/factories/providerRegistry.js +2 -2
  10. package/dist/lib/core/factory.js +77 -4
  11. package/dist/lib/factories/providerFactory.js +3 -0
  12. package/dist/lib/factories/providerRegistry.js +2 -2
  13. package/dist/lib/mcp/externalServerManager.js +13 -14
  14. package/dist/lib/mcp/flexibleToolValidator.d.ts +50 -0
  15. package/dist/lib/mcp/flexibleToolValidator.js +161 -0
  16. package/dist/lib/mcp/toolRegistry.d.ts +2 -2
  17. package/dist/lib/mcp/toolRegistry.js +25 -50
  18. package/dist/lib/neurolink.d.ts +299 -4
  19. package/dist/lib/neurolink.js +434 -73
  20. package/dist/lib/providers/amazonBedrock.d.ts +47 -6
  21. package/dist/lib/providers/amazonBedrock.js +282 -23
  22. package/dist/lib/providers/aws/credentialProvider.d.ts +58 -0
  23. package/dist/lib/providers/aws/credentialProvider.js +267 -0
  24. package/dist/lib/providers/aws/credentialTester.d.ts +49 -0
  25. package/dist/lib/providers/aws/credentialTester.js +394 -0
  26. package/dist/lib/providers/googleVertex.js +13 -4
  27. package/dist/lib/proxy/awsProxyIntegration.d.ts +23 -0
  28. package/dist/lib/proxy/awsProxyIntegration.js +285 -0
  29. package/dist/lib/proxy/proxyFetch.d.ts +9 -5
  30. package/dist/lib/proxy/proxyFetch.js +232 -98
  31. package/dist/lib/proxy/utils/noProxyUtils.d.ts +39 -0
  32. package/dist/lib/proxy/utils/noProxyUtils.js +149 -0
  33. package/dist/lib/types/providers.d.ts +43 -0
  34. package/dist/lib/utils/providerConfig.d.ts +1 -0
  35. package/dist/lib/utils/providerConfig.js +2 -1
  36. package/dist/lib/utils/providerHealth.js +123 -5
  37. package/dist/mcp/externalServerManager.js +13 -14
  38. package/dist/mcp/flexibleToolValidator.d.ts +50 -0
  39. package/dist/mcp/flexibleToolValidator.js +161 -0
  40. package/dist/mcp/toolRegistry.d.ts +2 -2
  41. package/dist/mcp/toolRegistry.js +25 -50
  42. package/dist/neurolink.d.ts +299 -4
  43. package/dist/neurolink.js +434 -73
  44. package/dist/providers/amazonBedrock.d.ts +47 -6
  45. package/dist/providers/amazonBedrock.js +282 -23
  46. package/dist/providers/aws/credentialProvider.d.ts +58 -0
  47. package/dist/providers/aws/credentialProvider.js +267 -0
  48. package/dist/providers/aws/credentialTester.d.ts +49 -0
  49. package/dist/providers/aws/credentialTester.js +394 -0
  50. package/dist/providers/googleVertex.js +13 -4
  51. package/dist/proxy/awsProxyIntegration.d.ts +23 -0
  52. package/dist/proxy/awsProxyIntegration.js +285 -0
  53. package/dist/proxy/proxyFetch.d.ts +9 -5
  54. package/dist/proxy/proxyFetch.js +232 -98
  55. package/dist/proxy/utils/noProxyUtils.d.ts +39 -0
  56. package/dist/proxy/utils/noProxyUtils.js +149 -0
  57. package/dist/types/providers.d.ts +43 -0
  58. package/dist/utils/providerConfig.d.ts +1 -0
  59. package/dist/utils/providerConfig.js +2 -1
  60. package/dist/utils/providerHealth.js +123 -5
  61. package/package.json +5 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [7.29.2](https://github.com/juspay/neurolink/compare/v7.29.1...v7.29.2) (2025-08-29)
2
+
3
+ ### Bug Fixes
4
+
5
+ - **(providers):** enable drop-in replacement for bedrock-mcp-connector ([9b67d23](https://github.com/juspay/neurolink/commit/9b67d233c2e8400a401759e34ffaf46a9a9c77a8))
6
+
7
+ ## [7.29.1](https://github.com/juspay/neurolink/compare/v7.29.0...v7.29.1) (2025-08-28)
8
+
9
+ ### Bug Fixes
10
+
11
+ - **(vertex):** restored support for adc ([238666a](https://github.com/juspay/neurolink/commit/238666ab907fc16945d5de6c5f79637be128f4e6))
12
+
1
13
  ## [7.29.0](https://github.com/juspay/neurolink/compare/v7.28.1...v7.29.0) (2025-08-26)
2
14
 
3
15
  ### Features
@@ -60,8 +60,8 @@ declare const ConfigSchema: z.ZodObject<{
60
60
  }, {
61
61
  model?: string | undefined;
62
62
  projectId?: string | undefined;
63
- location?: string | undefined;
64
63
  credentials?: string | undefined;
64
+ location?: string | undefined;
65
65
  serviceAccountKey?: string | undefined;
66
66
  clientEmail?: string | undefined;
67
67
  privateKey?: string | undefined;
@@ -201,8 +201,8 @@ declare const ConfigSchema: z.ZodObject<{
201
201
  vertex?: {
202
202
  model?: string | undefined;
203
203
  projectId?: string | undefined;
204
- location?: string | undefined;
205
204
  credentials?: string | undefined;
205
+ location?: string | undefined;
206
206
  serviceAccountKey?: string | undefined;
207
207
  clientEmail?: string | undefined;
208
208
  privateKey?: string | undefined;
@@ -570,8 +570,8 @@ declare const ConfigSchema: z.ZodObject<{
570
570
  vertex?: {
571
571
  model?: string | undefined;
572
572
  projectId?: string | undefined;
573
- location?: string | undefined;
574
573
  credentials?: string | undefined;
574
+ location?: string | undefined;
575
575
  serviceAccountKey?: string | undefined;
576
576
  clientEmail?: string | undefined;
577
577
  privateKey?: string | undefined;
@@ -10,6 +10,31 @@ import chalk from "chalk";
10
10
  import ora from "ora";
11
11
  import fs from "fs";
12
12
  import path from "path";
13
+ // Using MCPCommandArgs from types/cli.ts
14
+ /**
15
+ * Response interface for MCP status information returned from the NeuroLink SDK.
16
+ * This interface represents the raw status data that gets converted to CLI-friendly format.
17
+ *
18
+ * @interface MCPStatusResponse
19
+ * @since 7.6.1
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const status: MCPStatusResponse = {
24
+ * autoDiscoveredServers: [
25
+ * {
26
+ * name: "filesystem",
27
+ * id: "fs-server-001",
28
+ * status: "connected",
29
+ * source: "claude-desktop"
30
+ * }
31
+ * ],
32
+ * mcpInitialized: true,
33
+ * totalServers: 3,
34
+ * availableServers: 2
35
+ * };
36
+ * ```
37
+ */
13
38
  /**
14
39
  * Popular MCP servers registry
15
40
  */
@@ -8,6 +8,7 @@ export declare class CLICommandFactory {
8
8
  private static processOptions;
9
9
  private static handleOutput;
10
10
  private static isValidTokenUsage;
11
+ private static normalizeTokenUsage;
11
12
  private static formatAnalyticsForTextMode;
12
13
  /**
13
14
  * Create the new primary 'generate' command
@@ -273,14 +273,53 @@ export class CLICommandFactory {
273
273
  logger.always(output);
274
274
  }
275
275
  }
276
- // Helper method to validate token usage data
276
+ // Helper method to validate token usage data with fallback handling
277
277
  static isValidTokenUsage(tokens) {
278
- return !!(tokens &&
279
- typeof tokens === "object" &&
280
- tokens !== null &&
281
- typeof tokens.input === "number" &&
282
- typeof tokens.output === "number" &&
283
- typeof tokens.total === "number");
278
+ if (!tokens || typeof tokens !== "object" || tokens === null) {
279
+ return false;
280
+ }
281
+ const tokensObj = tokens;
282
+ // Check primary format: analytics.tokens {input, output, total}
283
+ if (typeof tokensObj.input === "number" &&
284
+ typeof tokensObj.output === "number" &&
285
+ typeof tokensObj.total === "number") {
286
+ return true;
287
+ }
288
+ // Check fallback format: tokenUsage {inputTokens, outputTokens, totalTokens}
289
+ if (typeof tokensObj.inputTokens === "number" &&
290
+ typeof tokensObj.outputTokens === "number" &&
291
+ typeof tokensObj.totalTokens === "number") {
292
+ return true;
293
+ }
294
+ return false;
295
+ }
296
+ // Helper method to normalize token usage data to standard format
297
+ static normalizeTokenUsage(tokens) {
298
+ if (!this.isValidTokenUsage(tokens)) {
299
+ return null;
300
+ }
301
+ const tokensObj = tokens;
302
+ // Primary format: analytics.tokens {input, output, total}
303
+ if (typeof tokensObj.input === "number" &&
304
+ typeof tokensObj.output === "number" &&
305
+ typeof tokensObj.total === "number") {
306
+ return {
307
+ input: tokensObj.input,
308
+ output: tokensObj.output,
309
+ total: tokensObj.total,
310
+ };
311
+ }
312
+ // Fallback format: tokenUsage {inputTokens, outputTokens, totalTokens}
313
+ if (typeof tokensObj.inputTokens === "number" &&
314
+ typeof tokensObj.outputTokens === "number" &&
315
+ typeof tokensObj.totalTokens === "number") {
316
+ return {
317
+ input: tokensObj.inputTokens,
318
+ output: tokensObj.outputTokens,
319
+ total: tokensObj.totalTokens,
320
+ };
321
+ }
322
+ return null;
284
323
  }
285
324
  // Helper method to format analytics for text mode display
286
325
  static formatAnalyticsForTextMode(result) {
@@ -299,10 +338,10 @@ export class CLICommandFactory {
299
338
  analyticsText += ` (${modelName})`;
300
339
  }
301
340
  analyticsText += "\n";
302
- // Token usage
303
- if (this.isValidTokenUsage(analytics.tokens)) {
304
- const tokens = analytics.tokens;
305
- analyticsText += ` Tokens: ${tokens.input} input + ${tokens.output} output = ${tokens.total} total\n`;
341
+ // Token usage with fallback handling
342
+ const normalizedTokens = this.normalizeTokenUsage(analytics.tokens);
343
+ if (normalizedTokens) {
344
+ analyticsText += ` Tokens: ${normalizedTokens.input} input + ${normalizedTokens.output} output = ${normalizedTokens.total} total\n`;
306
345
  }
307
346
  // Cost information
308
347
  if (analytics.cost !== undefined &&
@@ -310,9 +349,12 @@ export class CLICommandFactory {
310
349
  typeof analytics.cost === "number") {
311
350
  analyticsText += ` Cost: $${analytics.cost.toFixed(5)}\n`;
312
351
  }
313
- // Response time
314
- if (analytics.responseTime && typeof analytics.responseTime === "number") {
315
- const timeInSeconds = (analytics.responseTime / 1000).toFixed(1);
352
+ // Response time with fallback handling for requestDuration vs responseTime
353
+ const duration = analytics.responseTime ||
354
+ analytics.requestDuration ||
355
+ analytics.duration;
356
+ if (duration && typeof duration === "number") {
357
+ const timeInSeconds = (duration / 1000).toFixed(1);
316
358
  analyticsText += ` Time: ${timeInSeconds}s\n`;
317
359
  }
318
360
  // Tools used
@@ -935,14 +977,66 @@ export class CLICommandFactory {
935
977
  : undefined,
936
978
  });
937
979
  let fullContent = "";
938
- // Process the stream
939
- for await (const chunk of stream.stream) {
940
- if (options.delay && options.delay > 0) {
941
- // Demo mode - add delay between chunks
942
- await new Promise((resolve) => setTimeout(resolve, options.delay));
980
+ let contentReceived = false;
981
+ const abortController = new AbortController();
982
+ // Create timeout promise for stream consumption (30 seconds)
983
+ const timeoutPromise = new Promise((_, reject) => {
984
+ const timeoutId = setTimeout(() => {
985
+ if (!contentReceived) {
986
+ const timeoutError = new Error("\n❌ Stream timeout - no content received within 30 seconds\n" +
987
+ "This usually indicates authentication or network issues\n\n" +
988
+ "🔧 Try these steps:\n" +
989
+ "1. Check your provider credentials are configured correctly\n" +
990
+ `2. Test generate mode: neurolink generate "test" --provider ${options.provider}\n` +
991
+ `3. Use debug mode: neurolink stream "test" --provider ${options.provider} --debug`);
992
+ reject(timeoutError);
993
+ }
994
+ }, 30000);
995
+ // Clean up timeout when aborted
996
+ abortController.signal.addEventListener("abort", () => {
997
+ clearTimeout(timeoutId);
998
+ });
999
+ });
1000
+ try {
1001
+ // Process the stream with timeout handling
1002
+ const streamIterator = stream.stream[Symbol.asyncIterator]();
1003
+ let timeoutActive = true;
1004
+ while (true) {
1005
+ let nextResult;
1006
+ if (timeoutActive && !contentReceived) {
1007
+ // Race between next chunk and timeout for first chunk only
1008
+ nextResult = await Promise.race([
1009
+ streamIterator.next(),
1010
+ timeoutPromise,
1011
+ ]);
1012
+ }
1013
+ else {
1014
+ // No timeout for subsequent chunks
1015
+ nextResult = await streamIterator.next();
1016
+ }
1017
+ if (nextResult.done) {
1018
+ break;
1019
+ }
1020
+ if (!contentReceived) {
1021
+ contentReceived = true;
1022
+ timeoutActive = false;
1023
+ abortController.abort(); // Cancel timeout
1024
+ }
1025
+ if (options.delay && options.delay > 0) {
1026
+ // Demo mode - add delay between chunks
1027
+ await new Promise((resolve) => setTimeout(resolve, options.delay));
1028
+ }
1029
+ process.stdout.write(nextResult.value.content);
1030
+ fullContent += nextResult.value.content;
943
1031
  }
944
- process.stdout.write(chunk.content);
945
- fullContent += chunk.content;
1032
+ }
1033
+ catch (error) {
1034
+ abortController.abort(); // Clean up timeout
1035
+ throw error;
1036
+ }
1037
+ if (!contentReceived) {
1038
+ throw new Error("\n❌ No content received from stream\n" +
1039
+ "Check your credentials and provider configuration");
946
1040
  }
947
1041
  if (!options.quiet) {
948
1042
  process.stdout.write("\n");
package/dist/cli/index.js CHANGED
@@ -14,6 +14,14 @@ import { fileURLToPath } from "url";
14
14
  import { CLICommandFactory } from "./factories/commandFactory.js";
15
15
  import { AuthenticationError, AuthorizationError, NetworkError, RateLimitError, } from "../lib/types/errors.js";
16
16
  import { logger } from "../lib/utils/logger.js";
17
+ // Clean up pnpm-specific environment variables that cause npm warnings
18
+ // These variables are set by pnpm but cause "Unknown env config" warnings in npm
19
+ if (process.env.npm_config_verify_deps_before_run) {
20
+ delete process.env.npm_config_verify_deps_before_run;
21
+ }
22
+ if (process.env.npm_config__jsr_registry) {
23
+ delete process.env.npm_config__jsr_registry;
24
+ }
17
25
  // Get version from package.json
18
26
  const __filename = fileURLToPath(import.meta.url);
19
27
  const __dirname = path.dirname(__filename);
@@ -55,12 +55,18 @@ export class AIProviderFactory {
55
55
  * @returns AIProvider instance
56
56
  */
57
57
  static async createProvider(providerName, modelName, enableMCP = true, sdk) {
58
- const functionTag = "AIawait ProviderFactory.createProvider";
58
+ const functionTag = "AIProviderFactory.createProvider";
59
59
  // Providers are registered via ProviderFactory.initialize() on first use
60
60
  logger.debug(`[${functionTag}] Provider creation started`, {
61
61
  providerName,
62
62
  modelName: modelName || "default",
63
63
  enableMCP,
64
+ environmentVariables: {
65
+ BEDROCK_MODEL: process.env.BEDROCK_MODEL || "not set",
66
+ BEDROCK_MODEL_ID: process.env.BEDROCK_MODEL_ID || "not set",
67
+ VERTEX_MODEL: process.env.VERTEX_MODEL || "not set",
68
+ OPENAI_MODEL: process.env.OPENAI_MODEL || "not set",
69
+ },
64
70
  });
65
71
  try {
66
72
  // DYNAMIC MODEL PROVIDER STATUS (2025): Enhanced with timeout handling
@@ -73,12 +79,57 @@ export class AIProviderFactory {
73
79
  //
74
80
  // The dynamic model provider now provides reliable functionality without hanging
75
81
  let resolvedModelName = modelName;
76
- // Enable dynamic model resolution with timeout-protected initialization
82
+ // PRIORITY 1: Check environment variables BEFORE dynamic resolution
77
83
  if (!modelName || modelName === "default") {
84
+ logger.debug(`[${functionTag}] Checking environment variables for provider: ${providerName}`);
85
+ // Check for provider-specific environment variables first
86
+ if (providerName.toLowerCase().includes("bedrock")) {
87
+ const envModel = process.env.BEDROCK_MODEL || process.env.BEDROCK_MODEL_ID;
88
+ if (envModel) {
89
+ resolvedModelName = envModel;
90
+ logger.debug(`[${functionTag}] Environment variable found for Bedrock`, {
91
+ envVariable: process.env.BEDROCK_MODEL
92
+ ? "BEDROCK_MODEL"
93
+ : "BEDROCK_MODEL_ID",
94
+ resolvedModel: envModel,
95
+ });
96
+ }
97
+ else {
98
+ logger.debug(`[${functionTag}] No Bedrock environment variables found (BEDROCK_MODEL, BEDROCK_MODEL_ID)`);
99
+ }
100
+ }
101
+ else if (providerName.toLowerCase().includes("vertex")) {
102
+ const envModel = process.env.VERTEX_MODEL;
103
+ if (envModel) {
104
+ resolvedModelName = envModel;
105
+ logger.debug(`[${functionTag}] Environment variable found for Vertex`, {
106
+ envVariable: "VERTEX_MODEL",
107
+ resolvedModel: envModel,
108
+ });
109
+ }
110
+ else {
111
+ logger.debug(`[${functionTag}] No Vertex environment variables found (VERTEX_MODEL)`);
112
+ }
113
+ }
114
+ else {
115
+ logger.debug(`[${functionTag}] Provider ${providerName} - no environment variable check implemented`);
116
+ }
117
+ }
118
+ else {
119
+ logger.debug(`[${functionTag}] Skipping environment variable check - explicit model provided: ${modelName}`);
120
+ }
121
+ // PRIORITY 2: Enable dynamic model resolution only if no env var found
122
+ if ((!resolvedModelName || resolvedModelName === "default") &&
123
+ (!modelName || modelName === "default")) {
124
+ logger.debug(`[${functionTag}] Attempting dynamic model resolution`, {
125
+ currentResolvedModel: resolvedModelName || "none",
126
+ reason: "No environment variable found and no explicit model provided",
127
+ });
78
128
  try {
79
129
  const normalizedProvider = this.normalizeProviderName(providerName);
80
130
  // Initialize with timeout protection - won't hang anymore
81
131
  if (dynamicModelProvider.needsRefresh()) {
132
+ logger.debug(`[${functionTag}] Dynamic model provider needs refresh - initializing`);
82
133
  await this.initializeDynamicProviderWithTimeout();
83
134
  }
84
135
  const dynamicModel = dynamicModelProvider.resolveModel(normalizedProvider, modelName || undefined);
@@ -92,6 +143,12 @@ export class AIProviderFactory {
92
143
  pricing: dynamicModel.pricing.input,
93
144
  });
94
145
  }
146
+ else {
147
+ logger.debug(`[${functionTag}] Dynamic model resolution returned null`, {
148
+ provider: normalizedProvider,
149
+ requestedModel: modelName || "default",
150
+ });
151
+ }
95
152
  }
96
153
  catch (resolveError) {
97
154
  logger.debug(`[${functionTag}] Dynamic model resolution failed, using static fallback`, {
@@ -102,6 +159,12 @@ export class AIProviderFactory {
102
159
  // Continue with static model name - no functionality loss
103
160
  }
104
161
  }
162
+ else {
163
+ logger.debug(`[${functionTag}] Skipping dynamic model resolution`, {
164
+ resolvedModelName: resolvedModelName || "none",
165
+ reason: "Model already resolved from environment variables or explicit parameter",
166
+ });
167
+ }
105
168
  // CRITICAL FIX: Initialize providers before using them
106
169
  await ProviderRegistry.registerAllProviders();
107
170
  // PURE FACTORY PATTERN: No switch statements - use ProviderFactory exclusively
@@ -109,8 +172,18 @@ export class AIProviderFactory {
109
172
  const finalModelName = resolvedModelName === "default" || resolvedModelName === null
110
173
  ? undefined
111
174
  : resolvedModelName;
175
+ logger.debug(`[${functionTag}] Final provider configuration`, {
176
+ originalProviderName: providerName,
177
+ normalizedProviderName: normalizedName,
178
+ originalModelName: modelName || "not provided",
179
+ resolvedModelName: resolvedModelName || "not resolved",
180
+ finalModelName: finalModelName || "using provider default",
181
+ });
112
182
  // Create provider with enhanced SDK
113
183
  const provider = await ProviderFactory.createProvider(normalizedName, finalModelName, sdk);
184
+ // Summary logging in format expected by debugging tools
185
+ logger.debug(`[AIProviderFactory] Provider creation completed { providerName: '${normalizedName}', modelName: '${finalModelName}' }`);
186
+ logger.debug(`[AIProviderFactory] Resolved model: ${finalModelName}`);
114
187
  logger.debug(componentIdentifier, "Pure factory pattern provider created", {
115
188
  providerName: normalizedName,
116
189
  modelName: finalModelName,
@@ -153,7 +226,7 @@ export class AIProviderFactory {
153
226
  * @returns AIProvider instance
154
227
  */
155
228
  static async createProviderWithModel(provider, model) {
156
- const functionTag = "AIawait ProviderFactory.createProviderWithModel";
229
+ const functionTag = "AIProviderFactory.createProviderWithModel";
157
230
  logger.debug(`[${functionTag}] Provider model creation started`, {
158
231
  provider,
159
232
  model,
@@ -214,7 +287,7 @@ export class AIProviderFactory {
214
287
  * @returns Object with primary and fallback providers
215
288
  */
216
289
  static async createProviderWithFallback(primaryProvider, fallbackProvider, modelName, enableMCP = true) {
217
- const functionTag = "AIawait ProviderFactory.createProviderWithFallback";
290
+ const functionTag = "AIProviderFactory.createProviderWithFallback";
218
291
  logger.debug(`[${functionTag}] Fallback provider setup started`, {
219
292
  primaryProvider,
220
293
  fallbackProvider,
@@ -42,6 +42,9 @@ export class ProviderFactory {
42
42
  if (providerName.toLowerCase().includes("vertex")) {
43
43
  model = process.env.VERTEX_MODEL;
44
44
  }
45
+ else if (providerName.toLowerCase().includes("bedrock")) {
46
+ model = process.env.BEDROCK_MODEL || process.env.BEDROCK_MODEL_ID;
47
+ }
45
48
  // Fallback to registry default if no env var
46
49
  model = model || registration.defaultModel;
47
50
  }
@@ -39,9 +39,9 @@ export class ProviderRegistry {
39
39
  return new AnthropicProvider(modelName, sdk);
40
40
  }, "claude-3-5-sonnet-20241022", ["claude", "anthropic"]);
41
41
  // Register Amazon Bedrock provider
42
- ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName) => {
42
+ ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName, _providerName, sdk) => {
43
43
  const { AmazonBedrockProvider } = await import("../providers/amazonBedrock.js");
44
- return new AmazonBedrockProvider(modelName);
44
+ return new AmazonBedrockProvider(modelName, undefined, sdk);
45
45
  }, undefined, // Let provider read BEDROCK_MODEL from .env
46
46
  ["bedrock", "aws"]);
47
47
  // Register Azure OpenAI provider
@@ -55,12 +55,18 @@ export class AIProviderFactory {
55
55
  * @returns AIProvider instance
56
56
  */
57
57
  static async createProvider(providerName, modelName, enableMCP = true, sdk) {
58
- const functionTag = "AIawait ProviderFactory.createProvider";
58
+ const functionTag = "AIProviderFactory.createProvider";
59
59
  // Providers are registered via ProviderFactory.initialize() on first use
60
60
  logger.debug(`[${functionTag}] Provider creation started`, {
61
61
  providerName,
62
62
  modelName: modelName || "default",
63
63
  enableMCP,
64
+ environmentVariables: {
65
+ BEDROCK_MODEL: process.env.BEDROCK_MODEL || "not set",
66
+ BEDROCK_MODEL_ID: process.env.BEDROCK_MODEL_ID || "not set",
67
+ VERTEX_MODEL: process.env.VERTEX_MODEL || "not set",
68
+ OPENAI_MODEL: process.env.OPENAI_MODEL || "not set",
69
+ },
64
70
  });
65
71
  try {
66
72
  // DYNAMIC MODEL PROVIDER STATUS (2025): Enhanced with timeout handling
@@ -73,12 +79,57 @@ export class AIProviderFactory {
73
79
  //
74
80
  // The dynamic model provider now provides reliable functionality without hanging
75
81
  let resolvedModelName = modelName;
76
- // Enable dynamic model resolution with timeout-protected initialization
82
+ // PRIORITY 1: Check environment variables BEFORE dynamic resolution
77
83
  if (!modelName || modelName === "default") {
84
+ logger.debug(`[${functionTag}] Checking environment variables for provider: ${providerName}`);
85
+ // Check for provider-specific environment variables first
86
+ if (providerName.toLowerCase().includes("bedrock")) {
87
+ const envModel = process.env.BEDROCK_MODEL || process.env.BEDROCK_MODEL_ID;
88
+ if (envModel) {
89
+ resolvedModelName = envModel;
90
+ logger.debug(`[${functionTag}] Environment variable found for Bedrock`, {
91
+ envVariable: process.env.BEDROCK_MODEL
92
+ ? "BEDROCK_MODEL"
93
+ : "BEDROCK_MODEL_ID",
94
+ resolvedModel: envModel,
95
+ });
96
+ }
97
+ else {
98
+ logger.debug(`[${functionTag}] No Bedrock environment variables found (BEDROCK_MODEL, BEDROCK_MODEL_ID)`);
99
+ }
100
+ }
101
+ else if (providerName.toLowerCase().includes("vertex")) {
102
+ const envModel = process.env.VERTEX_MODEL;
103
+ if (envModel) {
104
+ resolvedModelName = envModel;
105
+ logger.debug(`[${functionTag}] Environment variable found for Vertex`, {
106
+ envVariable: "VERTEX_MODEL",
107
+ resolvedModel: envModel,
108
+ });
109
+ }
110
+ else {
111
+ logger.debug(`[${functionTag}] No Vertex environment variables found (VERTEX_MODEL)`);
112
+ }
113
+ }
114
+ else {
115
+ logger.debug(`[${functionTag}] Provider ${providerName} - no environment variable check implemented`);
116
+ }
117
+ }
118
+ else {
119
+ logger.debug(`[${functionTag}] Skipping environment variable check - explicit model provided: ${modelName}`);
120
+ }
121
+ // PRIORITY 2: Enable dynamic model resolution only if no env var found
122
+ if ((!resolvedModelName || resolvedModelName === "default") &&
123
+ (!modelName || modelName === "default")) {
124
+ logger.debug(`[${functionTag}] Attempting dynamic model resolution`, {
125
+ currentResolvedModel: resolvedModelName || "none",
126
+ reason: "No environment variable found and no explicit model provided",
127
+ });
78
128
  try {
79
129
  const normalizedProvider = this.normalizeProviderName(providerName);
80
130
  // Initialize with timeout protection - won't hang anymore
81
131
  if (dynamicModelProvider.needsRefresh()) {
132
+ logger.debug(`[${functionTag}] Dynamic model provider needs refresh - initializing`);
82
133
  await this.initializeDynamicProviderWithTimeout();
83
134
  }
84
135
  const dynamicModel = dynamicModelProvider.resolveModel(normalizedProvider, modelName || undefined);
@@ -92,6 +143,12 @@ export class AIProviderFactory {
92
143
  pricing: dynamicModel.pricing.input,
93
144
  });
94
145
  }
146
+ else {
147
+ logger.debug(`[${functionTag}] Dynamic model resolution returned null`, {
148
+ provider: normalizedProvider,
149
+ requestedModel: modelName || "default",
150
+ });
151
+ }
95
152
  }
96
153
  catch (resolveError) {
97
154
  logger.debug(`[${functionTag}] Dynamic model resolution failed, using static fallback`, {
@@ -102,6 +159,12 @@ export class AIProviderFactory {
102
159
  // Continue with static model name - no functionality loss
103
160
  }
104
161
  }
162
+ else {
163
+ logger.debug(`[${functionTag}] Skipping dynamic model resolution`, {
164
+ resolvedModelName: resolvedModelName || "none",
165
+ reason: "Model already resolved from environment variables or explicit parameter",
166
+ });
167
+ }
105
168
  // CRITICAL FIX: Initialize providers before using them
106
169
  await ProviderRegistry.registerAllProviders();
107
170
  // PURE FACTORY PATTERN: No switch statements - use ProviderFactory exclusively
@@ -109,8 +172,18 @@ export class AIProviderFactory {
109
172
  const finalModelName = resolvedModelName === "default" || resolvedModelName === null
110
173
  ? undefined
111
174
  : resolvedModelName;
175
+ logger.debug(`[${functionTag}] Final provider configuration`, {
176
+ originalProviderName: providerName,
177
+ normalizedProviderName: normalizedName,
178
+ originalModelName: modelName || "not provided",
179
+ resolvedModelName: resolvedModelName || "not resolved",
180
+ finalModelName: finalModelName || "using provider default",
181
+ });
112
182
  // Create provider with enhanced SDK
113
183
  const provider = await ProviderFactory.createProvider(normalizedName, finalModelName, sdk);
184
+ // Summary logging in format expected by debugging tools
185
+ logger.debug(`[AIProviderFactory] Provider creation completed { providerName: '${normalizedName}', modelName: '${finalModelName}' }`);
186
+ logger.debug(`[AIProviderFactory] Resolved model: ${finalModelName}`);
114
187
  logger.debug(componentIdentifier, "Pure factory pattern provider created", {
115
188
  providerName: normalizedName,
116
189
  modelName: finalModelName,
@@ -153,7 +226,7 @@ export class AIProviderFactory {
153
226
  * @returns AIProvider instance
154
227
  */
155
228
  static async createProviderWithModel(provider, model) {
156
- const functionTag = "AIawait ProviderFactory.createProviderWithModel";
229
+ const functionTag = "AIProviderFactory.createProviderWithModel";
157
230
  logger.debug(`[${functionTag}] Provider model creation started`, {
158
231
  provider,
159
232
  model,
@@ -214,7 +287,7 @@ export class AIProviderFactory {
214
287
  * @returns Object with primary and fallback providers
215
288
  */
216
289
  static async createProviderWithFallback(primaryProvider, fallbackProvider, modelName, enableMCP = true) {
217
- const functionTag = "AIawait ProviderFactory.createProviderWithFallback";
290
+ const functionTag = "AIProviderFactory.createProviderWithFallback";
218
291
  logger.debug(`[${functionTag}] Fallback provider setup started`, {
219
292
  primaryProvider,
220
293
  fallbackProvider,
@@ -42,6 +42,9 @@ export class ProviderFactory {
42
42
  if (providerName.toLowerCase().includes("vertex")) {
43
43
  model = process.env.VERTEX_MODEL;
44
44
  }
45
+ else if (providerName.toLowerCase().includes("bedrock")) {
46
+ model = process.env.BEDROCK_MODEL || process.env.BEDROCK_MODEL_ID;
47
+ }
45
48
  // Fallback to registry default if no env var
46
49
  model = model || registration.defaultModel;
47
50
  }
@@ -39,9 +39,9 @@ export class ProviderRegistry {
39
39
  return new AnthropicProvider(modelName, sdk);
40
40
  }, "claude-3-5-sonnet-20241022", ["claude", "anthropic"]);
41
41
  // Register Amazon Bedrock provider
42
- ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName) => {
42
+ ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName, _providerName, sdk) => {
43
43
  const { AmazonBedrockProvider } = await import("../providers/amazonBedrock.js");
44
- return new AmazonBedrockProvider(modelName);
44
+ return new AmazonBedrockProvider(modelName, undefined, sdk);
45
45
  }, undefined, // Let provider read BEDROCK_MODEL from .env
46
46
  ["bedrock", "aws"]);
47
47
  // Register Azure OpenAI provider
@@ -664,6 +664,9 @@ export class ExternalServerManager extends EventEmitter {
664
664
  const delay = Math.min(1000 *
665
665
  Math.pow(this.config.restartBackoffMultiplier, instance.reconnectAttempts - 1), 30000);
666
666
  mcpLogger.info(`[ExternalServerManager] Scheduling restart for ${serverId} in ${delay}ms (attempt ${instance.reconnectAttempts})`);
667
+ if (instance.restartTimer) {
668
+ return;
669
+ } // already scheduled
667
670
  instance.restartTimer = setTimeout(async () => {
668
671
  try {
669
672
  await this.stopServer(serverId);
@@ -914,6 +917,7 @@ export class ExternalServerManager extends EventEmitter {
914
917
  }
915
918
  try {
916
919
  mcpLogger.debug(`[ExternalServerManager] Registering ${instance.toolsMap.size} tools with main registry for server: ${serverId}`);
920
+ const registrations = [];
917
921
  for (const [toolName, tool] of instance.toolsMap.entries()) {
918
922
  const toolId = `${serverId}.${toolName}`;
919
923
  const toolInfo = {
@@ -923,21 +927,16 @@ export class ExternalServerManager extends EventEmitter {
923
927
  serverId: serverId,
924
928
  category: detectCategory({ isExternal: true, serverId }),
925
929
  };
926
- // Register with main tool registry
927
- try {
928
- toolRegistry.registerTool(toolId, toolInfo, {
929
- execute: async (params, context) => {
930
- // Execute tool via ExternalServerManager for proper lifecycle management
931
- return await this.executeTool(serverId, toolName, params, { timeout: this.config.defaultTimeout });
932
- },
933
- });
934
- mcpLogger.debug(`[ExternalServerManager] Registered tool with main registry: ${toolId}`);
935
- }
936
- catch (registrationError) {
937
- mcpLogger.warn(`[ExternalServerManager] Failed to register tool ${toolId} with main registry:`, registrationError);
938
- }
930
+ registrations.push(toolRegistry.registerTool(toolId, toolInfo, {
931
+ execute: async (params) => await this.executeTool(serverId, toolName, params, {
932
+ timeout: this.config.defaultTimeout,
933
+ }),
934
+ }));
939
935
  }
940
- mcpLogger.info(`[ExternalServerManager] Successfully registered ${instance.toolsMap.size} tools with main registry for ${serverId}`);
936
+ const results = await Promise.allSettled(registrations);
937
+ const ok = results.filter((r) => r.status === "fulfilled").length;
938
+ const failed = results.length - ok;
939
+ mcpLogger.info(`[ExternalServerManager] Registered ${ok}/${results.length} tools with main registry for ${serverId}${failed ? ` (${failed} failed)` : ""}`);
941
940
  }
942
941
  catch (error) {
943
942
  mcpLogger.error(`[ExternalServerManager] Failed to register tools with main registry for ${serverId}:`, error);