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"); }