Skip to content

fix(xai): stream OAuth Grok through Responses - #2104

Closed
olddonkey wants to merge 2 commits into
lidge-jun:devfrom
olddonkey:codex/fix-xai-oauth-responses-streaming
Closed

fix(xai): stream OAuth Grok through Responses#2104
olddonkey wants to merge 2 commits into
lidge-jun:devfrom
olddonkey:codex/fix-xai-oauth-responses-streaming

Conversation

@olddonkey

@olddonkey olddonkey commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Route native Codex Responses traffic for OAuth-backed xai/grok-4.5 and xai/grok-4.6 through the Responses backend declared by the official Grok CLI model catalog.
  • Scope the registry wire default by authentication mode, so API-key xAI requests, translated Chat/Anthropic callers, other Grok models, generic Responses providers, and explicit adapter overrides retain their existing behavior.
  • Extend the existing one-shot xAI OAuth 401 refresh/replay contract to native Responses passthrough requests without changing credential storage or logging.
  • Fail closed for caller-owned service_tier on the xAI OAuth gateway. The registry default explicitly denies forwarding it, and that denial applies only when the registry default wins; API-key Fast and explicit overrides remain isolated.
  • Add regression coverage for routing boundaries, Fast/service-tier policy, OAuth replay, and relaying the first native Responses delta before upstream completion; document the mixed-wire contract in structure/04_transports-and-sidecars.md.

The previous xAI OAuth preset intentionally followed the older Grok CLI Chat Completions contract. The current official model catalog reports api_backend: "responses" for Grok 4.5 and 4.6, while OpenCodex still selected its provider-wide openai-chat adapter. That compatibility drift could leave Codex waiting until the reasoning turn was effectively complete before seeing output.

Security boundary: this reuses the existing generation-checked, singleflight OAuth refresh and permits only one pre-stream replay. It does not add credential persistence, forwarding destinations, request-body logging, or new OAuth scopes. Because it touches the OAuth replay path, it still requires explicit maintainer security review before merge.

Verification

