From f29925d75ffb4adf063039a6ae605070973e7904 Mon Sep 17 00:00:00 2001 From: Epinephrine Date: Sat, 7 Nov 2026 17:26:31 +0900 Subject: [PATCH 1/8] fix(responses): reject malformed retained compact input --- src/responses/retained-compaction.ts | 9 ++++++++- src/server/responses/compact.ts | 5 ++++- ...ponses-native-compact-ocx-envelope.test.ts | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/responses/retained-compaction.ts b/src/responses/retained-compaction.ts index 4552503a207..cc9a0d9a92a 100644 --- a/src/responses/retained-compaction.ts +++ b/src/responses/retained-compaction.ts @@ -8,6 +8,13 @@ export interface RetainedCompaction { reasoning: string[]; } +export class InvalidRetainedCompactionEnvelopeError extends Error { + constructor() { + super("Invalid OpenCodex retained compaction envelope"); + this.name = "InvalidRetainedCompactionEnvelopeError"; + } +} + export function encodeRetainedCompaction(summary: string, reasoning: string[]): string { return RETAINED_COMPACTION_PREFIX + Buffer.from(JSON.stringify({ version: 2, summary, reasoning }), "utf-8").toString("base64"); } @@ -37,7 +44,7 @@ export function expandRetainedCompactionInput(input: unknown): unknown { if (!item || typeof item !== "object" || !["compaction", "compaction_summary", "context_compaction"].includes(item.type) || typeof item.encrypted_content !== "string" || !item.encrypted_content.startsWith(RETAINED_COMPACTION_PREFIX)) return [item]; const data = decodeRetainedCompaction(item.encrypted_content); - if (!data) throw new Error("Invalid OpenCodex retained compaction envelope"); + if (!data) throw new InvalidRetainedCompactionEnvelopeError(); return [ { ...item, encrypted_content: "ocx1:" + Buffer.from(data.summary, "utf-8").toString("base64") }, ...data.reasoning.map(text => ({ type: "message", role: "user", content: [{ type: "input_text", text }] })), diff --git a/src/server/responses/compact.ts b/src/server/responses/compact.ts index e9bb55f4acd..743f48e6cc8 100644 --- a/src/server/responses/compact.ts +++ b/src/server/responses/compact.ts @@ -152,6 +152,7 @@ import { requiresPlaintextReasoningReplay } from "../../adapters/openai-response import { destinationDecodesNativeCompactionBlob, isOpenAiOperatedResponsesDestination } from "../../providers/openai-tiers-destination"; import { bindRouteReasoningReplayScope } from "./core-replay"; import { commitReasoningReplayServingIdentity } from "../../responses/reasoning-replay-cache"; +import { InvalidRetainedCompactionEnvelopeError } from "../../responses/retained-compaction"; import { nativeCompactResponseSchema } from "../../responses/schema"; import { NATIVE_RESERVE_MODEL } from "../../codex/catalog/native-models"; import { @@ -1305,7 +1306,9 @@ export async function handleResponsesCompact( let outcomeCtx = authCtx; const localDispatchRefusal = (error: unknown): Response | undefined => { const cause = unwrapUpstreamRetryEvidenceError(error); - const response = requestPacingOverloadResponse(cause) ?? spendLedgerStorageErrorResponse(error, logCtx) ?? (cause instanceof SendBudgetExhaustedError + const response = cause instanceof InvalidRetainedCompactionEnvelopeError + ? formatErrorResponse(400, "invalid_request_error", cause.message) + : requestPacingOverloadResponse(cause) ?? spendLedgerStorageErrorResponse(error, logCtx) ?? (cause instanceof SendBudgetExhaustedError ? unboundPoolSpendRefusalResponse(logCtx) ?? formatErrorResponse(429, "request_send_budget_exhausted", cause.message) : mapCodexAuthContextErrorToResponse(cause, { now: Date.now(), accountSelector: route.codexAccountNamespace, diff --git a/tests/responses/responses-native-compact-ocx-envelope.test.ts b/tests/responses/responses-native-compact-ocx-envelope.test.ts index e7697daf743..c101b024830 100644 --- a/tests/responses/responses-native-compact-ocx-envelope.test.ts +++ b/tests/responses/responses-native-compact-ocx-envelope.test.ts @@ -66,3 +66,22 @@ test.each([ nativeItem(), ]); }); + +test("malformed ocx2 compact input is rejected locally as a caller error", async () => { + const settings = getDefaultConfig(); delete settings.compactionRouting; settings.defaultProvider = "openai"; settings.providers = { + openai: { adapter: "openai-responses", authMode: "forward", codexAccountMode: "direct", baseUrl: "https://chatgpt.com/backend-api/codex" }, + }; + let fetchCalls = 0; + globalThis.fetch = (async () => { fetchCalls++; return Response.json({}); }) as typeof fetch; + const req = new Request("http://localhost/v1/responses/compact", { + method: "POST", + headers: { "content-type": "application/json", authorization: `Bearer ${fakeChatGptJwt({ chatgpt_account_id: "fixture-account" })}` }, + body: JSON.stringify({ model: "gpt-6-luna", input: [{ type: "compaction", encrypted_content: "ocx2:invalid" }] }), + }); + + const response = await handleResponsesCompact(req, settings, { model: "", provider: "" }); + + expect(response.status).toBe(400); + expect(await response.json()).toMatchObject({ error: { type: "invalid_request_error" } }); + expect(fetchCalls).toBe(0); +}); From 64b629d01277c7a8e6e3d5cb764270e0e68e01bf Mon Sep 17 00:00:00 2001 From: Epinephrine Date: Sat, 7 Nov 2026 17:42:29 +0900 Subject: [PATCH 2/8] test: strengthen malformed compact envelope regression coverage --- docs-site/src/content/docs/reference/proxy-formats.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index b17aaec2094..24c27b5b44b 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -859,6 +859,12 @@ and of `decodesNativeCompactionBlobs` for replay. None grants canonical OpenAI i caller credential forwarding. Cross-provider overrides remain portable; v2 success alone does not establish support for `/responses/compact`. See [provider configuration](/reference/configuration/providers/). +For native compact routes, malformed OpenCodex-owned retained-compaction input +(`ocx2:`) returns HTTP 400 with `error.type: "invalid_request_error"` before +upstream dispatch. This caller validation error does not trigger upstream retries +or record a failure against a pooled Codex account. This guarantee applies to the +native compact path, not every routed compaction path. + If the native compact endpoint returns HTTP 404, OpenCodex retries compaction through a regular Responses turn with the same model selector and session headers. Canonical ChatGPT fallback turns use upstream SSE; the compact caller still receives JSON. A completed native opaque From d6afbeeafe39c6a939807cf7cc31cf14fc10361c Mon Sep 17 00:00:00 2001 From: Epinephrine Date: Sat, 7 Nov 2026 17:42:34 +0900 Subject: [PATCH 3/8] test: strengthen malformed compact envelope regression coverage --- .../compact-transient-alternate.test.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/responses/compact-transient-alternate.test.ts b/tests/responses/compact-transient-alternate.test.ts index 92112f605ed..206abd38dda 100644 --- a/tests/responses/compact-transient-alternate.test.ts +++ b/tests/responses/compact-transient-alternate.test.ts @@ -152,6 +152,29 @@ function failures(accountId: string): number { return getCodexUpstreamHealth(accountId)?.consecutiveFailures ?? 0; } +test("malformed retained compact input does not poison pooled account health", async () => { + const config = poolConfig(); + const healthBefore = [WORK, OTHER].map(id => getCodexUpstreamHealth(id)); + upstream(compacted); + for (let attempt = 0; attempt < 3; attempt++) { + const request = new Request("http://localhost/v1/responses/compact", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ model: "gpt-5.5", input: [{ type: "compaction", encrypted_content: "ocx2:invalid" }] }), + }); + const response = await handleResponsesCompact(request, config, { model: "", provider: "" }); + expect(response.status).toBe(400); + expect(await response.json()).toMatchObject({ error: { type: "invalid_request_error" } }); + expect(sends).toHaveLength(0); + expect([WORK, OTHER].map(id => getCodexUpstreamHealth(id))).toEqual(healthBefore); + } + const { response } = await compact({ config }); + expect(response.status).toBe(200); + expect(sends).toHaveLength(1); + expect(failures(WORK)).toBe(0); + expect(failures(OTHER)).toBe(0); +}); + describe("native compact moves a surviving transient 5xx to one alternate account (#6969)", () => { test("A's ladder, then B from the final recovery reserve, serves the compact", async () => { upstream(overloaded(), overloaded(), overloaded(), compacted); From 8c9a4652edb3f12b30957fc36b086458e3d27d90 Mon Sep 17 00:00:00 2001 From: Epinephrine Date: Sat, 7 Nov 2026 17:42:39 +0900 Subject: [PATCH 4/8] test: strengthen malformed compact envelope regression coverage --- tests/responses/responses-native-compact-ocx-envelope.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/responses/responses-native-compact-ocx-envelope.test.ts b/tests/responses/responses-native-compact-ocx-envelope.test.ts index c101b024830..c0c4af69f2c 100644 --- a/tests/responses/responses-native-compact-ocx-envelope.test.ts +++ b/tests/responses/responses-native-compact-ocx-envelope.test.ts @@ -15,6 +15,10 @@ import { removeTreeWithRetry } from "../helpers/remove-tree"; // envelopes verbatim, and the upstream refused them as invalid_encrypted_content. Only the custom // gateway send lowered them; ordinary turns always do. const fetchBefore = globalThis.fetch; const homeBefore = process.env.OPENCODEX_HOME; +const proxyKeys = ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "all_proxy", "no_proxy"] as const; +let proxyBefore: Array = []; +beforeEach(() => { proxyBefore = proxyKeys.map(key => process.env[key]); for (const key of proxyKeys) delete process.env[key]; }); +afterEach(() => { for (const [index, key] of proxyKeys.entries()) { if (proxyBefore[index] === undefined) delete process.env[key]; else process.env[key] = proxyBefore[index]; } }); let home: string; let release: (() => void) | undefined; beforeEach(() => { home = mkdtempSync(join(tmpdir(), "ocx-native-compact-ocx-envelope-")); process.env.OPENCODEX_HOME = home; release = acquireOwnedSpendHome(); clearCompactHandoffRoutesForTests(); }); afterEach(() => { globalThis.fetch = fetchBefore; release?.(); clearCompactHandoffRoutesForTests(); if (homeBefore === undefined) delete process.env.OPENCODEX_HOME; else process.env.OPENCODEX_HOME = homeBefore; removeTreeWithRetry(home); }); From de5b1a7379903dc5b92feee5da2dfa6226aa92d3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 8 Nov 2026 05:13:09 +0000 Subject: [PATCH 5/8] fix(responses): reject malformed retained compact input before credential refresh Co-Authored-By: Epinephrine --- .../content/docs/reference/proxy-formats.md | 10 +++--- src/responses/retained-compaction.ts | 25 +++++++++++--- src/server/responses/compact.ts | 6 +++- .../compact-transient-alternate.test.ts | 33 +++++++++++++++++++ 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index 24c27b5b44b..21bdfd6ff11 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -859,11 +859,11 @@ and of `decodesNativeCompactionBlobs` for replay. None grants canonical OpenAI i caller credential forwarding. Cross-provider overrides remain portable; v2 success alone does not establish support for `/responses/compact`. See [provider configuration](/reference/configuration/providers/). -For native compact routes, malformed OpenCodex-owned retained-compaction input -(`ocx2:`) returns HTTP 400 with `error.type: "invalid_request_error"` before -upstream dispatch. This caller validation error does not trigger upstream retries -or record a failure against a pooled Codex account. This guarantee applies to the -native compact path, not every routed compaction path. +Malformed OpenCodex-owned retained-compaction input (`ocx2:`) on a compact +request returns HTTP 400 with `error.type: "invalid_request_error"` before +routing, account selection, credential refresh, or upstream dispatch. This +caller validation error does not trigger upstream retries or record a failure +against a pooled Codex account. If the native compact endpoint returns HTTP 404, OpenCodex retries compaction through a regular Responses turn with the same model selector and session headers. Canonical ChatGPT fallback diff --git a/src/responses/retained-compaction.ts b/src/responses/retained-compaction.ts index cc9a0d9a92a..1754ae165c1 100644 --- a/src/responses/retained-compaction.ts +++ b/src/responses/retained-compaction.ts @@ -35,14 +35,31 @@ export function decodeRetainedCompaction(value: string): RetainedCompaction | nu } catch { return null; } } +function isRetainedCompactionEnvelopeItem(item: unknown): item is { type: string; encrypted_content: string } { + if (!item || typeof item !== "object") return false; + const candidate = item as { type?: unknown; encrypted_content?: unknown }; + return typeof candidate.type === "string" + && ["compaction", "compaction_summary", "context_compaction"].includes(candidate.type) + && typeof candidate.encrypted_content === "string" + && candidate.encrypted_content.startsWith(RETAINED_COMPACTION_PREFIX); +} + +/** First malformed proxy-owned retained envelope in `input`, if any. */ +export function findInvalidRetainedCompactionEnvelope(input: unknown): InvalidRetainedCompactionEnvelopeError | null { + if (!Array.isArray(input)) return null; + for (const item of input) { + if (!isRetainedCompactionEnvelopeItem(item)) continue; + if (!decodeRetainedCompaction(item.encrypted_content)) return new InvalidRetainedCompactionEnvelopeError(); + } + return null; +} + /** Expand only our structured envelopes; callers retain their existing native/ocx1 policy. */ export function expandRetainedCompactionInput(input: unknown): unknown { if (!Array.isArray(input)) return input; - if (!input.some(item => item && typeof item === "object" && ["compaction", "compaction_summary", "context_compaction"].includes(item.type) - && typeof item.encrypted_content === "string" && item.encrypted_content.startsWith(RETAINED_COMPACTION_PREFIX))) return input; + if (!input.some(isRetainedCompactionEnvelopeItem)) return input; return input.flatMap(item => { - if (!item || typeof item !== "object" || !["compaction", "compaction_summary", "context_compaction"].includes(item.type) - || typeof item.encrypted_content !== "string" || !item.encrypted_content.startsWith(RETAINED_COMPACTION_PREFIX)) return [item]; + if (!isRetainedCompactionEnvelopeItem(item)) return [item]; const data = decodeRetainedCompaction(item.encrypted_content); if (!data) throw new InvalidRetainedCompactionEnvelopeError(); return [ diff --git a/src/server/responses/compact.ts b/src/server/responses/compact.ts index 743f48e6cc8..f922c98636d 100644 --- a/src/server/responses/compact.ts +++ b/src/server/responses/compact.ts @@ -152,7 +152,7 @@ import { requiresPlaintextReasoningReplay } from "../../adapters/openai-response import { destinationDecodesNativeCompactionBlob, isOpenAiOperatedResponsesDestination } from "../../providers/openai-tiers-destination"; import { bindRouteReasoningReplayScope } from "./core-replay"; import { commitReasoningReplayServingIdentity } from "../../responses/reasoning-replay-cache"; -import { InvalidRetainedCompactionEnvelopeError } from "../../responses/retained-compaction"; +import { findInvalidRetainedCompactionEnvelope, InvalidRetainedCompactionEnvelopeError } from "../../responses/retained-compaction"; import { nativeCompactResponseSchema } from "../../responses/schema"; import { NATIVE_RESERVE_MODEL } from "../../codex/catalog/native-models"; import { @@ -700,6 +700,10 @@ export async function handleResponsesCompact( if (typeof raw.model !== "string" || raw.model.length === 0) { return formatErrorResponse(400, "invalid_request_error", "compaction request requires a model"); } + // A malformed proxy-owned envelope is a caller error, so reject it before routing or + // credential resolution can spend a token refresh on a request that cannot succeed. + const invalidEnvelope = findInvalidRetainedCompactionEnvelope(raw.input); + if (invalidEnvelope) return formatErrorResponse(400, "invalid_request_error", invalidEnvelope.message); options.onRequestBodyRead?.(); // Correct the IDENTITY before routing, or the synthetic id does not route at all. Held in // a local rather than written back to `raw.model`: assigning to the property widens it out diff --git a/tests/responses/compact-transient-alternate.test.ts b/tests/responses/compact-transient-alternate.test.ts index 206abd38dda..50c223b47c1 100644 --- a/tests/responses/compact-transient-alternate.test.ts +++ b/tests/responses/compact-transient-alternate.test.ts @@ -175,6 +175,39 @@ test("malformed retained compact input does not poison pooled account health", a expect(failures(OTHER)).toBe(0); }); +test("malformed retained compact input is rejected before a pooled credential refresh", async () => { + // expiresAt inside the 60s refresh skew makes getValidCodexToken refresh, so an + // unvalidated envelope would spend a token-refresh fetch before the 400. + writeFileSync(join(home, "codex-accounts.json"), JSON.stringify(Object.fromEntries( + [WORK, OTHER].map(id => [id, { + credential: { + accessToken: `${id}-access`, + refreshToken: `${id}-grant`, + expiresAt: Date.now() + 30_000, + chatgptAccountId: `acc-${id}`, + }, + generation: 1, + refreshGrantFingerprint: createHash("sha256").update(`codex-refresh-grant:${id}-grant`).digest("hex"), + }]), + ))); + let fetchCalls = 0; + globalThis.fetch = (async () => { + fetchCalls++; + return Response.json({ access_token: "refreshed-access", refresh_token: "refreshed-grant", expires_in: 3600 }); + }) as typeof fetch; + const request = new Request("http://localhost/v1/responses/compact", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ model: "gpt-5.5", input: [{ type: "compaction", encrypted_content: "ocx2:invalid" }] }), + }); + + const response = await handleResponsesCompact(request, poolConfig(), { model: "", provider: "" }); + + expect(response.status).toBe(400); + expect(await response.json()).toMatchObject({ error: { type: "invalid_request_error" } }); + expect(fetchCalls).toBe(0); +}); + describe("native compact moves a surviving transient 5xx to one alternate account (#6969)", () => { test("A's ladder, then B from the final recovery reserve, serves the compact", async () => { upstream(overloaded(), overloaded(), overloaded(), compacted); From 5fc167aa2f58b40116d47e60d7b60358ecc7f8f8 Mon Sep 17 00:00:00 2001 From: Epinephrine Date: Mon, 9 Nov 2026 10:08:13 +0900 Subject: [PATCH 6/8] docs: clarify malformed compact input in translated references --- docs-site/src/content/docs/ja/reference/proxy-formats.md | 2 ++ docs-site/src/content/docs/ko/reference/proxy-formats.md | 2 ++ docs-site/src/content/docs/ru/reference/proxy-formats.md | 2 ++ docs-site/src/content/docs/zh-cn/reference/proxy-formats.md | 2 ++ 4 files changed, 8 insertions(+) diff --git a/docs-site/src/content/docs/ja/reference/proxy-formats.md b/docs-site/src/content/docs/ja/reference/proxy-formats.md index 499819c5812..3b90fa2390d 100644 --- a/docs-site/src/content/docs/ja/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ja/reference/proxy-formats.md @@ -241,6 +241,8 @@ Connections > API keys に音声入力とリアルタイム音声の項目があ ## `POST /v1/responses/compact` +compact リクエストに不正な OpenCodex 管理の retained-compaction 入力(`ocx2:`)が含まれる場合、HTTP 400(`error.type: "invalid_request_error"`)を返します。検証のタイミングとアカウントへの影響は[英語の正規リファレンス](/reference/proxy-formats/#post-v1responsescompact)を参照してください。 + 圧縮により、長い応答会話を短縮する必要があるクライアントの置換履歴が返されます。 |ルートの種類 |行動 | diff --git a/docs-site/src/content/docs/ko/reference/proxy-formats.md b/docs-site/src/content/docs/ko/reference/proxy-formats.md index 3b473e0dd72..77ed94107ad 100644 --- a/docs-site/src/content/docs/ko/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ko/reference/proxy-formats.md @@ -320,6 +320,8 @@ API 키 프로바이더는 자체 bearer를 씁니다. Codex가 join을 프록 ## `POST /v1/responses/compact` +compact 요청에 잘못된 OpenCodex 소유 retained-compaction 입력(`ocx2:`)이 있으면 HTTP 400(`error.type: "invalid_request_error"`)을 반환합니다. 검증 시점과 계정에 미치는 영향은 [영문 기준 문서](/reference/proxy-formats/#post-v1responsescompact)를 참조하세요. + Compaction은 긴 Responses 대화를 줄여야 하는 클라이언트를 위해 대체 히스토리를 반환합니다. | 경로 유형 | 동작 | diff --git a/docs-site/src/content/docs/ru/reference/proxy-formats.md b/docs-site/src/content/docs/ru/reference/proxy-formats.md index 59019908f43..ba56f2852bb 100644 --- a/docs-site/src/content/docs/ru/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ru/reference/proxy-formats.md @@ -318,6 +318,8 @@ Proxy нормализует upstream-join URL и затем прозрачно ## `POST /v1/responses/compact` +Если compact-запрос содержит некорректные данные retained-compaction в формате OpenCodex (`ocx2:`), возвращается HTTP 400 с `error.type: "invalid_request_error"`. Порядок проверки и влияние на состояние аккаунта описаны в [каноническом справочнике на английском языке](/reference/proxy-formats/#post-v1responsescompact). + Compaction возвращает replacement history для клиентов, которым нужно сократить длинный Responses conversation. diff --git a/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md b/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md index 395837a2b29..840481180d4 100644 --- a/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md +++ b/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md @@ -259,6 +259,8 @@ Connections > API keys 包含独立的听写和实时语音区域。数据密钥 ## `POST /v1/responses/compact` +如果 compact 请求包含格式错误的 OpenCodex 自有 retained-compaction 输入(`ocx2:`),则返回 HTTP 400,且 `error.type` 为 `"invalid_request_error"`。验证时机及对账号状态的影响见[英文规范参考](/reference/proxy-formats/#post-v1responsescompact)。 + Compaction 会为需要缩短长 Responses 会话的客户端返回替换历史。 | 路由类型 | 行为 | From 848b28c04efabf5f1be44663a3994a358affba1a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 05:16:26 +0000 Subject: [PATCH 7/8] docs(responses): document retained envelope helpers Co-Authored-By: Epinephrine --- src/responses/retained-compaction.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/responses/retained-compaction.ts b/src/responses/retained-compaction.ts index 1754ae165c1..28c13a27b37 100644 --- a/src/responses/retained-compaction.ts +++ b/src/responses/retained-compaction.ts @@ -8,6 +8,7 @@ export interface RetainedCompaction { reasoning: string[]; } +/** Raised when a proxy-owned retained compaction envelope fails to decode. */ export class InvalidRetainedCompactionEnvelopeError extends Error { constructor() { super("Invalid OpenCodex retained compaction envelope"); @@ -35,6 +36,7 @@ export function decodeRetainedCompaction(value: string): RetainedCompaction | nu } catch { return null; } } +/** True when `item` carries a proxy-owned retained envelope marker, valid payload or not. */ function isRetainedCompactionEnvelopeItem(item: unknown): item is { type: string; encrypted_content: string } { if (!item || typeof item !== "object") return false; const candidate = item as { type?: unknown; encrypted_content?: unknown }; From 16e55c7df92643fca035437cdbb6186d113a1608 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 06:37:32 +0000 Subject: [PATCH 8/8] docs(responses): document the compact route entrypoint Co-Authored-By: Epinephrine --- src/server/responses/compact.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/server/responses/compact.ts b/src/server/responses/compact.ts index f922c98636d..8867cdc3a78 100644 --- a/src/server/responses/compact.ts +++ b/src/server/responses/compact.ts @@ -671,6 +671,11 @@ export async function bufferCompactResponse( +/** + * Route one `/v1/responses/compact` request: validate the body (rejecting malformed + * proxy-owned retained envelopes before routing or credential resolution), select the + * compact target, and dispatch through the adapter pipeline. + */ export async function handleResponsesCompact( req: Request, config: OcxConfig,