Skip to content

Add xAI as a commit message provider - #34

Merged
rafaeelricco merged 5 commits into
mainfrom
rafaeelricco/add-xai-provider
Aug 2, 2026
Merged

Add xAI as a commit message provider#34
rafaeelricco merged 5 commits into
mainfrom
rafaeelricco/add-xai-provider

Conversation

@rafaeelricco

Copy link
Copy Markdown
Owner

Motivation

Just adding a new provider.

What's New

OAuth Token Persistence

  • Collapse Google/OpenAI token writers into one updateOAuthTokens updater for any OAuth auth method.
  • Refresh paths call the shared updater so a third OAuth provider does not need a new storage helper.

xAI Provider (API Key)

  • Add xai provider, models, and effort options in config and the commit model catalog.
  • Route completions through generateContentWithXai to https://api.x.ai/v1 via the OpenAI SDK.
  • Retry once without reasoning_effort when the model rejects it.

Grok Subscription OAuth

  • PKCE sign-in against auth.x.ai, token refresh, and xai_oauth config variant.
  • Subscription traffic uses cli-chat-proxy.grok.com with X-XAI-Token-Auth and maxRetries: 0.
  • Send x-grok-client-version so the proxy accepts completions (maps 426 to a local bump hint).

CLI and Docs

  • Wire xAI into setup, doctor token expiry, effort picker, and README provider list.

Tests

  • Cover OAuth options, refresh, completion routing, effort fallback, and storage updater behavior.

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:2px
Loading

Testing & Feedback

  • Run commit setup, choose xAI with API key, and generate a commit message against a real diff.
  • Run setup again with Sign in with Grok; confirm browser OAuth completes and doctor shows token status.
  • With Grok OAuth, confirm completions hit the CLI proxy and do not fail with a 426 version gate.
  • Confirm an expired/near-expiry OAuth token refreshes without re-running setup.
  • Confirm effort on an unsupported model falls back once without reasoning_effort.

If you find any bugs or have recommendations for improvements, please open an issue and assign it to me.

- 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.
@rafaeelricco rafaeelricco self-assigned this Aug 2, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/domain/commit/models.ts Outdated
- 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.
@rafaeelricco

Copy link
Copy Markdown
Owner Author

@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.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: a30039e2f5

ℹ️ 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".

@rafaeelricco
rafaeelricco merged commit 5a7d88e into main Aug 2, 2026
4 checks passed
@rafaeelricco rafaeelricco mentioned this pull request Sep 1, 2026
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