Repository navigation
[Provider compatibility] xAI Responses: interrupted tool-call history snowballs because adjacency repair is not seeded #4870
Description
Client or integration
Codex App
Provider or upstream service
xai
OpenCodex version
2.57.0
Endpoint or capability
/v1/responses tool history replay
Current behaviour
On Codex Desktop through OpenCodex, xai/grok-4.6 OAuth uses the native Responses wire (modelWireDefaults, xaiResponsesDefaultVersion: 1). The first failed tool turn in a thread is often an upstream 502 / connection-reset (commonly around 15s). After that, later turns in the same thread fail much more often, while neighboring healthy threads on the same machine keep returning 200.
Local usage log (redacted counts, OpenCodex 2.57.0):
- google-antigravity: about 1.06% failed requests
- xAI grok-4.6: about 3.3-3.9% failed requests, including 200 HTTP 502 and 150 connection-reset events, with a cluster near 15s
- After the first failure in a thread, the next 10 requests in that thread fail about 20.6% of the time
- Threads that never fail stay clean (one sampled healthy thread: 37/37 and 4529/4529 successes)
Google already synthesizes a missing tool_result ([missing tool_result for this tool_use in history], #2199). xAI Responses does not. Codex can therefore replay a function_call / custom_tool_call with no matching output, or with hook-injected developer context between the pair. The existing repair (normalizeResponsesToolResultAdjacency + orphan-call placeholder) is gated on requiresAdjacentResponsesToolResults / statelessResponses. DeepSeek and Kimi seed that capability; xAI does not. xAI also cannot be marked statelessResponses: the public Responses API stores conversations for 30 days and documents previous_response_id.
This is distinct from the 15s upstream reset itself. Adjacency repair cannot stop the first 502; it stops the dirty history from 400ing every later turn.
Expected behaviour
xAI should get the same Responses tool-history repair as Kimi (#4726) and DeepSeek (#1292): seed requiresAdjacentResponsesToolResults: true, reorder an unambiguous call/result batch around hook-injected context, and synthesize an honest placeholder function_call_output when a call has no recorded result. Do not set statelessResponses (would strip store / previous_response_id). Forward-auth replay should stay fail-closed and not synthesize.
Minimal redacted request or reproduction
Codex App -> local OpenCodex proxy -> xai/grok-4.6 OAuth Responses. Run a long tool-using thread until an upstream 502 / connection-reset, then continue the same thread.
Equivalent replay body the proxy currently forwards after an interrupted tool turn (redacted):
{
"model": "grok-4.6",
"stream": true,
"input": [
{ "type": "message", "role": "user", "content": [{ "type": "input_text", "text": "continue the task" }] },
{ "type": "function_call", "call_id": "call_interrupted", "name": "exec_command", "arguments": "{}" },
{ "type": "message", "role": "developer", "content": [{ "type": "input_text", "text": "[hook] LSP diagnostics: none" }] },
{ "type": "function_call_output", "call_id": "call_other", "output": "ok" }
]
}Actual response or error
HTTP 502 / connection-reset on the first interrupted tool turn (often ~15s).
Later turns in the same thread then 400 or fail closed because the replayed input still contains
a function_call with no matching function_call_output, or a hook-injected developer message
between the call and its result.
Upstream documentation
- https://docs.x.ai/developers/model-capabilities/text/comparison (Responses API is stateful;
storedefaults true;previous_response_idcontinues a stored conversation) - https://docs.x.ai/developers/rest-api-reference/inference/responses
- Same OpenCodex repair path as [Provider] repair orphaned and missing tool results in the Google / Claude-on-Antigravity adapter #2199 (Google missing tool_result), [Provider] kimi: no requiresAdjacentResponsesToolResults → 400 when hook-injected developer context splits a tool call from its result #4726 (Kimi adjacency), [Provider compatibility] DeepSeek V4 Flash returns 400 when developer message is interleaved between function_call and function_call_output #1292 (DeepSeek adjacency)
Suggested mapping or implementation notes
Seed requiresAdjacentResponsesToolResults: true on the xai registry entry. Keep statelessResponses unset. In src/adapters/openai-responses/passthrough.ts, run the existing repairOrphanedInputItems(..., synthesizeMissingCallOutputs) for non-forward adjacency providers, not only for statelessResponses. Cursor is a separate protobuf adapter and should stay out of this change.
Additional context and attachments
Related: #2199, #4726, #1292, #2156, #3384, #186, #4191, #4808, #3506. Cursor 429 / empty-spin is a different adapter; not requested here. The 15s connection-reset cluster is an upstream cut-off and should stay a separate issue.
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 17, 2026
Confirmed on current
dev(7868f5df5). The xAI registry does not currently seedrequiresAdjacentResponsesToolResults, and the Responses adapter only synthesizes a missing call output for forward/stateless routes. xAI is stateful, so marking it stateless would be incorrect; the narrow fix is the one proposed here: seed the existing adjacency capability and let non-forward adjacency providers reuse orphan-call repair without strippingstoreorprevious_response_id.Draft PR #4871 implements that boundary and covers stale-registry backfill, missing-output synthesis, hook-split pair reordering, multi-call pairing, and the forward-auth fail-closed control. This can prevent an interrupted turn from poisoning later replays, but it does not claim to fix the original upstream 502/reset. Keeping the issue open until #4871 is ready, exact-head CI is complete, and a maintainer approves the current head.
fix(xai): seed Responses tool-result adjacency for interrupted Codex …
lidge-jun commentedon Sep 17, 2026
리뷰 · 우선순위 28 / 80
이 이슈는 xAI Responses 네이티브 와이어에서 끊긴 tool-call 히스토리에 adjacency repair 시드가 없어, 같은 스레드가 첫 실패 이후 연쇄로 502/connection-reset에 가깝게 깨진다는 보고다. Google은 이미 missing tool_result를 심고(#2199), xAI는 안 심었다는 대비가 본문 핵심이다.
현재 tip 41f1832(package 2.58.0)에는 이미 #4871 fix(xai): seed Responses tool-result adjacency for interrupted Codex threads (7c8e961)가 있다. 레지스트리 xAI 쪽 requiresAdjacentResponsesToolResults: true와 openai-responses passthrough의 adjacency 경로가 tip에 존재한다. 본문이 요구한 시드는 랜딩된 상태다.
이슈가 아직 open인 것은 자동 종결 누락으로 보인다. 보고 버전 2.57.0 → tip 2.58.0+#4871. tip에서 xai/grok-4.6 OAuth로 "첫 실패 후 같은 스레드"를 한 번 더 보고 싶으면 smoke만 하고, 새 증상은 새 이슈로 연다.
경로/심볼 - 7c8e961 / #4871: tip 랜딩. interrupted Codex thread tool_result adjacency 시드
경로/심볼 - src/providers/registry/entries-core.ts requiresAdjacentResponsesToolResults (xAI 등)
경로/심볼 - src/adapters/openai-responses/passthrough.ts adjacentToolResults / adjacency 정규화
경로/심볼 - #2199: Google missing tool_result 선행. 이 이슈는 xAI 대칭
메인테이너의 판단이 필요한 지점
너의 추천
Fixed by #4871 (7c8e961) on dev @41f1832f6 로 close. 재발 시 새 이슈에 tip SHA와 usage 비율만 붙인다. 라벨은 바꾸지 않는다.
이 댓글은 grok-bot이 작성했습니다