




















@@ -27,8 +27,13 @@ import {
2727toAcpRuntimeError,
2828withAcpRuntimeErrorBoundary,
2929} from "../runtime/errors.js";
30-import type { AcpRuntimeErrorCode } from "../runtime/errors.js";
3130import { clearAcpTurnActive, markAcpTurnActive } from "./active-turns.js";
31+import {
32+isFailoverWorthyBackendError,
33+resolveBackendCandidatePlan,
34+shouldAttemptBackendFailover,
35+type BackendAttempt,
36+} from "./manager.backend-failover.js";
3237import {
3338appendBackgroundTaskProgressSummary,
3439createBackgroundTaskRecord,
@@ -689,34 +694,12 @@ export class AcpSessionManager {
689694 sessionKey,
690695});
691696const initialMeta = requireReadySessionMeta(initialResolution);
692-const configuredPrimaryBackend = normalizeText(input.cfg.acp?.backend);
693-const resolvedPrimaryBackend = normalizeText(initialMeta.backend);
694-const fallbackBackends = Array.isArray(input.cfg.acp?.fallbacks)
695- ? input.cfg.acp.fallbacks
696-.map((backend) => normalizeText(backend))
697-.filter((backend): backend is string => backend != null)
698- : [];
699-const candidateBackends = Array.from(
700-new Set([configuredPrimaryBackend ?? resolvedPrimaryBackend ?? "", ...fallbackBackends]),
701-);
702-const describeBackendCandidate = (backend: string) =>
703-backend || resolvedPrimaryBackend || configuredPrimaryBackend || "<auto>";
704-705-type BackendAttempt = {
706-backend: string;
707-error: string;
708-code: AcpRuntimeErrorCode;
709-sawOutput: boolean;
710-};
697+const { candidateBackends, describeBackendCandidate } = resolveBackendCandidatePlan({
698+configuredPrimaryBackend: input.cfg.acp?.backend,
699+resolvedPrimaryBackend: initialMeta.backend,
700+fallbackBackends: input.cfg.acp?.fallbacks,
701+});
711702const backendAttempts: BackendAttempt[] = [];
712-const isFailoverWorthyBackendError = (attempt: BackendAttempt) =>
713-!attempt.sawOutput &&
714-(attempt.code === "ACP_TURN_FAILED" ||
715-attempt.code === "ACP_SESSION_INIT_FAILED" ||
716-attempt.code === "ACP_BACKEND_UNAVAILABLE") &&
717-/\b(?:unavailable|rate[-\s]?limit(?:ed|ing)?|quota|exhausted|temporar(?:y|ily)|overloaded)\b/i.test(
718-attempt.error,
719-);
720703const recordBackendFailure = async (error: AcpRuntimeError) => {
721704const failedBackends = backendAttempts
722705.map((attempt) => `${attempt.backend}: ${attempt.error}`)
@@ -751,8 +734,6 @@ export class AcpSessionManager {
751734});
752735throw errorToRecord;
753736};
754-const shouldAttemptFailover = (backendIdx: number) =>
755-backendIdx < candidateBackends.length - 1;
756737757738let acpTurnMarkedActive = false;
758739// Liveness spans the whole task, not one attempt: mark once before the backend loop
@@ -967,7 +948,10 @@ export class AcpSessionManager {
967948backendAttempts.push(backendAttempt);
968949if (
969950!isFailoverWorthyBackendError(backendAttempt) ||
970-!shouldAttemptFailover(backendIdx)
951+!shouldAttemptBackendFailover({
952+backendIndex: backendIdx,
953+ candidateBackends,
954+})
971955) {
972956await recordBackendFailure(acpError);
973957}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。