Repository navigation
[Provider]: xAI Responses opt-in (grok-4.x) 400s on codex_app automation_update — openai-responses path skips root-schema flattening #2753
Description
Client or integration
Codex App (Codex Desktop 0.150.0-alpha.8, which injects the built-in codex_app automation MCP toolset into every routed request)
Provider or upstream service
xai (api.x.ai, OAuth)
OpenCodex version
2.33.0 (@bitkyc08/opencodex)
Endpoint or capability
/v1/responses — the xAI native Responses opt-in (xaiResponsesOptIn), which flips providers.xai.modelAdapters for grok-4.6/grok-4.5 from openai-chat to openai-responses; affects client tool declarations / tool calls.
Current behaviour
An existing Codex Desktop thread runs normally while grok-4.6 routes through the provider-level openai-chat adapter: consecutive requests return 200 with the full tool list, including the built-in mcp__codex_app__* automation tools.
After the xAI Responses opt-in is enabled and routing switches to openai-responses, the very next sampling attempt of the same thread fails upstream with HTTP 400 in ~2.5 s. Every further turn fails identically because the same client tool list is redeclared on every request — the thread becomes unusable until the adapter is reverted.
Upstream rejects the Codex App automation_update tool, whose parameter schema root is an anyOf union containing a nested union (i.e. a non-object branch); minimized shape, same family as #122:
{
"anyOf": [
{ "type": "object", "properties": { "...": { } } },
{ "oneOf": [ { "type": "object" }, { "type": "object" } ] }
]
}Per xAI's function-calling docs, a root oneOf/anyOf is only accepted when every branch is directly an object schema; nested unions count as non-object branches.
Timeline from usage.jsonl (single proxy instance, same conversation ID, same tool catalog throughout — the only delta is the selected adapter):
10:30:21 UTC adapter=openai-chat -> 200
10:31:20 UTC adapter=openai-chat -> 200
< xaiResponsesOptIn enabled; modelAdapters rewritten >
10:52:04 UTC adapter=openai-responses -> 400 invalid_request_error (first attempt, ~2.5 s)
Expected behaviour
Routing grok-4.6/grok-4.5 through the native Responses path should apply the same xAI-specific tool-schema sanitization the openai-chat adapter already performs (normalizeXaiToolParameters, introduced by #124 for #122): flatten the union root when the merge is lossless, and otherwise omit just the incompatible tool rather than forwarding a declaration xAI is guaranteed to reject. Today a single built-in Codex App tool poisons the entire request.
Minimal redacted request or reproduction
- Log in to xAI OAuth, pick
xai/grok-4.6in Codex Desktop under defaultopenai-chatrouting, confirm turns succeed. - Enable the native Responses opt-in (dashboard toggle or management API):
curl -X PUT http://127.0.0.1:<port>/api/providers/<provider-config-route> \
-H 'Authorization: Bearer <admin-token>' \
-H 'Content-Type: application/json' \
-d '{"xaiResponsesOptIn": true}'- Continue the same Codex App thread (its requests carry the built-in
codex_appautomation tools). - Continuation returns 400
invalid_client_tool_schemanamingmcp__codex_app__automation_update, and every subsequent turn repeats it.
Adapter-dependence check: earlier in the very same thread, the identical tool list produced 200s while routed through openai-chat; switching routing to openai-responses reproduces the 400 deterministically.
Actual response or error
HTTP 400
{"code":"invalid-argument","error":"Failed to start sampling: [invalid_client_tool_schema] mcp__codex_app__automation_update: tool parameter root must be an object type (root schema is an anyOf/oneOf union with a non-object branch)"}Proxy-side record: status 400, errorCode: invalid_request_error, adapter openai-responses, first attempt.
Upstream documentation
https://docs.x.ai/developers/tools/function-calling#parameter-schema — parameter schemas for function calling; root oneOf/anyOf accepted only when all branches are direct object schemas (the same requirement quoted in #122).
Suggested mapping or implementation notes
normalizeFunctionToolSchemaon the responses path (src/adapters/openai-responses.ts, around line 505) only stamps"type": "object"next to existing keywords when the root is not an object. A root holdinganyOf/oneOfstill ships as a union, and when a branch is itself a union xAI rejects the whole request — the siblingtypekeyword does not neutralize the union for their validator.- For
isXaiSchemaTargetproviders, reuse/export the lossless root-flattening fromnormalizeXaiToolParameters(src/adapters/openai-chat.ts) in the responses translation step. Where flattening is not lossless, dropping just the offending tool (the chat adapter's behavior) keeps the thread alive — the othercodex_apptools carry plain object roots. - Ideally make the opt-in/discovery layer aware of this so enabling
xaiResponsesOptIncannot silently regress previously-working threads.
Additional context and attachments
- Same tool + provider pair as [Bug]: xAI/Grok 400 after tool_search loads automation_update's nested oneOf schema #122 (closed via PR fix(xai): normalize nested tool schemas #124), which fixed exactly this
automation_updateschema on theopenai-chatpath; the newer native-Responses opt-in opens a second entry point that bypasses that normalization. - Related precedent of adapter-scoped schema-normalization gaps: [Bug]: Kimi returns 400 when a Codex tool schema has no root object type #228 (Kimi 400 when a Codex tool schema has no root object type), [Provider]: Kimi/Moonshot 400 — $ref with sibling keywords in tool schema $defs is not normalized (openai-chat adapter) #2673 (
$refwith sibling keywords not normalized on the chat adapter).
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
lidge-jun commentedon Aug 27, 2026
리뷰 · 우선순위 42 / 80
이 이슈는 Codex Desktop이 매 요청에 넣는
mcp__codex_app__automation_update도구 스키마 때문에 생긴다. 그 도구의 parameters 루트가anyOf이고, 그 안에 또oneOf가 들어 있다. xAI 문서는 루트anyOf/oneOf를 모든 가지가 바로 object일 때만 받는다. 중첩 유니온은 non-object branch로 취급되어invalid_client_tool_schema400이 난다.작성자가 적은 타임라인도 그 그림과 맞다. 같은 스레드·같은 도구 목록인데
openai-chat일 때는 200,xaiResponsesOptIn으로openai-responses로 바꾼 뒤에는 바로 400이다. 예전openai-chat경로는 #122/#124에서normalizeXaiToolParameters로 이미 고쳤고, Responses opt-in이 그 정규화를 우회하는 두 번째 입구였다는 설명도 맞다. 리포터 환경은 2.33.0이다.다만 지금
dev(HEADeeb774026, package2.34.0) 기준으로는 이미 고쳐져 있다. #2690(fix(xai): normalize Responses root tool schemas,7a28fa552)이src/adapters/openai-responses.ts의normalizeFunctionToolSchema에서xaiTarget일 때normalizeXaiToolParameters를 그대로 호출한다. 지금 코드는 대략 이렇게 보인다.즉 이슈 본문이 지적한 “Responses 경로는 type stamp만 한다”는 서술은 2.33.0에는 맞고, 현재
dev에는 더 이상 맞지 않는다. 평탄화에 실패하면 그 도구만 빼고(undefined→ omit),tool_choice도reconcileToolChoiceForOmittedTools로 맞춘다.automation_update처럼 중첩 유니온이 lossless merge가 안 되면 해당 도구만 빠지고 나머지codex_app도구는 살아남아 스레드가 죽지 않는 쪽이 기대 동작이다.라인 - (이슈 본문 제안)
openai-responses.ts~505 “type stamp만” — 현재dev에서는 ~L540이normalizeXaiToolParameters를 탄다. 제안 패치는 이미 #2690에 들어 있다.경로 -
src/adapters/xai-tool-schema.tsnormalizeXaiToolParameters/expandXaiRootObjectSchemas— 루트 유니온 평탄화·실패 시 omit이 여기 있다. 추가 구현이 아니라 회귀 확인 대상이다.경로 - 리포터 버전 2.33.0 vs
dev2.34.0 — main에 아직 안 올라간dev-only 픽스일 수 있으니, “릴리스에 포함됐는지”만 확인하면 된다.메인테이너의 판단이 필요한 지점
dev에 픽스됨(fix(xai): normalize Responses root tool schemas #2690) 으로 닫을지, 다음 정식 릴리스 태그에 포함될 때까지 open으로 둘지.automation_update중첩 anyOf/oneOf를 유닛 테스트로 한 번 더 핀할지(이미 유사 케이스가 있으면 중복 close).너의 추천
작성자에게 “2.33.0의 Responses 우회 버그는 맞다. 현재
dev는 #2690으로 같은normalizeXaiToolParameters를 Responses 경로에도 넣었다.dev또는 그 픽스가 들어간 다음 릴리스로 올린 뒤 같은 Codex App 스레드로 재현이 사라지는지 확인해 달라”고 안내하고, 재현이 안 되면 completed/superseded by #2690 으로 닫자. 새 코드 패치는 지금dev기준으로 필요 없다.이 댓글은 grok-bot이 작성했습니다
Ingwannu commentedon Aug 27, 2026
Confirmed: this was a real 2.33.0 adapter-parity bug, but it is already fixed on
devby merged PR #2727, which carries the #2690 xAI Responses normalization change.On current
devat8b1b65b8d858d3b92e4fd4852e9e368d43e73f39, the xAI branch innormalizeFunctionToolSchema()now delegates tonormalizeXaiToolParameters(). An incompatible nested-union tool such asmcp__codex_app__automation_updateis omitted instead of poisoning the whole request, andtool_choiceis reconciled when an omitted tool was referenced.I re-ran the focused xAI Responses/schema/transport suites in an isolated HOME on that exact
devhead: 163 passed, 0 failed. No duplicate patch is needed. I am closing this as completed ondev; users on 2.33.0 need a release containing #2727. If the same 400 persists after upgrading to that release, please reopen with the redacted tool schema and adapter record.