Skip to content

Commit 99adf9a

Browse files
navedmerchantedelauna
authored andcommitted
feat: add Grok 4.5 model support and fix xAI reasoning format
Add grok-4.5 model definition with 500K context window, .00/.00 input/output pricing, /bin/sh.50 cache pricing, and configurable reasoning (low/medium/high, default high). Update xaiDefaultModelId from grok-4.20 to grok-4.5 as the new flagship model. Fix a latent bug in the xAI handler where reasoning effort was sent in Chat Completions format (reasoning: { reasoning_effort }) instead of the Responses API format (reasoning: { effort }). This affected grok-3-mini and would have broken grok-4.5's configurable reasoning. Update tests to cover the reasoning format fix and add grok-4.5 reasoning support tests. Update e2e test primary model to grok-4.5. Fixes #866
1 parent c39535e commit 99adf9a

4 files changed

Lines changed: 66 additions & 7 deletions

File tree

apps/vscode-e2e/src/suite/providers/xai.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const XAI_API_KEY = process.env.XAI_API_KEY
1212
const XAI_BASE_URL = "https://api.x.ai/v1"
1313
const XAI_RESPONSES_URL = `${XAI_BASE_URL}/responses`
1414
// Primary model for the full round-trip test (completion-text assertion included).
15-
const XAI_MODEL_ID = "grok-4.20"
15+
const XAI_MODEL_ID = "grok-4.5"
1616
// Fast variants: tested for API parameter contract only. They consistently call
1717
// attempt_completion with an empty result field after a no-tool-error recovery
1818
// loop, so they cannot satisfy the completion-text assertion at this time.
@@ -492,7 +492,7 @@ suite("xAI provider", function () {
492492
const readCallId = modelFixture?.readCallId ?? "call_xai_read_001"
493493

494494
if (request.functionCallOutputIds.some((id) => id === readCallId)) {
495-
// Use recorded turn2 when it contains a function_call (grok-4.20).
495+
// Use recorded turn2 when it contains a function_call (grok-4.5).
496496
// Fast models return plain text in turn2 — hand-craft attempt_completion
497497
// so the task can reach completion.
498498
const turn2HasFunctionCall = (modelFixture?.turn2 as ResponsesStreamEvent[] | undefined)?.some(

packages/types/src/providers/xai.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,25 @@ import type { ModelInfo } from "../model.js"
33
// https://docs.x.ai/docs/api-reference
44
export type XAIModelId = keyof typeof xaiModels
55

6-
export const xaiDefaultModelId: XAIModelId = "grok-4.20"
6+
export const xaiDefaultModelId: XAIModelId = "grok-4.5"
77

88
export const xaiModels = {
9+
"grok-4.5": {
10+
maxTokens: 65_536,
11+
contextWindow: 500_000,
12+
supportsImages: true,
13+
supportsPromptCache: true,
14+
inputPrice: 2.0,
15+
outputPrice: 6.0,
16+
cacheWritesPrice: 0.5,
17+
cacheReadsPrice: 0.5,
18+
description:
19+
"xAI's flagship Grok 4.5 model with 500K context, configurable reasoning (low/medium/high), and agentic tool calling via Responses API.",
20+
supportsReasoningEffort: ["low", "medium", "high"],
21+
reasoningEffort: "high",
22+
includedTools: ["search_replace"],
23+
excludedTools: ["apply_diff"],
24+
},
925
"grok-4.20": {
1026
maxTokens: 65_536,
1127
contextWindow: 2_000_000,

src/api/providers/__tests__/xai.spec.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ describe("XAIHandler", () => {
255255
await expect(handler.completePrompt("test prompt")).rejects.toThrow(`xAI completion error: ${errorMessage}`)
256256
})
257257

258-
it("should include reasoning_effort for mini models", async () => {
258+
it("should include reasoning effort for mini models in Responses API format", async () => {
259259
const miniModelHandler = new XAIHandler({
260260
apiModelId: "grok-3-mini",
261261
reasoningEffort: "high",
@@ -269,7 +269,48 @@ describe("XAIHandler", () => {
269269
expect(mockResponsesCreate).toHaveBeenCalledWith(
270270
expect.objectContaining({
271271
reasoning: expect.objectContaining({
272-
reasoning_effort: "high",
272+
effort: "high",
273+
}),
274+
}),
275+
)
276+
})
277+
278+
it("should include reasoning effort for grok-4.5 with default high effort", async () => {
279+
const grok45Handler = new XAIHandler({
280+
apiModelId: "grok-4.5",
281+
})
282+
283+
mockResponsesCreate.mockResolvedValueOnce(mockStream([]))
284+
285+
const stream = grok45Handler.createMessage("test prompt", [])
286+
await stream.next()
287+
288+
expect(mockResponsesCreate).toHaveBeenCalledWith(
289+
expect.objectContaining({
290+
model: "grok-4.5",
291+
reasoning: expect.objectContaining({
292+
effort: "high",
293+
}),
294+
}),
295+
)
296+
})
297+
298+
it("should include reasoning effort for grok-4.5 with custom low effort", async () => {
299+
const grok45Handler = new XAIHandler({
300+
apiModelId: "grok-4.5",
301+
reasoningEffort: "low",
302+
})
303+
304+
mockResponsesCreate.mockResolvedValueOnce(mockStream([]))
305+
306+
const stream = grok45Handler.createMessage("test prompt", [])
307+
await stream.next()
308+
309+
expect(mockResponsesCreate).toHaveBeenCalledWith(
310+
expect.objectContaining({
311+
model: "grok-4.5",
312+
reasoning: expect.objectContaining({
313+
effort: "low",
273314
}),
274315
}),
275316
)

src/api/providers/xai.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,11 @@ export class XAIHandler extends BaseProvider implements SingleCompletionHandler
120120
requestBody.parallel_tool_calls = metadata?.parallelToolCalls ?? true
121121
}
122122

123-
// Pass reasoning effort for models that support it (e.g., mini models)
123+
// Pass reasoning effort for models that support it (e.g., grok-4.5, grok-3-mini).
124+
// The xAI Responses API uses `reasoning: { effort }` format (not `reasoning_effort`
125+
// which is the Chat Completions format), so we convert from the OpenAI params shape.
124126
if (model.reasoning) {
125-
requestBody.reasoning = model.reasoning
127+
requestBody.reasoning = { effort: model.reasoning.reasoning_effort }
126128
}
127129

128130
let stream: AsyncIterable<any>

0 commit comments

Comments
 (0)