@juspay/neurolink 7.6.1 → 7.7.1

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 (138) hide show
  1. package/CHANGELOG.md +15 -4
  2. package/README.md +78 -3
  3. package/dist/cli/commands/config.d.ts +275 -3
  4. package/dist/cli/commands/config.js +121 -0
  5. package/dist/cli/commands/mcp.js +77 -28
  6. package/dist/cli/factories/commandFactory.js +359 -6
  7. package/dist/core/analytics.js +7 -27
  8. package/dist/core/baseProvider.js +43 -4
  9. package/dist/core/constants.d.ts +46 -0
  10. package/dist/core/constants.js +47 -0
  11. package/dist/core/dynamicModels.d.ts +16 -4
  12. package/dist/core/dynamicModels.js +130 -26
  13. package/dist/core/evaluation.js +5 -1
  14. package/dist/core/evaluationProviders.d.ts +6 -2
  15. package/dist/core/evaluationProviders.js +41 -125
  16. package/dist/core/factory.d.ts +5 -0
  17. package/dist/core/factory.js +62 -50
  18. package/dist/core/modelConfiguration.d.ts +246 -0
  19. package/dist/core/modelConfiguration.js +775 -0
  20. package/dist/core/types.d.ts +22 -3
  21. package/dist/core/types.js +5 -1
  22. package/dist/factories/providerRegistry.js +3 -3
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/lib/core/analytics.js +7 -27
  26. package/dist/lib/core/baseProvider.js +43 -4
  27. package/dist/lib/core/constants.d.ts +46 -0
  28. package/dist/lib/core/constants.js +47 -0
  29. package/dist/lib/core/dynamicModels.d.ts +16 -4
  30. package/dist/lib/core/dynamicModels.js +130 -26
  31. package/dist/lib/core/evaluation.js +5 -1
  32. package/dist/lib/core/evaluationProviders.d.ts +6 -2
  33. package/dist/lib/core/evaluationProviders.js +41 -125
  34. package/dist/lib/core/factory.d.ts +5 -0
  35. package/dist/lib/core/factory.js +63 -50
  36. package/dist/lib/core/modelConfiguration.d.ts +246 -0
  37. package/dist/lib/core/modelConfiguration.js +775 -0
  38. package/dist/lib/core/types.d.ts +22 -3
  39. package/dist/lib/core/types.js +5 -1
  40. package/dist/lib/factories/providerRegistry.js +3 -3
  41. package/dist/lib/index.d.ts +1 -1
  42. package/dist/lib/index.js +1 -1
  43. package/dist/lib/mcp/factory.d.ts +5 -5
  44. package/dist/lib/mcp/factory.js +2 -2
  45. package/dist/lib/mcp/servers/utilities/utilityServer.d.ts +1 -1
  46. package/dist/lib/mcp/servers/utilities/utilityServer.js +1 -1
  47. package/dist/lib/mcp/toolRegistry.js +2 -2
  48. package/dist/lib/neurolink.d.ts +168 -12
  49. package/dist/lib/neurolink.js +685 -123
  50. package/dist/lib/providers/anthropic.js +52 -2
  51. package/dist/lib/providers/googleAiStudio.js +4 -0
  52. package/dist/lib/providers/googleVertex.d.ts +75 -9
  53. package/dist/lib/providers/googleVertex.js +365 -46
  54. package/dist/lib/providers/huggingFace.d.ts +52 -11
  55. package/dist/lib/providers/huggingFace.js +180 -42
  56. package/dist/lib/providers/litellm.d.ts +9 -9
  57. package/dist/lib/providers/litellm.js +103 -16
  58. package/dist/lib/providers/ollama.d.ts +52 -17
  59. package/dist/lib/providers/ollama.js +276 -68
  60. package/dist/lib/sdk/toolRegistration.d.ts +42 -0
  61. package/dist/lib/sdk/toolRegistration.js +269 -27
  62. package/dist/lib/telemetry/telemetryService.d.ts +6 -0
  63. package/dist/lib/telemetry/telemetryService.js +38 -3
  64. package/dist/lib/types/contextTypes.d.ts +75 -11
  65. package/dist/lib/types/contextTypes.js +227 -1
  66. package/dist/lib/types/domainTypes.d.ts +62 -0
  67. package/dist/lib/types/domainTypes.js +5 -0
  68. package/dist/lib/types/generateTypes.d.ts +52 -0
  69. package/dist/lib/types/index.d.ts +1 -0
  70. package/dist/lib/types/mcpTypes.d.ts +1 -1
  71. package/dist/lib/types/mcpTypes.js +1 -1
  72. package/dist/lib/types/streamTypes.d.ts +14 -0
  73. package/dist/lib/types/universalProviderOptions.d.ts +1 -1
  74. package/dist/lib/utils/errorHandling.d.ts +142 -0
  75. package/dist/lib/utils/errorHandling.js +316 -0
  76. package/dist/lib/utils/factoryProcessing.d.ts +74 -0
  77. package/dist/lib/utils/factoryProcessing.js +588 -0
  78. package/dist/lib/utils/optionsConversion.d.ts +54 -0
  79. package/dist/lib/utils/optionsConversion.js +126 -0
  80. package/dist/lib/utils/optionsUtils.d.ts +246 -0
  81. package/dist/lib/utils/optionsUtils.js +960 -0
  82. package/dist/lib/utils/providerConfig.js +6 -2
  83. package/dist/lib/utils/providerHealth.d.ts +107 -0
  84. package/dist/lib/utils/providerHealth.js +543 -0
  85. package/dist/lib/utils/providerUtils.d.ts +17 -0
  86. package/dist/lib/utils/providerUtils.js +271 -16
  87. package/dist/lib/utils/timeout.js +1 -1
  88. package/dist/lib/utils/tokenLimits.d.ts +33 -0
  89. package/dist/lib/utils/tokenLimits.js +118 -0
  90. package/dist/mcp/factory.d.ts +5 -5
  91. package/dist/mcp/factory.js +2 -2
  92. package/dist/mcp/servers/utilities/utilityServer.d.ts +1 -1
  93. package/dist/mcp/servers/utilities/utilityServer.js +1 -1
  94. package/dist/mcp/toolRegistry.js +2 -2
  95. package/dist/neurolink.d.ts +168 -12
  96. package/dist/neurolink.js +685 -123
  97. package/dist/providers/anthropic.js +52 -2
  98. package/dist/providers/googleAiStudio.js +4 -0
  99. package/dist/providers/googleVertex.d.ts +75 -9
  100. package/dist/providers/googleVertex.js +365 -46
  101. package/dist/providers/huggingFace.d.ts +52 -11
  102. package/dist/providers/huggingFace.js +181 -43
  103. package/dist/providers/litellm.d.ts +9 -9
  104. package/dist/providers/litellm.js +103 -16
  105. package/dist/providers/ollama.d.ts +52 -17
  106. package/dist/providers/ollama.js +276 -68
  107. package/dist/sdk/toolRegistration.d.ts +42 -0
  108. package/dist/sdk/toolRegistration.js +269 -27
  109. package/dist/telemetry/telemetryService.d.ts +6 -0
  110. package/dist/telemetry/telemetryService.js +38 -3
  111. package/dist/types/contextTypes.d.ts +75 -11
  112. package/dist/types/contextTypes.js +227 -2
  113. package/dist/types/domainTypes.d.ts +62 -0
  114. package/dist/types/domainTypes.js +5 -0
  115. package/dist/types/generateTypes.d.ts +52 -0
  116. package/dist/types/index.d.ts +1 -0
  117. package/dist/types/mcpTypes.d.ts +1 -1
  118. package/dist/types/mcpTypes.js +1 -1
  119. package/dist/types/streamTypes.d.ts +14 -0
  120. package/dist/types/universalProviderOptions.d.ts +1 -1
  121. package/dist/types/universalProviderOptions.js +0 -1
  122. package/dist/utils/errorHandling.d.ts +142 -0
  123. package/dist/utils/errorHandling.js +316 -0
  124. package/dist/utils/factoryProcessing.d.ts +74 -0
  125. package/dist/utils/factoryProcessing.js +588 -0
  126. package/dist/utils/optionsConversion.d.ts +54 -0
  127. package/dist/utils/optionsConversion.js +126 -0
  128. package/dist/utils/optionsUtils.d.ts +246 -0
  129. package/dist/utils/optionsUtils.js +960 -0
  130. package/dist/utils/providerConfig.js +6 -2
  131. package/dist/utils/providerHealth.d.ts +107 -0
  132. package/dist/utils/providerHealth.js +543 -0
  133. package/dist/utils/providerUtils.d.ts +17 -0
  134. package/dist/utils/providerUtils.js +271 -16
  135. package/dist/utils/timeout.js +1 -1
  136. package/dist/utils/tokenLimits.d.ts +33 -0
  137. package/dist/utils/tokenLimits.js +118 -0
  138. package/package.json +2 -2
