From 17c4f623125d93d4d27dbb4dc0144217d8a858a6 Mon Sep 17 00:00:00 2001 From: OpenCodeEngineer Date: Tue, 14 Apr 2026 10:13:55 -0700 Subject: [PATCH] fix(agents): classify unknown-no-details Responses failures as unknown for failover (#65254) Merged via squash. Prepared head SHA: 92ed4381b684b19bb912a920fbaf43ff00b2729f Co-authored-by: OpenCodeEngineer <261470075+OpenCodeEngineer@users.noreply.github.com> Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com> Reviewed-by: @altaywtf --- CHANGELOG.md | 1 + .../pi-embedded-helpers.isbillingerrormessage.test.ts | 6 ++++++ src/agents/pi-embedded-helpers/errors.ts | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d0a76669c0..2b4a6630352 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai - Telegram/documents: drop leaked binary caption bytes from inbound Telegram text handling so document uploads like `.mobi` or `.epub` no longer explode prompt token counts. (#66663) Thanks @joelnishanth. - Gateway/auth: resolve the active gateway bearer per-request on the HTTP server and the HTTP upgrade handler via `getResolvedAuth()`, mirroring the WebSocket path, so a secret rotated through `secrets.reload` or config hot-reload stops authenticating on `/v1/*`, `/tools/invoke`, plugin HTTP routes, and the canvas upgrade path immediately instead of remaining valid on HTTP until gateway restart. (#66651) Thanks @mmaps. - Agents/compaction: cap the compaction reserve-token floor to the model context window so small-context local models (e.g. Ollama with 16K tokens) no longer trigger context-overflow errors or infinite compaction loops on every prompt. (#65671) Thanks @openperf. +- Agents/OpenAI Responses: classify the exact `Unknown error (no error details in response)` transport failure as failover reason `unknown` so assistant/model fallback still runs for that no-details failure path. (#65254) Thanks @OpenCodeEngineer. ## 2026.4.14 diff --git a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts index 41a10d8c533..2f478af3b6d 100644 --- a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts +++ b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts @@ -684,6 +684,12 @@ describe("classifyFailoverReason", () => { ).toBeNull(); }); + it("classifies OpenAI Responses unknown-no-details message as unknown", () => { + const message = "Unknown error (no error details in response)"; + expect(classifyFailoverReason(message)).toBe("unknown"); + expect(isFailoverErrorMessage(message)).toBe(true); + }); + it("classifies provider-scoped generic upstream messages", () => { expect(classifyFailoverReason("An unknown error occurred", { provider: "anthropic" })).toBe( "timeout", diff --git a/src/agents/pi-embedded-helpers/errors.ts b/src/agents/pi-embedded-helpers/errors.ts index 560981b09f8..e81407f6e9c 100644 --- a/src/agents/pi-embedded-helpers/errors.ts +++ b/src/agents/pi-embedded-helpers/errors.ts @@ -668,6 +668,10 @@ function isOpenRouterKeyLimitExceededError(raw: string, provider?: string): bool ); } +function isExactUnknownNoDetailsError(raw: string): boolean { + return normalizeOptionalLowercaseString(raw)?.trim() === "unknown error (no error details in response)"; +} + function classifyFailoverClassificationFromMessage( raw: string, provider?: string, @@ -737,6 +741,9 @@ function classifyFailoverClassificationFromMessage( if (isCloudCodeAssistFormatError(raw)) { return toReasonClassification("format"); } + if (isExactUnknownNoDetailsError(raw)) { + return toReasonClassification("unknown"); + } if (isTimeoutErrorMessage(raw)) { return toReasonClassification("timeout"); }