@juspay/neurolink 2.0.0 → 2.1.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 (43) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +31 -5
  3. package/dist/cli/commands/config.d.ts +6 -6
  4. package/dist/cli/index.js +29 -30
  5. package/dist/core/types.d.ts +2 -0
  6. package/dist/lib/core/types.d.ts +2 -0
  7. package/dist/lib/neurolink.d.ts +2 -0
  8. package/dist/lib/neurolink.js +23 -2
  9. package/dist/lib/providers/agent-enhanced-provider.d.ts +1 -0
  10. package/dist/lib/providers/agent-enhanced-provider.js +59 -3
  11. package/dist/lib/providers/amazonBedrock.js +70 -24
  12. package/dist/lib/providers/anthropic.js +77 -15
  13. package/dist/lib/providers/azureOpenAI.js +77 -15
  14. package/dist/lib/providers/googleAIStudio.js +70 -26
  15. package/dist/lib/providers/googleVertexAI.js +70 -24
  16. package/dist/lib/providers/huggingFace.js +70 -26
  17. package/dist/lib/providers/mistralAI.js +70 -26
  18. package/dist/lib/providers/ollama.d.ts +1 -1
  19. package/dist/lib/providers/ollama.js +24 -10
  20. package/dist/lib/providers/openAI.js +67 -23
  21. package/dist/lib/providers/timeout-wrapper.d.ts +40 -0
  22. package/dist/lib/providers/timeout-wrapper.js +100 -0
  23. package/dist/lib/utils/timeout.d.ts +69 -0
  24. package/dist/lib/utils/timeout.js +130 -0
  25. package/dist/neurolink.d.ts +2 -0
  26. package/dist/neurolink.js +23 -2
  27. package/dist/providers/agent-enhanced-provider.d.ts +1 -0
  28. package/dist/providers/agent-enhanced-provider.js +59 -3
  29. package/dist/providers/amazonBedrock.js +70 -24
  30. package/dist/providers/anthropic.js +77 -15
  31. package/dist/providers/azureOpenAI.js +77 -15
  32. package/dist/providers/googleAIStudio.js +70 -26
  33. package/dist/providers/googleVertexAI.js +70 -24
  34. package/dist/providers/huggingFace.js +70 -26
  35. package/dist/providers/mistralAI.js +70 -26
  36. package/dist/providers/ollama.d.ts +1 -1
  37. package/dist/providers/ollama.js +24 -10
  38. package/dist/providers/openAI.js +67 -23
  39. package/dist/providers/timeout-wrapper.d.ts +40 -0
  40. package/dist/providers/timeout-wrapper.js +100 -0
  41. package/dist/utils/timeout.d.ts +69 -0
  42. package/dist/utils/timeout.js +130 -0
  43. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { createGoogleGenerativeAI } from "@ai-sdk/google";
2
2
  import { streamText, generateText, Output, } from "ai";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { createTimeoutController, TimeoutError, getDefaultTimeout } from "../utils/timeout.js";
4
5
  // CRITICAL: Setup environment variables early for AI SDK compatibility
5
6
  // The AI SDK specifically looks for GOOGLE_GENERATIVE_AI_API_KEY
6
7
  // We need to ensure this is set before any AI SDK operations
@@ -109,7 +110,7 @@ export class GoogleAIStudio {
109
110
  const options = typeof optionsOrPrompt === "string"
110
111
  ? { prompt: optionsOrPrompt }
111
112
  : optionsOrPrompt;
112
- const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, tools, } = options;
113
+ const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, tools, timeout = getDefaultTimeout(provider, 'stream'), } = options;
113
114
  // Use schema from options or fallback parameter
114
115
  const finalSchema = schema || analysisSchema;
