diff --git a/apps/vscode-e2e/src/suite/providers/xai.test.ts b/apps/vscode-e2e/src/suite/providers/xai.test.ts index 013f8f55a..7403d7127 100644 --- a/apps/vscode-e2e/src/suite/providers/xai.test.ts +++ b/apps/vscode-e2e/src/suite/providers/xai.test.ts @@ -12,7 +12,7 @@ const XAI_API_KEY = process.env.XAI_API_KEY const XAI_BASE_URL = "https://api.x.ai/v1" const XAI_RESPONSES_URL = `${XAI_BASE_URL}/responses` // Primary model for the full round-trip test (completion-text assertion included). -const XAI_MODEL_ID = "grok-4.20" +const XAI_MODEL_ID = "grok-4.5" // Fast variants: tested for API parameter contract only. They consistently call // attempt_completion with an empty result field after a no-tool-error recovery // loop, so they cannot satisfy the completion-text assertion at this time. @@ -492,7 +492,7 @@ suite("xAI provider", function () { const readCallId = modelFixture?.readCallId ?? "call_xai_read_001" if (request.functionCallOutputIds.some((id) => id === readCallId)) { - // Use recorded turn2 when it contains a function_call (grok-4.20). + // Use recorded turn2 when it contains a function_call (grok-4.5). // Fast models return plain text in turn2 — hand-craft attempt_completion // so the task can reach completion. const turn2HasFunctionCall = (modelFixture?.turn2 as ResponsesStreamEvent[] | undefined)?.some( diff --git a/packages/types/src/providers/xai.ts b/packages/types/src/providers/xai.ts index a80e0d735..9e83dd4e1 100644 --- a/packages/types/src/providers/xai.ts +++ b/packages/types/src/providers/xai.ts @@ -3,9 +3,25 @@ import type { ModelInfo } from "../model.js" // https://docs.x.ai/docs/api-reference export type XAIModelId = keyof typeof xaiModels -export const xaiDefaultModelId: XAIModelId = "grok-4.20" +export const xaiDefaultModelId: XAIModelId = "grok-4.5" export const xaiModels = { + "grok-4.5": { + maxTokens: 65_536, + contextWindow: 500_000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 2.0, + outputPrice: 6.0, + cacheWritesPrice: 0.5, + cacheReadsPrice: 0.5, + description: + "xAI's flagship Grok 4.5 model with 500K context, configurable reasoning (low/medium/high), and agentic tool calling via Responses API.", + supportsReasoningEffort: ["low", "medium", "high"], + reasoningEffort: "high", + includedTools: ["search_replace"], + excludedTools: ["apply_diff"], + }, "grok-4.20": { maxTokens: 65_536, contextWindow: 2_000_000, diff --git a/src/api/providers/__tests__/xai.spec.ts b/src/api/providers/__tests__/xai.spec.ts index 78f091b8e..794faa5eb 100644 --- a/src/api/providers/__tests__/xai.spec.ts +++ b/src/api/providers/__tests__/xai.spec.ts @@ -255,7 +255,7 @@ describe("XAIHandler", () => { await expect(handler.completePrompt("test prompt")).rejects.toThrow(`xAI completion error: ${errorMessage}`) }) - it("should include reasoning_effort for mini models", async () => { + it("should include reasoning effort for mini models in Responses API format", async () => { const miniModelHandler = new XAIHandler({ apiModelId: "grok-3-mini", reasoningEffort: "high", @@ -269,7 +269,48 @@ describe("XAIHandler", () => { expect(mockResponsesCreate).toHaveBeenCalledWith( expect.objectContaining({ reasoning: expect.objectContaining({ - reasoning_effort: "high", + effort: "high", + }), + }), + ) + }) + + it("should include reasoning effort for grok-4.5 with default high effort", async () => { + const grok45Handler = new XAIHandler({ + apiModelId: "grok-4.5", + }) + + mockResponsesCreate.mockResolvedValueOnce(mockStream([])) + + const stream = grok45Handler.createMessage("test prompt", []) + await stream.next() + + expect(mockResponsesCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "grok-4.5", + reasoning: expect.objectContaining({ + effort: "high", + }), + }), + ) + }) + + it("should include reasoning effort for grok-4.5 with custom low effort", async () => { + const grok45Handler = new XAIHandler({ + apiModelId: "grok-4.5", + reasoningEffort: "low", + }) + + mockResponsesCreate.mockResolvedValueOnce(mockStream([])) + + const stream = grok45Handler.createMessage("test prompt", []) + await stream.next() + + expect(mockResponsesCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "grok-4.5", + reasoning: expect.objectContaining({ + effort: "low", }), }), ) diff --git a/src/api/providers/xai.ts b/src/api/providers/xai.ts index 17ac40c8b..15753c004 100644 --- a/src/api/providers/xai.ts +++ b/src/api/providers/xai.ts @@ -120,9 +120,11 @@ export class XAIHandler extends BaseProvider implements SingleCompletionHandler requestBody.parallel_tool_calls = metadata?.parallelToolCalls ?? true } - // Pass reasoning effort for models that support it (e.g., mini models) + // Pass reasoning effort for models that support it (e.g., grok-4.5, grok-3-mini). + // The xAI Responses API uses `reasoning: { effort }` format (not `reasoning_effort` + // which is the Chat Completions format), so we convert from the OpenAI params shape. if (model.reasoning) { - requestBody.reasoning = model.reasoning + requestBody.reasoning = { effort: model.reasoning.reasoning_effort } } let stream: AsyncIterable