Skip to content
Closed
40 changes: 40 additions & 0 deletions docs-site/src/content/docs/reference/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,46 @@ with `forwardClientHeaders`; provider `headers` win for this option, and credent
names are refused. Canonical ChatGPT forward auth retains its separate fixed header allowlist.
Only `originator`, `x-client-request-id`, `x-codex-app-version`, and `user-agent` are supported by `forwardClientHeaders`; arbitrary names are rejected on load/write and ignored at runtime.

### Native compaction on custom gateways

Responses compatibility alone is not evidence of native compaction support. Custom gateways
continue using portable text summaries unless the operator declares the relevant capability:

- `supportsNativeCompactionTrigger: true` preserves v2 `compaction_trigger` requests and native output.
- `supportsNativeCompactEndpoint: true` opts key/local/forward routes into the separate v1 endpoint.
OAuth retains routed compaction and its existing credential lifecycle. V2 support does not imply v1 support.
- `decodesNativeCompactionBlobs: true` preserves native blobs on subsequent turns when there is
no known serving-provider mismatch. Neither generation flag implies this replay capability.

Custom native v1 also honors `preserveResponsesReasoningContent: true` for plaintext reasoning
input, just like ordinary custom Responses requests. Absent or `false` keeps content blank;
OpenAI-operated compact destinations keep blanking even if the flag is set. Internal `ocxr1:`
envelopes are always removed. Plaintext preservation is independent of the generation flags,
native blob replay capability, and serving-identity checks.

If the custom provider also requires adjacent tool results (`requiresAdjacentResponsesToolResults: true`),
both ordinary Responses and native v1 remove opaque reasoning ciphertext and require plaintext replay.
Missing `reasoning_text` is filled from the item's `summary_text`, or a minimal placeholder if no
usable summary exists. Existing plaintext is preserved. OpenAI-operated compact keeps its own policy.

For a gateway whose **v2 generation and replay** have both been verified, merge these fields into
its existing provider configuration, retaining its real URL and configured authentication:

```json
{
"adapter": "openai-responses",
"supportsNativeCompactionTrigger": true,
"decodesNativeCompactionBlobs": true
}
```

These flags do not make the gateway an official OpenAI destination, forward caller credentials,
change account selection, or bypass normal compatibility sanitization. Validate an actual compact
response and continued conversation, not just HTTP 200. Keep blobs on the backend that minted them;
cross-provider compaction routing overrides still use portable summaries. V1 fallback summaries
remain portable even when the destination separately accepts v2 triggers. Native-capable routes
are excluded from portable emergency compaction recovery for their respective protocol.