115
116
  logger.debug(`[${functionTag}] Stream request started`, {
@@ -121,8 +122,11 @@ export class GoogleAIStudio {
121
122
  hasSchema: !!finalSchema,
122
123
  hasTools: !!tools,
123
124
  toolCount: tools ? Object.keys(tools).length : 0,
125
+ timeout,
124
126
  });
125
127
  const model = this.getModel();
128
+ // Create timeout controller if timeout is specified
129
+ const timeoutController = createTimeoutController(timeout, provider, 'stream');
126
130
  const streamOptions = {
127
131
  model: model,
128
132
  prompt: prompt,
@@ -130,6 +134,8 @@ export class GoogleAIStudio {
130
134
  temperature,
131
135
  maxTokens,
132
136
  ...(tools && { tools }), // Add tools if provided
137
+ // Add abort signal if available
138
+ ...(timeoutController && { abortSignal: timeoutController.controller.signal }),
133
139
  onError: (event) => {
134
140
  const error = event.error;
135
141
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -171,18 +177,31 @@ export class GoogleAIStudio {
171
177
  });
172
178
  }
173
179
  const result = streamText(streamOptions);
180
+ // For streaming, we can't clean up immediately, but the timeout will auto-clean
181
+ // The user should handle the stream and any timeout errors
174
182
  return result;
175
183
  }
176
184
  catch (err) {
177
- logger.error(`[${functionTag}] Exception`, {
178
- provider,
179
- modelName: this.modelName,
180
- message: "Error in streaming text",
181
- err: String(err),
182
- promptLength: typeof optionsOrPrompt === "string"
183
- ? optionsOrPrompt.length
184
- : optionsOrPrompt.prompt.length,
185
- });
185
+ // Log timeout errors specifically
186
+ if (err instanceof TimeoutError) {
187
+ logger.error(`[${functionTag}] Timeout error`, {
188
+ provider,
189
+ modelName: this.modelName,
190
+ timeout: err.timeout,
191
+ message: err.message,
192
+ });
193
+ }
194
+ else {
195
+ logger.error(`[${functionTag}] Exception`, {
196
+ provider,
197
+ modelName: this.modelName,
198
+ message: "Error in streaming text",
199
+ err: String(err),
200
+ promptLength: typeof optionsOrPrompt === "string"
201
+ ? optionsOrPrompt.length
202
+ : optionsOrPrompt.prompt.length,
203
+ });
204
+ }
186
205
  throw err; // Re-throw error to trigger fallback
187
206
  }
188
207
  }
@@ -200,7 +219,7 @@ export class GoogleAIStudio {
200
219
  const options = typeof optionsOrPrompt === "string"
201
220
  ? { prompt: optionsOrPrompt }
202
221
  : optionsOrPrompt;
203
- const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, tools, } = options;
222
+ const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, tools, timeout = getDefaultTimeout(provider, 'generate'), } = options;
204
223
  // Use schema from options or fallback parameter
205
224
  const finalSchema = schema || analysisSchema;
206
225
  logger.debug(`[${functionTag}] Generate request started`, {
@@ -211,8 +230,11 @@ export class GoogleAIStudio {
211
230
  maxTokens,
212
231
  hasTools: !!tools,
213
232
  toolCount: tools ? Object.keys(tools).length : 0,
233
+ timeout,
214
234
  });
215
235
  const model = this.getModel();
236
+ // Create timeout controller if timeout is specified
237
+ const timeoutController = createTimeoutController(timeout, provider, 'generate');
216
238
  const generateOptions = {
217
239
  model: model,
218
240
  prompt: prompt,
@@ -223,29 +245,51 @@ export class GoogleAIStudio {
223
245
  tools,
224
246
  maxSteps: 5, // Allow multiple steps for tool execution and response generation
225
247
  }), // Add tools if provided
248
+ // Add abort signal if available
249
+ ...(timeoutController && { abortSignal: timeoutController.controller.signal }),
226
250
  };
227
251
  if (finalSchema) {
228
252
  generateOptions.experimental_output = Output.object({
229
253
  schema: finalSchema,
230
254
  });
231
255
  }
