





















@@ -44,6 +44,9 @@ const GROQ_TOO_MANY_REQUESTS_MESSAGE =
4444"429 Too Many Requests: Too many requests were sent in a given timeframe.";
4545const GROQ_SERVICE_UNAVAILABLE_MESSAGE =
4646"503 Service Unavailable: The server is temporarily unable to handle the request due to overloading or maintenance.";
47+// Structured OpenAI-compatible server_error payload shape seen in Codex/OpenAI runs.
48+const OPENAI_SERVER_ERROR_PAYLOAD =
49+'Codex error: {"type":"error","error":{"type":"server_error","code":"server_error","message":"An error occurred while processing your request."},"sequence_number":2}';
47504851describe("failover-error", () => {
4952it("infers failover reason from HTTP status", () => {
@@ -866,6 +869,10 @@ describe("failover-error", () => {
866869expect(resolveFailoverStatus("overloaded")).toBe(503);
867870});
868871872+it("maps server_error to a 500 fallback status", () => {
873+expect(resolveFailoverStatus("server_error")).toBe(500);
874+});
875+869876it("coerces format errors with a 400 status", () => {
870877const err = coerceToFailoverError("invalid request format", {
871878provider: "google",
@@ -973,6 +980,39 @@ describe("failover-error", () => {
973980expect(described.reason).toBeUndefined();
974981});
975982983+it("classifies OpenAI-compatible server_error payloads at the error boundary", () => {
984+expect(
985+resolveFailoverReasonFromError({
986+message: OPENAI_SERVER_ERROR_PAYLOAD,
987+}),
988+).toBe("server_error");
989+expect(
990+resolveFailoverReasonFromError({
991+status: 500,
992+message: OPENAI_SERVER_ERROR_PAYLOAD,
993+}),
994+).toBe("server_error");
995+996+const err = coerceToFailoverError(
997+{
998+status: 500,
999+message: OPENAI_SERVER_ERROR_PAYLOAD,
1000+},
1001+{ provider: "openai-codex", model: "gpt-5.4" },
1002+);
1003+expect(err?.reason).toBe("server_error");
1004+expect(err?.status).toBe(500);
1005+});
1006+1007+it("keeps explicit 4xx classification ahead of server_error markers", () => {
1008+const payload = '{"type":"error","error":{"type":"server_error","code":"server_error"}}';
1009+1010+expect(resolveFailoverReasonFromError({ status: 401, message: payload })).toBe("auth");
1011+expect(resolveFailoverReasonFromError({ status: 402, message: payload })).toBe("billing");
1012+expect(resolveFailoverReasonFromError({ status: 422, message: payload })).toBe("format");
1013+expect(resolveFailoverReasonFromError(`402 Payment Required ${payload}`)).toBe("billing");
1014+});
1015+9761016it("propagates sessionId/lane/provider attribution through FailoverError (#42713)", () => {
9771017const err = new FailoverError("all fallbacks exhausted", {
9781018reason: "rate_limit",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。