@juspay/neurolink 8.13.0 → 8.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/adapters/providerImageAdapter.d.ts +5 -0
- package/dist/adapters/providerImageAdapter.js +97 -9
- package/dist/lib/adapters/providerImageAdapter.d.ts +5 -0
- package/dist/lib/adapters/providerImageAdapter.js +97 -9
- package/dist/lib/utils/fileDetector.d.ts +2 -0
- package/dist/lib/utils/fileDetector.js +7 -3
- package/dist/utils/fileDetector.d.ts +2 -0
- package/dist/utils/fileDetector.js +7 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [8.13.2](https://github.com/juspay/neurolink/compare/v8.13.1...v8.13.2) (2025-12-14)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- **(sdk):** Replace hardcoded timeouts with class constants ([a34c291](https://github.com/juspay/neurolink/commit/a34c29155e82ef4f498714c031401463351171bd))
|
|
6
|
+
|
|
7
|
+
## [8.13.1](https://github.com/juspay/neurolink/compare/v8.13.0...v8.13.1) (2025-12-13)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **(provider):** Implement image count limits with validation and warnings ([ff3e27a](https://github.com/juspay/neurolink/commit/ff3e27a5ab3aafffc8312f645e0ebc566600cc63))
|
|
12
|
+
|
|
1
13
|
## [8.13.0](https://github.com/juspay/neurolink/compare/v8.12.0...v8.13.0) (2025-12-13)
|
|
2
14
|
|
|
3
15
|
### Features
|
|
@@ -33,6 +33,11 @@ export declare class ProviderImageAdapter {
|
|
|
33
33
|
* Format content for Vertex AI (model-specific routing)
|
|
34
34
|
*/
|
|
35
35
|
private static formatForVertex;
|
|
36
|
+
/**
|
|
37
|
+
* Validate image count against provider limits
|
|
38
|
+
* Warns at 80% threshold, throws error if limit exceeded
|
|
39
|
+
*/
|
|
40
|
+
private static validateImageCount;
|
|
36
41
|
/**
|
|
37
42
|
* Validate that provider and model support vision
|
|
38
43
|
*/
|
|
@@ -16,6 +16,28 @@ export class MultimodalLogger {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Image count limits per provider
|
|
21
|
+
* These limits prevent API rejections when too many images are sent
|
|
22
|
+
*/
|
|
23
|
+
const IMAGE_LIMITS = {
|
|
24
|
+
openai: 10,
|
|
25
|
+
azure: 10, // Same as OpenAI
|
|
26
|
+
"google-ai": 16,
|
|
27
|
+
google: 16,
|
|
28
|
+
anthropic: 20,
|
|
29
|
+
vertex: {
|
|
30
|
+
// Vertex has model-specific limits
|
|
31
|
+
claude: 20, // Claude models on Vertex
|
|
32
|
+
gemini: 16, // Gemini models on Vertex
|
|
33
|
+
default: 16,
|
|
34
|
+
},
|
|
35
|
+
ollama: 10, // Conservative limit for Ollama
|
|
36
|
+
litellm: 10, // Conservative limit, as it proxies to various providers
|
|
37
|
+
mistral: 10, // Conservative limit for Mistral
|
|
38
|
+
// Note: Bedrock limit defined for future use when vision support is added
|
|
39
|
+
bedrock: 20, // Same as Anthropic for Claude models on Bedrock
|
|
40
|
+
};
|
|
19
41
|
/**
|
|
20
42
|
* Vision capability definitions for each provider
|
|
21
43
|
*/
|
|
@@ -368,7 +390,9 @@ export class ProviderImageAdapter {
|
|
|
368
390
|
break;
|
|
369
391
|
case "azure":
|
|
370
392
|
case "azure-openai":
|
|
371
|
-
|
|
393
|
+
// Azure uses same format as OpenAI but validate with azure provider name
|
|
394
|
+
this.validateImageCount(images.length, "azure");
|
|
395
|
+
adaptedPayload = this.formatForOpenAI(text, images, true);
|
|
372
396
|
break;
|
|
373
397
|
case "google-ai":
|
|
374
398
|
case "google":
|
|
@@ -381,7 +405,9 @@ export class ProviderImageAdapter {
|
|
|
381
405
|
adaptedPayload = this.formatForVertex(text, images, model);
|
|
382
406
|
break;
|
|
383
407
|
case "ollama":
|
|
384
|
-
|
|
408
|
+
// Ollama uses same format as OpenAI but validate with ollama provider name
|
|
409
|
+
this.validateImageCount(images.length, "ollama");
|
|
410
|
+
adaptedPayload = this.formatForOpenAI(text, images, true);
|
|
385
411
|
break;
|
|
386
412
|
case "huggingface":
|
|
387
413
|
adaptedPayload = this.formatForOpenAI(text, images);
|
|
@@ -415,7 +441,11 @@ export class ProviderImageAdapter {
|
|
|
415
441
|
/**
|
|
416
442
|
* Format content for OpenAI (GPT-4o format)
|
|
417
443
|
*/
|
|
418
|
-
static formatForOpenAI(text, images) {
|
|
444
|
+
static formatForOpenAI(text, images, skipValidation = false) {
|
|
445
|
+
// Validate image count before processing (unless called from another formatter)
|
|
446
|
+
if (!skipValidation) {
|
|
447
|
+
this.validateImageCount(images.length, "openai");
|
|
448
|
+
}
|
|
419
449
|
const content = [{ type: "text", text }];
|
|
420
450
|
images.forEach((image, index) => {
|
|
421
451
|
try {
|
|
@@ -438,7 +468,11 @@ export class ProviderImageAdapter {
|
|
|
438
468
|
/**
|
|
439
469
|
* Format content for Google AI (Gemini format)
|
|
440
470
|
*/
|
|
441
|
-
static formatForGoogleAI(text, images) {
|
|
471
|
+
static formatForGoogleAI(text, images, skipValidation = false) {
|
|
472
|
+
// Validate image count before processing (unless called from another formatter)
|
|
473
|
+
if (!skipValidation) {
|
|
474
|
+
this.validateImageCount(images.length, "google-ai");
|
|
475
|
+
}
|
|
442
476
|
const parts = [{ text }];
|
|
443
477
|
images.forEach((image, index) => {
|
|
444
478
|
try {
|
|
@@ -460,7 +494,11 @@ export class ProviderImageAdapter {
|
|
|
460
494
|
/**
|
|
461
495
|
* Format content for Anthropic (Claude format)
|
|
462
496
|
*/
|
|
463
|
-
static formatForAnthropic(text, images) {
|
|
497
|
+
static formatForAnthropic(text, images, skipValidation = false) {
|
|
498
|
+
// Validate image count before processing (unless called from another formatter)
|
|
499
|
+
if (!skipValidation) {
|
|
500
|
+
this.validateImageCount(images.length, "anthropic");
|
|
501
|
+
}
|
|
464
502
|
const content = [{ type: "text", text }];
|
|
465
503
|
images.forEach((image, index) => {
|
|
466
504
|
try {
|
|
@@ -488,15 +526,65 @@ export class ProviderImageAdapter {
|
|
|
488
526
|
* Format content for Vertex AI (model-specific routing)
|
|
489
527
|
*/
|
|
490
528
|
static formatForVertex(text, images, model) {
|
|
491
|
-
//
|
|
529
|
+
// Validate image count with model-specific limits before processing
|
|
530
|
+
this.validateImageCount(images.length, "vertex", model);
|
|
531
|
+
// Route based on model type, skip validation in delegated methods
|
|
492
532
|
if (model.includes("gemini")) {
|
|
493
|
-
return this.formatForGoogleAI(text, images);
|
|
533
|
+
return this.formatForGoogleAI(text, images, true);
|
|
494
534
|
}
|
|
495
535
|
else if (model.includes("claude")) {
|
|
496
|
-
return this.formatForAnthropic(text, images);
|
|
536
|
+
return this.formatForAnthropic(text, images, true);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
return this.formatForGoogleAI(text, images, true);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Validate image count against provider limits
|
|
544
|
+
* Warns at 80% threshold, throws error if limit exceeded
|
|
545
|
+
*/
|
|
546
|
+
static validateImageCount(imageCount, provider, model) {
|
|
547
|
+
const normalizedProvider = provider.toLowerCase();
|
|
548
|
+
let limit;
|
|
549
|
+
// Determine the limit based on provider
|
|
550
|
+
if (normalizedProvider === "vertex" && model) {
|
|
551
|
+
// Vertex has model-specific limits
|
|
552
|
+
if (model.includes("claude")) {
|
|
553
|
+
limit = IMAGE_LIMITS.vertex.claude;
|
|
554
|
+
}
|
|
555
|
+
else if (model.includes("gemini")) {
|
|
556
|
+
limit = IMAGE_LIMITS.vertex.gemini;
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
limit = IMAGE_LIMITS.vertex.default;
|
|
560
|
+
}
|
|
497
561
|
}
|
|
498
562
|
else {
|
|
499
|
-
|
|
563
|
+
// Use provider-specific limit
|
|
564
|
+
const providerLimit = normalizedProvider in IMAGE_LIMITS
|
|
565
|
+
? IMAGE_LIMITS[normalizedProvider]
|
|
566
|
+
: undefined;
|
|
567
|
+
// If provider not found in limits map, use a conservative default
|
|
568
|
+
if (providerLimit === undefined) {
|
|
569
|
+
// Conservative default for unknown providers
|
|
570
|
+
limit = 10;
|
|
571
|
+
logger.warn(`Image count limit not defined for provider ${provider}. Using conservative default of 10 images.`);
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
// providerLimit is always a number when defined (except vertex which is handled separately)
|
|
575
|
+
limit = providerLimit;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
// Warn only once at 80% threshold to avoid noise in batch processing
|
|
579
|
+
const warningThreshold = Math.floor(limit * 0.8);
|
|
580
|
+
if (imageCount === warningThreshold) {
|
|
581
|
+
logger.warn(`Image count (${imageCount}) is approaching the limit for ${provider}. ` +
|
|
582
|
+
`Maximum allowed: ${limit}. Please reduce the number of images.`);
|
|
583
|
+
}
|
|
584
|
+
// Throw error if limit exceeded
|
|
585
|
+
if (imageCount > limit) {
|
|
586
|
+
throw new Error(`Image count (${imageCount}) exceeds the maximum limit for ${provider}. ` +
|
|
587
|
+
`Maximum allowed: ${limit}. Please reduce the number of images.`);
|
|
500
588
|
}
|
|
501
589
|
}
|
|
502
590
|
/**
|
|
@@ -33,6 +33,11 @@ export declare class ProviderImageAdapter {
|
|
|
33
33
|
* Format content for Vertex AI (model-specific routing)
|
|
34
34
|
*/
|
|
35
35
|
private static formatForVertex;
|
|
36
|
+
/**
|
|
37
|
+
* Validate image count against provider limits
|
|
38
|
+
* Warns at 80% threshold, throws error if limit exceeded
|
|
39
|
+
*/
|
|
40
|
+
private static validateImageCount;
|
|
36
41
|
/**
|
|
37
42
|
* Validate that provider and model support vision
|
|
38
43
|
*/
|
|
@@ -16,6 +16,28 @@ export class MultimodalLogger {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Image count limits per provider
|
|
21
|
+
* These limits prevent API rejections when too many images are sent
|
|
22
|
+
*/
|
|
23
|
+
const IMAGE_LIMITS = {
|
|
24
|
+
openai: 10,
|
|
25
|
+
azure: 10, // Same as OpenAI
|
|
26
|
+
"google-ai": 16,
|
|
27
|
+
google: 16,
|
|
28
|
+
anthropic: 20,
|
|
29
|
+
vertex: {
|
|
30
|
+
// Vertex has model-specific limits
|
|
31
|
+
claude: 20, // Claude models on Vertex
|
|
32
|
+
gemini: 16, // Gemini models on Vertex
|
|
33
|
+
default: 16,
|
|
34
|
+
},
|
|
35
|
+
ollama: 10, // Conservative limit for Ollama
|
|
36
|
+
litellm: 10, // Conservative limit, as it proxies to various providers
|
|
37
|
+
mistral: 10, // Conservative limit for Mistral
|
|
38
|
+
// Note: Bedrock limit defined for future use when vision support is added
|
|
39
|
+
bedrock: 20, // Same as Anthropic for Claude models on Bedrock
|
|
40
|
+
};
|
|
19
41
|
/**
|
|
20
42
|
* Vision capability definitions for each provider
|
|
21
43
|
*/
|
|
@@ -368,7 +390,9 @@ export class ProviderImageAdapter {
|
|
|
368
390
|
break;
|
|
369
391
|
case "azure":
|
|
370
392
|
case "azure-openai":
|
|
371
|
-
|
|
393
|
+
// Azure uses same format as OpenAI but validate with azure provider name
|
|
394
|
+
this.validateImageCount(images.length, "azure");
|
|
395
|
+
adaptedPayload = this.formatForOpenAI(text, images, true);
|
|
372
396
|
break;
|
|
373
397
|
case "google-ai":
|
|
374
398
|
case "google":
|
|
@@ -381,7 +405,9 @@ export class ProviderImageAdapter {
|
|
|
381
405
|
adaptedPayload = this.formatForVertex(text, images, model);
|
|
382
406
|
break;
|
|
383
407
|
case "ollama":
|
|
384
|
-
|
|
408
|
+
// Ollama uses same format as OpenAI but validate with ollama provider name
|
|
409
|
+
this.validateImageCount(images.length, "ollama");
|
|
410
|
+
adaptedPayload = this.formatForOpenAI(text, images, true);
|
|
385
411
|
break;
|
|
386
412
|
case "huggingface":
|
|
387
413
|
adaptedPayload = this.formatForOpenAI(text, images);
|
|
@@ -415,7 +441,11 @@ export class ProviderImageAdapter {
|
|
|
415
441
|
/**
|
|
416
442
|
* Format content for OpenAI (GPT-4o format)
|
|
417
443
|
*/
|
|
418
|
-
static formatForOpenAI(text, images) {
|
|
444
|
+
static formatForOpenAI(text, images, skipValidation = false) {
|
|
445
|
+
// Validate image count before processing (unless called from another formatter)
|
|
446
|
+
if (!skipValidation) {
|
|
447
|
+
this.validateImageCount(images.length, "openai");
|
|
448
|
+
}
|
|
419
449
|
const content = [{ type: "text", text }];
|
|
420
450
|
images.forEach((image, index) => {
|
|
421
451
|
try {
|
|
@@ -438,7 +468,11 @@ export class ProviderImageAdapter {
|
|
|
438
468
|
/**
|
|
439
469
|
* Format content for Google AI (Gemini format)
|
|
440
470
|
*/
|
|
441
|
-
static formatForGoogleAI(text, images) {
|
|
471
|
+
static formatForGoogleAI(text, images, skipValidation = false) {
|
|
472
|
+
// Validate image count before processing (unless called from another formatter)
|
|
473
|
+
if (!skipValidation) {
|
|
474
|
+
this.validateImageCount(images.length, "google-ai");
|
|
475
|
+
}
|
|
442
476
|
const parts = [{ text }];
|
|
443
477
|
images.forEach((image, index) => {
|
|
444
478
|
try {
|
|
@@ -460,7 +494,11 @@ export class ProviderImageAdapter {
|
|
|
460
494
|
/**
|
|
461
495
|
* Format content for Anthropic (Claude format)
|
|
462
496
|
*/
|
|
463
|
-
static formatForAnthropic(text, images) {
|
|
497
|
+
static formatForAnthropic(text, images, skipValidation = false) {
|
|
498
|
+
// Validate image count before processing (unless called from another formatter)
|
|
499
|
+
if (!skipValidation) {
|
|
500
|
+
this.validateImageCount(images.length, "anthropic");
|
|
501
|
+
}
|
|
464
502
|
const content = [{ type: "text", text }];
|
|
465
503
|
images.forEach((image, index) => {
|
|
466
504
|
try {
|
|
@@ -488,15 +526,65 @@ export class ProviderImageAdapter {
|
|
|
488
526
|
* Format content for Vertex AI (model-specific routing)
|
|
489
527
|
*/
|
|
490
528
|
static formatForVertex(text, images, model) {
|
|
491
|
-
//
|
|
529
|
+
// Validate image count with model-specific limits before processing
|
|
530
|
+
this.validateImageCount(images.length, "vertex", model);
|
|
531
|
+
// Route based on model type, skip validation in delegated methods
|
|
492
532
|
if (model.includes("gemini")) {
|
|
493
|
-
return this.formatForGoogleAI(text, images);
|
|
533
|
+
return this.formatForGoogleAI(text, images, true);
|
|
494
534
|
}
|
|
495
535
|
else if (model.includes("claude")) {
|
|
496
|
-
return this.formatForAnthropic(text, images);
|
|
536
|
+
return this.formatForAnthropic(text, images, true);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
return this.formatForGoogleAI(text, images, true);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Validate image count against provider limits
|
|
544
|
+
* Warns at 80% threshold, throws error if limit exceeded
|
|
545
|
+
*/
|
|
546
|
+
static validateImageCount(imageCount, provider, model) {
|
|
547
|
+
const normalizedProvider = provider.toLowerCase();
|
|
548
|
+
let limit;
|
|
549
|
+
// Determine the limit based on provider
|
|
550
|
+
if (normalizedProvider === "vertex" && model) {
|
|
551
|
+
// Vertex has model-specific limits
|
|
552
|
+
if (model.includes("claude")) {
|
|
553
|
+
limit = IMAGE_LIMITS.vertex.claude;
|
|
554
|
+
}
|
|
555
|
+
else if (model.includes("gemini")) {
|
|
556
|
+
limit = IMAGE_LIMITS.vertex.gemini;
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
limit = IMAGE_LIMITS.vertex.default;
|
|
560
|
+
}
|
|
497
561
|
}
|
|
498
562
|
else {
|
|
499
|
-
|
|
563
|
+
// Use provider-specific limit
|
|
564
|
+
const providerLimit = normalizedProvider in IMAGE_LIMITS
|
|
565
|
+
? IMAGE_LIMITS[normalizedProvider]
|
|
566
|
+
: undefined;
|
|
567
|
+
// If provider not found in limits map, use a conservative default
|
|
568
|
+
if (providerLimit === undefined) {
|
|
569
|
+
// Conservative default for unknown providers
|
|
570
|
+
limit = 10;
|
|
571
|
+
logger.warn(`Image count limit not defined for provider ${provider}. Using conservative default of 10 images.`);
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
// providerLimit is always a number when defined (except vertex which is handled separately)
|
|
575
|
+
limit = providerLimit;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
// Warn only once at 80% threshold to avoid noise in batch processing
|
|
579
|
+
const warningThreshold = Math.floor(limit * 0.8);
|
|
580
|
+
if (imageCount === warningThreshold) {
|
|
581
|
+
logger.warn(`Image count (${imageCount}) is approaching the limit for ${provider}. ` +
|
|
582
|
+
`Maximum allowed: ${limit}. Please reduce the number of images.`);
|
|
583
|
+
}
|
|
584
|
+
// Throw error if limit exceeded
|
|
585
|
+
if (imageCount > limit) {
|
|
586
|
+
throw new Error(`Image count (${imageCount}) exceeds the maximum limit for ${provider}. ` +
|
|
587
|
+
`Maximum allowed: ${limit}. Please reduce the number of images.`);
|
|
500
588
|
}
|
|
501
589
|
}
|
|
502
590
|
/**
|
|
@@ -15,6 +15,8 @@ import type { FileInput, FileProcessingResult, FileDetectorOptions } from "../ty
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
export declare class FileDetector {
|
|
18
|
+
static readonly DEFAULT_NETWORK_TIMEOUT = 30000;
|
|
19
|
+
static readonly DEFAULT_HEAD_TIMEOUT = 5000;
|
|
18
20
|
/**
|
|
19
21
|
* Auto-detect file type and process in one call
|
|
20
22
|
*
|
|
@@ -35,6 +35,10 @@ function formatFileSize(bytes) {
|
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
37
|
export class FileDetector {
|
|
38
|
+
// FD-017: Replace hardcoded timeouts with constants.
|
|
39
|
+
// These default ensure consistent timeout behavior across all file-detection logic.
|
|
40
|
+
static DEFAULT_NETWORK_TIMEOUT = 30000; // 30 seconds
|
|
41
|
+
static DEFAULT_HEAD_TIMEOUT = 5000; // 5 seconds
|
|
38
42
|
/**
|
|
39
43
|
* Auto-detect file type and process in one call
|
|
40
44
|
*
|
|
@@ -144,7 +148,7 @@ export class FileDetector {
|
|
|
144
148
|
*/
|
|
145
149
|
static async loadFromURL(url, options) {
|
|
146
150
|
const maxSize = options?.maxSize || 10 * 1024 * 1024;
|
|
147
|
-
const timeout = options?.timeout ||
|
|
151
|
+
const timeout = options?.timeout || this.DEFAULT_NETWORK_TIMEOUT;
|
|
148
152
|
const response = await request(url, {
|
|
149
153
|
dispatcher: getGlobalDispatcher().compose(interceptors.redirect({ maxRedirections: 5 })),
|
|
150
154
|
method: "GET",
|
|
@@ -273,8 +277,8 @@ class MimeTypeStrategy {
|
|
|
273
277
|
const response = await request(input, {
|
|
274
278
|
dispatcher: getGlobalDispatcher().compose(interceptors.redirect({ maxRedirections: 5 })),
|
|
275
279
|
method: "HEAD",
|
|
276
|
-
headersTimeout:
|
|
277
|
-
bodyTimeout:
|
|
280
|
+
headersTimeout: FileDetector.DEFAULT_HEAD_TIMEOUT,
|
|
281
|
+
bodyTimeout: FileDetector.DEFAULT_HEAD_TIMEOUT,
|
|
278
282
|
});
|
|
279
283
|
const contentType = response.headers["content-type"] || "";
|
|
280
284
|
const type = this.mimeToFileType(contentType);
|
|
@@ -15,6 +15,8 @@ import type { FileInput, FileProcessingResult, FileDetectorOptions } from "../ty
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
export declare class FileDetector {
|
|
18
|
+
static readonly DEFAULT_NETWORK_TIMEOUT = 30000;
|
|
19
|
+
static readonly DEFAULT_HEAD_TIMEOUT = 5000;
|
|
18
20
|
/**
|
|
19
21
|
* Auto-detect file type and process in one call
|
|
20
22
|
*
|
|
@@ -35,6 +35,10 @@ function formatFileSize(bytes) {
|
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
37
|
export class FileDetector {
|
|
38
|
+
// FD-017: Replace hardcoded timeouts with constants.
|
|
39
|
+
// These default ensure consistent timeout behavior across all file-detection logic.
|
|
40
|
+
static DEFAULT_NETWORK_TIMEOUT = 30000; // 30 seconds
|
|
41
|
+
static DEFAULT_HEAD_TIMEOUT = 5000; // 5 seconds
|
|
38
42
|
/**
|
|
39
43
|
* Auto-detect file type and process in one call
|
|
40
44
|
*
|
|
@@ -144,7 +148,7 @@ export class FileDetector {
|
|
|
144
148
|
*/
|
|
145
149
|
static async loadFromURL(url, options) {
|
|
146
150
|
const maxSize = options?.maxSize || 10 * 1024 * 1024;
|
|
147
|
-
const timeout = options?.timeout ||
|
|
151
|
+
const timeout = options?.timeout || this.DEFAULT_NETWORK_TIMEOUT;
|
|
148
152
|
const response = await request(url, {
|
|
149
153
|
dispatcher: getGlobalDispatcher().compose(interceptors.redirect({ maxRedirections: 5 })),
|
|
150
154
|
method: "GET",
|
|
@@ -273,8 +277,8 @@ class MimeTypeStrategy {
|
|
|
273
277
|
const response = await request(input, {
|
|
274
278
|
dispatcher: getGlobalDispatcher().compose(interceptors.redirect({ maxRedirections: 5 })),
|
|
275
279
|
method: "HEAD",
|
|
276
|
-
headersTimeout:
|
|
277
|
-
bodyTimeout:
|
|
280
|
+
headersTimeout: FileDetector.DEFAULT_HEAD_TIMEOUT,
|
|
281
|
+
bodyTimeout: FileDetector.DEFAULT_HEAD_TIMEOUT,
|
|
278
282
|
});
|
|
279
283
|
const contentType = response.headers["content-type"] || "";
|
|
280
284
|
const type = this.mimeToFileType(contentType);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "8.13.
|
|
3
|
+
"version": "8.13.2",
|
|
4
4
|
"description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 9 major providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Juspay Technologies",
|