232
- const result = await generateText(generateOptions);
233
- logger.debug(`[${functionTag}] Generate text completed`, {
234
- provider,
235
- modelName: this.modelName,
236
- usage: result.usage,
237
- finishReason: result.finishReason,
238
- responseLength: result.text?.length || 0,
239
- });
240
- return result;
256
+ try {
257
+ const result = await generateText(generateOptions);
258
+ // Clean up timeout if successful
259
+ timeoutController?.cleanup();
260
+ logger.debug(`[${functionTag}] Generate text completed`, {
261
+ provider,
262
+ modelName: this.modelName,
263
+ usage: result.usage,
264
+ finishReason: result.finishReason,
265
+ responseLength: result.text?.length || 0,
266
+ timeout,
267
+ });
268
+ return result;
269
+ }
270
+ finally {
271
+ // Always cleanup timeout
272
+ timeoutController?.cleanup();
273
+ }
241
274
  }
242
275
  catch (err) {
243
- logger.error(`[${functionTag}] Exception`, {
244
- provider,
245
- modelName: this.modelName,
246
- message: "Error in generating text",
247
- err: String(err),
248
- });
276
+ // Log timeout errors specifically
277
+ if (err instanceof TimeoutError) {
278
+ logger.error(`[${functionTag}] Timeout error`, {
279
+ provider,
280
+ modelName: this.modelName,
281
+ timeout: err.timeout,
282
+ message: err.message,
283
+ });
284
+ }
285
+ else {
286
+ logger.error(`[${functionTag}] Exception`, {
287
+ provider,
288
+ modelName: this.modelName,
289
+ message: "Error in generating text",
290
+ err: String(err),
291
+ });
292
+ }
249
293
  throw err; // Re-throw error to trigger fallback
250
294
  }
251
295
  }
@@ -23,6 +23,7 @@ async function getCreateVertexAnthropic() {
23
23
  }
24
24
  import { streamText, generateText, Output, } from "ai";
25
25
  import { logger } from "../utils/logger.js";
26
+ import { createTimeoutController, TimeoutError, getDefaultTimeout } from "../utils/timeout.js";
26
27
  // Default system context
27
28
  const DEFAULT_SYSTEM_CONTEXT = {
28
29
  systemPrompt: "You are a helpful AI assistant.",
@@ -285,7 +286,7 @@ export class GoogleVertexAI {
285
286
  const options = typeof optionsOrPrompt === "string"
286
287
  ? { prompt: optionsOrPrompt }
287
288
  : optionsOrPrompt;
288
- const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, } = options;
289
+ const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, 'stream'), } = options;
289
290
  // Use schema from options or fallback parameter
290
291
  const finalSchema = schema || analysisSchema;
291
292
  logger.debug(`[${functionTag}] Stream request started`, {
@@ -296,14 +297,19 @@ export class GoogleVertexAI {
296
297
  temperature,
297
298
  maxTokens,
298
299
  hasSchema: !!finalSchema,
300
+ timeout,
299
301
  });
300
302
  const model = await this.getModel();
303
+ // Create timeout controller if timeout is specified
304
+ const timeoutController = createTimeoutController(timeout, provider, 'stream');
301
305
  const streamOptions = {
302
306
  model: model,
303
307
  prompt: prompt,
304
308
  system: systemPrompt,
305
309
  temperature,
306
310
  maxTokens,
311
+ // Add abort signal if available
312
+ ...(timeoutController && { abortSignal: timeoutController.controller.signal }),
307
313
  onError: (event) => {
308
314
  const error = event.error;
309
315
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -345,16 +351,30 @@ export class GoogleVertexAI {
345
351
  });
346
352
  }
347
353
  const result = streamText(streamOptions);
354
+ // For streaming, we can't clean up immediately, but the timeout will auto-clean
355
+ // The user should handle the stream and any timeout errors
348
356
  return result;
349
357
  }
350
358
  catch (err) {
351
- logger.error(`[${functionTag}] Exception`, {
352
- provider,
353
- modelName: this.modelName,
354
- message: "Error in streaming text",
355
- err: String(err),
356
- promptLength: prompt.length,
357
- });
359
+ // Log timeout errors specifically
360
+ if (err instanceof TimeoutError) {
361
+ logger.error(`[${functionTag}] Timeout error`, {
362
+ provider,
363
+ modelName: this.modelName,
364
+ isAnthropic: isAnthropicModel(this.modelName),
365
+ timeout: err.timeout,
366
+ message: err.message,
367
+ });
368
+ }
369
+ else {
370
+ logger.error(`[${functionTag}] Exception`, {
371
+ provider,
372
+ modelName: this.modelName,
373
+ message: "Error in streaming text",
374
+ err: String(err),
375
+ promptLength: prompt.length,
376
+ });
377
+ }
358
378
  throw err; // Re-throw error to trigger fallback
359
379
  }
