diff --git a/open-sse/executors/cliproxyapi.ts b/open-sse/executors/cliproxyapi.ts index 07bece15c0..83095f4d20 100644 --- a/open-sse/executors/cliproxyapi.ts +++ b/open-sse/executors/cliproxyapi.ts @@ -428,7 +428,7 @@ export class CliproxyapiExecutor extends BaseExecutor { input.log?.warn?.("CPA", `CLIProxyAPI rate limited: ${response.status}`); } - return { response, url, headers, transformedBody }; + return { response, url, headers, transformedBody, transport: "cliproxyapi" as const }; } /** diff --git a/open-sse/handlers/chatCore.ts b/open-sse/handlers/chatCore.ts index 78cc5c25cb..368cb70095 100644 --- a/open-sse/handlers/chatCore.ts +++ b/open-sse/handlers/chatCore.ts @@ -549,8 +549,9 @@ export async function handleChatCore({ // and delegate so the existing call sites stay byte-identical. const recordKeyHealthStatus = ( status: number, - creds: Record | null | undefined - ): void => recordKeyHealthStatusFor(status, creds, log); + creds: Record | null | undefined, + transport?: string + ): void => recordKeyHealthStatusFor(status, creds, log, transport); const persistCodexQuotaState = async (headers: Record | null, status = 0) => { const currentConnectionId = getCurrentConnectionId(); @@ -2988,7 +2989,11 @@ export async function handleChatCore({ rawResult._executionCredentials?.connectionId && rawResult._executionCredentials?.apiKey ) { - recordKeyHealthStatus(status, rawResult._executionCredentials); + recordKeyHealthStatus( + status, + rawResult._executionCredentials, + rawResult.transport + ); } releaseRawResultAccountSemaphore = typeof rawResult._accountSemaphoreRelease === "function" diff --git a/open-sse/handlers/chatCore/keyHealth.ts b/open-sse/handlers/chatCore/keyHealth.ts index 100185b442..a3d6949651 100644 --- a/open-sse/handlers/chatCore/keyHealth.ts +++ b/open-sse/handlers/chatCore/keyHealth.ts @@ -31,8 +31,13 @@ type KeyHealthLog = { export function recordKeyHealthStatus( status: number, creds: Record | null | undefined, - log?: KeyHealthLog + log?: KeyHealthLog, + transport?: string ): void { + // CLIProxyAPI owns a shared external credential pool. Its auth failures cannot be + // attributed to the native OmniRoute connection selected before proxy dispatch. + if (transport === "cliproxyapi") return; + const connId = creds?.connectionId as string | undefined; if (!connId) return; diff --git a/open-sse/handlers/chatCore/upstreamTimeouts.ts b/open-sse/handlers/chatCore/upstreamTimeouts.ts index 0c63c53346..551b952e2c 100644 --- a/open-sse/handlers/chatCore/upstreamTimeouts.ts +++ b/open-sse/handlers/chatCore/upstreamTimeouts.ts @@ -106,8 +106,15 @@ export function normalizeExecutorResult( url?: string; headers?: Record; transformedBody?: unknown; + transport?: string; } -): { response: Response; url: string; headers: Record; transformedBody: unknown } { +): { + response: Response; + url: string; + headers: Record; + transformedBody: unknown; + transport?: string; +} { if (result instanceof Response) { return { response: result, url: "", headers: {}, transformedBody: null }; } @@ -116,6 +123,7 @@ export function normalizeExecutorResult( url: result.url || "", headers: result.headers || {}, transformedBody: result.transformedBody ?? null, + transport: result.transport, }; } diff --git a/tests/unit/chatcore-key-health.test.ts b/tests/unit/chatcore-key-health.test.ts index 28e3e2c8c8..bcb1167997 100644 --- a/tests/unit/chatcore-key-health.test.ts +++ b/tests/unit/chatcore-key-health.test.ts @@ -68,3 +68,9 @@ test("non-401 / non-2xx status does not touch key health", () => { recordKeyHealthStatus(500, creds(conn), noopLog); assert.equal(getAllKeyHealth()[`${conn}:primary`], undefined); }); + +test("CPA pool failures do not poison the selected native connection key", () => { + const conn = "kh-cpa-pool-isolation"; + recordKeyHealthStatus(401, creds(conn), noopLog, "cliproxyapi"); + assert.equal(getAllKeyHealth()[`${conn}:primary`], undefined); +});