@@ -1,6 +1,7 @@
1
1
  import { logger } from "../utils/logger.js";
2
2
  import { SYSTEM_LIMITS } from "../core/constants.js";
3
3
  import { directAgentTools } from "../agent/directTools.js";
4
+ import { getSafeMaxTokens } from "../utils/tokenLimits.js";
4
5
  /**
5
6
  * Validates if a result contains a valid toolsObject structure
6
7
  * @param result - The result object to validate
@@ -192,6 +193,29 @@ export class BaseProvider {
192
193
  }
193
194
  // Remove duplicates
194
195
  const uniqueToolsUsed = [...new Set(toolsUsed)];
196
+ // ✅ Extract tool executions from AI SDK result
197
+ const toolExecutions = [];
198
+ // Extract tool executions from AI SDK result steps
199
+ // Extract tool executions from steps (where tool results are stored)
200
+ if (result.steps &&
201
+ Array.isArray(result.steps)) {
202
+ for (const step of result.steps ||
203
+ []) {
204
+ // Focus only on tool results (which have complete execution data)
205
+ // Tool calls are just the requests, tool results contain the actual execution data
206
+ if (step?.toolResults && Array.isArray(step.toolResults)) {
207
+ for (const toolResult of step.toolResults) {
208
+ const trRecord = toolResult;
209
+ toolExecutions.push({
210
+ name: trRecord.toolName || "unknown",
211
+ input: trRecord.args || {},
212
+ output: trRecord.result || "success",
213
+ duration: 0, // AI SDK doesn't track duration
214
+ });
215
+ }
216
+ }
217
+ }
218
+ }
195
219
  // Format the result with tool executions included
196
220
  const enhancedResult = {
197
221
  content: result.text,
@@ -217,6 +241,7 @@ export class BaseProvider {
217
241
  : [],
218
242
  toolResults: result.toolResults,
219
243
  toolsUsed: uniqueToolsUsed,
244
+ toolExecutions, // ✅ Add extracted tool executions
220
245
  };
221
246
  // Enhanced result with analytics and evaluation
222
247
  return await this.enhanceResult(enhancedResult, options, startTime);
@@ -327,33 +352,47 @@ export class BaseProvider {
327
352
  // ===================
328
353
  normalizeTextOptions(optionsOrPrompt) {
329
354
  if (typeof optionsOrPrompt === "string") {
355
+ const safeMaxTokens = getSafeMaxTokens(this.providerName, this.modelName);
330
356
  return {
331
357
  prompt: optionsOrPrompt,
332
358
  provider: this.providerName,
333
359
  model: this.modelName,
360
+ maxTokens: safeMaxTokens,
334
361
  };
335
362
  }
336
363
  // Handle both prompt and input.text formats
337
364
  const prompt = optionsOrPrompt.prompt || optionsOrPrompt.input?.text || "";
365
+ const modelName = optionsOrPrompt.model || this.modelName;
366
+ const providerName = optionsOrPrompt.provider || this.providerName;
367
+ // Apply safe maxTokens based on provider and model
368
+ const safeMaxTokens = getSafeMaxTokens(providerName, modelName, optionsOrPrompt.maxTokens);
338
369
  return {
339
370
  ...optionsOrPrompt,
340
371
  prompt,
341
- provider: optionsOrPrompt.provider || this.providerName,
342
- model: optionsOrPrompt.model || this.modelName,
372
+ provider: providerName,
373
+ model: modelName,
374
+ maxTokens: safeMaxTokens,
343
375
  };
344
376
  }
345
377
  normalizeStreamOptions(optionsOrPrompt) {
346
378
  if (typeof optionsOrPrompt === "string") {
379
+ const safeMaxTokens = getSafeMaxTokens(this.providerName, this.modelName);
347
380
  return {
348
381
  input: { text: optionsOrPrompt },
349
382
  provider: this.providerName,
350
383
  model: this.modelName,
384
+ maxTokens: safeMaxTokens,
351
385
  };
352
386
  }
387
+ const modelName = optionsOrPrompt.model || this.modelName;
388
+ const providerName = optionsOrPrompt.provider || this.providerName;
389
+ // Apply safe maxTokens based on provider and model
390
+ const safeMaxTokens = getSafeMaxTokens(providerName, modelName, optionsOrPrompt.maxTokens);
353
391
  return {
354
392
  ...optionsOrPrompt,
355
- provider: optionsOrPrompt.provider || this.providerName,
356
- model: optionsOrPrompt.model || this.modelName,
393
+ provider: providerName,
394
+ model: modelName,
395
+ maxTokens: safeMaxTokens,
357
396
  };
358
397
  }
359
398
  async enhanceResult(result, options, startTime) {
@@ -24,6 +24,52 @@ export declare const PROVIDER_CONFIG: {
24
24
  temperature: number;
25
25
  };
26
26
  };
27
+ export declare const PROVIDER_MAX_TOKENS: {
28
+ anthropic: {
29
+ "claude-3-haiku-20240307": number;
30
+ "claude-3-5-sonnet-20241022": number;
31
+ "claude-3-opus-20240229": number;
32
+ "claude-3-5-sonnet-20240620": number;
33
+ default: number;
34
+ };
35
+ openai: {
36
+ "gpt-4o": number;
37
+ "gpt-4o-mini": number;
38
+ "gpt-3.5-turbo": number;
39
+ "gpt-4": number;
40
+ "gpt-4-turbo": number;
41
+ default: number;
42
+ };
43
+ "google-ai": {
44
+ "gemini-1.5-pro": number;
45
+ "gemini-1.5-flash": number;
46
+ "gemini-2.5-pro": number;
47
+ "gemini-2.5-flash": number;
48
+ "gemini-pro": number;
49
+ default: number;
50
+ };
51
+ vertex: {
52
+ "gemini-1.5-pro": number;
53
+ "gemini-1.5-flash": number;
54
+ "gemini-2.5-pro": number;
55
+ "gemini-2.5-flash": number;
56
+ "claude-4.0-sonnet": number;
57
+ default: number;
58
+ };
59
+ bedrock: {
60
+ "anthropic.claude-3-sonnet-20240229-v1:0": number;
61
+ "anthropic.claude-3-haiku-20240307-v1:0": number;
62
+ "anthropic.claude-3-5-sonnet-20240620-v1:0": number;
63
+ default: number;
64
+ };
65
+ ollama: {
66
+ default: number;
67
+ };
68
+ litellm: {
69
+ default: number;
70
+ };
71
+ default: number;
72
+ };
27
73
  export declare const CLI_LIMITS: {
28
74
  maxTokens: {
29
75
  min: number;
@@ -27,6 +27,53 @@ export const PROVIDER_CONFIG = {
27
27
  temperature: 0.4,
28
28
  },
29
29
  };
30
+ // Provider-specific maxTokens limits (discovered through testing)
31
+ export const PROVIDER_MAX_TOKENS = {
32
+ anthropic: {
33
+ "claude-3-haiku-20240307": 4096,
34
+ "claude-3-5-sonnet-20241022": 4096,
35
+ "claude-3-opus-20240229": 4096,
36
+ "claude-3-5-sonnet-20240620": 4096,
37
+ default: 4096, // Conservative default for Anthropic
38
+ },
39
+ openai: {
40
+ "gpt-4o": 16384,
41
+ "gpt-4o-mini": 16384,
42
+ "gpt-3.5-turbo": 4096,
43
+ "gpt-4": 8192,
44
+ "gpt-4-turbo": 4096,
45
+ default: 8192, // OpenAI generally supports higher limits
46
+ },
47
+ "google-ai": {
48
+ "gemini-1.5-pro": 8192,
49
+ "gemini-1.5-flash": 8192,
50
+ "gemini-2.5-pro": 8192,
51
+ "gemini-2.5-flash": 8192,
52
+ "gemini-pro": 4096,
53
+ default: 4096, // Conservative default due to 500 errors at high limits
54
+ },
55
+ vertex: {
56
+ "gemini-1.5-pro": 8192,
57
+ "gemini-1.5-flash": 8192,
58
+ "gemini-2.5-pro": 8192,
59
+ "gemini-2.5-flash": 8192,
60
+ "claude-4.0-sonnet": 4096,
61
+ default: 4096,
62
+ },
63
+ bedrock: {
64
+ "anthropic.claude-3-sonnet-20240229-v1:0": 4096,
65
+ "anthropic.claude-3-haiku-20240307-v1:0": 4096,
66
+ "anthropic.claude-3-5-sonnet-20240620-v1:0": 4096,
67
+ default: 4096,
68
+ },
69
+ ollama: {
70
+ default: 8192, // Ollama typically supports higher limits
71
+ },
72
+ litellm: {
73
+ default: 4096, // Conservative default
74
+ },
75
+ default: 4096, // Safe default across all providers
76
+ };
30
77
  // CLI Validation Limits
31
78
  export const CLI_LIMITS = {
32
79
  maxTokens: {
@@ -102,8 +102,8 @@ declare const ModelRegistrySchema: z.ZodObject<{
102
102
  releaseDate: string;
103
103
  }>>;
104
104
  lastUpdated: string;
105
- aliases?: Record<string, string> | undefined;
106
105
  defaults?: Record<string, string> | undefined;
106
+ aliases?: Record<string, string> | undefined;
107
107
  }, {
108
108
  version: string;
109
109
  models: Record<string, Record<string, {
@@ -119,8 +119,8 @@ declare const ModelRegistrySchema: z.ZodObject<{
119
119
  releaseDate: string;
120
120
  }>>;
121
121
  lastUpdated: string;
122
- aliases?: Record<string, string> | undefined;
123
122
  defaults?: Record<string, string> | undefined;
123
+ aliases?: Record<string, string> | undefined;
124
124
  }>;
125
125
  export type ModelConfig = z.infer<typeof ModelConfigSchema>;
126
126
  export type ModelRegistry = z.infer<typeof ModelRegistrySchema>;
@@ -136,11 +136,23 @@ export declare class DynamicModelProvider {
136
136
  private constructor();
137
137
  static getInstance(): DynamicModelProvider;
138
138
  /**
139
- * Initialize the model registry from multiple sources
139
+ * Initialize the model registry from multiple sources with timeout handling
140
+ * Addresses hanging issues when localhost:3001 is not running or GitHub URLs timeout
140
141
  */