360
380
  }
@@ -372,7 +392,7 @@ export class GoogleVertexAI {
372
392
  const options = typeof optionsOrPrompt === "string"
373
393
  ? { prompt: optionsOrPrompt }
374
394
  : optionsOrPrompt;
375
- const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, } = options;
395
+ const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, 'generate'), } = options;
376
396
  // Use schema from options or fallback parameter
377
397
  const finalSchema = schema || analysisSchema;
378
398
  logger.debug(`[${functionTag}] Generate request started`, {
@@ -382,37 +402,63 @@ export class GoogleVertexAI {
382
402
  promptLength: prompt.length,
383
403
  temperature,
384
404
  maxTokens,
405
+ timeout,
385
406
  });
386
407
  const model = await this.getModel();
408
+ // Create timeout controller if timeout is specified
409
+ const timeoutController = createTimeoutController(timeout, provider, 'generate');
387
410
  const generateOptions = {
388
411
  model: model,
389
412
  prompt: prompt,
390
413
  system: systemPrompt,
391
414
  temperature,
392
415
  maxTokens,
416
+ // Add abort signal if available
417
+ ...(timeoutController && { abortSignal: timeoutController.controller.signal }),
393
418
  };
394
419
  if (finalSchema) {
395
420
  generateOptions.experimental_output = Output.object({
396
421
  schema: finalSchema,
397
422
  });
398
423
  }
399
- const result = await generateText(generateOptions);
400
- logger.debug(`[${functionTag}] Generate text completed`, {
401
- provider,
402
- modelName: this.modelName,
403
- usage: result.usage,
404
- finishReason: result.finishReason,
405
- responseLength: result.text?.length || 0,
406
- });
407
- return result;
424
+ try {
425
+ const result = await generateText(generateOptions);
426
+ // Clean up timeout if successful
427
+ timeoutController?.cleanup();
428
+ logger.debug(`[${functionTag}] Generate text completed`, {
429
+ provider,
430
+ modelName: this.modelName,
431
+ usage: result.usage,
432
+ finishReason: result.finishReason,
433
+ responseLength: result.text?.length || 0,
434
+ timeout,
435
+ });
436
+ return result;
437
+ }
438
+ finally {
439
+ // Always cleanup timeout
440
+ timeoutController?.cleanup();
441
+ }
408
442
  }
409
443
  catch (err) {
410
- logger.error(`[${functionTag}] Exception`, {
411
- provider,
412
- modelName: this.modelName,
413
- message: "Error in generating text",
414
- err: String(err),
415
- });
444
+ // Log timeout errors specifically
445
+ if (err instanceof TimeoutError) {
446
+ logger.error(`[${functionTag}] Timeout error`, {
447
+ provider,
448
+ modelName: this.modelName,
449
+ isAnthropic: isAnthropicModel(this.modelName),
450
+ timeout: err.timeout,
451
+ message: err.message,
452
+ });
453
+ }
454
+ else {
455
+ logger.error(`[${functionTag}] Exception`, {
456
+ provider,
457
+ modelName: this.modelName,
458
+ message: "Error in generating text",
459
+ err: String(err),
460
+ });
461
+ }
416
462
  throw err; // Re-throw error to trigger fallback
417
463
  }
418
464
  }
@@ -1,6 +1,7 @@
1
1
  import { HfInference } from "@huggingface/inference";
2
2
  import { streamText, generateText, Output, } from "ai";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { createTimeoutController, TimeoutError, getDefaultTimeout } from "../utils/timeout.js";
4
5
  // Default system context
5
6
  const DEFAULT_SYSTEM_CONTEXT = {
6
7
  systemPrompt: "You are a helpful AI assistant.",
@@ -228,7 +229,7 @@ export class HuggingFace {
228
229
  const options = typeof optionsOrPrompt === "string"
229
230
  ? { prompt: optionsOrPrompt }
230
231
  : optionsOrPrompt;
231
- const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, } = options;
232
+ const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, 'stream'), } = options;
232
233
  // Use schema from options or fallback parameter
233
234
  const finalSchema = schema || analysisSchema;
234
235
  logger.debug(`[${functionTag}] Stream request started`, {
@@ -238,14 +239,19 @@ export class HuggingFace {
238
239
  temperature,
239
240
  maxTokens,
240
241
  hasSchema: !!finalSchema,
242
+ timeout,
241
243
  });
242
244
  const model = this.getModel();
245
+ // Create timeout controller if timeout is specified
246
+ const timeoutController = createTimeoutController(timeout, provider, 'stream');
243
247
  const streamOptions = {
244
248
  model: model,
245
249
  prompt: prompt,
246
250
  system: systemPrompt,
247
251
  temperature,
248
252
  maxTokens,
253
+ // Add abort signal if available
254
+ ...(timeoutController && { abortSignal: timeoutController.controller.signal }),
249
255
  onError: (event) => {
250
256
  const error = event.error;
251
257
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -287,18 +293,31 @@ export class HuggingFace {
287
293
  });
288
294
  }
289
295
  const result = streamText(streamOptions);
296
+ // For streaming, we can't clean up immediately, but the timeout will auto-clean
297
+ // The user should handle the stream and any timeout errors
290
298
  return result;
291
299
  }
292
300
  catch (err) {
293
- logger.error(`[${functionTag}] Exception`, {
294
- provider,
295
- modelName: this.modelName,
296
- message: "Error in streaming text",
297
- err: String(err),
298
- promptLength: typeof optionsOrPrompt === "string"
299
- ? optionsOrPrompt.length
300
- : optionsOrPrompt.prompt.length,
301
- });
301
+ // Log timeout errors specifically
302
+ if (err instanceof TimeoutError) {
303
+ logger.error(`[${functionTag}] Timeout error`, {
304
+ provider,
305
+ modelName: this.modelName,
306
+ timeout: err.timeout,
307
+ message: err.message,
308
+ });
309
+ }
310
+ else {
311
+ logger.error(`[${functionTag}] Exception`, {
312
+ provider,
313
+ modelName: this.modelName,
314
+ message: "Error in streaming text",
315
+ err: String(err),
316
+ promptLength: typeof optionsOrPrompt === "string"
317
+ ? optionsOrPrompt.length
318
+ : optionsOrPrompt.prompt.length,
319
+ });
320
+ }
302
321
  throw err; // Re-throw error to trigger fallback
303
322
  }
304
323
  }
@@ -316,7 +335,7 @@ export class HuggingFace {
316
335
  const options = typeof optionsOrPrompt === "string"
317
336
  ? { prompt: optionsOrPrompt }
318
337
  : optionsOrPrompt;
319
- const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, } = options;
338
+ const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, 'generate'), } = options;
320
339
  // Use schema from options or fallback parameter
321
340
  const finalSchema = schema || analysisSchema;
322
341
  logger.debug(`[${functionTag}] Generate request started`, {
@@ -325,37 +344,62 @@ export class HuggingFace {
325
344
  promptLength: prompt.length,
326
345
  temperature,
327
346
  maxTokens,
347
+ timeout,
328
348
  });
329
349
  const model = this.getModel();
350
+ // Create timeout controller if timeout is specified
351
+ const timeoutController = createTimeoutController(timeout, provider, 'generate');
330
352
  const generateOptions = {
331
353
  model: model,
332
354
  prompt: prompt,
333
355
  system: systemPrompt,
334
356
  temperature,
335
357
  maxTokens,
358
+ // Add abort signal if available
359
+ ...(timeoutController && { abortSignal: timeoutController.controller.signal }),
336
360
  };
337
361
  if (finalSchema) {
338
362
  generateOptions.experimental_output = Output.object({
339
363
  schema: finalSchema,
340
364
  });
341
365
  }
342
- const result = await generateText(generateOptions);
343
- logger.debug(`[${functionTag}] Generate text completed`, {
344
- provider,
345
- modelName: this.modelName,
346
- usage: result.usage,
347
- finishReason: result.finishReason,
348
- responseLength: result.text?.length || 0,
349
- });
350
- return result;
366
+ try {
367
+ const result = await generateText(generateOptions);
368
+ // Clean up timeout if successful
369
+ timeoutController?.cleanup();
370
+ logger.debug(`[${functionTag}] Generate text completed`, {
371
+ provider,
372
+ modelName: this.modelName,
373
+ usage: result.usage,
374
+ finishReason: result.finishReason,
375
+ responseLength: result.text?.length || 0,
376
+ timeout,
377
+ });
378
+ return result;
379
+ }
380
+ finally {
381
+ // Always cleanup timeout
382
+ timeoutController?.cleanup();
383
+ }
351
384
  }
