


















@@ -257,6 +257,7 @@ export type ProviderRuntimeFailureKind =
257257| "auth_scope"
258258| "auth_refresh"
259259| "auth_html_403"
260+| "upstream_html"
260261| "proxy"
261262| "rate_limit"
262263| "dns"
@@ -324,29 +325,38 @@ const REPLAY_INVALID_RE =
324325const SANDBOX_BLOCKED_RE =
325326/\bapproval is required\b|\bapproval timed out\b|\bapproval was denied\b|\bblocked by sandbox\b|\bsandbox\b.*\b(?:blocked|denied|forbidden|disabled|not allowed)\b/i;
326327328+function stripErrorPrefix(raw: string): string {
329+return raw.replace(/^error:\s*/i, "").trim();
330+}
331+327332function inferSignalStatus(signal: FailoverSignal): number | undefined {
328333if (typeof signal.status === "number" && Number.isFinite(signal.status)) {
329334return signal.status;
330335}
331-return extractLeadingHttpStatus(signal.message?.trim() ?? "")?.code;
336+return extractLeadingHttpStatus(stripErrorPrefix(signal.message?.trim() ?? ""))?.code;
332337}
333338334339function isHtmlErrorResponse(raw: string, status?: number): boolean {
335340const trimmed = raw.trim();
336341if (!trimmed) {
337342return false;
338343}
344+const candidate = extractLeadingHttpStatus(trimmed) ? trimmed : stripErrorPrefix(trimmed);
339345const inferred =
340346typeof status === "number" && Number.isFinite(status)
341347 ? status
342- : extractLeadingHttpStatus(trimmed)?.code;
348+ : extractLeadingHttpStatus(candidate)?.code;
343349if (typeof inferred !== "number" || inferred < 400) {
344350return false;
345351}
346-const rest = extractLeadingHttpStatus(trimmed)?.rest ?? trimmed;
352+const rest = extractLeadingHttpStatus(candidate)?.rest ?? candidate;
347353return HTML_BODY_RE.test(rest) && HTML_CLOSE_RE.test(rest);
348354}
349355356+function isTransportHtmlErrorStatus(status: number | undefined): boolean {
357+return status !== 401 && status !== 403 && status !== 407;
358+}
359+350360function isOpenAICodexScopeContext(raw: string, provider?: string): boolean {
351361const normalizedProvider = normalizeLowercaseStringOrEmpty(provider);
352362return (
@@ -669,7 +679,9 @@ function isOpenRouterKeyLimitExceededError(raw: string, provider?: string): bool
669679}
670680671681function isExactUnknownNoDetailsError(raw: string): boolean {
672-return normalizeOptionalLowercaseString(raw)?.trim() === "unknown error (no error details in response)";
682+return (
683+normalizeOptionalLowercaseString(raw)?.trim() === "unknown error (no error details in response)"
684+);
673685}
674686675687function classifyFailoverClassificationFromMessage(
@@ -757,6 +769,13 @@ function classifyFailoverClassificationFromMessage(
757769758770export function classifyFailoverSignal(signal: FailoverSignal): FailoverClassification | null {
759771const inferredStatus = inferSignalStatus(signal);
772+if (
773+signal.message &&
774+isTransportHtmlErrorStatus(inferredStatus) &&
775+isHtmlErrorResponse(signal.message, inferredStatus)
776+) {
777+return toReasonClassification("timeout");
778+}
760779const messageClassification = signal.message
761780 ? classifyFailoverClassificationFromMessage(signal.message, signal.provider)
762781 : null;
@@ -791,12 +810,12 @@ export function classifyProviderRuntimeFailureKind(
791810if (message && isAuthScopeErrorMessage(message, status, normalizedSignal.provider)) {
792811return "auth_scope";
793812}
794-if (message && status === 403 && isHtmlErrorResponse(message, status)) {
795-return "auth_html_403";
796-}
797813if (message && isProxyErrorMessage(message, status)) {
798814return "proxy";
799815}
816+if (message && isHtmlErrorResponse(message, status)) {
817+return status === 403 ? "auth_html_403" : "upstream_html";
818+}
800819const failoverClassification = classifyFailoverSignal({
801820 ...normalizedSignal,
802821 status,
@@ -885,6 +904,14 @@ export function formatAssistantErrorText(
885904);
886905}
887906907+if (providerRuntimeFailureKind === "upstream_html") {
908+return (
909+"The provider returned an HTML error page instead of an API response. " +
910+"This usually means a CDN or gateway (e.g. Cloudflare) blocked the request. " +
911+"Retry in a moment or check provider status."
912+);
913+}
914+888915if (providerRuntimeFailureKind === "proxy") {
889916return "LLM request failed: proxy or tunnel configuration blocked the provider request.";
890917}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。