@juspay/neurolink 7.10.3 → 7.11.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 (64) hide show
  1. package/CHANGELOG.md +6 -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
@@ -38,346 +38,7 @@ export declare abstract class BaseProvider implements AIProvider {
38
38
  protected readonly modelName: string;
39
39
  protected readonly providerName: AIProviderName;
40
40
  protected readonly defaultTimeout: number;
41
- protected readonly directTools: {
42
- getCurrentTime: Tool<import("zod").ZodObject<{
43
- timezone: import("zod").ZodOptional<import("zod").ZodString>;
44
- }, "strip", import("zod").ZodTypeAny, {
45
- timezone?: string | undefined;
46
- }, {
47
- timezone?: string | undefined;
48
- }>, {
49
- success: boolean;
50
- time: string;
51
- timezone: string;
52
- iso: string;
53
- timestamp?: undefined;
54
- error?: undefined;
55
- } | {
56
- success: boolean;
57
- time: string;
58
- iso: string;
59
- timestamp: number;
60
- timezone?: undefined;
61
- error?: undefined;
62
- } | {
63
- success: boolean;
64
- error: string;
65
- time?: undefined;
66
- timezone?: undefined;
67
- iso?: undefined;
68
- timestamp?: undefined;
69
- }> & {
70
- execute: (args: {
71
- timezone?: string | undefined;
72
- }, options: import("ai").ToolExecutionOptions) => PromiseLike<{
73
- success: boolean;
74
- time: string;
75
- timezone: string;
76
- iso: string;
77
- timestamp?: undefined;
78
- error?: undefined;
79
- } | {
80
- success: boolean;
81
- time: string;
82
- iso: string;
83
- timestamp: number;
84
- timezone?: undefined;
85
- error?: undefined;
86
- } | {
87
- success: boolean;
88
- error: string;
89
- time?: undefined;
90
- timezone?: undefined;
91
- iso?: undefined;
92
- timestamp?: undefined;
93
- }>;
94
- };
95
- readFile: Tool<import("zod").ZodObject<{
96
- path: import("zod").ZodString;
97
- }, "strip", import("zod").ZodTypeAny, {
98
- path: string;
99
- }, {
100
- path: string;
101
- }>, {
102
- success: boolean;
103
- error: string;
104
- content?: undefined;
105
- size?: undefined;
106
- path?: undefined;
107
- lastModified?: undefined;
108
- } | {
109
- success: boolean;
110
- content: string;
111
- size: number;
112
- path: string;
113
- lastModified: string;
114
- error?: undefined;
115
- } | {
116
- success: boolean;
117
- error: string;
118
- path: string;
119
- content?: undefined;
120
- size?: undefined;
121
- lastModified?: undefined;
122
- }> & {
123
- execute: (args: {
124
- path: string;
125
- }, options: import("ai").ToolExecutionOptions) => PromiseLike<{
126
- success: boolean;
127
- error: string;
128
- content?: undefined;
129
- size?: undefined;
130
- path?: undefined;
131
- lastModified?: undefined;
132
- } | {
133
- success: boolean;
134
- content: string;
135
- size: number;
136
- path: string;
137
- lastModified: string;
138
- error?: undefined;
139
- } | {
140
- success: boolean;
141
- error: string;
142
- path: string;
143
- content?: undefined;
144
- size?: undefined;
145
- lastModified?: undefined;
146
- }>;
147
- };
148
- listDirectory: Tool<import("zod").ZodObject<{
149
- path: import("zod").ZodString;
150
- includeHidden: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
151
- }, "strip", import("zod").ZodTypeAny, {
152
- path: string;
153
- includeHidden: boolean;
154
- }, {
155
- path: string;
156
- includeHidden?: boolean | undefined;
157
- }>, {
158
- success: boolean;
159
- path: string;
160
- items: {
161
- name: string;
162
- type: string;
163
- size: number | undefined;
164
- lastModified: string;
165
- }[];
166
- count: number;
167
- error?: undefined;
168
- } | {
169
- success: boolean;
170
- error: string;
171
- path: string;
172
- items?: undefined;
173
- count?: undefined;
174
- }> & {
175
- execute: (args: {
176
- path: string;
177
- includeHidden: boolean;
178
- }, options: import("ai").ToolExecutionOptions) => PromiseLike<{
179
- success: boolean;
180
- path: string;
181
- items: {
182
- name: string;
183
- type: string;
184
- size: number | undefined;
185
- lastModified: string;
186
- }[];
187
- count: number;
188
- error?: undefined;
189
- } | {
190
- success: boolean;
191
- error: string;
192
- path: string;
193
- items?: undefined;
194
- count?: undefined;
195
- }>;
196
- };
197
- calculateMath: Tool<import("zod").ZodObject<{
198
- expression: import("zod").ZodString;
199
- precision: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodNumber>>;
200
- }, "strip", import("zod").ZodTypeAny, {
201
- expression: string;
202
- precision: number;
203
- }, {
204
- expression: string;
205
- precision?: number | undefined;
206
- }>, {
207
- success: boolean;
208
- error: string;
209
- expression?: undefined;
210
- result?: undefined;
211
- type?: undefined;
212
- } | {
213
- success: boolean;
214
- expression: string;
215
- result: any;
216
- type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
217
- error?: undefined;
218
- } | {
219
- success: boolean;
220
- error: string;
221
- expression: string;
222
- result?: undefined;
223
- type?: undefined;
224
- }> & {
225
- execute: (args: {
226
- expression: string;
227
- precision: number;
228
- }, options: import("ai").ToolExecutionOptions) => PromiseLike<{
229
- success: boolean;
230
- error: string;
231
- expression?: undefined;
232
- result?: undefined;
233
- type?: undefined;
234
- } | {
235
- success: boolean;
236
- expression: string;
237
- result: any;
238
- type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
239
- error?: undefined;
240
- } | {
241
- success: boolean;
242
- error: string;
243
- expression: string;
244
- result?: undefined;
245
- type?: undefined;
246
- }>;
247
- };
248
- writeFile: Tool<import("zod").ZodObject<{
249
- path: import("zod").ZodString;
250
- content: import("zod").ZodString;
251
- mode: import("zod").ZodDefault<import("zod").ZodEnum<["create", "overwrite", "append"]>>;
252
- }, "strip", import("zod").ZodTypeAny, {
253
- path: string;
254
- content: string;
255
- mode: "create" | "overwrite" | "append";
256
- }, {
257
- path: string;
258
- content: string;
259
- mode?: "create" | "overwrite" | "append" | undefined;
260
- }>, {
261
- success: boolean;
262
- error: string;
263
- path?: undefined;
264
- mode?: undefined;
265
- size?: undefined;
266
- written?: undefined;
267
- } | {
268
- success: boolean;
269
- path: string;
270
- mode: "create" | "overwrite" | "append";
271
- size: number;
272
- written: number;
273
- error?: undefined;
274
- } | {
275
- success: boolean;
276
- error: string;
277
- path: string;
278
- mode?: undefined;
279
- size?: undefined;
280
- written?: undefined;
281
- }> & {
282
- execute: (args: {
283
- path: string;
284
- content: string;
285
- mode: "create" | "overwrite" | "append";
286
- }, options: import("ai").ToolExecutionOptions) => PromiseLike<{
287
- success: boolean;
288
- error: string;
289
- path?: undefined;
290
- mode?: undefined;
291
- size?: undefined;
292
- written?: undefined;
293
- } | {
294
- success: boolean;
295
- path: string;
296
- mode: "create" | "overwrite" | "append";
297
- size: number;
298
- written: number;
299
- error?: undefined;
300
- } | {
301
- success: boolean;
302
- error: string;
303
- path: string;
304
- mode?: undefined;
305
- size?: undefined;
306
- written?: undefined;
307
- }>;
308
- };
309
- searchFiles: Tool<import("zod").ZodObject<{
310
- directory: import("zod").ZodString;
311
- pattern: import("zod").ZodString;
312
- recursive: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
313
- }, "strip", import("zod").ZodTypeAny, {
314
- directory: string;
315
- pattern: string;
316
- recursive: boolean;
317
- }, {
318
- directory: string;
319
- pattern: string;
320
- recursive?: boolean | undefined;
321
- }>, {
322
- success: boolean;
323
- error: string;
324
- directory?: undefined;
325
- pattern?: undefined;
326
- matches?: undefined;
327
- count?: undefined;
328
- } | {
329
- success: boolean;
330
- directory: string;
331
- pattern: string;
332
- matches: {
333
- name: string;
334
- path: string;
335
- size: number;
336
- lastModified: string;
337
- }[];
338
- count: number;
339
- error?: undefined;
340
- } | {
341
- success: boolean;
342
- error: string;
343
- directory: string;
344
- pattern: string;
345
- matches?: undefined;
346
- count?: undefined;
347
- }> & {
348
- execute: (args: {
349
- directory: string;
350
- pattern: string;
351
- recursive: boolean;
352
- }, options: import("ai").ToolExecutionOptions) => PromiseLike<{
353
- success: boolean;
354
- error: string;
355
- directory?: undefined;
356
- pattern?: undefined;
357
- matches?: undefined;
358
- count?: undefined;
359
- } | {
360
- success: boolean;
361
- directory: string;
362
- pattern: string;
363
- matches: {
364
- name: string;
365
- path: string;
366
- size: number;
367
- lastModified: string;
368
- }[];
369
- count: number;
370
- error?: undefined;
371
- } | {
372
- success: boolean;
373
- error: string;
374
- directory: string;
375
- pattern: string;
376
- matches?: undefined;
377
- count?: undefined;
378
- }>;
379
- };
380
- };
41
+ protected readonly directTools: {};
381
42
  protected mcpTools?: Record<string, Tool>;
382
43
  protected sessionId?: string;
383
44
  protected userId?: string;
@@ -433,6 +94,50 @@ export declare abstract class BaseProvider implements AIProvider {
433
94
  * Provider-specific error handling
434
95
  */
435
96
  protected abstract handleProviderError(error: unknown): Error;
97
+ /**
98
+ * Execute operation with timeout and proper cleanup
99
+ * Consolidates identical timeout handling from 8/10 providers
100
+ */
101
+ protected executeWithTimeout<T>(operation: () => Promise<T>, options: {
102
+ timeout?: number | string;
103
+ operationType?: string;
104
+ }): Promise<T>;
105
+ /**
106
+ * Validate stream options - consolidates validation from 7/10 providers
107
+ */
108
+ protected validateStreamOptions(options: StreamOptions): void;
109
+ /**
110
+ * Create text stream transformation - consolidates identical logic from 7/10 providers
111
+ */
112
+ protected createTextStream(result: {
113
+ textStream: AsyncIterable<string>;
114
+ }): AsyncGenerator<{
115
+ content: string;
116
+ }>;
117
+ /**
118
+ * Create standardized stream result - consolidates result structure
119
+ */
120
+ protected createStreamResult(stream: AsyncGenerator<{
121
+ content: string;
122
+ }>, additionalProps?: Partial<StreamResult>): StreamResult;
123
+ /**
124
+ * Create stream analytics - consolidates analytics from 4/10 providers
125
+ */
126
+ protected createStreamAnalytics(result: UnknownRecord, startTime: number, options: StreamOptions): Promise<UnknownRecord | undefined>;
127
+ /**
128
+ * Handle common error patterns - consolidates error handling from multiple providers
129
+ */
130
+ protected handleCommonErrors(error: unknown): Error | null;
131
+ /**
132
+ * Set up tool executor for a provider to enable actual tool execution
133
+ * Consolidates identical setupToolExecutor logic from neurolink.ts (used in 4 places)
134
+ * @param sdk - The NeuroLinkSDK instance for tool execution
135
+ * @param functionTag - Function name for logging
136
+ */
137
+ setupToolExecutor(sdk: {
138
+ customTools: Map<string, unknown>;
139
+ executeTool: (toolName: string, params: unknown) => Promise<unknown>;
140
+ }, functionTag: string): void;
436
141
  protected normalizeTextOptions(optionsOrPrompt: TextGenerationOptions | string): TextGenerationOptions;
437
142
  protected normalizeStreamOptions(optionsOrPrompt: StreamOptions | string): StreamOptions;
438
143
  protected enhanceResult(result: EnhancedGenerateResult, options: TextGenerationOptions, startTime: number): Promise<EnhancedGenerateResult>;
@@ -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
  }