141
142
  initialize(): Promise<void>;
142
143
  /**
143
- * Load configuration from a source (URL or file path)
144
+ * Load configuration from a source with timeout handling
145
+ * Prevents hanging when local servers are down or network requests timeout
146
+ */
147
+ private loadFromSourceWithTimeout;
148
+ /**
149
+ * Quick health check for localhost endpoints
150
+ * Prevents hanging on non-responsive local servers
151
+ */
152
+ private healthCheckLocalhost;
153
+ /**
154
+ * Load configuration from a source (URL or file path) - Legacy method for compatibility
155
+ * @deprecated Use loadFromSourceWithTimeout instead
144
156
  */
145
157
  private loadFromSource;
146
158
  /**
@@ -39,60 +39,164 @@ export class DynamicModelProvider {
39
39
  return this.instance;
40
40
  }
41
41
  /**
42
- * Initialize the model registry from multiple sources
42
+ * Initialize the model registry from multiple sources with timeout handling
43
+ * Addresses hanging issues when localhost:3001 is not running or GitHub URLs timeout
43
44
  */
44
45
  async initialize() {
45
46
  const sources = [
46
- process.env.MODEL_CONFIG_URL || "http://localhost:3001/api/v1/models",
47
- `https://raw.githubusercontent.com/${process.env.MODEL_CONFIG_GITHUB_REPO || "juspay/neurolink"}/${process.env.MODEL_CONFIG_GITHUB_BRANCH || "release"}/config/models.json`,
48
- "./config/models.json", // Local fallback
47
+ {
48
+ url: process.env.MODEL_CONFIG_URL || "http://localhost:3001/api/v1/models",
49
+ timeout: 3000, // 3s for localhost
50
+ name: "local-server",
51
+ },
52
+ {
53
+ url: `https://raw.githubusercontent.com/${process.env.MODEL_CONFIG_GITHUB_REPO || "juspay/neurolink"}/${process.env.MODEL_CONFIG_GITHUB_BRANCH || "release"}/config/models.json`,
54
+ timeout: 5000, // 5s for GitHub
55
+ name: "github-raw",
56
+ },
57
+ {
58
+ url: "./config/models.json",
59
+ timeout: 1000, // 1s for local file
60
+ name: "local-file",
61
+ },
49
62
  ];
63
+ const errors = [];
50
64
  for (const source of sources) {
51
65
  try {
52
- logger.debug(`[DynamicModelProvider] Attempting to load from: ${source}`);
53
- const config = await this.loadFromSource(source);
66
+ logger.debug(`[DynamicModelProvider] Attempting to load from: ${source.url} (timeout: ${source.timeout}ms)`);
67
+ const config = await this.loadFromSourceWithTimeout(source.url, source.timeout);
54
68
  // Validate the configuration
55
69
  const validatedConfig = ModelRegistrySchema.parse(config);
56
70
  this.modelRegistry = validatedConfig;
57
71
  this.lastFetch = Date.now();
58
- logger.info(`[DynamicModelProvider] Successfully loaded model registry from: ${source}`, {
72
+ logger.info(`[DynamicModelProvider] Successfully loaded model registry from: ${source.name}`, {
73
+ source: source.url,
59
74
  modelCount: this.getTotalModelCount(),
60
75
  providerCount: Object.keys(validatedConfig.models).length,
76
+ loadTime: `<${source.timeout}ms`,
61
77
  });
62
78
  return; // Success, stop trying other sources
63
79
  }
64
80
  catch (error) {
65
- logger.warn(`[DynamicModelProvider] Failed to load from ${source}:`, error);
81
+ const errorMessage = error instanceof Error ? error.message : String(error);
82
+ errors.push({ source: source.name, error: errorMessage });
83
+ logger.warn(`[DynamicModelProvider] Failed to load from ${source.name} (${source.url}):`, {
84
+ error: errorMessage,
85
+ timeout: source.timeout,
86
+ });
66
87
  continue;
67
88
  }
68
89
  }
69
- throw new Error("Failed to load model configuration from any source");
90
+ // Log all failures for debugging
91
+ logger.warn(`[DynamicModelProvider] All model configuration sources failed`, { errors });
92
+ throw new Error(`Failed to load model configuration from any source. Attempted: ${errors.map((e) => e.source).join(", ")}`);
70
93
  }
71
94
  /**
72
- * Load configuration from a source (URL or file path)
95
+ * Load configuration from a source with timeout handling
96
+ * Prevents hanging when local servers are down or network requests timeout
73
97
  */
74
- async loadFromSource(source) {
98
+ async loadFromSourceWithTimeout(source, timeoutMs) {
75
99
  if (source.startsWith("http")) {
76
- // Load from URL
77
- const response = await fetch(source, {
78
- headers: {
79
- "User-Agent": "NeuroLink/1.0 (+https://github.com/juspay/neurolink)",
80
- },
81
- });
82
- if (!response.ok) {
83
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
100
+ // Setup timeout and abort controller
101
+ const controller = new AbortController();
102
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
103
+ try {
104
+ // Add health check for localhost before attempting full request
105
+ if (source.includes("localhost") || source.includes("127.0.0.1")) {
106
+ await this.healthCheckLocalhost(source, Math.min(timeoutMs, 1000));
107
+ }
108
+ const response = await fetch(source, {
109
+ headers: {
110
+ "User-Agent": "NeuroLink/1.0 (+https://github.com/sachinsharma92/neurolink)",
111
+ Accept: "application/json",
112
+ "Cache-Control": "no-cache",
113
+ },
114
+ signal: controller.signal,
115
+ });
116
+ clearTimeout(timeoutId);
117
+ if (!response.ok) {
118
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
119
+ }
120
+ const data = await response.json();
121
+ return data;
122
+ }
123
+ catch (error) {
124
+ clearTimeout(timeoutId);
125
+ if (error instanceof Error && error.name === "AbortError") {
126
+ throw new Error(`Request timeout after ${timeoutMs}ms`);
127
+ }
128
+ throw error;
84
129
  }
85
- return response.json();
86
130
  }
87
131
  else {
88
- // Load from local file
89
- const fs = await import("fs");
90
- const path = await import("path");
91
- const fullPath = path.resolve(source);
92
- const content = fs.readFileSync(fullPath, "utf8");
93
- return JSON.parse(content);
132
+ // Load from local file with timeout (for very large files)
133
+ return new Promise((resolve, reject) => {
134
+ const timeoutId = setTimeout(() => {
135
+ reject(new Error(`File read timeout after ${timeoutMs}ms`));
136
+ }, timeoutMs);
137
+ (async () => {
138
+ try {
139
+ const fs = await import("fs");
140
+ const path = await import("path");
141
+ const fullPath = path.resolve(source);
142
+ // Check if file exists first
143
+ if (!fs.existsSync(fullPath)) {
144
+ throw new Error(`File not found: ${fullPath}`);
145
+ }
146
+ const content = fs.readFileSync(fullPath, "utf8");
147
+ const data = JSON.parse(content);
148
+ clearTimeout(timeoutId);
149
+ resolve(data);
150
+ }
151
+ catch (error) {
152
+ clearTimeout(timeoutId);
153
+ reject(error);
154
+ }
155
+ })();
156
+ });
94
157
  }
95
158
  }
159
+ /**
160
+ * Quick health check for localhost endpoints
161
+ * Prevents hanging on non-responsive local servers
162
+ */
163
+ async healthCheckLocalhost(url, timeoutMs) {
164
+ const healthUrl = url.replace(/\/api\/.*$/, "/health") || `${url}/health`;
165
+ const controller = new AbortController();
166
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
167
+ try {
168
+ const response = await fetch(healthUrl, {
169
+ method: "HEAD", // Lightweight request
170
+ signal: controller.signal,
171
+ });
172
+ clearTimeout(timeoutId);
173
+ // Don't throw on 404 - the main endpoint might still work
174
+ if (response.status >= 500) {
175
+ throw new Error(`Server error: ${response.status}`);
176
+ }
177
+ }
178
+ catch (error) {
179
+ clearTimeout(timeoutId);
180
+ if (error instanceof Error && error.name === "AbortError") {
181
+ throw new Error(`Localhost health check timeout - server may not be running`);
182
+ }
183
+ // For connection refused, throw a more specific error
184
+ if (error instanceof Error && error.message.includes("ECONNREFUSED")) {
185
+ throw new Error(`Localhost server not running at ${url}`);
186
+ }
187
+ // For other errors, let the main request handle them
188
+ logger.debug(`Health check failed for ${url}, proceeding with main request`, {
189
+ error: error instanceof Error ? error.message : String(error),
190
+ });
191
+ }
192
+ }
193
+ /**
194
+ * Load configuration from a source (URL or file path) - Legacy method for compatibility
195
+ * @deprecated Use loadFromSourceWithTimeout instead
196
+ */
197
+ async loadFromSource(source) {
198
+ return this.loadFromSourceWithTimeout(source, 10000); // 10s default timeout
199
+ }
96
200
  /**
97
201
  * Get all available models for a provider
98
202
  */
@@ -5,6 +5,7 @@ import { logger } from "../utils/logger.js";
5
5
  import { AIProviderFactory } from "./factory.js";
6
6
  import { z } from "zod";
7
7
  import { ProviderRegistry } from "../factories/providerRegistry.js";
8
+ import { modelConfig } from "./modelConfiguration.js";
8
9
  // Zod schema for validation
9
10
  const UnifiedEvaluationSchema = z.object({
10
11
  relevance: z.number().min(1).max(10),
@@ -152,7 +153,10 @@ export async function generateUnifiedEvaluation(context) {
152
153
  await ProviderRegistry.registerAllProviders();
153
154
  // Get evaluation provider
154
155
  const evaluationProvider = process.env.NEUROLINK_EVALUATION_PROVIDER || "google-ai";
155
- const evaluationModel = process.env.NEUROLINK_EVALUATION_MODEL || "gemini-2.5-flash";
156
+ // Use configurable model selection instead of hardcoded default
157
+ const evaluationModel = process.env.NEUROLINK_EVALUATION_MODEL ||
158
+ modelConfig.getModelForTier(evaluationProvider, "fast") ||
159
+ "gemini-2.5-flash"; // Ultimate fallback
156
160
  logger.debug(`[${functionTag}] Using provider: ${evaluationProvider}, model: ${evaluationModel}`);
157
161
  const provider = await AIProviderFactory.createProvider(evaluationProvider, evaluationModel);
158
162
  if (!provider) {
@@ -1,15 +1,17 @@
1
1
  import type { ProviderModelConfig } from "./types.js";
2
2
  /**
3
- * Comprehensive provider configurations for evaluation
4
- * All 9 NeuroLink providers with cost and performance data
3
+ * Dynamic provider configurations for evaluation
4
+ * Now uses configurable system instead of hardcoded values
5
5
  */
6
6
  export declare const EVALUATION_PROVIDER_CONFIGS: Record<string, ProviderModelConfig>;
7
7
  /**
8
8
  * Get provider configuration by name
9
+ * Now uses the configurable system
9
10
  */
10
11
  export declare function getProviderConfig(providerName: string): ProviderModelConfig | null;
11
12
  /**
12
13
  * Get all available providers with required API keys present
14
+ * Now uses the configurable system
13
15
  */
14
16
  export declare function getAvailableProviders(): ProviderModelConfig[];
15
17
  /**
@@ -18,10 +20,12 @@ export declare function getAvailableProviders(): ProviderModelConfig[];
18
20
  export declare function sortProvidersByPreference(providers: ProviderModelConfig[], preferCheap?: boolean): ProviderModelConfig[];
19
21
  /**
20
22
  * Estimate cost for a specific provider and token usage
23
+ * Now uses the configurable system
21
24
  */
22
25
  export declare function estimateProviderCost(providerName: string, inputTokens: number, outputTokens: number): number;
23
26
  /**
24
27
  * Check if a provider is available (has required API keys)
28
+ * Now uses the configurable system
25
29
  */
26
30
  export declare function isProviderAvailable(providerName: string): boolean;
27
31
  /**