Add grok_build backend: xAI Grok via a Grok subscription login - #34
Open
rickythefox wants to merge 4 commits into
Open
Add grok_build backend: xAI Grok via a Grok subscription login#34rickythefox wants to merge 4 commits into
rickythefox wants to merge 4 commits into
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a new route type
grok_buildso 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.pyis a credential/token helper only: it selects the OIDC subscription credential from the Grok CLI's~/.grok/auth.json, refreshes the OAuth token againstauth.x.aiwhen it nears its ~6h expiry, and supplies the pinned endpoint + session headers._handle_grok()then reuses the existingopenai_compatpath, so all message / tool-call / streaming / reasoning translation is shared (DRY), never duplicated. Grok returns reasoning in a separate field, so noreasoning_splitis needed.Setup for the user:
grok login --oauthonce (orgrok login --device-authheadless). 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 defaultCLI_CHAT_PROXY_BASE_URL_DEFAULT. xAI's own endpoint resolver comments thatapi.x.ai"is the inference endpoint (API-key auth) only." The subscription OAuth token also works againstapi.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-suppliedupstreamis ignored so the implicitly-loaded OAuth bearer is never sent elsewhere — and there is no fallback toapi.x.ai(for API-key use, configure a separateopenai_compatroute with anXAI_API_KEY).(Note: whether
api.x.aibills a subscription token differently is unverified —cost_in_usd_ticksis 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 file0600; never clobbersauth.jsonwhen it can't be re-read), pinned endpoint + session headers.proxy.py: optional import, dispatch branch,_handle_grok()(pins the CLI proxy + injects headers), agrok_buildbranch in the auto-router classifier (shared Chat Completions helper), startup warning, and agrok_helperflag on/healthz.scripts/doctor.py: validates a real subscription (OIDC) entry — not merely thatauth.jsonexists.config.example.json:claude-grok-4-6example model + route.test_proxy.py: offline tests — OIDC selection, serialized/concurrent refresh, safe persist, expiry policy, pinned endpoint/headers (runs in CI).README.md,AGENTS.mdrunbook,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-buildsource. Fixes landed inca40950:api.x.aito the pinned session proxy the official CLI uses (xAI's source labelsapi.x.aithe API-key surface), with the required session headers and no fallback.xai::api_keyor legacy entry), newest first.principal_type/principal_idon refresh (team-scoped creds).expires_at→create_time + 30d; malformed → force refresh.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
test_proxy.py, auto_router_demo,doctor.py --no-test --ci) — 0 failures.grok-4.6) via the pinned session endpoint: non-streaming and streaming both return correct replies with a cleanend_turn; tools flow through the reused openai_compat path.Notes
grok_buildis purely additive.