Adapter selection does not select the upstream transport. Eligible requests can use the
[upstream WebSocket proxy route](/reference/proxy-formats/#json-and-sse-output); invalid or unsupported
WebSocket proxy settings fall back to HTTP/SSE. HTTP fetch-based Responses handling uses the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,10 @@ Providers can expose a built-in shorthand, such as `agy` for `google-antigravity
| `modelSupportsServiceTier?` | `Record<string, boolean>` | Exact upstream model capability overrides. Exact `true` enables canonical Fast for that model; exact `false` narrows provider defaults. An explicit provider-level `supportsServiceTier: false` remains fail-closed and cannot be reopened. Exact `true` does not authorize foreign caller-tier forwarding on Chat. Undeclared models fall back to provider-wide behavior. Management `PATCH /api/providers` merges entries and accepts `null` to clear one. |
| `chatServiceTier?` | `boolean` | Provider-wide Chat-wire opt-in for forwarding caller `service_tier` values. On a classified route it governs foreign values such as `flex`, not proxy-owned canonical Fast after capability validation; on an unclassified route it governs every caller value because no Fast capability has been validated. Exact model capability does not authorize foreign forwarding. Responses routes retain their capability-based caller forwarding behavior. |
| `promptCacheKey?` | `boolean` | Provider-wide `openai-chat` opt-in for forwarding a `prompt_cache_key`. The adapter forwards the key it is given and never invents one, but the key is not always the caller's: Claude Messages translation derives one from `metadata.user_id`, or from a model/system/tools cohort when no metadata is sent. Default off. Enable only when the upstream documents support, because strict gateways may reject the unknown field with HTTP 400. |
| `preserveResponsesReasoningContent?` | `boolean` | Default off for custom providers. In **Providers → Settings**, enable **Replay plaintext reasoning** for a custom Responses endpoint only if it accepts this history. This sends prior plaintext reasoning to that endpoint and may increase token use. Keep plaintext reasoning content on replayed Responses reasoning items instead of blanking it (blanking is the ChatGPT backend's rule). Enable for upstreams whose contract accepts reasoning replay, such as DeepSeek or a self-hosted Kimi on vLLM. Proxy-minted `ocxr1` envelopes are always stripped. A hand-configured `openai-responses` provider without it logs one warning per host the first time plaintext reasoning is dropped. `preserveReasoningContentModels` does not affect this wire. |
| `preserveResponsesReasoningContent?` | `boolean` | Default off for custom providers. In **Providers → Settings**, enable **Replay plaintext reasoning** for a custom Responses endpoint only if it accepts this history. This sends prior plaintext reasoning to that endpoint and may increase token use. Keep plaintext reasoning content on replayed Responses reasoning items instead of blanking it, including custom native v1 compact input (blanking is the ChatGPT backend's rule). Enable for upstreams whose contract accepts reasoning replay, such as DeepSeek or a self-hosted Kimi on vLLM. Proxy-minted `ocxr1` envelopes are always stripped. A hand-configured `openai-responses` provider without it logs one warning per host the first time plaintext reasoning is dropped. `preserveReasoningContentModels` does not affect this wire. |
| `preserveResponsesInputItemIds?` | `boolean` | Default off. Preserve valid `input[].id` when `store: false` for explicitly trusted launcher relays that require turn identity. Ordinary Responses providers keep stripping IDs; xAI custom-call ID repair remains active. |
| `preserveResponsesMessageMetadata?` | `boolean` | Default off. Preserve private `internal_chat_message_metadata_passthrough` on input items for explicitly trusted launcher relays. This forwards private turn/session metadata to that destination; do not enable for ordinary gateways. |
| `dropResponsesReasoningItems?` | `boolean` | Remove replayed Responses `reasoning` items from continuation input entirely, instead of forwarding them with blanked content. This is lossy: summaries, item ids, and `encrypted_content` go with them, so no reasoning item from the previous turn remains in the forwarded input. It does not remove `previous_response_id`, so an upstream holding its own turn state may still reach it. Enable only for an upstream that rejects reasoning replay outright — the built-in Volcengine Ark Coding Plan preset sets it because validated tool continuations answered `400 InvalidParameter` otherwise. Set it to `false` on that provider to forward reasoning items again. |
| `preserveResponsesMessageMetadata?` | `boolean` | Default off. Preserve private `internal_chat_message_metadata_passthrough` on input items for explicitly trusted launcher relays, including custom native v1 compact requests. This forwards private turn/session metadata to that destination; do not enable for ordinary gateways. |
| `dropResponsesReasoningItems?` | `boolean` | Remove replayed Responses `reasoning` items from continuation input entirely, including custom native v1 compact requests, instead of forwarding them with blanked content. This is lossy: summaries, item ids, and `encrypted_content` go with them, so no reasoning item from the previous turn remains in the forwarded input. It does not remove `previous_response_id`, so an upstream holding its own turn state may still reach it. Enable only for an upstream that rejects reasoning replay outright — the built-in Volcengine Ark Coding Plan preset sets it because validated tool continuations answered `400 InvalidParameter` otherwise. Set it to `false` on that provider to forward reasoning items again. |
| `disabled?` | `boolean` | Keep the provider on disk but exclude it from routing and model/catalog listings. |
| `apiKey?` | `string` | API key, an `${ENV_VAR}` / `$ENV_VAR` reference, or a `keychain:<provider>` reference written by `ocx provider keychain <name> store`. References resolve at request time. See [Storing keys in the OS keychain](#storing-keys-in-the-os-keychain). |
| `apiKeyTransport?` | `"x-api-key" \| "bearer"` | Anthropic key header style. Defaults to native `x-api-key`; valid only for key-auth `anthropic` providers. |
Expand All @@ -286,6 +286,9 @@ Providers can expose a built-in shorthand, such as `agy` for `google-antigravity
| `modelCosts?` | `Record<string, Cost4>` | Per-model display prices (USD per 1M tokens), keyed by that provider's exact upstream model id — not a provider identifier or a routed `provider/model` label, e.g. `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`. Any model id is a valid key — custom providers may target any OpenAI-compatible endpoint through the `openai-chat` adapter, and local or internal provider ids work even when they are absent from the built-in catalogs. User-configured prices win over the built-in catalogs in the Logs `~$` and Usage estimates; historical entries are repriced from the current overlay, so editing a price can move past totals. The fallback order is user `modelCosts` → exact official correction → jawcode catalog → expected-price overlay → model-level vendor fallback, and an explicit all-zero user entry means a known-zero estimate; delete that model entry to restore automatic pricing. All-zero catalog metadata still falls through. Each rate must be a non-negative finite number at most 1,000,000 (USD per 1M tokens); out-of-range rows are rejected by the management boundary and dropped on load. Display-time estimation only: overlays never affect routing, account selection, quotas, or billing. |
| `headers?` | `Record<string, string>` | Extra upstream headers. Authorization, cookies, API-key headers, embedded newlines, and invalid names are rejected. Requests that ride the provider outbound wrapper — model discovery, connection tests, and other proxy-originated diagnostics such as the Ollama show probe — send `User-Agent: opencodex` unless a User-Agent is set here or by the provider preset. |
| `forwardClientHeaders?` | `string[]` | `openai-responses` only: opt in to copying named inbound client metadata headers onto inference requests when the provider has not already set that header. Credential and transport-owned names such as `Authorization`, cookies, API-key headers, `Content-Type`, `Content-Length`, `Host`, and `x-oai-attestation` are rejected and also filtered at runtime. Header names are case-insensitive and may not repeat. `headers` remains authoritative; the existing caller `User-Agent` fallback still applies when neither surface sets one. Supported names: `originator`, `x-client-request-id`, `x-codex-app-version`, `user-agent`; all other names are refused. |
| `supportsNativeCompactionTrigger?` | `boolean` | `openai-responses` only: declare support for native v2 `compaction_trigger` input items. Defaults off for noncanonical gateways; preserves native compaction rather than requesting a portable text summary. Independent of the v1 endpoint and blob replay capabilities. |
| `supportsNativeCompactEndpoint?` | `boolean` | `openai-responses` only: declare support for native v1 `POST /responses/compact`. Defaults off for custom gateways. Key/local/forward routes use the provider's Responses URL plus `/compact` and its normal transport authentication; OAuth keeps routed compaction and its existing credential lifecycle. Does not enable v2 triggers or grant official OpenAI identity. |
| `decodesNativeCompactionBlobs?` | `boolean` | Declare that this destination can replay native, non-`ocx1:` compaction blobs. Independent of either generation capability; a known serving-provider mismatch still degrades foreign ciphertext. Enable only after testing compact and a subsequent turn on the same backend. |
| `openRouterRouting?` | `OpenRouterProviderRouting` | Default OpenRouter `order`, `only`, and `allowFallbacks` preferences; valid only for canonical OpenRouter with `openai-chat`. |
| `modelOpenRouterRouting?` | `Record<string, OpenRouterProviderRouting>` | Exact model-id overrides that replace the provider-wide OpenRouter preference. |
| `vercelGatewayRouting?` | `VercelGatewayRouting` | Default Vercel AI Gateway `order`, `only`, and `sort` (`"cost"` \| `"ttft"` \| `"tps"`) preferences; valid only for canonical Vercel AI Gateway with `openai-chat`. |
Expand Down
6 changes: 6 additions & 0 deletions docs-site/src/content/docs/reference/proxy-formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -705,8 +705,14 @@ conversation.
| Route type | Behavior |
| --- | --- |
| Canonical ChatGPT or official OpenAI route | Tries the native `/responses/compact` endpoint with the resolved account and model authentication; HTTP 404 falls back to a regular Responses compaction turn |
| Explicitly opted-in custom `openai-responses` gateway | `supportsNativeCompactEndpoint: true` tries the native v1 endpoint for key/local/forward auth using the provider's normal Responses transport; HTTP 404 uses portable fallback; OAuth retains routed compaction and credential resolution |
| Other routed model | Runs an internal, non-streaming, no-tools compaction turn with a `compaction_trigger`; requires exactly one synthetic `compaction` item whose `encrypted_content` is an `ocx1:` envelope; decodes that summary into v1 replacement history |

The custom v1 endpoint capability is independent of v2 `supportsNativeCompactionTrigger`
and of `decodesNativeCompactionBlobs` for replay. None grants canonical OpenAI identity or
caller credential forwarding. Cross-provider overrides remain portable; v2 success alone
does not establish support for `/responses/compact`. See [provider configuration](/reference/configuration/providers/).

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
Expand Down
6 changes: 6 additions & 0 deletions docs-site/src/content/docs/zh-cn/reference/proxy-formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,14 @@ Compaction 会为需要缩短长 Responses 会话的客户端返回替换历史
| 路由类型 | 行为 |
| --- | --- |
| Canonical ChatGPT 或官方 OpenAI 路由 | 将请求转发到原生 `/responses/compact` 端点,并使用已解析的账号和模型认证 |
| Explicitly opted-in custom `openai-responses` gateway | `supportsNativeCompactEndpoint: true` tries the native v1 endpoint for key/local/forward auth using the provider's normal Responses transport; HTTP 404 uses portable fallback; OAuth retains routed compaction and credential resolution |
| 其他路由模型 | 运行一次内部的、非流式、无工具的 compaction 轮次,并带 `compaction_trigger`;要求且只允许一个 synthetic `compaction` 项,其 `encrypted_content` 是一个 `ocx1:` 封装;把该摘要解码为 v1 替换历史 |

The custom v1 capability is independent of v2 `supportsNativeCompactionTrigger` and
`decodesNativeCompactionBlobs` for replay. None grants canonical identity or caller credential
forwarding; cross-provider overrides remain portable. See the canonical
[provider configuration](/reference/configuration/providers/) before opting in.

原生 compact 响应会被缓冲,最大 32 MiB,即使其声明的 `Content-Length` 已经超过该限制也是如此。compact 专用失败包括:

| 状态 | 类型或 code | 含义 |
Expand Down
6 changes: 6 additions & 0 deletions docs-site/src/content/docs/zh-tw/reference/proxy-formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,14 @@ Compaction 為需要縮短長 Responses 對話的客戶端回傳取代歷史。
| 路由型別 | 行為 |
| --- | --- |
| 規範 ChatGPT 或官方 OpenAI 路由 | 以解析的帳號與模型認證將請求轉發到原生 `/responses/compact` 端點 |
| Explicitly opted-in custom `openai-responses` gateway | `supportsNativeCompactEndpoint: true` tries the native v1 endpoint for key/local/forward auth using the provider's normal Responses transport; HTTP 404 uses portable fallback; OAuth retains routed compaction and credential resolution |
| 其他路由模型 | 執行一個內部、非串流、無工具的 compaction 回合,帶有 `compaction_trigger`;需要恰好一個合成的 `compaction` 項目,其 `encrypted_content` 為 `ocx1:` 封裝;將該摘要解碼為 v1 取代歷史 |

The custom v1 capability is independent of v2 `supportsNativeCompactionTrigger` and
`decodesNativeCompactionBlobs` for replay. None grants canonical identity or caller credential
forwarding; cross-provider overrides remain portable. See the canonical
[provider configuration](/reference/configuration/providers/) before opting in.

原生 compact 回應以 32 MiB 上限緩衝,包含其宣告的 `Content-Length` 已超過限制的回應。Compact 專屬失敗包含:

| 狀態 | 型別或代碼 | 意義 |
Expand Down
2 changes: 1 addition & 1 deletion scripts/test-layout/layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -1463,7 +1463,7 @@
"responses-compaction-override.test.ts": "responses",
"responses-compaction-policy-identity.test.ts": "responses",
"responses-compaction-http-isolation.test.ts": "responses", "responses-compaction-routing.test.ts": "responses",
"responses-compaction.test.ts": "responses",
"native-compaction-gateway.test.ts": "responses", "native-compaction-gateway-policy.test.ts": "responses", "native-compaction-provenance.test.ts": "responses", "native-compaction-oauth.test.ts": "responses", "native-compaction-gateway-credentials.test.ts": "responses", "responses-compaction.test.ts": "responses",
"responses-console-go-upload-retry.test.ts": "responses",
"responses-context-overflow.test.ts": "responses",
"responses-continuation-boundaries.test.ts": "responses",
Expand Down
3 changes: 2 additions & 1 deletion scripts/test-layout/seeds.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"codex-integration": {
"match": [
"^context-compat\\.test\\.ts$",
"^(?:active|app|bearer|catalog|combos\\.test\\.ts|doctor\\.test\\.ts|effort|gather|history|injection|issue|multi|native|parallel|project|selected|slug|ultrafast|warmup\\.test\\.ts)-"
"^(?:active|app|bearer|catalog|combos\\.test\\.ts|doctor\\.test\\.ts|effort|gather|history|injection|issue|multi|native(?!-compaction-(?:gateway|provenance|oauth))|parallel|project|selected|slug|ultrafast|warmup\\.test\\.ts)-"
]
},
"server": {
Expand Down Expand Up @@ -62,6 +62,7 @@
},
"responses": {
"match": [
"^native-compaction-(?:gateway|provenance|oauth)\\.test\\.ts$",
"^openai-responses-summary-none\\.test\\.ts$",
"^(?:apply|chat|citation|continuation|eventstream|legacy|namespace|passthrough|responses|sse|thought|ws)-"
]
Expand Down
Loading
Loading