From 4c2b40f8b3d2617af56f2003d2fffef5ec951bd9 Mon Sep 17 00:00:00 2001 From: usr-bin-roygbiv Date: Sun, 26 Jul 2026 21:37:38 +0000 Subject: [PATCH] fix: preserve streaming compaction auth errors (cherry picked from commit 6fe25c6a08e169a15fca057a56e1ce36f46bc641) --- .../src/compaction/compaction-v2-streaming.ts | 6 ++-- packages/agent/test/remote-compaction.test.ts | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/agent/src/compaction/compaction-v2-streaming.ts b/packages/agent/src/compaction/compaction-v2-streaming.ts index e14f6b422..5511e2ff6 100644 --- a/packages/agent/src/compaction/compaction-v2-streaming.ts +++ b/packages/agent/src/compaction/compaction-v2-streaming.ts @@ -21,6 +21,7 @@ import { parseAzureDeploymentNameMap, resolveOpenAIRequestSetup, } from "@oh-my-pi/pi-ai/providers/openai-shared"; +import { captureOpenAIHttpError } from "@oh-my-pi/pi-ai/utils/openai-http"; import { CODEX_BASE_URL, getCodexAccountId, @@ -334,18 +335,19 @@ async function attemptCompactionV2Streaming( }); if (!response.ok) { - const errorText = await response.text().catch(() => ""); + const cause = await captureOpenAIHttpError(response); logger.warn("V2 remote compaction failed", { endpoint, status: response.status, statusText: response.statusText, - errorText, + errorText: cause.captured.bodyText ?? "", }); throw new ProviderHttpError( `V2 remote compaction failed (${response.status} ${response.statusText})`, response.status, { headers: response.headers, + cause, }, ); } diff --git a/packages/agent/test/remote-compaction.test.ts b/packages/agent/test/remote-compaction.test.ts index 18d4e48f9..b23127307 100644 --- a/packages/agent/test/remote-compaction.test.ts +++ b/packages/agent/test/remote-compaction.test.ts @@ -20,6 +20,7 @@ import { trimRemoteCompactionInputToContextWindow, } from "@oh-my-pi/pi-agent-core/compaction/openai"; import * as ai from "@oh-my-pi/pi-ai"; +import * as AIError from "@oh-my-pi/pi-ai/error"; import { getOpenAICodexTransportDetails } from "@oh-my-pi/pi-ai/providers/openai-codex-responses"; import type { AssistantMessage, @@ -733,6 +734,36 @@ describe("requestCompactionV2Streaming", () => { expect(attempts).toBe(2); }); + + test("preserves auth_unavailable from V2 HTTP failures", async () => { + const model = makeOpenAiModel({ + remoteCompaction: { + enabled: true, + v2StreamingEnabled: true, + v2Endpoint: "https://compact.example/v1/responses", + }, + }); + const request = buildCompactionV2Request( + model, + [{ type: "message", role: "user", content: [{ type: "input_text", text: "real user" }] }], + "instructions", + ); + const fetchMock = vi.fn(async () => + Response.json( + { error: { type: "auth_unavailable", message: "no auth available for codex" } }, + { status: 503, statusText: "Service Unavailable" }, + ), + ); + + const error = await requestCompactionV2Streaming(model, "test-key", request, undefined, { + fetch: fetchMock, + retryWait: async () => {}, + }).catch(cause => cause); + + expect(fetchMock).toHaveBeenCalled(); + expect(error).toBeInstanceOf(AIError.ProviderHttpError); + expect(AIError.is(AIError.classify(error), AIError.Flag.AuthFailed)).toBe(true); + }); }); describe("Responses Lite remote compaction", () => {