Add xAI as a commit message provider - #34
Conversation
- Rename `schema_OpenAITokens` -> `schema_BearerTokens` and `OpenAITokens` -> `BearerTokens`, updating importers in `src/infra/auth/openai.ts` and `src/infra/storage/config.ts`, since the shape is not OpenAI-specific. - Replace `updateGoogleTokens` and `updateOpenAITokens` with a single `updateOAuthTokens` taking the tagged `RefreshableAuthMethod` variant, so the tag and payload cannot disagree and the two exhaustive `auth_method.type` switches disappear. - Derive `RefreshableAuthMethod` structurally from `RefreshTokens` so it widens on its own when a refreshable auth variant is added. - Pass the tagged variant from `resolveProvider` in `src/domain/llm/auth-resolver.ts`. - Replace the `google_oauth || openai_oauth` boolean chain in `src/cli/doctor.ts` with an exhaustive `tokenExpiry` helper returning `Maybe<number>`, so a new auth variant is a compile error rather than a silently missing Token Status row. - Return `absurd` from the `authMethodLabel` default instead of a placeholder string, for the same reason. - Delete the unused `AI_PROVIDERS` export, which had no importers and did not drive the setup picker. - Cover `updateOAuthTokens` with tests for the matching, mismatched, and sibling-field-preservation cases, which neither original updater had.
- Add the `xai` variant to `schema_ProviderConfig` with `XAI_EFFORTS` (`low`, `high`), checked with `satisfies` against the OpenAI SDK's own reasoning effort type. - Add `src/infra/auth/xai.ts` exposing `xaiApiKeyOptions`, which points the `openai` client at `https://api.x.ai/v1`; xAI's API is OpenAI-compatible so no new SDK is needed. - Add `src/infra/llm/xai.ts` calling `chat.completions` non-streaming, since the response carries both the message and usage in one payload. - Retry once without `reasoning_effort` when Grok rejects it, because support is per-model and `/v1/models` does not advertise it; skip the retry when no effort was sent. - Route `xai` through `generateContent` and report its effort as `provider default`, matching what the client reports after an effort-stripping retry. - Add `xai` arms to `seedProviderConfig`, `withModel`, `selectEffortForProvider`, `selectXaiEffort`, and `fetchModels`. - Offer xAI in `commit setup` and label its key in `commit doctor`. - Script the `@clack/prompts` `select` mock per test in `test/cli/setup.test.ts` so wizard tests no longer share one positional chain. - Cover the xAI client, model listing, router dispatch, config round-trip, and setup wizard with tests. - Document xAI in the setup prompts and providers list in `README.md`.
- Add the `xai_oauth` auth variant carrying `schema_BearerTokens`, so a SuperGrok or X Premium subscription can drive the provider instead of a metered API key. - Add the authorization-code + PKCE S256 flow in `src/infra/auth/xai.ts` against `https://auth.x.ai`, with endpoints read once from the OIDC discovery document and hardcoded, since refresh runs on every command and discovery would add a round-trip to each one. - Bind the loopback callback server on an OS-assigned port and read the bound port back, rather than reserving a fixed one; the redirect URI is therefore built inside the bracket, once the server is listening. - Point OAuth requests at `https://cli-chat-proxy.grok.com/v1` with `X-XAI-Token-Auth: xai-grok-cli`, which is what marks the bearer as a user token rather than a deployment key. - Set `maxRetries: 0` on the proxy client so a 429 against a metered subscription is not silently retried three times; `withTransientRetry` already owns retry policy. - Extract `generateCodeVerifier`, `generateCodeChallenge`, `generateState`, `stopCallbackServer`, `openBrowser`, and `oauthTimeout` into `src/infra/auth/oauth.ts`, shared by the OpenAI and xAI flows. - Refresh and persist xAI tokens through `resolveProvider`, and report their expiry in `commit doctor`. - Offer "Sign in with Grok" as the default xAI auth method in `commit setup`. - Add `xai_oauth` arms to the auth switches in the Gemini, OpenAI, and Anthropic clients and in `fetchModels`. - Cover the authorize URL, PKCE derivation, refresh buffer, token rotation, and revoked-token message with tests, plus the proxy client options for chat and model listing. - Document the subscription sign-in in `README.md`.
- Add `x-grok-client-version` to the OAuth client headers; `/chat/completions` on the proxy returns HTTP 426 without it and enforces a server-side minimum version. - Take the value from `xai-grok-pager` in xai-org/grok-build, and record in `XAI_CLIENT_VERSION` that it must be bumped whenever xAI raises the floor. - Map a 426 to a message naming `XAI_CLIENT_VERSION`, since xAI's own text tells the user to run `grok update`, which does not apply to this CLI. - Re-export `APIError` from the `openai` mock, which the new status check needs. - Cover the version header and the 426 message with tests.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8b05261493
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Keep only `grok-` ids that do not include `-image` in `fetchXaiModelsWith`, matching the OpenAI chat-only prefix filter so setup cannot persist image models. - Cover image and non-grok exclusions with a unit test on the xAI catalog path.
|
@codex review — focus only on P0/P1: security, correctness, broken contracts, auth, data loss. Skip P2/P3 style, nits, and speculative edge cases. Report only major issues or say you didn't find any major issue. |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Motivation
Just adding a new provider.
What's New
OAuth Token Persistence
updateOAuthTokensupdater for any OAuth auth method.xAI Provider (API Key)
xaiprovider, models, and effort options in config and the commit model catalog.generateContentWithXaitohttps://api.x.ai/v1via the OpenAI SDK.reasoning_effortwhen the model rejects it.Grok Subscription OAuth
auth.x.ai, token refresh, andxai_oauthconfig variant.cli-chat-proxy.grok.comwithX-XAI-Token-AuthandmaxRetries: 0.x-grok-client-versionso the proxy accepts completions (maps 426 to a local bump hint).CLI and Docs
Tests
xAI Auth and Completion Flow
graph TD Setup[commit setup] --> Pick{Auth method} Pick -->|API key| ApiKey[Store api_key] Pick -->|Grok OAuth| OAuth[PKCE via auth.x.ai] OAuth --> Tokens[Store xai_oauth tokens] ApiKey --> Commit[generateCommitMessage] Tokens --> Refresh[ensureFreshXaiTokens] Refresh --> Commit Commit --> Xai[generateContentWithXai] Xai --> Auth{auth_method} Auth -->|api_key| Public[api.x.ai/v1] Auth -->|xai_oauth| Proxy[cli-chat-proxy.grok.com + client version] style Xai fill:#808080,stroke:#333,stroke-width:2px style Proxy fill:#808080,stroke:#333,stroke-width:2pxTesting & Feedback
commit setup, choose xAI with API key, and generate a commit message against a real diff.reasoning_effort.If you find any bugs or have recommendations for improvements, please open an issue and assign it to me.