-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpdf-native-provider-fallback.ts
More file actions
146 lines (129 loc) · 4.08 KB
/
pdf-native-provider-fallback.ts
File metadata and controls
146 lines (129 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import {
AiProviderRequestError,
type AiProviderRequestErrorKind
} from '../ai-provider-errors';
import type {
PdfNativeFallbackCategory,
PdfNativeFallbackDecision
} from './pdf-processing-types';
const FILE_CONTEXT_PATTERN =
/\b(pdf|file|files|document|documents|attachment|attachments|upload|uploads|file-parser)\b/i;
const QUOTA_PATTERN =
/\b(credit|credits|quota|balance|billing|billable|funds|payment|insufficient)\b/i;
const UNSUPPORTED_PATTERN =
/\b(unsupported|not supported|does not support|doesn't support|cannot accept|can't accept|feature unavailable|feature not available|plugin unavailable|parser unavailable)\b/i;
const ENDPOINT_PATTERN =
/\b(endpoint|api|files api|uploads api|document api|parser plugin|service disabled|not enabled|disabled|not available|unavailable|not found|404)\b/i;
const REJECTION_PATTERN =
/\b(reject|rejected|cannot process|can't process|failed to parse|parse failed|invalid pdf|not allowed|blocked)\b/i;
type FallbackEligibleErrorKind =
| 'pdf-native-files-endpoint-unavailable'
| 'pdf-native-files-quota-exhausted'
| 'pdf-native-files-unsupported'
| 'pdf-native-files-rejected';
const FALLBACK_ELIGIBLE_KINDS = new Set<FallbackEligibleErrorKind>([
'pdf-native-files-endpoint-unavailable',
'pdf-native-files-quota-exhausted',
'pdf-native-files-unsupported',
'pdf-native-files-rejected'
]);
export const toPdfNativeFallbackKind = (
category: PdfNativeFallbackCategory
): FallbackEligibleErrorKind => {
switch (category) {
case 'files-quota':
return 'pdf-native-files-quota-exhausted';
case 'files-unsupported':
return 'pdf-native-files-unsupported';
case 'files-endpoint-unavailable':
return 'pdf-native-files-endpoint-unavailable';
case 'pdf-rejected':
return 'pdf-native-files-rejected';
}
};
const toCategoryFromKind = (
kind: AiProviderRequestErrorKind | undefined
): PdfNativeFallbackCategory | null => {
switch (kind) {
case 'pdf-native-files-quota-exhausted':
return 'files-quota';
case 'pdf-native-files-unsupported':
return 'files-unsupported';
case 'pdf-native-files-endpoint-unavailable':
return 'files-endpoint-unavailable';
case 'pdf-native-files-rejected':
return 'pdf-rejected';
default:
return null;
}
};
/**
* Matches only explicit file/PDF-related native-input failures. Generic errors
* intentionally do not qualify for fallback.
*/
export const classifyPdfNativeFailure = ({
message,
kind
}: {
message?: string;
kind?: AiProviderRequestErrorKind;
}): PdfNativeFallbackCategory | null => {
const categoryFromKind = toCategoryFromKind(kind);
if (categoryFromKind) {
return categoryFromKind;
}
const normalizedMessage = message?.trim().toLowerCase() ?? '';
if (!normalizedMessage) {
return null;
}
const hasFileContext = FILE_CONTEXT_PATTERN.test(normalizedMessage);
if (hasFileContext && QUOTA_PATTERN.test(normalizedMessage)) {
return 'files-quota';
}
if (hasFileContext && UNSUPPORTED_PATTERN.test(normalizedMessage)) {
return 'files-unsupported';
}
if (
(FILE_CONTEXT_PATTERN.test(normalizedMessage) || normalizedMessage.includes('files api')) &&
ENDPOINT_PATTERN.test(normalizedMessage)
) {
return 'files-endpoint-unavailable';
}
if (hasFileContext && REJECTION_PATTERN.test(normalizedMessage)) {
return 'pdf-rejected';
}
return null;
};
/**
* Decides whether the workflow may safely fall back from native PDF input to
* validated text extraction.
*/
export const decidePdfTextFallback = (error: unknown): PdfNativeFallbackDecision => {
if (!(error instanceof AiProviderRequestError)) {
return {
shouldFallback: false,
reason: 'La falla no tiene la forma esperada de error del proveedor.'
};
}
const category = classifyPdfNativeFailure({
message: error.message,
kind: error.kind
});
if (!category) {
return {
shouldFallback: false,
reason:
'La falla del proveedor no coincide con la allowlist de errores de files/PDF.'
};
}
return {
shouldFallback: true,
category,
reason: error.message,
providerErrorKind: FALLBACK_ELIGIBLE_KINDS.has(
error.kind as FallbackEligibleErrorKind
)
? error.kind
: toPdfNativeFallbackKind(category)
};
};