Skip to content

Commit eae3fc1

Browse files
authored
feat(xai): add Grok 4.5 support (#102316)
* feat(xai): add Grok 4.5 support * chore: leave release notes to release automation
1 parent aad9974 commit eae3fc1

21 files changed

Lines changed: 229 additions & 39 deletions

docs/concepts/model-providers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ messages and normalizes `stats.cached` into `cacheRead`; legacy
326326
Model ids use a `nvidia/<vendor>/<model>` namespace (for example `nvidia/nvidia/nemotron-...` alongside `nvidia/moonshotai/kimi-k2.5`); pickers preserve the literal `<provider>/<model-id>` composition while the canonical key sent to the API stays single-prefixed.
327327
</Accordion>
328328
<Accordion title="xAI">
329-
Uses the xAI Responses path. The recommended path is SuperGrok/X Premium OAuth; API keys still work via `XAI_API_KEY` or plugin config, and Grok `web_search` reuses the same auth profile before API-key fallback. `grok-4.3` is the bundled default chat model, and `grok-build-0.1` is selectable for build/coding-focused work. `/fast` or `params.fastMode: true` rewrites `grok-3`, `grok-3-mini`, `grok-4`, and `grok-4-0709` to their `*-fast` variants. `tool_stream` defaults on; disable via `agents.defaults.models["xai/<model>"].params.tool_stream=false`.
329+
Uses the xAI Responses path. The recommended path is SuperGrok/X Premium OAuth; API keys still work via `XAI_API_KEY` or plugin config, and Grok `web_search` reuses the same auth profile before API-key fallback. Grok 4.5 is selectable for chat, coding, and agentic work where available; `grok-4.3` remains the regional-safe bundled default. `/fast` or `params.fastMode: true` rewrites `grok-3`, `grok-3-mini`, `grok-4`, and `grok-4-0709` to their `*-fast` variants. `tool_stream` defaults on; disable via `agents.defaults.models["xai/<model>"].params.tool_stream=false`.
330330
</Accordion>
331331
</AccordionGroup>
332332

docs/help/testing-live.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ Live is opt-in, so there is no fixed "CI model list." `OPENCLAW_LIVE_MODELS=mode
403403
| `openrouter/minimax/minimax-m2.7` | |
404404
| `opencode-go/glm-5` | |
405405
| `openrouter/ai21/jamba-large-1.7` | |
406-
| `xai/grok-4.3` | |
406+
| `xai/grok-4.5` | |
407407
| `zai/glm-5.1` | |
408408
| `fireworks/accounts/fireworks/models/glm-5p1` | |
409409
| `minimax-portal/minimax-m3` | |

docs/providers/xai.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,15 @@ see [legacy compatibility aliases](#legacy-compatibility-aliases).
110110

111111
| Family | Model ids |
112112
| -------------- | ------------------------------------------------------------------------ |
113+
| Grok 4.5 | `grok-4.5` (aliases: `grok-4.5-latest`, `grok-build-latest`) |
113114
| Grok Build 0.1 | `grok-build-0.1` |
114115
| Grok 4.3 | `grok-4.3` |
115116
| Grok 4.20 Beta | `grok-4.20-beta-latest-reasoning`, `grok-4.20-beta-latest-non-reasoning` |
116117

117118
<Tip>
118-
Use `grok-4.3` for general chat and `grok-build-0.1` for build/coding-focused
119-
workloads unless you need a Grok 4.20 beta alias.
119+
Use `grok-4.5` for general chat, coding, and agentic work where it is available.
120+
Grok 4.3 remains the regional-safe setup default; `grok-build-0.1` and the Grok
121+
4.20 beta aliases remain selectable.
120122
</Tip>
121123

122124
## Feature coverage
@@ -493,9 +495,9 @@ Legacy aliases normalize to the canonical bundled ids:
493495
`agents.defaults.models["xai/<model>"].params.tool_stream` to `false`
494496
to disable it.
495497
- The bundled xAI wrapper strips unsupported strict tool-schema flags and
496-
reasoning *effort* payload keys before sending native xAI requests. Only
497-
`grok-4.3` / `grok-4.3-*` advertise configurable reasoning effort; all
498-
other reasoning-capable xAI models still request
498+
reasoning *effort* payload keys before sending native xAI requests. Grok
499+
4.5 supports low, medium, and high effort (default high); Grok 4.3 also
500+
supports disabling reasoning. All other reasoning-capable xAI models request
499501
`include: ["reasoning.encrypted_content"]` so prior encrypted reasoning
500502
can be replayed on follow-up turns.
501503
- `web_search`, `x_search`, and `code_execution` are exposed as OpenClaw

extensions/xai/index.test.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ describe("xai provider plugin", () => {
108108
const fetchGuard: LiveModelCatalogFetchGuard = vi.fn(async () => ({
109109
response: Response.json({
110110
data: [
111-
{ id: "grok-4.3", object: "model" },
111+
{ id: "grok-4.5", object: "model" },
112112
{ id: "not-in-manifest", object: "model" },
113113
],
114114
}),
@@ -122,7 +122,7 @@ describe("xai provider plugin", () => {
122122
});
123123

124124
expect(provider.apiKey).toBe("xai-key");
125-
expect(provider.models.map((model) => model.id)).toContain("grok-4.3");
125+
expect(provider.models.map((model) => model.id)).toContain("grok-4.5");
126126
expect(provider.models.map((model) => model.id)).not.toContain("not-in-manifest");
127127
const fetchParams = vi.mocked(fetchGuard).mock.calls[0]?.[0];
128128
expect(fetchParams?.url).toBe("https://api.x.ai/v1/models");
@@ -550,6 +550,19 @@ describe("xai provider plugin", () => {
550550
expect(resolved?.reasoning).toBe(true);
551551
expect(resolved?.input).toEqual(["text", "image"]);
552552
expect(resolved?.contextWindow).toBe(1_000_000);
553+
554+
const buildAlias = provider.resolveDynamicModel?.({
555+
provider: "xai",
556+
modelId: "grok-build-latest",
557+
modelRegistry: { find: () => null } as never,
558+
providerConfig: {
559+
api: "openai-responses",
560+
baseUrl: "https://api.x.ai/v1",
561+
},
562+
} as never);
563+
expect(buildAlias?.id).toBe("grok-4.5");
564+
expect(buildAlias?.reasoning).toBe(true);
565+
expect(buildAlias?.contextWindow).toBe(500_000);
553566
});
554567

555568
it("marks modern Grok refs without accepting multi-agent ids", async () => {

extensions/xai/model-definitions.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const XAI_DEFAULT_IMAGE_MODEL = "grok-imagine-image";
77
export const XAI_IMAGE_MODELS = ["grok-imagine-image", "grok-imagine-image-quality"] as const;
88
export const XAI_DEFAULT_CONTEXT_WINDOW = 1_000_000;
99
const XAI_LARGE_CONTEXT_WINDOW = 2_000_000;
10+
const XAI_GROK_45_CONTEXT_WINDOW = 500_000;
1011
const XAI_GROK_4_CONTEXT_WINDOW = 256_000;
1112
const XAI_CODE_CONTEXT_WINDOW = 256_000;
1213
export const XAI_DEFAULT_MAX_TOKENS = 64_000;
@@ -54,6 +55,13 @@ const XAI_GROK_43_COST = {
5455
cacheWrite: 0,
5556
} satisfies XaiCost;
5657

58+
const XAI_GROK_45_COST = {
59+
input: 2,
60+
output: 6,
61+
cacheRead: 0.5,
62+
cacheWrite: 0,
63+
} satisfies XaiCost;
64+
5765
const XAI_GROK_BUILD_COST = {
5866
input: 1,
5967
output: 2,
@@ -69,6 +77,15 @@ const XAI_CODE_FAST_COST = {
6977
} satisfies XaiCost;
7078

7179
const XAI_MODEL_CATALOG = [
80+
{
81+
id: "grok-4.5",
82+
name: "Grok 4.5",
83+
reasoning: true,
84+
input: ["text", "image"],
85+
contextWindow: XAI_GROK_45_CONTEXT_WINDOW,
86+
maxTokens: XAI_DEFAULT_MAX_TOKENS,
87+
cost: XAI_GROK_45_COST,
88+
},
7289
{
7390
id: "grok-build-0.1",
7491
name: "Grok Build 0.1",
@@ -197,6 +214,7 @@ const XAI_MODEL_CATALOG = [
197214
] as const satisfies readonly XaiCatalogEntry[];
198215

199216
const XAI_SELECTABLE_MODEL_IDS = new Set<string>([
217+
"grok-4.5",
200218
"grok-build-0.1",
201219
"grok-4.3",
202220
"grok-4.20-beta-latest-reasoning",
@@ -216,6 +234,9 @@ const XAI_RETIRED_BUILTIN_MODEL_IDS = new Set<string>(
216234
function normalizeXaiCatalogModelId(modelId: string): string {
217235
const lower = normalizeOptionalLowercaseString(modelId) ?? "";
218236
const unprefixed = lower.startsWith("xai/") ? lower.slice("xai/".length) : lower;
237+
if (unprefixed === "grok-build-latest") {
238+
return "grok-4.5";
239+
}
219240
if (XAI_GROK_BUILD_ALIASES.has(unprefixed)) {
220241
return "grok-build-0.1";
221242
}
@@ -310,6 +331,7 @@ export function resolveXaiCatalogEntry(modelId: string) {
310331
});
311332
}
312333
if (
334+
lower.startsWith("grok-4.5") ||
313335
lower.startsWith("grok-4.3") ||
314336
lower.startsWith("grok-4.20") ||
315337
lower.startsWith("grok-4-1") ||
@@ -320,15 +342,22 @@ export function resolveXaiCatalogEntry(modelId: string) {
320342
name: trimmed,
321343
reasoning: !lower.includes("non-reasoning"),
322344
input: ["text", "image"],
323-
contextWindow: lower.startsWith("grok-4.3")
324-
? XAI_DEFAULT_CONTEXT_WINDOW
325-
: XAI_LARGE_CONTEXT_WINDOW,
326-
maxTokens: lower.startsWith("grok-4.3") ? XAI_DEFAULT_MAX_TOKENS : 30_000,
327-
cost: lower.startsWith("grok-4.3")
328-
? XAI_GROK_43_COST
329-
: lower.startsWith("grok-4.20")
330-
? XAI_GROK_420_COST
331-
: XAI_FAST_COST,
345+
contextWindow: lower.startsWith("grok-4.5")
346+
? XAI_GROK_45_CONTEXT_WINDOW
347+
: lower.startsWith("grok-4.3")
348+
? XAI_DEFAULT_CONTEXT_WINDOW
349+
: XAI_LARGE_CONTEXT_WINDOW,
350+
maxTokens:
351+
lower.startsWith("grok-4.5") || lower.startsWith("grok-4.3")
352+
? XAI_DEFAULT_MAX_TOKENS
353+
: 30_000,
354+
cost: lower.startsWith("grok-4.5")
355+
? XAI_GROK_45_COST
356+
: lower.startsWith("grok-4.3")
357+
? XAI_GROK_43_COST
358+
: lower.startsWith("grok-4.20")
359+
? XAI_GROK_420_COST
360+
: XAI_FAST_COST,
332361
});
333362
}
334363
if (lower.startsWith("grok-4")) {

extensions/xai/model-id.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { describe, expect, it } from "vitest";
33
import { normalizeXaiModelId } from "./api.js";
44

55
describe("normalizeXaiModelId", () => {
6+
it("normalizes the current Grok Build alias", () => {
7+
expect(normalizeXaiModelId("grok-build-latest")).toBe("grok-4.5");
8+
});
9+
610
it("maps deprecated grok 4.20 beta ids to GA ids", () => {
711
expect(normalizeXaiModelId("grok-4.20-experimental-beta-0304-reasoning")).toBe(
812
"grok-4.20-beta-latest-reasoning",

extensions/xai/model-id.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// Xai plugin module implements model id behavior.
22
export function normalizeXaiModelId(id: string): string {
3+
if (id === "grok-build-latest") {
4+
return "grok-4.5";
5+
}
36
if (id === "grok-code-fast-1" || id === "grok-code-fast" || id === "grok-code-fast-1-0825") {
47
return "grok-build-0.1";
58
}

extensions/xai/onboard.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ describe("xai onboard", () => {
5858
expect(cfg.models?.providers?.xai?.apiKey).toBe("old-key");
5959
expect(cfg.models?.providers?.xai?.models.map((m) => m.id)).toEqual([
6060
"custom-model",
61+
"grok-4.5",
6162
"grok-build-0.1",
6263
"grok-4.3",
6364
"grok-4.20-beta-latest-reasoning",
@@ -71,6 +72,7 @@ describe("xai onboard", () => {
7172
expect(cfg.models?.providers?.xai?.baseUrl).toBe("https://api.x.ai/v1");
7273
expect(cfg.models?.providers?.xai?.api).toBe("openai-responses");
7374
expect(cfg.models?.providers?.xai?.models.map((m) => m.id)).toEqual([
75+
"grok-4.5",
7476
"grok-build-0.1",
7577
"grok-4.3",
7678
"grok-4.20-beta-latest-reasoning",

extensions/xai/openclaw.plugin.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"providers": {
1111
"xai": {
1212
"aliases": {
13+
"grok-build-latest": "grok-4.5",
1314
"grok-4.20-experimental-beta-0304-reasoning": "grok-4.20-beta-latest-reasoning",
1415
"grok-4.20-experimental-beta-0304-non-reasoning": "grok-4.20-beta-latest-non-reasoning",
1516
"grok-4.20-reasoning": "grok-4.20-beta-latest-reasoning",

extensions/xai/openclaw.plugin.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { describe, expect, it } from "vitest";
44
const manifest = JSON.parse(
55
readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf8"),
66
) as {
7+
modelIdNormalization?: {
8+
providers?: Record<string, { aliases?: Record<string, string> }>;
9+
};
710
modelCatalog?: {
811
suppressions?: Array<{ provider?: string; model?: string }>;
912
};
@@ -20,6 +23,12 @@ const XAI_MULTI_AGENT_MODELS = [
2023
] as const;
2124

2225
describe("xAI plugin manifest", () => {
26+
it("normalizes the Grok Build latest alias to Grok 4.5", () => {
27+
expect(manifest.modelIdNormalization?.providers?.xai?.aliases?.["grok-build-latest"]).toBe(
28+
"grok-4.5",
29+
);
30+
});
31+
2332
it("suppresses the unsupported multi-agent model aliases", () => {
2433
const suppressionRefs = new Set(
2534
(manifest.modelCatalog?.suppressions ?? []).map(

0 commit comments

Comments
 (0)