Skip to content

Add grok_build backend: xAI Grok via a Grok subscription login - #34

Open
rickythefox wants to merge 4 commits into
OnlyTerp:mainfrom
rickythefox:add-grok-build-provider
Open

Add grok_build backend: xAI Grok via a Grok subscription login#34
rickythefox wants to merge 4 commits into
OnlyTerp:mainfrom
rickythefox:add-grok-build-provider

Conversation

@rickythefox

@rickythefox rickythefox commented Aug 21, 2026

Copy link
Copy Markdown

Adds a new route type grok_build so a model can use xAI Grok through the official Grok CLI login (SuperGrok / X Premium+ subscription) instead of an xAI API key.

How it works

Grok's inference endpoint speaks plain OpenAI Chat Completions, which the proxy already handles. So providers/grok_build.py is a credential/token helper only: it selects the OIDC subscription credential from the Grok CLI's ~/.grok/auth.json, refreshes the OAuth token against auth.x.ai when it nears its ~6h expiry, and supplies the pinned endpoint + session headers. _handle_grok() then reuses the existing openai_compat path, so all message / tool-call / streaming / reasoning translation is shared (DRY), never duplicated. Grok returns reasoning in a separate field, so no reasoning_split is needed.

Setup for the user: grok login --oauth once (or grok login --device-auth headless). No API key.

Endpoint: the session path the CLI uses

The official Grok CLI performs session inference against https://cli-chat-proxy.grok.com/v1 — its default CLI_CHAT_PROXY_BASE_URL_DEFAULT. xAI's own endpoint resolver comments that api.x.ai "is the inference endpoint (API-key auth) only." The subscription OAuth token also works against api.x.ai, but that is the API-key surface, not the sanctioned session path, so this backend routes to the CLI proxy with its session headers (X-XAI-Token-Auth, x-grok-client-version, x-grok-model-override, …). The endpoint is pinned — a route-supplied upstream is ignored so the implicitly-loaded OAuth bearer is never sent elsewhere — and there is no fallback to api.x.ai (for API-key use, configure a separate openai_compat route with an XAI_API_KEY).

