@juspay/neurolink 7.10.3 → 7.11.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 (64) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/config/types.d.ts +14 -0
  3. package/dist/config/types.js +6 -0
  4. package/dist/core/baseProvider.d.ts +45 -340
  5. package/dist/core/baseProvider.js +205 -30
  6. package/dist/core/types.d.ts +4 -0
  7. package/dist/factories/providerFactory.js +1 -1
  8. package/dist/factories/providerRegistry.js +8 -8
  9. package/dist/lib/config/types.d.ts +14 -0
  10. package/dist/lib/config/types.js +6 -0
  11. package/dist/lib/core/baseProvider.d.ts +45 -340
  12. package/dist/lib/core/baseProvider.js +205 -30
  13. package/dist/lib/core/types.d.ts +4 -0
  14. package/dist/lib/factories/providerFactory.js +1 -1
  15. package/dist/lib/factories/providerRegistry.js +8 -8
  16. package/dist/lib/mcp/servers/agent/directToolsServer.js +80 -68
  17. package/dist/lib/mcp/toolRegistry.js +8 -2
  18. package/dist/lib/neurolink.js +20 -0
  19. package/dist/lib/providers/amazonBedrock.d.ts +0 -1
  20. package/dist/lib/providers/amazonBedrock.js +0 -13
  21. package/dist/lib/providers/anthropic.js +8 -25
  22. package/dist/lib/providers/googleAiStudio.d.ts +0 -1
  23. package/dist/lib/providers/googleAiStudio.js +10 -15
  24. package/dist/lib/providers/googleVertex.d.ts +0 -1
  25. package/dist/lib/providers/googleVertex.js +17 -24
  26. package/dist/lib/providers/huggingFace.d.ts +0 -1
  27. package/dist/lib/providers/huggingFace.js +0 -8
  28. package/dist/lib/providers/litellm.d.ts +0 -1
  29. package/dist/lib/providers/litellm.js +0 -8
  30. package/dist/lib/providers/mistral.d.ts +9 -24
  31. package/dist/lib/providers/mistral.js +44 -82
  32. package/dist/lib/providers/ollama.d.ts +0 -1
  33. package/dist/lib/providers/ollama.js +0 -12
  34. package/dist/lib/providers/openAI.d.ts +2 -3
  35. package/dist/lib/providers/openAI.js +12 -20
  36. package/dist/lib/providers/openaiCompatible.d.ts +0 -1
  37. package/dist/lib/providers/openaiCompatible.js +0 -8
  38. package/dist/lib/utils/toolUtils.d.ts +32 -0
  39. package/dist/lib/utils/toolUtils.js +60 -0
  40. package/dist/mcp/servers/agent/directToolsServer.js +80 -68
  41. package/dist/mcp/toolRegistry.js +8 -2
  42. package/dist/neurolink.js +20 -0
  43. package/dist/providers/amazonBedrock.d.ts +0 -1
  44. package/dist/providers/amazonBedrock.js +0 -13
  45. package/dist/providers/anthropic.js +8 -25
  46. package/dist/providers/googleAiStudio.d.ts +0 -1
  47. package/dist/providers/googleAiStudio.js +10 -15
  48. package/dist/providers/googleVertex.d.ts +0 -1
  49. package/dist/providers/googleVertex.js +17 -24
  50. package/dist/providers/huggingFace.d.ts +0 -1
  51. package/dist/providers/huggingFace.js +0 -8
  52. package/dist/providers/litellm.d.ts +0 -1
  53. package/dist/providers/litellm.js +0 -8
  54. package/dist/providers/mistral.d.ts +9 -24
  55. package/dist/providers/mistral.js +44 -82
  56. package/dist/providers/ollama.d.ts +0 -1
  57. package/dist/providers/ollama.js +0 -12
  58. package/dist/providers/openAI.d.ts +2 -3
  59. package/dist/providers/openAI.js +12 -20
  60. package/dist/providers/openaiCompatible.d.ts +0 -1
  61. package/dist/providers/openaiCompatible.js +0 -8
  62. package/dist/utils/toolUtils.d.ts +32 -0
  63. package/dist/utils/toolUtils.js +60 -0
  64. package/package.json +1 -1
@@ -1,7 +1,9 @@
1
1
  import { logger } from "../utils/logger.js";
2
- import { SYSTEM_LIMITS } from "../core/constants.js";
2
+ import { SYSTEM_LIMITS, DEFAULT_MAX_STEPS } from "../core/constants.js";
3
3
  import { directAgentTools } from "../agent/directTools.js";
4
4
  import { getSafeMaxTokens } from "../utils/tokenLimits.js";