At commit 5a1fc91a7, rebased directly onto upstream/dev commit cd8f9b8ab:

  • bun run typecheck
  • bun run test13,540 pass / 10 skip / 0 fail across 856 files
  • bun run privacy:scan
  • git diff --check upstream/dev...HEAD
  • Focused xAI/Fast/service-tier regression set — 288 pass / 0 fail
  • Real outbound regression: with fastMode: true and inbound service_tier: "priority", the OAuth xAI /responses request contains no service_tier; generic Responses passthrough and explicit overrides retain their existing contracts.
  • Common-base synthetic composition with feat(xai): B2 — enable Priority Processing on the API-key transport (#1886, closes #1875) #2072bun run typecheck plus 337 focused tests passed / 0 failed, covering API-key Fast remaining enabled while OAuth stays unclassified and blocks caller tier forwarding. The current feat(xai): B2 — enable Priority Processing on the API-key transport (#1886, closes #1875) #2072 head is 136 commits behind dev and has unrelated merge conflicts against the latest tree, so this PR also carries the combined boundary as a direct regression test.

Five authenticated Grok 4.6 canaries were run on the preceding streaming commit 3c5a34f73: 5/5 completed, and all selected openai-responses. Those calls validate the transport change, while the final service-tier guard is covered deterministically on 5a1fc91a7.

Live canary latency is not a controlled benchmark: TTFT was 0.656s, 0.598s, 77.824s, 0.733s, and 31.169s. Three calls streamed promptly; two retained xAI-side long-tail latency. The deterministic regression therefore asserts the proxy property this PR owns—first-delta relay before completion—rather than claiming that it removes upstream generation variance.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed. (structure/04_transports-and-sidecars.md documents the routing, replay, and caller-tier boundaries; there is no new user configuration.)
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. (Author review found no new persistence, logging, scope, or destination; explicit maintainer security approval remains required before merge.)

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • New Features

    • Added native Responses API support for OAuth-authenticated xAI Grok 4.5 and 4.6 models.
    • Added automatic credential refresh and one-time request retry when OAuth requests receive an initial 401 response.
    • Preserved Chat API routing for API-key authentication, unsupported models, translated requests, and explicit overrides.
    • Improved service-tier handling for supported subscription routes.
  • Bug Fixes

    • Improved error handling for failed credential refreshes, request reconstruction, and replay attempts.
  • Tests

    • Added coverage for authentication-aware routing, streaming Responses, and OAuth retry behavior.

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c028223d-ba03-477f-9645-2df70815e9e1

📥 Commits

Reviewing files that changed from the base of the PR and between 806c9ff and 5a1fc91.

📒 Files selected for processing (3)
  • src/providers/registry.ts
  • src/providers/service-tier.ts
  • src/server/responses/core.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The change adds authentication-scoped xAI wire defaults for Grok 4.5 and 4.6. OAuth requests use native Responses passthrough. Native Responses OAuth requests refresh credentials and replay once after a pre-stream 401.

Changes

xAI authentication-aware wire selection

Layer / File(s) Summary
Authentication-aware registry and policy resolution
src/providers/registry.ts, src/providers/service-tier.ts, src/providers/fastwire.ts
Registry defaults now support authentication-mode filters and caller-tier controls. OAuth Grok 4.5 and 4.6 select openai-responses; other routes retain openai-chat.
Routing validation and documentation
tests/adapter-resolve.test.ts, tests/fastwire-policy.test.ts, structure/04-transports-and-sidecars.md
Tests cover OAuth, key authentication, translated callers, unsupported models, and explicit overrides. Documentation describes the routing and caller-tier rules.

Native Responses OAuth recovery

Layer / File(s) Summary
Pre-stream 401 refresh and replay
src/server/responses/core.ts
Native Responses OAuth providers force-refresh credentials after a pre-stream 401, rebuild request state, re-resolve routing, and retry once.
Responses replay and streaming validation
tests/server-xai-oauth-401-replay.test.ts, tests/server-xai-responses-streaming.test.ts
Tests use the Responses endpoint and schema. Streaming tests verify SSE forwarding, request fields, headers, early deltas, completion events, and cleanup.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 5a1fc

The PR changes xAI OAuth routing, streaming, replay, and service-tier handling with regression coverage and documented behavior; no actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ResponsesCore
  participant OAuthCredentialProvider
  participant xAIResponses
  Client->>ResponsesCore: Send native Responses request
  ResponsesCore->>xAIResponses: Forward request
  xAIResponses-->>ResponsesCore: Pre-stream 401
  ResponsesCore->>OAuthCredentialProvider: Force-refresh OAuth credential
  OAuthCredentialProvider-->>ResponsesCore: Refreshed credential
  ResponsesCore->>xAIResponses: Replay rebuilt request once
  xAIResponses-->>Client: Responses stream
Loading

Possibly related PRs

Suggested reviewers: lidge-jun

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: routing OAuth-backed Grok streaming through the Responses API.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Aug 19, 2026
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request is already Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently.
Maintainers: @lidge-jun @Ingwannu @Wibias

@github-actions
github-actions Bot marked this pull request as ready for review August 19, 2026 07:57
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 63 / 80

OAuth xai/grok-4.5·grok-4.6의 Codex Responses 트래픽을 공식 Grok CLI 카탈로그의 Responses 백엔드로 보낸다. 지금은 프로바이더 전역 openai-chat이라서 추론 턴이 끝나야 첫 토큰이 보인다. API 키, Chat/Anthropic 번역, 다른 Grok 모델, 명시 어댑터 오버라이드는 기존 Chat 와이어를 유지한다. 기존 one-shot OAuth 401 refresh/replay를 native Responses 패스스루에도 붙인다. hygiene 통과, review-ready, 체크리스트 4/4, 저자가 보안 리뷰를 직접 요청했다. 방향은 dev의 FastWire/xAI 수송 정리(#1886, #2072)와 맞아서 63이다. OAuth 재생 경로를 만지므로 70은 아니다.

레지스트리 계약이 중심이다. src/providers/registry.tsModelWireDefaultauthModes?: readonly ProviderAuthKind[]를 받는다. xAI는 grok-4.5/grok-4.6{ wire: "openai-responses", inbound: ["responses"], authModes: ["oauth"] }다. providerModelWireDefault()는 inbound와 provider.authMode ?? entry.authKind가 맞을 때만 와이어를 고른다. src/providers/fastwire.tsregistryDefaultForModel()src/providers/service-tier.ts의 clone/authority가 같은 authModes를 복사하고 providerAuthMode를 넘긴다. 카탈로그와 런타임이 한 선언을 보게 하려는 A1 형태다.

src/server/responses/core.ts는 native Responses가 generic adapter recovery 루프보다 먼저 끝나는 구멍을 메운다. 401이고 isOAuth401ReplayProvider이며 sentOAuthSnapshot이 있으면 바디를 cancel하고 forceRefreshOAuthAccessSnapshot을 한 번 돌린 뒤 어댑터를 다시 풀어 buildRequest로 재전송한다. refresh가 와이어를 바꾸면 502다. 저자 말대로 저장소, 로그, 스코프, 목적지는 안 늘린다. 그래도 이 분기는 Chat 경로와 쌍둥이여야 한다. 패치는 추측하지 않음 — Chat 쪽 헬퍼를 공유하는지는 잘린 diff만으로 단정하지 않는다.

테스트는 계약을 꽤 정확히 고정한다. tests/server-xai-responses-streaming.test.ts는 OAuth 설정에서 /responses로 나가고, completion 게이트가 열리기 전에 첫 output_text.delta가 중계되며, messages/reasoning_effort가 없는 Responses 바디와 Grok CLI 헤더를 본다. tests/server-xai-oauth-401-replay.test.ts는 엔드포인트를 Chat에서 OAUTH_RESPONSES_ENDPOINT로 옮기고 401→refresh→재시도, 거절 메시지 "rejected"를 본다. Fast 정책/어댑터 resolve 테스트도 authModes를 따라간다.

#2072가 API 키 수송의 Priority/Fast를 열고 OAuth는 미분류로 둔다. 이 PR은 OAuth Responses 와이어만 바꾼다. 두 개가 겹치면 Fast가 OAuth 게이트웨이로 새지 않는지 한 번 더 봐야 한다. 라이브 카나리는 5/5 완료지만 TTFT가 0.6s와 77s로 갈라져서, 이 PR이 주장하는 건 첫 델타 중계이지 업스트림 지연 제거가 아니다.

해결방안

메인테이너가 OAuth 401 replay 쌍둥이 경로를 Chat 구현과 나란히 읽고 maintainer-sponsored에 해당하는 보안 승인을 하면 머지할 수 있다. 그 전에 #2072와 같이 두었을 때 OAuth Fast가 주입되지 않는 회귀 한 줄을 확인하고, replay가 한 번뿐이며 refresh 실패가 자격 증명을 로그에 안 남기는지만 보면 된다. 라이브 TTFT 분산은 이 PR의 머지 조건이 아니다.

이 댓글은 grok-bot이 작성했습니다

@olddonkey
olddonkey force-pushed the codex/fix-xai-oauth-responses-streaming branch from 806c9ff to 5a1fc91 Compare August 19, 2026 19:25
@github-actions
github-actions Bot marked this pull request as ready for review August 19, 2026 19:26
@olddonkey

Copy link
Copy Markdown
Contributor Author

Addressed the requested Fast/#2072 boundary in 5a1fc91a7:

  • The auth-scoped xAI registry default now declares forwardCallerServiceTier: false for OAuth Grok 4.5/4.6. The denial is applied only when that registry default wins, so API-key Fast, generic Responses passthrough, and explicit adapter overrides keep their existing contracts.
  • The real outbound regression runs with fastMode: true and inbound service_tier: "priority", then asserts that the OAuth xAI /responses request contains no service_tier.
  • The Responses 401 tests retain the one-refresh/one-replay assertions, including a second 401 stopping after the replay. The new replay branch adds no logging; refresh failures are projected through the existing public OAuth error sanitizer, with path canaries asserted absent. bun run privacy:scan is green.

Compatibility evidence: a common-base synthetic composition with #2072 passed bun run typecheck and 337 focused tests with API-key Fast enabled and OAuth caller-tier forwarding blocked. The current #2072 head is 136 commits behind dev and now has unrelated conflicts against the latest tree, so the combined boundary is also asserted directly in this PR rather than claiming a clean merge of that stale head.

Final-head verification on latest dev: 13,540 pass / 10 skip / 0 fail, typecheck, privacy scan, diff check, and 288 focused tests all pass. CodeRabbit completed its review of 5a1fc91a7 with no actionable comments. Explicit maintainer security approval for the OAuth replay path remains the merge gate.

@lidge-jun

Copy link
Copy Markdown
Owner

Thanks for this, @olddonkey — closing as superseded by #2147, which carries your PR unchanged. Nothing needed correcting: an independent read-only audit of the diff came back clean, and CodeRabbit had no actionable comments either.

Two things worth recording for whoever reviews #2147:

The streaming test is the load-bearing one. Asserting the first response.output_text.delta arrives while completionReleased === false pins the actual user-visible symptom — Codex sitting blank through the reasoning turn — rather than a proxy for it.

The 401 replay you added is structurally one-shot, not a loop, so a second 401 cannot trigger a second refresh; your 401 then 401 test is what proves it. It also closes the same pre-existing hole for Copilot, whose Responses wire defaults already returned before the generic recovery loop.

I verified your core.ts insert does not collide with the other three PRs touching that file in this pass (#2137, #2145, #2146) — different regions, no conflict.

Your work is credited in #2147's description.

@lidge-jun lidge-jun closed this Aug 19, 2026
yansigit pushed a commit to yansigit/opencodex that referenced this pull request Aug 20, 2026
OAuth xai/grok-4.5 and grok-4.6 Codex /v1/responses traffic still used the
provider-wide openai-chat adapter, while the official Grok CLI catalog declares
api_backend: "responses". Chat Completions compatibility holds the stream until
the reasoning turn finishes, so Codex sat blank until the turn was effectively
done.

Declare the Responses wire default for those two models, scoped to OAuth and to
responses-shaped inbound traffic. API-key xAI, Chat/Anthropic translation, other
Grok models, and any explicit modelAdapters override all stay on Chat.

Native Responses returns before the generic recovery loop, so the OAuth 401
replay never ran on this path. Add the equivalent one-shot: refresh once, rebuild
the provider and adapter, replay once. It is a single branch rather than a loop,
so a second 401 cannot refresh again. Refresh failures go through the existing
public OAuth error projector, which the tests pin against path canaries.

Carries @olddonkey's lidge-jun#2104 unchanged.

Closes lidge-jun#1886
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants