Skip to content

Commit b0c6721

Browse files
authored
🤖 feat: add Grok provider support (#661)
## Summary - add the xAI provider and Grok model metadata - extend configuration, env hydration, and runtime wiring for xai - refresh docs and tests to surface Grok support ## Testing - bun test ./tests/models/knownModels.test.ts - make typecheck _Generated with _
1 parent e463ecb commit b0c6721

File tree

15 files changed

+212
-15
lines changed

15 files changed

+212
-15
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Here are some specific use cases we enable:
3636
- **Isolated workspaces** with central view on git divergence
3737
- **Local**: git worktrees on your local machine ([docs](https://cmux.io/local.html))
3838
- **SSH**: regular git clones on a remote server ([docs](https://cmux.io/ssh.html))
39-
- **Multi-model** (`sonnet-4-*`, `gpt-5-*`, `opus-4-*`)
39+
- **Multi-model** (`sonnet-4-*`, `grok-*`, `gpt-5-*`, `opus-4-*`)
4040
- Ollama supported for local LLMs ([docs](https://cmux.io/models.html#ollama-local))
4141
- OpenRouter supported for long-tail of LLMs ([docs](https://cmux.io/models.html#openrouter-cloud))
4242
- **VS Code Extension**: Jump into mux workspaces directly from VS Code ([docs](https://cmux.io/vscode-extension.html))

bun.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
{
22
"lockfileVersion": 1,
3+
"configVersion": 0,
34
"workspaces": {
45
"": {
56
"name": "@coder/cmux",
67
"dependencies": {
78
"@ai-sdk/anthropic": "^2.0.44",
89
"@ai-sdk/google": "^2.0.38",
910
"@ai-sdk/openai": "^2.0.66",
11+
"@ai-sdk/xai": "^2.0.33",
1012
"@openrouter/ai-sdk-provider": "^1.2.2",
1113
"@radix-ui/react-checkbox": "^1.3.3",
1214
"@radix-ui/react-dialog": "^1.1.15",
@@ -141,10 +143,14 @@
141143

142144
"@ai-sdk/openai": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-qUSLFkqgUoFArzBwttu0KWVAZYjbsdZGOklSJXpfZ2nDC61yseHxtcnuG8u6tqKnGXDh4eakEgREDWU2sRht7A=="],
143145

146+
"@ai-sdk/openai-compatible": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bpYruxVLhrTbVH6CCq48zMJNeHu6FmHtEedl9FXckEgcIEAi036idFhJlcRwC1jNCwlacbzb8dPD7OAH1EKJaQ=="],
147+
144148
"@ai-sdk/provider": ["@ai-sdk/[email protected]", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="],
145149

146150
"@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw=="],
147151

152+
"@ai-sdk/xai": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.27", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-0+S+hxbAj8dA8/3dYQsmgkVkPcs8yptO1ueLWtJpa6PYjrdyliDcPSCZREL8aE76vHGvFsYlRABFfH9Ps2M8tg=="],
153+
148154
"@antfu/install-pkg": ["@antfu/[email protected]", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
149155

150156
"@antfu/utils": ["@antfu/[email protected]", "", {}, "sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA=="],

docs/intro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
mux helps you work with multiple coding assistants more effectively via:
1010

1111
- Isolated workspaces with central view on git status updates
12-
- Multi-model (`sonnet-4-*`, `gpt-5-*`, `opus-4-*`) support
12+
- Multi-model (`sonnet-4-*`, `grok-*`, `gpt-5-*`, `opus-4-*`) support
1313
- Supporting UI and keybinds for efficiently managing a suite of agents
1414
- Rich markdown outputs (mermaid diagrams, LaTeX, etc.)
1515

docs/models.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,30 @@ Access Gemini models directly via Google's generative AI API:
4949

5050
TODO: add issue link here.
5151

52+
#### xAI (Grok)
53+
54+
Frontier reasoning models from xAI with built-in search orchestration:
55+
56+
- `xai:grok-4-1` — Fast unified model (switches between reasoning/non-reasoning based on thinking toggle)
57+
- `xai:grok-code` — Optimized for coding tasks
58+
59+
**Setup:**
60+
61+
1. Create an API key at [console.x.ai](https://console.x.ai/)
62+
2. Add to `~/.mux/providers.jsonc`:
63+
64+
```jsonc
65+
{
66+
"xai": {
67+
"apiKey": "sk-xai-...",
68+
},
69+
}
70+
```
71+
72+
**Search orchestration:**
73+
74+
Mux enables Grok's live search by default using `mode: "auto"` with citations. Add [`searchParameters`](https://docs.x.ai/docs/resources/search) to `providers.jsonc` if you want to customize the defaults (e.g., regional focus, time filters, or disabling search entirely per workspace).
75+
5276
#### OpenRouter (Cloud)
5377

5478
Access 300+ models from multiple providers through a single API:
@@ -167,6 +191,10 @@ All providers are configured in `~/.mux/providers.jsonc`. Example configurations
167191
"google": {
168192
"apiKey": "AIza...",
169193
},
194+
// Required for Grok models
195+
"xai": {
196+
"apiKey": "sk-xai-...",
197+
},
170198
// Required for OpenRouter models
171199
"openrouter": {
172200
"apiKey": "sk-or-v1-...",

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"@ai-sdk/anthropic": "^2.0.44",
4949
"@ai-sdk/google": "^2.0.38",
5050
"@ai-sdk/openai": "^2.0.66",
51+
"@ai-sdk/xai": "^2.0.33",
5152
"@openrouter/ai-sdk-provider": "^1.2.2",
5253
"@radix-ui/react-checkbox": "^1.3.3",
5354
"@radix-ui/react-dialog": "^1.1.15",

src/browser/App.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ export const ActiveWorkspaceWithChat: Story = {
539539
apiOverrides: {
540540
providers: {
541541
setProviderConfig: () => Promise.resolve({ success: true, data: undefined }),
542-
list: () => Promise.resolve(["anthropic", "openai"]),
542+
list: () => Promise.resolve(["anthropic", "openai", "xai"]),
543543
},
544544
workspace: {
545545
create: (projectPath: string, branchName: string) =>

src/common/constants/knownModels.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Centralized model metadata. Update model versions here and everywhere else will follow.
33
*/
44

5-
type ModelProvider = "anthropic" | "openai" | "google";
5+
type ModelProvider = "anthropic" | "openai" | "google" | "xai";
66

77
interface KnownModelDefinition {
88
/** Provider identifier used by SDK factories */
@@ -76,6 +76,16 @@ const MODEL_DEFINITIONS = {
7676
aliases: ["gemini-3", "gemini-3-pro"],
7777
tokenizerOverride: "google/gemini-2.5-pro",
7878
},
79+
GROK_4_1: {
80+
provider: "xai",
81+
providerModelId: "grok-4-1-fast-non-reasoning",
82+
aliases: ["grok", "grok-4", "grok-4.1", "grok-4-1"],
83+
},
84+
GROK_CODE: {
85+
provider: "xai",
86+
providerModelId: "grok-code-fast-1",
87+
aliases: ["grok-code"],
88+
},
7989
} as const satisfies Record<string, KnownModelDefinition>;
8090

8191
export type KnownModelKey = keyof typeof MODEL_DEFINITIONS;

src/common/constants/providers.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ export async function importOpenRouter() {
4141
return await import("@openrouter/ai-sdk-provider");
4242
}
4343

44+
/**
45+
* Dynamically import the xAI provider package
46+
*/
47+
export async function importXAI() {
48+
return await import("@ai-sdk/xai");
49+
}
50+
4451
/**
4552
* Centralized provider registry mapping provider names to their import functions
4653
*
@@ -58,6 +65,7 @@ export const PROVIDER_REGISTRY = {
5865
anthropic: importAnthropic,
5966
openai: importOpenAI,
6067
google: importGoogle,
68+
xai: importXAI,
6169
ollama: importOllama,
6270
openrouter: importOpenRouter,
6371
} as const;

src/common/types/providerOptions.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { XaiProviderOptions } from "@ai-sdk/xai";
2+
13
/**
24
* Mux provider-specific options that get passed through the stack.
35
* Used by both frontend and backend to configure provider-specific features
@@ -54,11 +56,20 @@ export interface OpenRouterProviderOptions {}
5456
/**
5557
* Mux provider options - used by both frontend and backend
5658
*/
59+
/**
60+
* xAI-specific options
61+
*/
62+
export interface XaiProviderOverrides {
63+
/** Override Grok search parameters (defaults to auto search with citations) */
64+
searchParameters?: XaiProviderOptions["searchParameters"];
65+
}
66+
5767
export interface MuxProviderOptions {
5868
/** Provider-specific options */
5969
anthropic?: AnthropicProviderOptions;
6070
openai?: OpenAIProviderOptions;
6171
google?: GoogleProviderOptions;
6272
ollama?: OllamaProviderOptions;
6373
openrouter?: OpenRouterProviderOptions;
74+
xai?: XaiProviderOverrides;
6475
}

src/common/utils/ai/providerOptions.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import type { AnthropicProviderOptions } from "@ai-sdk/anthropic";
88
import type { OpenAIResponsesProviderOptions } from "@ai-sdk/openai";
99
import type { GoogleGenerativeAIProviderOptions } from "@ai-sdk/google";
10+
import type { XaiProviderOptions } from "@ai-sdk/xai";
11+
import type { MuxProviderOptions } from "@/common/types/providerOptions";
1012
import type { ThinkingLevel } from "@/common/types/thinking";
1113
import {
1214
ANTHROPIC_THINKING_BUDGETS,
@@ -38,6 +40,7 @@ type ProviderOptions =
3840
| { openai: OpenAIResponsesProviderOptions }
3941
| { google: GoogleGenerativeAIProviderOptions }
4042
| { openrouter: OpenRouterReasoningOptions }
43+
| { xai: XaiProviderOptions }
4144
| Record<string, never>; // Empty object for unsupported providers
4245

4346
/**
@@ -59,7 +62,8 @@ export function buildProviderOptions(
5962
modelString: string,
6063
thinkingLevel: ThinkingLevel,
6164
messages?: MuxMessage[],
62-
lostResponseIds?: (id: string) => boolean
65+
lostResponseIds?: (id: string) => boolean,
66+
muxProviderOptions?: MuxProviderOptions
6367
): ProviderOptions {
6468
// Always clamp to the model's supported thinking policy (e.g., gpt-5-pro = HIGH only)
6569
const effectiveThinking = enforceThinkingPolicy(modelString, thinkingLevel);
@@ -250,6 +254,25 @@ export function buildProviderOptions(
250254
return {};
251255
}
252256

257+
// Build xAI-specific options
258+
if (provider === "xai") {
259+
const overrides = muxProviderOptions?.xai ?? {};
260+
261+
const defaultSearchParameters: XaiProviderOptions["searchParameters"] = {
262+
mode: "auto",
263+
returnCitations: true,
264+
};
265+
266+
const options: ProviderOptions = {
267+
xai: {
268+
...overrides,
269+
searchParameters: overrides.searchParameters ?? defaultSearchParameters,
270+
},
271+
};
272+
log.debug("buildProviderOptions: Returning xAI options", options);
273+
return options;
274+
}
275+
253276
// No provider-specific options for unsupported providers
254277
log.debug("buildProviderOptions: Unsupported provider", provider);
255278
return {};

0 commit comments

Comments
 (0)