5
+ import { createTimeoutController, TimeoutError } from "../utils/timeout.js";
6
+ import { shouldDisableBuiltinTools } from "../utils/toolUtils.js";
5
7
  /**
6
8
  * Validates if a result contains a valid toolsObject structure
7
9
  * @param result - The result object to validate
@@ -23,8 +25,10 @@ export class BaseProvider {
23
25
  modelName;
24
26
  providerName;
25
27
  defaultTimeout = 30000; // 30 seconds
26
- // Tools are ALWAYS part of the provider - no flags, no conditions
27
- directTools = directAgentTools;
28
+ // Tools are conditionally included based on centralized configuration
29
+ directTools = shouldDisableBuiltinTools()
30
+ ? {}
31
+ : directAgentTools;
28
32
  mcpTools; // MCP tools loaded dynamically when available
29
33
  sessionId;
30
34
  userId;
@@ -163,7 +167,7 @@ export class BaseProvider {
163
167
  prompt: options.prompt || options.input?.text || "",
164
168
  system: options.systemPrompt,
165
169
  tools,
166
- maxSteps: options.maxSteps || 5,
170
+ maxSteps: options.maxSteps || DEFAULT_MAX_STEPS,
167
171
  toolChoice: shouldUseTools ? "auto" : "none",
168
172
  temperature: options.temperature,
169
173
  maxTokens: options.maxTokens || 8192,
@@ -290,33 +294,38 @@ export class BaseProvider {
290
294
  for (const [toolName, toolInfo] of toolEntries) {
291
295
  if (toolInfo && typeof toolInfo.execute === "function") {
292
296
  logger.debug(`[BaseProvider] Converting custom tool: ${toolName}`);
293
- // Convert to AI SDK tool format
294
- const { tool: createAISDKTool } = await import("ai");
295
- const { z } = await import("zod");
296
- tools[toolName] = createAISDKTool({
297
- description: toolInfo.description || `Tool ${toolName}`,
298
- parameters: toolInfo.inputSchema ||
299
- toolInfo.parameters ||
300
- z.object({}),
301
- execute: async (args) => {
302
- const result = await toolInfo.execute(args);
303
- // Handle MCP-style results
304
- if (result &&
305
- typeof result === "object" &&
306
- "success" in result) {
307
- if (result.success) {
308
- return result.data;
297
+ try {
298
+ // Convert to AI SDK tool format
299
+ const { tool: createAISDKTool } = await import("ai");
300
+ const { z } = await import("zod");
301
+ tools[toolName] = createAISDKTool({
302
+ description: toolInfo.description || `Tool ${toolName}`,
303
+ parameters: toolInfo.inputSchema ||
304
+ toolInfo.parameters ||
305
+ z.object({}),
306
+ execute: async (args) => {
307
+ const result = await toolInfo.execute(args);
308
+ // Handle MCP-style results
309
+ if (result &&
310
+ typeof result === "object" &&
311
+ "success" in result) {
312
+ if (result.success) {
313
+ return result.data;
314
+ }
315
+ else {
316
+ const errorMsg = typeof result.error === "string"
317
+ ? result.error
318
+ : "Tool execution failed";
319
+ throw new Error(errorMsg);
320
+ }
309
321
  }
310
- else {
311
- const errorMsg = typeof result.error === "string"
312
- ? result.error
313
- : "Tool execution failed";
314
- throw new Error(errorMsg);
315
- }
316
- }
317
- return result;
318
- },
319
- });
322
+ return result;
323
+ },
324
+ });
325
+ }
326
+ catch (toolCreationError) {
327
+ logger.error(`Failed to create tool: ${toolName}`, toolCreationError);
328
+ }
320
329
  }
321
330
  }
322
331
  }
@@ -348,6 +357,172 @@ export class BaseProvider {
348
357
  this.userId = userId;
349
358
  }
350
359
  // ===================
360
+ // CONSOLIDATED PROVIDER METHODS - MOVED FROM INDIVIDUAL PROVIDERS
361
+ // ===================
362
+ /**
363
+ * Execute operation with timeout and proper cleanup
364
+ * Consolidates identical timeout handling from 8/10 providers
365
+ */
366
+ async executeWithTimeout(operation, options) {
367
+ const timeout = this.getTimeout(options);
368
+ const timeoutController = createTimeoutController(timeout, this.providerName, options.operationType || "generate");
369
+ try {
370
+ if (timeoutController) {
371
+ return await Promise.race([
372
+ operation(),
373
+ new Promise((_, reject) => {
374
+ timeoutController.controller.signal.addEventListener("abort", () => {
375
+ reject(new TimeoutError(`${this.providerName} operation timed out`, timeoutController.timeoutMs, this.providerName, options.operationType ||
376
+ "generate"));
377
+ });
378
+ }),
379
+ ]);
380
+ }
381
+ else {
382
+ return await operation();
383
+ }
384
+ }
385
+ finally {
386
+ timeoutController?.cleanup();
387
+ }
388
+ }
389
+ /**
390
+ * Validate stream options - consolidates validation from 7/10 providers
391
+ */
392
+ validateStreamOptions(options) {
393
+ if (!options.input?.text || options.input.text.trim().length === 0) {
394
+ throw new Error("Input text is required and cannot be empty");
395
+ }
396
+ if (options.temperature !== undefined) {
397
+ if (options.temperature < 0 || options.temperature > 2) {
398
+ throw new Error("temperature must be between 0 and 2");
399
+ }
400
+ }
401
+ if (options.maxTokens !== undefined) {
402
+ if (options.maxTokens < 1) {
403
+ throw new Error("maxTokens must be at least 1");
404
+ }
405
+ }
406
+ }
407
+ /**
408
+ * Create text stream transformation - consolidates identical logic from 7/10 providers
409
+ */
410
+ createTextStream(result) {
411
+ return (async function* () {
412
+ for await (const chunk of result.textStream) {
413
+ yield { content: chunk };
414
+ }
415
+ })();
416
+ }
417
+ /**
418
+ * Create standardized stream result - consolidates result structure
419
+ */
420
+ createStreamResult(stream, additionalProps = {}) {
421
+ return {
422
+ stream,
423
+ provider: this.providerName,
424
+ model: this.modelName,
425
+ ...additionalProps,
426
+ };
427
+ }
428
+ /**
429
+ * Create stream analytics - consolidates analytics from 4/10 providers
430
+ */
431
+ async createStreamAnalytics(result, startTime, options) {
432
+ try {
433
+ const { createAnalytics } = await import("./analytics.js");
434
+ const analytics = await createAnalytics(this.providerName, this.modelName, result, Date.now() - startTime, {
435
+ requestId: `${this.providerName}-stream-${Date.now()}`,
436
+ streamingMode: true,
437
+ ...options.context,
438
+ });
439
+ return analytics;
440
+ }
441
+ catch (error) {
442
+ logger.warn(`Analytics creation failed for ${this.providerName}:`, error);
443
+ return undefined;
444
+ }
445
+ }
446
+ /**
447
+ * Handle common error patterns - consolidates error handling from multiple providers
448
+ */
449
+ handleCommonErrors(error) {
450
+ if (error instanceof TimeoutError) {
451
+ return new Error(`${this.providerName} request timed out after ${error.timeout}ms. Consider increasing timeout or using a lighter model.`);
452
+ }
453
+ const message = error instanceof Error ? error.message : String(error);
454
+ // Common API key errors
455
+ if (message.includes("API_KEY_INVALID") ||
456
+ message.includes("Invalid API key") ||
457
+ message.includes("authentication") ||
458
+ message.includes("unauthorized")) {
459
+ return new Error(`Invalid API key for ${this.providerName}. Please check your API key environment variable.`);
460
+ }
461
+ // Common rate limit errors
462
+ if (message.includes("rate limit") ||
463
+ message.includes("quota") ||
464
+ message.includes("429")) {
465
+ return new Error(`Rate limit exceeded for ${this.providerName}. Please wait before making more requests.`);
466
+ }
467
+ return null; // Not a common error, let provider handle it
468
+ }
469
+ /**
470
+ * Set up tool executor for a provider to enable actual tool execution
471
+ * Consolidates identical setupToolExecutor logic from neurolink.ts (used in 4 places)
472
+ * @param sdk - The NeuroLinkSDK instance for tool execution
473
+ * @param functionTag - Function name for logging
474
+ */
475
+ setupToolExecutor(sdk, functionTag) {
476
+ // Type guard to check for setToolExecutor method
477
+ function hasSetToolExecutor(obj) {
478
+ return (typeof obj === "object" &&
479
+ obj !== null &&
480
+ typeof obj.setToolExecutor ===
481
+ "function");
482
+ }
483
+ if (!hasSetToolExecutor(this)) {
484
+ logger.warn(`[${functionTag}] Provider does not support setToolExecutor - tools will not be executed`, {
485
+ hasProvider: true,
486
+ providerType: this.constructor.name,
487
+ availableCustomTools: sdk.customTools.size,
488
+ });
489
+ return;
490
+ }
491
+ logger.debug(`[${functionTag}] Setting up tool executor for provider`, {
492
+ providerType: this.constructor.name,
493
+ availableCustomTools: sdk.customTools.size,
494
+ });
495
+ // Set up tool executor to handle actual tool calls
496
+ this.setToolExecutor(async (toolName, params) => {
497
+ logger.debug(`[${functionTag}] AI provider requesting tool execution: ${toolName}`, {
498
+ toolName,
499
+ params,
500
+ availableCustomTools: sdk.customTools.size,
501
+ hasRequestedTool: sdk.customTools.has(toolName),
502
+ });
503
+ try {
504
+ // Execute the tool using NeuroLink's executeTool method
505
+ const result = await sdk.executeTool(toolName, params);
506
+ logger.debug(`[${functionTag}] Tool execution successful: ${toolName}`, {
507
+ toolName,
508
+ result: typeof result === "object"
509
+ ? JSON.stringify(result).substring(0, 200)
510
+ : result,
511
+ resultType: typeof result,
512
+ });
513
+ return result;
514
+ }
515
+ catch (error) {
516
+ logger.error(`[${functionTag}] Tool execution failed: ${toolName}`, {
517
+ toolName,
518
+ error: error instanceof Error ? error.message : String(error),
519
+ params,
520
+ });
521
+ throw error;
522
+ }
523
+ });
524
+ }
525
+ // ===================
351
526
  // TEMPLATE METHODS - COMMON FUNCTIONALITY
