@juspay/neurolink 11.1.0 → 11.2.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.
- package/CHANGELOG.md +15 -0
- package/dist/browser/neurolink.min.js +367 -367
- package/dist/cli/commands/setup.d.ts +4 -1
- package/dist/cli/commands/setup.js +44 -14
- package/dist/constants/networkErrorCodes.d.ts +14 -0
- package/dist/constants/networkErrorCodes.js +21 -0
- package/dist/factories/providerDescriptors.js +13 -3
- package/dist/lib/constants/networkErrorCodes.d.ts +14 -0
- package/dist/lib/constants/networkErrorCodes.js +22 -0
- package/dist/lib/factories/providerDescriptors.js +13 -3
- package/dist/lib/processors/base/BaseFileProcessor.d.ts +17 -0
- package/dist/lib/processors/base/BaseFileProcessor.js +40 -0
- package/dist/lib/processors/document/OpenDocumentProcessor.js +12 -2
- package/dist/lib/providers/configuredOpenAICompat.d.ts +24 -0
- package/dist/lib/providers/configuredOpenAICompat.js +60 -0
- package/dist/lib/providers/openaiCompatCatalog.d.ts +24 -0
- package/dist/lib/providers/openaiCompatCatalog.js +272 -0
- package/dist/lib/proxy/proxyFetch.js +1 -9
- package/dist/lib/types/cli.d.ts +2 -0
- package/dist/lib/types/providers.d.ts +116 -2
- package/dist/lib/utils/errorClassifier.js +100 -11
- package/dist/lib/utils/providerConfig.d.ts +39 -1
- package/dist/lib/utils/providerConfig.js +83 -0
- package/dist/lib/utils/providerHealth.d.ts +30 -24
- package/dist/lib/utils/providerHealth.js +42 -41
- package/dist/lib/utils/providerUtils.js +2 -2
- package/dist/processors/base/BaseFileProcessor.d.ts +17 -0
- package/dist/processors/base/BaseFileProcessor.js +40 -0
- package/dist/processors/document/OpenDocumentProcessor.js +12 -2
- package/dist/providers/configuredOpenAICompat.d.ts +24 -0
- package/dist/providers/configuredOpenAICompat.js +59 -0
- package/dist/providers/openaiCompatCatalog.d.ts +24 -0
- package/dist/providers/openaiCompatCatalog.js +271 -0
- package/dist/proxy/proxyFetch.js +1 -9
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/providers.d.ts +116 -2
- package/dist/utils/errorClassifier.js +100 -11
- package/dist/utils/providerConfig.d.ts +39 -1
- package/dist/utils/providerConfig.js +83 -0
- package/dist/utils/providerHealth.d.ts +30 -24
- package/dist/utils/providerHealth.js +42 -41
- package/dist/utils/providerUtils.js +2 -2
- package/package.json +2 -1
|
@@ -28,4 +28,7 @@ export declare function checkExistingConfigurations(): Promise<string[]>;
|
|
|
28
28
|
/**
|
|
29
29
|
* Delegate to existing provider setup commands
|
|
30
30
|
*/
|
|
31
|
-
export declare function delegateToProviderSetup(providerId: string
|
|
31
|
+
export declare function delegateToProviderSetup(providerId: string, flags?: {
|
|
32
|
+
check?: boolean;
|
|
33
|
+
nonInteractive?: boolean;
|
|
34
|
+
}): Promise<void>;
|
|
@@ -20,7 +20,7 @@ import { handleGCPSetup } from "./setup-gcp.js";
|
|
|
20
20
|
import { handleHuggingFaceSetup } from "./setup-huggingface.js";
|
|
21
21
|
import { handleMistralSetup } from "./setup-mistral.js";
|
|
22
22
|
import { PROVIDER_DESCRIPTORS_BY_NAME } from "../../lib/factories/providerDescriptors.js";
|
|
23
|
-
import { createCloudflareConfig, createCohereConfig, createDeepSeekConfig, createFireworksConfig, createGroqConfig, createIdeogramConfig, createJinaConfig, createNvidiaNimConfig, createOpenAICompatibleConfig, createPerplexityConfig, createRecraftConfig, createReplicateConfig, createStabilityConfig, createTogetherAIConfig, createVoyageConfig, createXaiConfig, } from "../../lib/utils/providerConfig.js";
|
|
23
|
+
import { createCloudflareConfig, createCohereConfig, createDeepSeekConfig, createFireworksConfig, createGroqConfig, createIdeogramConfig, createJinaConfig, createNvidiaNimConfig, createOpenAICompatibleConfig, createPerplexityConfig, createRecraftConfig, createReplicateConfig, createStabilityConfig, createTogetherAIConfig, createVoyageConfig, createXaiConfig, satisfiesFallbacks, } from "../../lib/utils/providerConfig.js";
|
|
24
24
|
// Provider information database
|
|
25
25
|
const PROVIDERS = [
|
|
26
26
|
{
|
|
@@ -277,15 +277,22 @@ function printGenericProviderSetup(providerId, config) {
|
|
|
277
277
|
*/
|
|
278
278
|
export async function handleSetup(argv) {
|
|
279
279
|
try {
|
|
280
|
-
// Handle specific flags
|
|
280
|
+
// Handle specific flags. `--list`/`--status` are documented as one-shot,
|
|
281
|
+
// non-interactive informational commands (see the `setup --list` /
|
|
282
|
+
// `setup --status` examples in setupCommandFactory.ts) — pass
|
|
283
|
+
// interactive: false so they print and return instead of chaining into
|
|
284
|
+
// the wizard's follow-up inquirer prompt below.
|
|
281
285
|
if (argv.list) {
|
|
282
|
-
return await showProviderList();
|
|
286
|
+
return await showProviderList(false);
|
|
283
287
|
}
|
|
284
288
|
if (argv.status) {
|
|
285
|
-
return await showProviderStatus();
|
|
289
|
+
return await showProviderStatus(false);
|
|
286
290
|
}
|
|
287
291
|
if (argv.provider && argv.provider !== "auto") {
|
|
288
|
-
return await delegateToProviderSetup(argv.provider
|
|
292
|
+
return await delegateToProviderSetup(argv.provider, {
|
|
293
|
+
check: argv.check,
|
|
294
|
+
nonInteractive: argv.nonInteractive,
|
|
295
|
+
});
|
|
289
296
|
}
|
|
290
297
|
// Main setup wizard
|
|
291
298
|
await showWelcomeScreen();
|
|
@@ -399,7 +406,7 @@ export async function checkExistingConfigurations() {
|
|
|
399
406
|
continue;
|
|
400
407
|
}
|
|
401
408
|
const requiredOk = (extraRequired ?? []).every((v) => !!process.env[v]) ||
|
|
402
|
-
(extraRequiredFallbacks
|
|
409
|
+
satisfiesFallbacks(extraRequiredFallbacks, process.env);
|
|
403
410
|
if (requiredOk) {
|
|
404
411
|
configured.push(p.id);
|
|
405
412
|
}
|
|
@@ -482,11 +489,16 @@ async function runProviderSelection() {
|
|
|
482
489
|
/**
|
|
483
490
|
* Delegate to existing provider setup commands
|
|
484
491
|
*/
|
|
485
|
-
export async function delegateToProviderSetup(providerId
|
|
492
|
+
export async function delegateToProviderSetup(providerId, flags = {
|
|
493
|
+
check: false,
|
|
494
|
+
nonInteractive: false,
|
|
495
|
+
}) {
|
|
496
|
+
const nonInteractive = flags.nonInteractive ?? false;
|
|
497
|
+
const check = flags.check ?? false;
|
|
486
498
|
const setupArgs = {
|
|
487
|
-
nonInteractive
|
|
488
|
-
"non-interactive":
|
|
489
|
-
check
|
|
499
|
+
nonInteractive,
|
|
500
|
+
"non-interactive": nonInteractive,
|
|
501
|
+
check,
|
|
490
502
|
_: [],
|
|
491
503
|
$0: "neurolink",
|
|
492
504
|
};
|
|
@@ -580,9 +592,15 @@ async function showSetupCompletion(providerId) {
|
|
|
580
592
|
logger.always(chalk.blue("Happy generating! 🚀"));
|
|
581
593
|
}
|
|
582
594
|
/**
|
|
583
|
-
* Show detailed provider information
|
|
595
|
+
* Show detailed provider information.
|
|
596
|
+
*
|
|
597
|
+
* @param interactive - When true (the default, used by the interactive
|
|
598
|
+
* wizard's "learn more" menu choice), follows up with a prompt offering to
|
|
599
|
+
* launch the setup wizard. When false (used by the direct `setup --list`
|
|
600
|
+
* flag), returns immediately after printing so the command exits cleanly
|
|
601
|
+
* without waiting on stdin.
|
|
584
602
|
*/
|
|
585
|
-
async function showProviderList() {
|
|
603
|
+
async function showProviderList(interactive = true) {
|
|
586
604
|
logger.always(chalk.blue("📚 NeuroLink Supported AI Providers"));
|
|
587
605
|
logger.always("");
|
|
588
606
|
for (const provider of PROVIDERS) {
|
|
@@ -612,6 +630,9 @@ async function showProviderList() {
|
|
|
612
630
|
logger.always("• neurolink setup --provider azure");
|
|
613
631
|
logger.always("• neurolink setup --provider bedrock");
|
|
614
632
|
logger.always("");
|
|
633
|
+
if (!interactive) {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
615
636
|
const { action } = await inquirer.prompt([
|
|
616
637
|
{
|
|
617
638
|
type: "select",
|
|
@@ -628,9 +649,15 @@ async function showProviderList() {
|
|
|
628
649
|
}
|
|
629
650
|
}
|
|
630
651
|
/**
|
|
631
|
-
* Show provider status with detailed information
|
|
652
|
+
* Show provider status with detailed information.
|
|
653
|
+
*
|
|
654
|
+
* @param interactive - When true (the default, used by the interactive
|
|
655
|
+
* wizard's "check status" menu choice), follows up with a prompt offering to
|
|
656
|
+
* set up another provider. When false (used by the direct `setup --status`
|
|
657
|
+
* flag), returns immediately after printing so the command exits cleanly
|
|
658
|
+
* without waiting on stdin.
|
|
632
659
|
*/
|
|
633
|
-
async function showProviderStatus() {
|
|
660
|
+
async function showProviderStatus(interactive = true) {
|
|
634
661
|
const spinner = ora("🔍 Checking all AI provider configurations...").start();
|
|
635
662
|
try {
|
|
636
663
|
// Get provider status using NeuroLink SDK
|
|
@@ -691,6 +718,9 @@ async function showProviderStatus() {
|
|
|
691
718
|
logger.always("• Check performance: neurolink provider status");
|
|
692
719
|
logger.always("");
|
|
693
720
|
}
|
|
721
|
+
if (!interactive) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
694
724
|
const { setupAnother } = await inquirer.prompt([
|
|
695
725
|
{
|
|
696
726
|
type: "confirm",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error codes that indicate a transient transport failure (dropped
|
|
3
|
+
* connection, socket reset, connect timeout) rather than a permanent
|
|
4
|
+
* misconfiguration. Shared between `proxy/proxyFetch.ts` (retry gating) and
|
|
5
|
+
* `utils/errorClassifier.ts` (NetworkError classification) so both stay in
|
|
6
|
+
* sync — a second hand-maintained copy would drift the two apart the same
|
|
7
|
+
* way the "5xx literal text vs statusCode" split did.
|
|
8
|
+
*
|
|
9
|
+
* undici's native `fetch()` wraps the real transport failure in
|
|
10
|
+
* `TypeError: fetch failed`, with the actionable code on `error.cause`
|
|
11
|
+
* (sometimes nested another level deep, e.g. a SocketError inside a
|
|
12
|
+
* ConnectTimeoutError) — never on the outer TypeError itself.
|
|
13
|
+
*/
|
|
14
|
+
export declare const TRANSIENT_NETWORK_CODES: ReadonlySet<string>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error codes that indicate a transient transport failure (dropped
|
|
3
|
+
* connection, socket reset, connect timeout) rather than a permanent
|
|
4
|
+
* misconfiguration. Shared between `proxy/proxyFetch.ts` (retry gating) and
|
|
5
|
+
* `utils/errorClassifier.ts` (NetworkError classification) so both stay in
|
|
6
|
+
* sync — a second hand-maintained copy would drift the two apart the same
|
|
7
|
+
* way the "5xx literal text vs statusCode" split did.
|
|
8
|
+
*
|
|
9
|
+
* undici's native `fetch()` wraps the real transport failure in
|
|
10
|
+
* `TypeError: fetch failed`, with the actionable code on `error.cause`
|
|
11
|
+
* (sometimes nested another level deep, e.g. a SocketError inside a
|
|
12
|
+
* ConnectTimeoutError) — never on the outer TypeError itself.
|
|
13
|
+
*/
|
|
14
|
+
export const TRANSIENT_NETWORK_CODES = new Set([
|
|
15
|
+
"ECONNRESET",
|
|
16
|
+
"ETIMEDOUT",
|
|
17
|
+
"ECONNREFUSED",
|
|
18
|
+
"EPIPE",
|
|
19
|
+
"UND_ERR_SOCKET",
|
|
20
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
21
|
+
]);
|
|
@@ -26,6 +26,9 @@ export const PROVIDER_DESCRIPTORS = [
|
|
|
26
26
|
timeouts: { generateMs: 45_000, streamMs: 120_000 },
|
|
27
27
|
autoSelectPriority: 7,
|
|
28
28
|
apiKeyFormatPattern: API_KEY_FORMATS.bedrock,
|
|
29
|
+
// Falls back to the AWS SDK's own default credential chain (shared
|
|
30
|
+
// profile, IAM role) when these env vars are absent — see field JSDoc.
|
|
31
|
+
credentialsResolvedExternally: true,
|
|
29
32
|
},
|
|
30
33
|
{
|
|
31
34
|
name: AIProviderName.OPENAI,
|
|
@@ -89,12 +92,14 @@ export const PROVIDER_DESCRIPTORS = [
|
|
|
89
92
|
// priority than GOOGLE_APPLICATION_CREDENTIALS by the real gating
|
|
90
93
|
// logic (hasGoogleCredentials() in googleVertex/client.ts and
|
|
91
94
|
// googleVertex/utils.ts) — corrected here vs. the plan snippet, which
|
|
92
|
-
// omitted it.
|
|
95
|
+
// omitted it. GOOGLE_AUTH_CLIENT_EMAIL and GOOGLE_AUTH_PRIVATE_KEY are
|
|
96
|
+
// nested together because hasGoogleCredentials() only accepts them as
|
|
97
|
+
// a pair — either alone is not valid auth, unlike the other flat
|
|
98
|
+
// entries here which are each independently sufficient.
|
|
93
99
|
extraRequiredFallbacks: [
|
|
94
100
|
"GOOGLE_APPLICATION_CREDENTIALS_NEUROLINK",
|
|
95
101
|
"GOOGLE_SERVICE_ACCOUNT_KEY",
|
|
96
|
-
"GOOGLE_AUTH_CLIENT_EMAIL",
|
|
97
|
-
"GOOGLE_AUTH_PRIVATE_KEY",
|
|
102
|
+
["GOOGLE_AUTH_CLIENT_EMAIL", "GOOGLE_AUTH_PRIVATE_KEY"],
|
|
98
103
|
],
|
|
99
104
|
},
|
|
100
105
|
defaultModel: VertexModels.CLAUDE_4_6_SONNET,
|
|
@@ -104,6 +109,9 @@ export const PROVIDER_DESCRIPTORS = [
|
|
|
104
109
|
setupUrl: "https://console.cloud.google.com/",
|
|
105
110
|
timeouts: { generateMs: 60_000, streamMs: 120_000 },
|
|
106
111
|
autoSelectPriority: 3,
|
|
112
|
+
// OR-of-multiple-auth-paths (file / individual fields / base64 key) —
|
|
113
|
+
// not a flat AND-list of required env vars. See field JSDoc.
|
|
114
|
+
credentialsResolvedExternally: true,
|
|
107
115
|
},
|
|
108
116
|
{
|
|
109
117
|
name: AIProviderName.ANTHROPIC,
|
|
@@ -241,6 +249,8 @@ export const PROVIDER_DESCRIPTORS = [
|
|
|
241
249
|
setupUrl: "https://docs.litellm.ai/docs/proxy/quick_start",
|
|
242
250
|
timeouts: { generateMs: 300_000, streamMs: 120_000 },
|
|
243
251
|
autoSelectPriority: 1,
|
|
252
|
+
// Documented zero-config local proxy — see field JSDoc.
|
|
253
|
+
credentialsResolvedExternally: true,
|
|
244
254
|
},
|
|
245
255
|
{
|
|
246
256
|
name: AIProviderName.SAGEMAKER,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error codes that indicate a transient transport failure (dropped
|
|
3
|
+
* connection, socket reset, connect timeout) rather than a permanent
|
|
4
|
+
* misconfiguration. Shared between `proxy/proxyFetch.ts` (retry gating) and
|
|
5
|
+
* `utils/errorClassifier.ts` (NetworkError classification) so both stay in
|
|
6
|
+
* sync — a second hand-maintained copy would drift the two apart the same
|
|
7
|
+
* way the "5xx literal text vs statusCode" split did.
|
|
8
|
+
*
|
|
9
|
+
* undici's native `fetch()` wraps the real transport failure in
|
|
10
|
+
* `TypeError: fetch failed`, with the actionable code on `error.cause`
|
|
11
|
+
* (sometimes nested another level deep, e.g. a SocketError inside a
|
|
12
|
+
* ConnectTimeoutError) — never on the outer TypeError itself.
|
|
13
|
+
*/
|
|
14
|
+
export declare const TRANSIENT_NETWORK_CODES: ReadonlySet<string>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error codes that indicate a transient transport failure (dropped
|
|
3
|
+
* connection, socket reset, connect timeout) rather than a permanent
|
|
4
|
+
* misconfiguration. Shared between `proxy/proxyFetch.ts` (retry gating) and
|
|
5
|
+
* `utils/errorClassifier.ts` (NetworkError classification) so both stay in
|
|
6
|
+
* sync — a second hand-maintained copy would drift the two apart the same
|
|
7
|
+
* way the "5xx literal text vs statusCode" split did.
|
|
8
|
+
*
|
|
9
|
+
* undici's native `fetch()` wraps the real transport failure in
|
|
10
|
+
* `TypeError: fetch failed`, with the actionable code on `error.cause`
|
|
11
|
+
* (sometimes nested another level deep, e.g. a SocketError inside a
|
|
12
|
+
* ConnectTimeoutError) — never on the outer TypeError itself.
|
|
13
|
+
*/
|
|
14
|
+
export const TRANSIENT_NETWORK_CODES = new Set([
|
|
15
|
+
"ECONNRESET",
|
|
16
|
+
"ETIMEDOUT",
|
|
17
|
+
"ECONNREFUSED",
|
|
18
|
+
"EPIPE",
|
|
19
|
+
"UND_ERR_SOCKET",
|
|
20
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
21
|
+
]);
|
|
22
|
+
//# sourceMappingURL=networkErrorCodes.js.map
|
|
@@ -26,6 +26,9 @@ export const PROVIDER_DESCRIPTORS = [
|
|
|
26
26
|
timeouts: { generateMs: 45_000, streamMs: 120_000 },
|
|
27
27
|
autoSelectPriority: 7,
|
|
28
28
|
apiKeyFormatPattern: API_KEY_FORMATS.bedrock,
|
|
29
|
+
// Falls back to the AWS SDK's own default credential chain (shared
|
|
30
|
+
// profile, IAM role) when these env vars are absent — see field JSDoc.
|
|
31
|
+
credentialsResolvedExternally: true,
|
|
29
32
|
},
|
|
30
33
|
{
|
|
31
34
|
name: AIProviderName.OPENAI,
|
|
@@ -89,12 +92,14 @@ export const PROVIDER_DESCRIPTORS = [
|
|
|
89
92
|
// priority than GOOGLE_APPLICATION_CREDENTIALS by the real gating
|
|
90
93
|
// logic (hasGoogleCredentials() in googleVertex/client.ts and
|
|
91
94
|
// googleVertex/utils.ts) — corrected here vs. the plan snippet, which
|
|
92
|
-
// omitted it.
|
|
95
|
+
// omitted it. GOOGLE_AUTH_CLIENT_EMAIL and GOOGLE_AUTH_PRIVATE_KEY are
|
|
96
|
+
// nested together because hasGoogleCredentials() only accepts them as
|
|
97
|
+
// a pair — either alone is not valid auth, unlike the other flat
|
|
98
|
+
// entries here which are each independently sufficient.
|
|
93
99
|
extraRequiredFallbacks: [
|
|
94
100
|
"GOOGLE_APPLICATION_CREDENTIALS_NEUROLINK",
|
|
95
101
|
"GOOGLE_SERVICE_ACCOUNT_KEY",
|
|
96
|
-
"GOOGLE_AUTH_CLIENT_EMAIL",
|
|
97
|
-
"GOOGLE_AUTH_PRIVATE_KEY",
|
|
102
|
+
["GOOGLE_AUTH_CLIENT_EMAIL", "GOOGLE_AUTH_PRIVATE_KEY"],
|
|
98
103
|
],
|
|
99
104
|
},
|
|
100
105
|
defaultModel: VertexModels.CLAUDE_4_6_SONNET,
|
|
@@ -104,6 +109,9 @@ export const PROVIDER_DESCRIPTORS = [
|
|
|
104
109
|
setupUrl: "https://console.cloud.google.com/",
|
|
105
110
|
timeouts: { generateMs: 60_000, streamMs: 120_000 },
|
|
106
111
|
autoSelectPriority: 3,
|
|
112
|
+
// OR-of-multiple-auth-paths (file / individual fields / base64 key) —
|
|
113
|
+
// not a flat AND-list of required env vars. See field JSDoc.
|
|
114
|
+
credentialsResolvedExternally: true,
|
|
107
115
|
},
|
|
108
116
|
{
|
|
109
117
|
name: AIProviderName.ANTHROPIC,
|
|
@@ -241,6 +249,8 @@ export const PROVIDER_DESCRIPTORS = [
|
|
|
241
249
|
setupUrl: "https://docs.litellm.ai/docs/proxy/quick_start",
|
|
242
250
|
timeouts: { generateMs: 300_000, streamMs: 120_000 },
|
|
243
251
|
autoSelectPriority: 1,
|
|
252
|
+
// Documented zero-config local proxy — see field JSDoc.
|
|
253
|
+
credentialsResolvedExternally: true,
|
|
244
254
|
},
|
|
245
255
|
{
|
|
246
256
|
name: AIProviderName.SAGEMAKER,
|
|
@@ -45,6 +45,23 @@
|
|
|
45
45
|
*/
|
|
46
46
|
import { FileErrorCode } from "../errors/index.js";
|
|
47
47
|
import type { BatchProcessingSummary, FileInfo, FileProcessingError, ProcessorFileProcessingResult, FileProcessorConfig, ProcessorOperationResult, ProcessedFileBase, ProcessOptions } from "../../types/index.js";
|
|
48
|
+
/**
|
|
49
|
+
* Marker on the error raised when a processor refuses content for exceeding
|
|
50
|
+
* the size limit *after* the download — a ZIP entry that expands past the
|
|
51
|
+
* bound, say.
|
|
52
|
+
*
|
|
53
|
+
* Separate from DOWNLOAD_TOO_LARGE because the two fire at different stages,
|
|
54
|
+
* but it exists for the same reason. Without it a bound that fires reaches
|
|
55
|
+
* `buildProcessedResultWithResult` as a plain Error and becomes
|
|
56
|
+
* PROCESSING_FAILED, which is `retryable: true` — so a caller retries a
|
|
57
|
+
* deterministic refusal three times and gets the identical answer each time.
|
|
58
|
+
* FILE_TOO_LARGE is `retryable: false`, which is the truth about this failure.
|
|
59
|
+
*/
|
|
60
|
+
export declare const CONTENT_TOO_LARGE_CODE = "CONTENT_TOO_LARGE";
|
|
61
|
+
/** An error that a processor's own size bound was exceeded. */
|
|
62
|
+
export declare function contentTooLargeError(message: string): Error;
|
|
63
|
+
/** Whether `error` is a processor size bound firing rather than a fault. */
|
|
64
|
+
export declare function isContentTooLarge(error: unknown): boolean;
|
|
48
65
|
/**
|
|
49
66
|
* Abstract base class for file processors.
|
|
50
67
|
* Provides common download, validation, and error handling functionality.
|
|
@@ -72,6 +72,29 @@ function downloadTooLargeError(maxSizeMB, typeName) {
|
|
|
72
72
|
function isDownloadTooLarge(error) {
|
|
73
73
|
return (error?.code === DOWNLOAD_TOO_LARGE_CODE);
|
|
74
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Marker on the error raised when a processor refuses content for exceeding
|
|
77
|
+
* the size limit *after* the download — a ZIP entry that expands past the
|
|
78
|
+
* bound, say.
|
|
79
|
+
*
|
|
80
|
+
* Separate from DOWNLOAD_TOO_LARGE because the two fire at different stages,
|
|
81
|
+
* but it exists for the same reason. Without it a bound that fires reaches
|
|
82
|
+
* `buildProcessedResultWithResult` as a plain Error and becomes
|
|
83
|
+
* PROCESSING_FAILED, which is `retryable: true` — so a caller retries a
|
|
84
|
+
* deterministic refusal three times and gets the identical answer each time.
|
|
85
|
+
* FILE_TOO_LARGE is `retryable: false`, which is the truth about this failure.
|
|
86
|
+
*/
|
|
87
|
+
export const CONTENT_TOO_LARGE_CODE = "CONTENT_TOO_LARGE";
|
|
88
|
+
/** An error that a processor's own size bound was exceeded. */
|
|
89
|
+
export function contentTooLargeError(message) {
|
|
90
|
+
const error = new Error(message);
|
|
91
|
+
error.code = CONTENT_TOO_LARGE_CODE;
|
|
92
|
+
return error;
|
|
93
|
+
}
|
|
94
|
+
/** Whether `error` is a processor size bound firing rather than a fault. */
|
|
95
|
+
export function isContentTooLarge(error) {
|
|
96
|
+
return (error?.code === CONTENT_TOO_LARGE_CODE);
|
|
97
|
+
}
|
|
75
98
|
/** Node's signal that a zlib output bound was reached. */
|
|
76
99
|
function isBufferTooLargeError(error) {
|
|
77
100
|
return (error?.code === "ERR_BUFFER_TOO_LARGE");
|
|
@@ -360,6 +383,23 @@ export class BaseFileProcessor {
|
|
|
360
383
|
return { success: true, data: result };
|
|
361
384
|
}
|
|
362
385
|
catch (error) {
|
|
386
|
+
// A size bound firing is a verdict, not a fault: PROCESSING_FAILED is
|
|
387
|
+
// retryable, and re-running a decompression that will hit the same
|
|
388
|
+
// ceiling is the one thing worth not doing three times.
|
|
389
|
+
if (isContentTooLarge(error)) {
|
|
390
|
+
return {
|
|
391
|
+
success: false,
|
|
392
|
+
// Same detail keys as the other FILE_TOO_LARGE sites, so anything
|
|
393
|
+
// reading them does not have to special-case where the verdict came
|
|
394
|
+
// from. `sizeMB` is absent on purpose: the decompressed size is the
|
|
395
|
+
// number this bound exists to never find out.
|
|
396
|
+
error: this.createError(FileErrorCode.FILE_TOO_LARGE, {
|
|
397
|
+
maxMB: this.config.maxSizeMB,
|
|
398
|
+
type: this.config.fileTypeName,
|
|
399
|
+
reason: error instanceof Error ? error.message : undefined,
|
|
400
|
+
}),
|
|
401
|
+
};
|
|
402
|
+
}
|
|
363
403
|
return {
|
|
364
404
|
success: false,
|
|
365
405
|
error: this.createError(FileErrorCode.PROCESSING_FAILED, { fileType: this.config.fileTypeName }, error instanceof Error ? error : undefined),
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import * as zlib from "node:zlib";
|
|
11
|
-
import { BaseFileProcessor } from "../base/BaseFileProcessor.js";
|
|
11
|
+
import { BaseFileProcessor, contentTooLargeError, isContentTooLarge, } from "../base/BaseFileProcessor.js";
|
|
12
12
|
import { readZipEntryWithinLimit } from "../archive/zipEntryReader.js";
|
|
13
13
|
import { SIZE_LIMITS } from "../config/index.js";
|
|
14
14
|
const require = createRequire(import.meta.url);
|
|
@@ -71,7 +71,10 @@ export class OpenDocumentProcessor extends BaseFileProcessor {
|
|
|
71
71
|
// `maxSizeMB` only ever saw the compressed archive on the way in.
|
|
72
72
|
const read = readZipEntryWithinLimit(contentEntry, SIZE_LIMITS.DOCUMENT_MAX_MB * 1024 * 1024, zlib);
|
|
73
73
|
if (read.status === "too-large") {
|
|
74
|
-
|
|
74
|
+
// Coded, so the bound surfaces as FILE_TOO_LARGE (not retryable)
|
|
75
|
+
// rather than PROCESSING_FAILED (retryable). The file will be
|
|
76
|
+
// exactly as oversized on the next attempt.
|
|
77
|
+
throw contentTooLargeError(`content.xml in "${this.getFilename(fileInfo)}" exceeds the ${SIZE_LIMITS.DOCUMENT_MAX_MB}MB limit for OpenDocument content`);
|
|
75
78
|
}
|
|
76
79
|
if (read.status !== "ok") {
|
|
77
80
|
throw new Error("content.xml could not be read from the archive");
|
|
@@ -93,6 +96,13 @@ export class OpenDocumentProcessor extends BaseFileProcessor {
|
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
catch (error) {
|
|
99
|
+
// A size verdict passes through intact. Re-wrapping it as a plain Error
|
|
100
|
+
// drops the code, and the base class then reports PROCESSING_FAILED —
|
|
101
|
+
// which is retryable, so the caller would refetch and decompress a file
|
|
102
|
+
// guaranteed to be exactly as oversized.
|
|
103
|
+
if (isContentTooLarge(error)) {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
96
106
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
97
107
|
throw new Error(`Failed to extract OpenDocument content: ${message}`, {
|
|
98
108
|
cause: error,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AIProviderName } from "../constants/enums.js";
|
|
2
|
+
import type { OpenAICompatCatalogEntry, OpenAICompatCredentials } from "../types/index.js";
|
|
3
|
+
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
4
|
+
/**
|
|
5
|
+
* Generic OpenAI-compatible provider driven entirely by an
|
|
6
|
+
* OpenAICompatCatalogEntry. Replaces a hand-written subclass for any
|
|
7
|
+
* provider whose only differences from its siblings are credentials, base
|
|
8
|
+
* URL, model defaults, and error-classification rules — see
|
|
9
|
+
* OPENAI_COMPAT_CATALOG in openaiCompatCatalog.ts for the entries.
|
|
10
|
+
*
|
|
11
|
+
* If a provider needs a real hook override (adjustRequestBody,
|
|
12
|
+
* adjustBodyAfter400, getChatCompletionsURL, getAuthHeaders,
|
|
13
|
+
* suppressResponseFormatWithTools, ...) it does NOT belong in the catalog —
|
|
14
|
+
* write a dedicated subclass instead (see deepseek.ts, azureOpenai.ts).
|
|
15
|
+
*/
|
|
16
|
+
export declare class ConfiguredOpenAICompatProvider extends OpenAIChatCompletionsProvider {
|
|
17
|
+
private readonly entry;
|
|
18
|
+
constructor(entry: OpenAICompatCatalogEntry, modelName?: string, sdk?: unknown, credentials?: OpenAICompatCredentials);
|
|
19
|
+
protected getProviderName(): AIProviderName;
|
|
20
|
+
protected getDefaultModel(): string;
|
|
21
|
+
protected getFallbackModelName(): string;
|
|
22
|
+
protected getFallbackModels(): string[];
|
|
23
|
+
protected formatProviderError(error: unknown): Error;
|
|
24
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { logger } from "../utils/logger.js";
|
|
2
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
3
|
+
import { getProviderModel, resolveOpenAICompatConfig, } from "../utils/providerConfig.js";
|
|
4
|
+
import { classifyProviderError } from "../utils/errorClassifier.js";
|
|
5
|
+
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
6
|
+
/**
|
|
7
|
+
* Generic OpenAI-compatible provider driven entirely by an
|
|
8
|
+
* OpenAICompatCatalogEntry. Replaces a hand-written subclass for any
|
|
9
|
+
* provider whose only differences from its siblings are credentials, base
|
|
10
|
+
* URL, model defaults, and error-classification rules — see
|
|
11
|
+
* OPENAI_COMPAT_CATALOG in openaiCompatCatalog.ts for the entries.
|
|
12
|
+
*
|
|
13
|
+
* If a provider needs a real hook override (adjustRequestBody,
|
|
14
|
+
* adjustBodyAfter400, getChatCompletionsURL, getAuthHeaders,
|
|
15
|
+
* suppressResponseFormatWithTools, ...) it does NOT belong in the catalog —
|
|
16
|
+
* write a dedicated subclass instead (see deepseek.ts, azureOpenai.ts).
|
|
17
|
+
*/
|
|
18
|
+
export class ConfiguredOpenAICompatProvider extends OpenAIChatCompletionsProvider {
|
|
19
|
+
entry;
|
|
20
|
+
constructor(entry, modelName, sdk, credentials) {
|
|
21
|
+
const { apiKey, baseURL } = resolveOpenAICompatConfig(entry, credentials);
|
|
22
|
+
// BaseProvider's constructor calls `this.getDefaultModel()` /
|
|
23
|
+
// `this.getProviderName()` synchronously inside `super()`, before this
|
|
24
|
+
// class's own constructor body (or field initializers) ever run — so
|
|
25
|
+
// `this.entry` is not yet assigned at that point and those overrides
|
|
26
|
+
// would read `undefined.modelEnvVar`. `entry.providerName` is always
|
|
27
|
+
// defined, so passing it straight through makes the base constructor's
|
|
28
|
+
// `providerName || this.getProviderName()` short-circuit; resolving the
|
|
29
|
+
// model up front and always passing a truthy `modelName` does the same
|
|
30
|
+
// for `getDefaultModel()`. Both overrides remain correct for any call
|
|
31
|
+
// made after construction, once `this.entry` is set below.
|
|
32
|
+
const resolvedModelName = modelName || getProviderModel(entry.modelEnvVar, entry.defaultModel);
|
|
33
|
+
super(entry.providerName, resolvedModelName, sdk, { baseURL, apiKey });
|
|
34
|
+
this.entry = entry;
|
|
35
|
+
logger.debug(`${entry.configOptions.providerName} Provider initialized`, {
|
|
36
|
+
modelName: this.modelName,
|
|
37
|
+
providerName: this.providerName,
|
|
38
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
getProviderName() {
|
|
42
|
+
return this.entry.providerName;
|
|
43
|
+
}
|
|
44
|
+
getDefaultModel() {
|
|
45
|
+
return getProviderModel(this.entry.modelEnvVar, this.entry.defaultModel);
|
|
46
|
+
}
|
|
47
|
+
getFallbackModelName() {
|
|
48
|
+
return this.entry.fallbackModelName;
|
|
49
|
+
}
|
|
50
|
+
getFallbackModels() {
|
|
51
|
+
return this.entry.fallbackModels;
|
|
52
|
+
}
|
|
53
|
+
formatProviderError(error) {
|
|
54
|
+
// classifyProviderError handles TimeoutError internally (always maps
|
|
55
|
+
// to NetworkError, ahead of any rule table) — no local pre-check
|
|
56
|
+
// needed or wanted here; see this task's design note.
|
|
57
|
+
return classifyProviderError(error, this.entry.errorRules, this.entry.providerName, this.modelName);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=configuredOpenAICompat.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { OpenAICompatCatalogEntry } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Config-driven catalog of the 7 zero-quirk OpenAI-compatible providers.
|
|
4
|
+
* Each entry fully replaces what used to be a hand-written
|
|
5
|
+
* OpenAIChatCompletionsProvider subclass — see ConfiguredOpenAICompatProvider
|
|
6
|
+
* for the class that reads these entries, and providerRegistry.ts for the
|
|
7
|
+
* registration loop that consumes this array.
|
|
8
|
+
*
|
|
9
|
+
* `errorRules` mirrors each provider's LIVE `formatProviderError` rule array
|
|
10
|
+
* (post plan-07/wave-2 migration), not the original hand-rolled ladder these
|
|
11
|
+
* providers had when plan 05 was first drafted: every provider below now
|
|
12
|
+
* keeps only its bespoke rule(s) — auth, plus Groq's model_decommissioned and
|
|
13
|
+
* xAI's insufficient_quota — before spreading the SAME exported
|
|
14
|
+
* `DEFAULT_ERROR_RULES` constant that the live subclasses spread (never an
|
|
15
|
+
* inlined copy, so this catalog cannot drift from that table independently).
|
|
16
|
+
* See plan-05/progress.md Ruling R4 for the full rationale.
|
|
17
|
+
*
|
|
18
|
+
* To add a new zero-quirk OpenAI-compatible provider: add one entry here.
|
|
19
|
+
* Do NOT add a provider here if it needs any hook override beyond the 3
|
|
20
|
+
* mandatory ones (getProviderName/getDefaultModel/formatProviderError) —
|
|
21
|
+
* write a dedicated subclass instead (see deepseek.ts, azureOpenai.ts, and
|
|
22
|
+
* Task 14's docs task for the deciding criteria).
|
|
23
|
+
*/
|
|
24
|
+
export declare const OPENAI_COMPAT_CATALOG: readonly OpenAICompatCatalogEntry[];
|