(Note: whether api.x.ai bills a subscription token differently is unverifiedcost_in_usd_ticks is returned on both endpoints and proves only that usage accounting exists, not that a charge is incurred. The pin follows xAI's own client design, not a measured billing difference.)

Changes

  • providers/grok_build.py (new): stdlib-only. OIDC credential selection, expiry policy, refresh (thread-serialized + in-memory cache so the rotating refresh token is never double-spent or lost on a failed persist), non-destructive persist (temp file 0600; never clobbers auth.json when it can't be re-read), pinned endpoint + session headers.
  • proxy.py: optional import, dispatch branch, _handle_grok() (pins the CLI proxy + injects headers), a grok_build branch in the auto-router classifier (shared Chat Completions helper), startup warning, and a grok_helper flag on /healthz.
  • scripts/doctor.py: validates a real subscription (OIDC) entry — not merely that auth.json exists.
  • config.example.json: claude-grok-4-6 example model + route.
  • test_proxy.py: offline tests — OIDC selection, serialized/concurrent refresh, safe persist, expiry policy, pinned endpoint/headers (runs in CI).
  • Docs: README.md, AGENTS.md runbook, docs/HOW_IT_WORKS.md, docs/SETUP.md, docs/TROUBLESHOOTING.md, docs/ADD_A_MODEL.md.

Cross-agent review

The branch went through an adversarial cross-agent review (Grok generated the initial findings; Codex/gpt-5.6-sol adjudicated over two passes), verified against a live Grok subscription login and xAI's published grok-build source. Fixes landed in ca40950:

  • Endpoint corrected from api.x.ai to the pinned session proxy the official CLI uses (xAI's source labels api.x.ai the API-key surface), with the required session headers and no fallback.
  • Select the OIDC credential (never an xai::api_key or legacy entry), newest first.
  • Serialized refresh + in-memory cache; non-destructive persist; forward principal_type/principal_id on refresh (team-scoped creds).
  • Expiry policy: missing expires_atcreate_time + 30d; malformed → force refresh.
  • Auto-router classifier supports grok_build; doctor validates a real OIDC entry.

Kept proportionate: no cross-process file lock, no 401-retry hook, no version-probe subprocess — the confirmed defect is in-process concurrency, handled by the thread lock + cache.

Verification

  • All five CI steps pass locally (compileall, ascii-ps1, test_proxy.py, auto_router_demo, doctor.py --no-test --ci) — 0 failures.
  • Live through the proxy to real Grok (grok-4.6) via the pinned session endpoint: non-streaming and streaming both return correct replies with a clean end_turn; tools flow through the reused openai_compat path.

Notes

  • No new dependencies (pure standard library).
  • No behavior change for existing routes; grok_build is purely additive.

Route type "grok_build" lets a model use xAI Grok through the official
Grok CLI login (SuperGrok / X Premium+ subscription) instead of a metered
xAI API key. providers/grok_build.py reads ~/.grok/auth.json, refreshes the
OAuth token against auth.x.ai near its ~6h expiry, and hands it to the
existing openai_compat path pointed at https://api.x.ai/v1 -- so message,
tool-call, streaming, and reasoning translation are all reused (Grok speaks
plain OpenAI Chat Completions), never duplicated.

- providers/grok_build.py: token read + refresh helper (stdlib only)
- proxy.py: import, dispatch branch, _handle_grok, startup warning
- scripts/doctor.py: validate grok_build routes (warn if not logged in)
- config.example.json: claude-grok-4-6 example route + models entry
- docs/ADD_A_MODEL.md: grok_build section + table row
- test_proxy.py: offline test for token read / refresh-on-expiry / persist

Verified: offline self-test passes; live non-stream and streaming requests
through the proxy reach real Grok (grok-4.6) via the login token.

Claude-Session: https://claude.ai/code/session_01Ud9r1NFBwsbFwdLfLhbwpp
Bring the Grok provider to parity with the other backends: add it to the
README intro list / route-type table / verified-live line, the AGENTS.md
runbook (Phase 3 options), HOW_IT_WORKS route-types + provider-files table,
SETUP credential row + a "Grok via login" section, and a TROUBLESHOOTING
401/login entry. Also expose a "grok_helper" flag on /healthz alongside
"codex_helper".

Claude-Session: https://claude.ai/code/session_01Ud9r1NFBwsbFwdLfLhbwpp
Address a cross-agent (Grok + Codex) adversarial review. Empirically verified
against a live Grok login.

- Route to xAI's SUBSCRIPTION endpoint (cli-chat-proxy.grok.com/v1) with the
  required CLI session headers, not the metered api.x.ai surface. The endpoint is
  pinned; a route-supplied `upstream` is ignored so the implicitly-loaded OAuth
  bearer is never sent elsewhere. No silent metered fallback.
- Select the OIDC subscription credential (never an xai::api_key or legacy entry),
  newest first.
- Serialize refresh across the threaded server + in-memory token cache so the
  rotating refresh token is never double-spent or lost on a failed persist.
- Non-destructive persist: never replace auth.json when it can't be re-read
  (would wipe other scopes); temp file created at 0600.
- Forward principal_type/principal_id on refresh (team-scoped creds).
- Expiry policy: missing expires_at -> create_time+30d; malformed -> force refresh.
- Auto-router classifier now supports grok_build (shared Chat Completions helper).
- Doctor validates a real OIDC entry, not just that auth.json exists.
- Tests cover OIDC selection, serialized/concurrent refresh, safe persist,
  expiry policy, and the pinned endpoint/headers.

Kept the change proportionate: no cross-process file lock, no 401 retry hook, no
version-probe subprocess -- the confirmed defect is in-process, handled by the
thread lock + cache.

Claude-Session: https://claude.ai/code/session_01Ud9r1NFBwsbFwdLfLhbwpp
The pin to cli-chat-proxy is justified because it is the session endpoint the
official Grok CLI uses (xAI's own resolver labels api.x.ai the API-key surface),
not because a subscription token is provably metered on api.x.ai -- that is
unverified (cost_in_usd_ticks appears on both endpoints and only proves usage
accounting). Reword code/docs accordingly; keep the accurate "an xAI API key is
metered" usages. Also fix a stale "threads/processes" note (refresh is serialized
across the proxy's threads; there is no cross-process file lock).

Claude-Session: https://claude.ai/code/session_01Ud9r1NFBwsbFwdLfLhbwpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant