File size: 2,420 Bytes
e249c6d | 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 | import { classifyProviderFailoverSignalWithPlugin } from "../../plugins/provider-failover.js";
import type { FailoverReason } from "./signal.js";
type ProviderErrorPattern = {
/** Regex to match against the raw error message. */
test: RegExp;
/** The failover reason this pattern maps to. */
reason: FailoverReason;
};
/**
* Provider-specific patterns that map to specific failover reasons.
* These handle cases where the generic message tables produce wrong results
* for specific providers.
*/
const PROVIDER_SPECIFIC_PATTERNS: readonly ProviderErrorPattern[] = [
{
test: /\bworkers_ai\b.*\bquota limit exceeded\b/i,
reason: "rate_limit",
},
{
test: /\bmodelnotreadyexception\b/i,
reason: "overloaded",
},
// Groq does not currently ship a bundled provider hook.
{
test: /model(?:_is)?_deactivated|model has been deactivated/i,
reason: "model_not_found",
},
];
type ProviderSpecificErrorContext = {
provider?: string;
modelId?: string;
errorMessage: string;
status?: number;
code?: string;
errorType?: string;
providerPlugin?: PreparedProviderFailoverOwner | null;
};
export type PreparedProviderFailoverOwner = {
id: string;
matchesContextOverflowError?: (ctx: ProviderSpecificErrorContext) => boolean | undefined;
classifyFailoverReason?: (ctx: ProviderSpecificErrorContext) => FailoverReason | null | undefined;
};
export function classifyProviderPluginError(
context: ProviderSpecificErrorContext,
): FailoverReason | null {
const { providerPlugin, ...providerContext } = context;
// Presentation has no provider owner; explicit absence must not trigger discovery.
if (providerPlugin === null) {
return null;
}
if (providerPlugin) {
const ownedContext = { ...providerContext, provider: providerPlugin.id };
if (providerPlugin.matchesContextOverflowError?.(ownedContext)) {
return "context_overflow";
}
return providerPlugin.classifyFailoverReason?.(ownedContext) ?? null;
}
return (
classifyProviderFailoverSignalWithPlugin({
provider: context.provider,
context: providerContext,
}) ?? null
);
}
export function classifyLegacyProviderSpecificError(
context: ProviderSpecificErrorContext,
): FailoverReason | null {
for (const pattern of PROVIDER_SPECIFIC_PATTERNS) {
if (pattern.test.test(context.errorMessage)) {
return pattern.reason;
}
}
return null;
}
|