352
527
  // ===================
353
528
  normalizeTextOptions(optionsOrPrompt) {
@@ -300,6 +300,10 @@ export interface AIProvider {
300
300
  stream(optionsOrPrompt: StreamOptions | string, analysisSchema?: ZodType<unknown, ZodTypeDef, unknown> | Schema<unknown>): Promise<StreamResult>;
301
301
  generate(optionsOrPrompt: TextGenerationOptions | string, analysisSchema?: ZodType<unknown, ZodTypeDef, unknown> | Schema<unknown>): Promise<EnhancedGenerateResult | null>;
302
302
  gen(optionsOrPrompt: TextGenerationOptions | string, analysisSchema?: ZodType<unknown, ZodTypeDef, unknown> | Schema<unknown>): Promise<EnhancedGenerateResult | null>;
303
+ setupToolExecutor(sdk: {
304
+ customTools: Map<string, unknown>;
305
+ executeTool: (toolName: string, params: unknown) => Promise<unknown>;
306
+ }, functionTag: string): void;
303
307
  }
304
308
  /**
305
309
  * Provider attempt result for iteration tracking
@@ -60,7 +60,7 @@ export class ProviderFactory {
60
60
  if (result &&
61
61
  typeof result === "object" &&
62
62
  typeof result.then === "function") {
63
- return await result;
63
+ result = await result;
64
64
  }
65
65
  return result;
66
66
  }
@@ -24,17 +24,17 @@ export class ProviderRegistry {
24
24
  // Register providers with dynamic import factory functions
25
25
  const { ProviderFactory } = await import("./providerFactory.js");
26
26
  // Register Google AI Studio Provider (our validated baseline)
27
- ProviderFactory.registerProvider(AIProviderName.GOOGLE_AI, async (modelName, providerName, sdk) => {
27
+ ProviderFactory.registerProvider(AIProviderName.GOOGLE_AI, async (modelName, _providerName, sdk) => {
28
28
  const { GoogleAIStudioProvider } = await import("../providers/googleAiStudio.js");
29
29
  return new GoogleAIStudioProvider(modelName, sdk);
30
30
  }, GoogleAIModels.GEMINI_2_5_FLASH, ["googleAiStudio", "google", "gemini", "google-ai"]);
31
31
  // Register OpenAI provider
32
- ProviderFactory.registerProvider(AIProviderName.OPENAI, async (modelName, providerName, sdk) => {
32
+ ProviderFactory.registerProvider(AIProviderName.OPENAI, async (modelName, _providerName, sdk) => {
33
33
  const { OpenAIProvider } = await import("../providers/openAI.js");
34
- return new OpenAIProvider(modelName);
34
+ return new OpenAIProvider(modelName, sdk);
35
35
  }, OpenAIModels.GPT_4O_MINI, ["gpt", "chatgpt"]);
36
36
  // Register Anthropic provider
37
- ProviderFactory.registerProvider(AIProviderName.ANTHROPIC, async (modelName, providerName, sdk) => {
37
+ ProviderFactory.registerProvider(AIProviderName.ANTHROPIC, async (modelName, _providerName, sdk) => {
38
38
  const { AnthropicProvider } = await import("../providers/anthropic.js");
39
39
  return new AnthropicProvider(modelName, sdk);
40
40
  }, "claude-3-5-sonnet-20241022", ["claude", "anthropic"]);
@@ -62,7 +62,7 @@ export class ProviderRegistry {
62
62
  return new HuggingFaceProvider(modelName);
63
63
  }, process.env.HUGGINGFACE_MODEL || "microsoft/DialoGPT-medium", ["huggingface", "hf"]);
64
64
  // Register Mistral AI provider
65
- ProviderFactory.registerProvider(AIProviderName.MISTRAL, async (modelName, providerName, sdk) => {
65
+ ProviderFactory.registerProvider(AIProviderName.MISTRAL, async (modelName, _providerName, sdk) => {
66
66
  const { MistralProvider } = await import("../providers/mistral.js");
67
67
  return new MistralProvider(modelName, sdk);
68
68
  }, "mistral-large-latest", ["mistral"]);
@@ -72,18 +72,18 @@ export class ProviderRegistry {
72
72
  return new OllamaProvider(modelName);
73
73
  }, process.env.OLLAMA_MODEL || "llama3.1:8b", ["ollama", "local"]);
74
74
  // Register LiteLLM provider
75
- ProviderFactory.registerProvider(AIProviderName.LITELLM, async (modelName, providerName, sdk) => {
75
+ ProviderFactory.registerProvider(AIProviderName.LITELLM, async (modelName, _providerName, sdk) => {
76
76
  const { LiteLLMProvider } = await import("../providers/litellm.js");
77
77
  return new LiteLLMProvider(modelName, sdk);
78
78
  }, process.env.LITELLM_MODEL || "openai/gpt-4o-mini", ["litellm"]);
79
79
  // Register OpenAI Compatible provider
80
- ProviderFactory.registerProvider(AIProviderName.OPENAI_COMPATIBLE, async (modelName, providerName, sdk) => {
80
+ ProviderFactory.registerProvider(AIProviderName.OPENAI_COMPATIBLE, async (modelName, _providerName, sdk) => {
81
81
  const { OpenAICompatibleProvider } = await import("../providers/openaiCompatible.js");
82
82
  return new OpenAICompatibleProvider(modelName, sdk);
83
83
  }, process.env.OPENAI_COMPATIBLE_MODEL || undefined, // Enable auto-discovery when no model specified
84
84
  ["openai-compatible", "openrouter", "vllm", "compatible"]);
85
85
  // Register Amazon SageMaker provider
86
- ProviderFactory.registerProvider(AIProviderName.SAGEMAKER, async (modelName, providerName, sdk) => {
86
+ ProviderFactory.registerProvider(AIProviderName.SAGEMAKER, async (modelName, _providerName, _sdk) => {
87
87
  const { AmazonSageMakerProvider } = await import("../providers/amazonSagemaker.js");
88
88
  return new AmazonSageMakerProvider(modelName);
89
89
  }, process.env.SAGEMAKER_MODEL || "sagemaker-model", ["sagemaker", "aws-sagemaker"]);
@@ -9,6 +9,7 @@ export interface NeuroLinkConfig {
9
9
  providers?: Record<string, ProviderConfig>;
10
10
  performance?: PerformanceConfig;
11
11
  analytics?: AnalyticsConfig;
12
+ tools?: ToolConfig;
12
13
  lastUpdated?: number;
13
14
  configVersion?: string;
14
15
  [key: string]: unknown;
@@ -90,6 +91,19 @@ export interface AnalyticsConfig {
90
91
  maxEntries?: number;
91
92
  };
92
93
  }
94
+ /**
95
+ * Tool configuration
96
+ */
97
+ export interface ToolConfig {
98
+ /** Whether built-in tools should be disabled */
99
+ disableBuiltinTools?: boolean;
100
+ /** Whether custom tools are allowed */
101
+ allowCustomTools?: boolean;
102
+ /** Maximum number of tools per provider */
103
+ maxToolsPerProvider?: number;
104
+ /** Whether MCP tools should be enabled */
105
+ enableMCPTools?: boolean;
106
+ }
93
107
  /**
94
108
  * Backup metadata information
95
109
  */
@@ -39,5 +39,11 @@ export const DEFAULT_CONFIG = {
39
39
  maxEntries: 10000,
40
40
  },
41
41
  },
42
+ tools: {
43
+ disableBuiltinTools: false,
44
+ allowCustomTools: true,
45
+ maxToolsPerProvider: 100,
46
+ enableMCPTools: true,
47
+ },
42
48
  configVersion: "3.0.1",
43
49
  };