352
385
  catch (err) {
353
- logger.error(`[${functionTag}] Exception`, {
354
- provider,
355
- modelName: this.modelName,
356
- message: "Error in generating text",
357
- err: String(err),
358
- });
386
+ // Log timeout errors specifically
387
+ if (err instanceof TimeoutError) {
388
+ logger.error(`[${functionTag}] Timeout error`, {
389
+ provider,
390
+ modelName: this.modelName,
391
+ timeout: err.timeout,
392
+ message: err.message,
393
+ });
394
+ }
395
+ else {
396
+ logger.error(`[${functionTag}] Exception`, {
397
+ provider,
398
+ modelName: this.modelName,
399
+ message: "Error in generating text",
400
+ err: String(err),
401
+ });
402
+ }
359
403
  throw err; // Re-throw error to trigger fallback
360
404
  }
361
405
  }
@@ -1,6 +1,7 @@
1
1
  import { createMistral } from "@ai-sdk/mistral";
2
2
  import { streamText, generateText, Output, } from "ai";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { createTimeoutController, TimeoutError, getDefaultTimeout } from "../utils/timeout.js";
4
5
  // Default system context
5
6
  const DEFAULT_SYSTEM_CONTEXT = {
6
7
  systemPrompt: "You are a helpful AI assistant.",
@@ -88,7 +89,7 @@ export class MistralAI {
88
89
  const options = typeof optionsOrPrompt === "string"
89
90
  ? { prompt: optionsOrPrompt }
90
91
  : optionsOrPrompt;
91
- const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, } = options;
92
+ const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, 'stream'), } = options;
92
93
  // Use schema from options or fallback parameter
93
94
  const finalSchema = schema || analysisSchema;
94
95
  logger.debug(`[${functionTag}] Stream request started`, {
@@ -98,14 +99,19 @@ export class MistralAI {
98
99
  temperature,
99
100
  maxTokens,
100
101
  hasSchema: !!finalSchema,
102
+ timeout,
101
103
  });
102
104
  const model = this.getModel();
105
+ // Create timeout controller if timeout is specified
106
+ const timeoutController = createTimeoutController(timeout, provider, 'stream');
103
107
  const streamOptions = {
104
108
  model: model,
105
109
  prompt: prompt,
106
110
  system: systemPrompt,
107
111
  temperature,
108
112
  maxTokens,
113
+ // Add abort signal if available
114
+ ...(timeoutController && { abortSignal: timeoutController.controller.signal }),
109
115
  onError: (event) => {
110
116
  const error = event.error;
111
117
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -147,18 +153,31 @@ export class MistralAI {
147
153
  });
148
154
  }
149
155
  const result = streamText(streamOptions);
156
+ // For streaming, we can't clean up immediately, but the timeout will auto-clean
157
+ // The user should handle the stream and any timeout errors
150
158
  return result;
151
159
  }
