Repository navigation
[Bug] Responses adapter drops client User-Agent, breaking Codex-specific provider compatibility #4699
Description
Client or integration
Codex CLI
Provider or upstream service
Volcengine Ark (火山方舟), and other Responses-compatible providers that use the caller's User-Agent to select Codex-specific compatibility handling.
OpenCodex version
Source inspection: dev at cc182a4. The affected user's installed OpenCodex version has not been collected; their upstream log shows Bun/1.4.0.
Endpoint or capability
OpenAI Responses-compatible requests (/v1/responses or the provider's equivalent Responses endpoint).
Current behaviour
OpenCodex drops the original client's User-Agent while building the upstream Responses request. Without an explicit provider header override, a Bun fetch can consequently send its default User-Agent, such as Bun/1.4.0.
Some Responses-compatible providers, including Volcengine Ark in the reported deployment, use User-Agent to recognize Codex requests and enable client-specific compatibility handling. Losing that identity prevents the compatibility handling from being selected and causes requests that depend on it to fail.
The Responses adapter creates a fresh header map. API-key mode adds Content-Type, Authorization, and provider.headers, but does not copy the incoming User-Agent. The OAuth forward-header allowlist also omits User-Agent.
Expected behaviour
Preserve the actual incoming User-Agent on Responses upstream requests when the provider has not explicitly configured a User-Agent. Treat configured header names case-insensitively and keep the provider's explicit override authoritative. If the caller sends no User-Agent, do not invent a Codex identity.
Minimal redacted request or reproduction
- Configure an API-key provider using the openai-responses adapter, with no User-Agent in provider.headers.
- Send a Codex request through OpenCodex to that provider, carrying the client's normal User-Agent.
- Compare the incoming User-Agent with the outgoing header at a controlled upstream receiver.
- The incoming identity is absent from the adapter's built request; the Bun transport can supply Bun/ instead.
- With an upstream that selects Codex compatibility by User-Agent, observe that the Codex compatibility path is no longer selected.
This can be regression-tested against a local HTTP receiver without provider credentials. A provider-backed reproduction has not yet been run as part of this report.
Actual response or error
Redacted diagnostic evidence supplied by the reporter:
{"upstream_request_headers":{"user_agent":"Bun/1.4.0"}}The reported consequence is a provider compatibility error. The exact provider status code and response body are not available, so this report does not attribute a specific error payload to Ark.
Upstream documentation
No public specification for Ark's User-Agent-based compatibility selection is supplied with this report; that requirement is based on the reported deployment behavior.
OpenCodex source: https://github.com/lidge-jun/opencodex/blob/cc182a40526a1d87cf5b4b7949fdc6979e70747f/src/adapters/openai-responses/passthrough.ts
Bun documents its default fetch User-Agent: https://bun.sh/docs/runtime/networking/fetch#debugging
Suggested mapping or implementation notes
Copy only the incoming User-Agent as a fallback in the Responses adapter. Preserve explicit provider overrides regardless of header-name casing, without expanding credential or arbitrary-header forwarding. Cover API-key and forward modes, custom overrides, missing UA, and the header actually received over HTTP.
Additional context and attachments
Related: #1751 discussed adding an OpenCodex-specific UA and was declined because providers depend on the upstream client's fingerprint. This report requests preservation of the caller's existing identity rather than a new product identity.
Checks
- I searched existing provider and compatibility issues.
- The request and response were redacted.
- The expected behaviour is based on an upstream specification or a concrete client requirement.
Activity
Ingwannu commentedon Sep 15, 2026
Confirmed on current
dev(cc182a405).createResponsesPassthroughAdapter().buildRequest()creates a fresh header record. Key mode adds only content type, bearer auth, and configured headers; canonical forward mode copies the narrowFORWARD_HEADERSset, which also excludesuser-agent. With no configured override, the caller identity is therefore absent and Bun may supply its own runtime User-Agent.\n\nI will patch this as a narrow non-credential fallback shared by both Responses auth modes: copy the incomingUser-Agentonly when it is present and no provider header with that name exists in any casing. A configured provider value remains authoritative, missing caller UA stays missing at the adapter boundary, and no arbitrary request headers are widened. I will cover key mode, canonical forward mode, case-insensitive override precedence, missing UA, and the value observed by a local upstream receiver, then link the exact-head PR here.Ingwannu commentedon Sep 15, 2026
Implemented in #4702 on exact current
devbase. The PR preserves only the callerUser-Agentfallback, keeps configured provider headers authoritative case-insensitively, and does not widen credential or arbitrary-header forwarding. Focused tests (24), typecheck, structure, privacy, docs build (441 pages), and diff checks passed under isolated temporary homes. @lidge-jun please review before merge; I will not self-approve or self-merge.lidge-jun commentedon Sep 15, 2026
리뷰 · 우선순위 70 / 80
이 이슈는 Responses 어댑터가 호출자 User-Agent를 버려, UA로 Codex 호환 경로를 고르는 Responses 호환 공급자(보고: Volcengine Ark)가 깨진다는 버그다. 현재 tip
51d577c3f의src/adapters/openai-responses/passthrough.ts를 확인하면 여전히 그렇다.buildRequest는 새 헤더 맵을 만들고, key 모드는 Content-Type·Bearer·provider.headers만 넣으며, forward 모드는FORWARD_HEADERS만 복사한다. 그 목록에user-agent는 없다. 호출자 UA가 없으면 Bun이Bun/<version>을 실을 수 있다. Ingwannu 확인 댓글·리포터 진단 JSON(user_agent: Bun/1.4.0)과 일치한다. 닫힌 #1751은 OpenCodex 전용 UA 신설을 거절했고, 이번 이슈는 ‘이미 들어온 호출자 지문 보존’이라 Decision Log와 맞다.구현 PR이 두 개 열려 있다. #4702(Ingwannu, ready)는 좁은
applyCallerUserAgentFallback만 넣고 이전에 74/80으로 머지 추천했다. #4712(RailyW, draft)는 같은 이슈를 Closes로 걸며 FORWARD_HEADERS 확장·search/vision·문서 산포까지 간다. 본선 수정은 #4702를 살리고, search/vision이 필요하면 그 부분만 #4702에 이식하거나 후속으로 받는 편이 깔끔하다.Ark 실계정 재현은 이슈에도 없고, 로컬 수신기 계약으로 고정하는 방향이 두 PR 모두와 맞다. types/config 스플릿·고드파일 모놀리스와 무관하다.
경로
src/adapters/openai-responses/passthrough.tsFORWARD_HEADERS/buildRequest- tip에 아직 caller UA 폴백 없음.경로 #4702 - 좁은 본선 수정, ready, 권장 랜딩 후보.
경로 #4712 - 중복 draft; search/vision이 유일한 추가 범위.
경로 #1751 - 제품 UA 신설은 거절됨; 이번 이슈와 구분.
메인테이너의 판단이 필요한 지점
너의 추천
이슈는 유효하다. #4702를 머지해 닫고, #4712는 중복으로 닫거나 search/vision만 후속으로 이식하라. 실 Ark 재현 없이도 로컬 수신기 테스트로 계약을 고정하면 충분하다.
이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Sep 16, 2026
Closing as completed on dev by #4702 (45cfb04). The implementation is still present at the audited dev commit ada3a9b: src/adapters/openai-responses/passthrough.ts applies applyCallerUserAgentFallback after provider headers, preserves case-insensitive explicit overrides, and does not invent a caller identity when none was supplied. This addresses the narrow contract requested here without widening arbitrary or credential header forwarding.
This records merged-on-dev completion, not a claim of a new release or a new live Ark reproduction. #4712 was already closed as the duplicate implementation.