152
160
  catch (err) {
153
- logger.error(`[${functionTag}] Exception`, {
154
- provider,
155
- modelName: this.modelName,
156
- message: "Error in streaming text",
157
- err: String(err),
158
- promptLength: typeof optionsOrPrompt === "string"
159
- ? optionsOrPrompt.length
160
- : optionsOrPrompt.prompt.length,
161
- });
161
+ // Log timeout errors specifically
162
+ if (err instanceof TimeoutError) {
163
+ logger.error(`[${functionTag}] Timeout error`, {
164
+ provider,
165
+ modelName: this.modelName,
166
+ timeout: err.timeout,
167
+ message: err.message,
168
+ });
169
+ }
170
+ else {
171
+ logger.error(`[${functionTag}] Exception`, {
172
+ provider,
173
+ modelName: this.modelName,
174
+ message: "Error in streaming text",
175
+ err: String(err),
176
+ promptLength: typeof optionsOrPrompt === "string"
177
+ ? optionsOrPrompt.length
178
+ : optionsOrPrompt.prompt.length,
179
+ });
180
+ }
162
181
  throw err; // Re-throw error to trigger fallback
163
182
  }
164
183
  }
@@ -176,7 +195,7 @@ export class MistralAI {
176
195
  const options = typeof optionsOrPrompt === "string"
177
196
  ? { prompt: optionsOrPrompt }
178
197
  : optionsOrPrompt;
179
- const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, } = options;
198
+ const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, 'generate'), } = options;
180
199
  // Use schema from options or fallback parameter
181
200
  const finalSchema = schema || analysisSchema;
182
201
  logger.debug(`[${functionTag}] Generate request started`, {
@@ -185,37 +204,62 @@ export class MistralAI {
185
204
  promptLength: prompt.length,
186
205
  temperature,
187
206
  maxTokens,
207
+ timeout,
188
208
  });
189
209
  const model = this.getModel();
210
+ // Create timeout controller if timeout is specified
211
+ const timeoutController = createTimeoutController(timeout, provider, 'generate');
190
212
  const generateOptions = {
191
213
  model: model,
192
214
  prompt: prompt,
193
215
  system: systemPrompt,
194
216
  temperature,
195
217
  maxTokens,
218
+ // Add abort signal if available
219
+ ...(timeoutController && { abortSignal: timeoutController.controller.signal }),
196
220
  };
197
221
  if (finalSchema) {
198
222
  generateOptions.experimental_output = Output.object({
199
223
  schema: finalSchema,
200
224
  });
201
225
  }
202
- const result = await generateText(generateOptions);
203
- logger.debug(`[${functionTag}] Generate text completed`, {
204
- provider,
205
- modelName: this.modelName,
206
- usage: result.usage,
207
- finishReason: result.finishReason,
208
- responseLength: result.text?.length || 0,
209
- });
210
- return result;
226
+ try {
227
+ const result = await generateText(generateOptions);
228
+ // Clean up timeout if successful
229
+ timeoutController?.cleanup();
230
+ logger.debug(`[${functionTag}] Generate text completed`, {
231
+ provider,
232
+ modelName: this.modelName,
233
+ usage: result.usage,
234
+ finishReason: result.finishReason,
235
+ responseLength: result.text?.length || 0,
236
+ timeout,
237
+ });
238
+ return result;
239
+ }
240
+ finally {
241
+ // Always cleanup timeout
242
+ timeoutController?.cleanup();
243
+ }
211
244
  }
212
245
  catch (err) {
213
- logger.error(`[${functionTag}] Exception`, {
214
- provider,
215
- modelName: this.modelName,
216
- message: "Error in generating text",
217
- err: String(err),
218
- });
246
+ // Log timeout errors specifically
247
+ if (err instanceof TimeoutError) {
248
+ logger.error(`[${functionTag}] Timeout error`, {
249
+ provider,
250
+ modelName: this.modelName,
251
+ timeout: err.timeout,
252
+ message: err.message,
253
+ });
254
+ }
255
+ else {
256
+ logger.error(`[${functionTag}] Exception`, {
257
+ provider,
258
+ modelName: this.modelName,
259
+ message: "Error in generating text",
260
+ err: String(err),
261
+ });
262
+ }
219
263
  throw err; // Re-throw error to trigger fallback
220
264
  }
221
265
  }
@@ -17,7 +17,7 @@ import type { Schema } from "ai";
17
17
  export declare class Ollama implements AIProvider {
18
18
  private baseUrl;
19
19
  private modelName;
20
- private timeout;
20
+ private defaultTimeout;
21
21
  constructor(modelName?: string);
22
22
  /**
23
23
  * Gets the appropriate model instance