fix: only send reasoningEffort for grok-3-mini (#200)

* fix: only send reasoningEffort for grok-3-mini

According to xAI documentation, only grok-3-mini supports the
reasoning_effort parameter. Other models (grok-3, grok-4, grok-4-fast-reasoning)
do not support this parameter and return a 'Bad request' error when it is sent.

Changes:
- Added supportsReasoningEffort field to ModelInfo interface
- Marked only grok-3-mini with supportsReasoningEffort: true
- Updated getSupportedReasoningEfforts() to check supportsReasoningEffort
  instead of the generic reasoning flag
- This prevents sending reasoningEffort to unsupported models

Fixes the 410 error when using models like grok-code-fast-1 with
reasoning effort configured.

Co-authored-by: Ismail Pelaseyed <homanp@users.noreply.github.com>

* test: update tests to reflect grok-3-mini-only reasoning effort support

Updated model tests to verify that only grok-3-mini supports
reasoningEffort parameter, and all other models (including reasoning
models like grok-4-0709, grok-code-fast-1) correctly return empty
supported efforts arrays.

Co-authored-by: Ismail Pelaseyed <homanp@users.noreply.github.com>

* test: add integration tests for resolveModelRuntime

Verify that providerOptions.xai.reasoningEffort is only included
for models that support it (currently only grok-3-mini), and is
correctly omitted for all other models regardless of their
reasoning flag.

Co-authored-by: Ismail Pelaseyed <homanp@users.noreply.github.com>

* fix: organize imports in client.test.ts for Biome linter

Biome requires imports to be sorted alphabetically. Moved @ai-sdk/xai
import before vitest import to satisfy the linter.

Co-authored-by: Ismail Pelaseyed <homanp@users.noreply.github.com>

* fix: add comprehensive tests for reasoningEffort with grok-3-mini

- Fixed misleading test name that said 'includes' but asserted undefined
- Added new test suite 'with configured reasoning effort' that mocks
  getReasoningEffortForModel to verify positive cases
- Tests now verify that grok-3-mini DOES receive providerOptions when
  reasoning effort is configured (high or low)
- Tests verify that other models (grok-4-0709, grok-code-fast-1, etc.)
  do NOT receive providerOptions even when effort is configured
- Increased test coverage from 90 to 100 tests

Addresses review feedback about missing positive test case.

Co-authored-by: Ismail Pelaseyed <homanp@users.noreply.github.com>

* refactor: remove dead code branches in getSupportedReasoningEfforts

Removed unreachable multiAgent and responsesOnly branches since only
grok-3-mini currently has supportsReasoningEffort: true, and it has
neither of those flags.

Added comment explaining that only grok-3-mini supports reasoning_effort
per xAI documentation, and it supports 'low' and 'high' efforts.

If xAI adds reasoning_effort support to other models in the future,
the logic can be expanded as needed.

Addresses review feedback about dead code.

Co-authored-by: Ismail Pelaseyed <homanp@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ismail Pelaseyed <homanp@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-03-23 14:00:49 +01:00
1 parent 994a307324
commit 75efd707f7
4 files changed
+121 -7

No files matched your search

+104
View File
@@ -0,0 +1,104 @@
import { createXai } from "@ai-sdk/xai";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import * as settings from "../utils/settings";
import { resolveModelRuntime } from "./client";
describe("client", () => {
const mockProvider = createXai({
apiKey: "test-key",
baseURL: "https://api.x.ai/v1",
});
describe("resolveModelRuntime", () => {
describe("without configured reasoning effort", () => {
it("does not include providerOptions for grok-3-mini when no effort configured", () => {
const runtime = resolveModelRuntime(mockProvider, "grok-3-mini");
expect(runtime.modelId).toBe("grok-3-mini");
expect(runtime.providerOptions).toBeUndefined();
});
it("does not include providerOptions for grok-4-0709 even though it has reasoning flag", () => {
const runtime = resolveModelRuntime(mockProvider, "grok-4-0709");
expect(runtime.modelId).toBe("grok-4-0709");
expect(runtime.providerOptions).toBeUndefined();
});
it("does not include providerOptions for grok-code-fast-1", () => {
const runtime = resolveModelRuntime(mockProvider, "grok-code-fast-1");
expect(runtime.modelId).toBe("grok-code-fast-1");
expect(runtime.providerOptions).toBeUndefined();
});
it("does not include providerOptions for grok-4-1-fast-reasoning", () => {
const runtime = resolveModelRuntime(mockProvider, "grok-4-1-fast-reasoning");
expect(runtime.modelId).toBe("grok-4-1-fast-reasoning");
expect(runtime.providerOptions).toBeUndefined();
});
it("does not include providerOptions for grok-4.20-multi-agent", () => {
const runtime = resolveModelRuntime(mockProvider, "grok-4.20-multi-agent");
expect(runtime.modelId).toBe("grok-4.20-multi-agent-0309");
expect(runtime.providerOptions).toBeUndefined();
});
it("does not include providerOptions for grok-3", () => {
const runtime = resolveModelRuntime(mockProvider, "grok-3");
expect(runtime.modelId).toBe("grok-3");
expect(runtime.providerOptions).toBeUndefined();
});
});
describe("with configured reasoning effort", () => {
beforeEach(() => {
vi.spyOn(settings, "getReasoningEffortForModel");
});
afterEach(() => {
vi.restoreAllMocks();
});
it("includes providerOptions with reasoningEffort for grok-3-mini when effort is configured", () => {
vi.mocked(settings.getReasoningEffortForModel).mockReturnValue("high");
const runtime = resolveModelRuntime(mockProvider, "grok-3-mini");
expect(runtime.modelId).toBe("grok-3-mini");
expect(runtime.providerOptions).toEqual({
xai: {
reasoningEffort: "high",
},
});
});
it("includes providerOptions with low effort for grok-3-mini when configured", () => {
vi.mocked(settings.getReasoningEffortForModel).mockReturnValue("low");
const runtime = resolveModelRuntime(mockProvider, "grok-3-mini");
expect(runtime.modelId).toBe("grok-3-mini");
expect(runtime.providerOptions).toEqual({
xai: {
reasoningEffort: "low",
},
});
});
it("does not include providerOptions for grok-4-0709 even when effort is configured", () => {
vi.mocked(settings.getReasoningEffortForModel).mockReturnValue("high");
const runtime = resolveModelRuntime(mockProvider, "grok-4-0709");
expect(runtime.modelId).toBe("grok-4-0709");
expect(runtime.providerOptions).toBeUndefined();
});
it("does not include providerOptions for grok-code-fast-1 even when effort is configured", () => {
vi.mocked(settings.getReasoningEffortForModel).mockReturnValue("high");
const runtime = resolveModelRuntime(mockProvider, "grok-code-fast-1");
expect(runtime.modelId).toBe("grok-code-fast-1");
expect(runtime.providerOptions).toBeUndefined();
});
it("does not include providerOptions for grok-4-1-fast-reasoning even when effort is configured", () => {
vi.mocked(settings.getReasoningEffortForModel).mockReturnValue("high");
const runtime = resolveModelRuntime(mockProvider, "grok-4-1-fast-reasoning");
expect(runtime.modelId).toBe("grok-4-1-fast-reasoning");
expect(runtime.providerOptions).toBeUndefined();
});
});
});
});
+12 -4
View File
@@ -26,14 +26,22 @@ describe("models", () => {
});
it("reports supported reasoning-effort levels", () => {
expect(getSupportedReasoningEfforts("grok-4.20-multi-agent-0309")).toEqual(["low", "medium", "high", "xhigh"]);
expect(getSupportedReasoningEfforts("grok-4-1-fast-reasoning")).toEqual(["low", "high"]);
expect(getSupportedReasoningEfforts("grok-3-mini")).toEqual(["low", "high"]);
expect(getSupportedReasoningEfforts("grok-4.20-multi-agent-0309")).toEqual([]);
expect(getSupportedReasoningEfforts("grok-4-1-fast-reasoning")).toEqual([]);
expect(getSupportedReasoningEfforts("grok-4-1-fast-non-reasoning")).toEqual([]);
expect(getSupportedReasoningEfforts("grok-code-fast-1")).toEqual([]);
expect(getSupportedReasoningEfforts("grok-4-0709")).toEqual([]);
expect(getSupportedReasoningEfforts("grok-3")).toEqual([]);
});
it("resolves effective reasoning effort with defaults and overrides", () => {
expect(getEffectiveReasoningEffort("grok-4.20-multi-agent-0309")).toBe("low");
expect(getEffectiveReasoningEffort("grok-4.20-multi-agent-0309", "high")).toBe("high");
expect(getEffectiveReasoningEffort("grok-3-mini")).toBeUndefined();
expect(getEffectiveReasoningEffort("grok-3-mini", "high")).toBe("high");
expect(getEffectiveReasoningEffort("grok-3-mini", "low")).toBe("low");
expect(getEffectiveReasoningEffort("grok-4.20-multi-agent-0309")).toBeUndefined();
expect(getEffectiveReasoningEffort("grok-4.20-multi-agent-0309", "high")).toBeUndefined();
expect(getEffectiveReasoningEffort("grok-4-1-fast-reasoning")).toBeUndefined();
expect(getEffectiveReasoningEffort("grok-code-fast-1", "high")).toBeUndefined();
});
});
+4 -3
View File
@@ -110,6 +110,7 @@ export const MODELS: ModelInfo[] = [
reasoning: false,
description: "Budget-friendly compact model",
aliases: ["grok-3-mini-fast"],
supportsReasoningEffort: true,
},
];
@@ -149,9 +150,9 @@ export function isKnownModelId(modelId: string): boolean {
export function getSupportedReasoningEfforts(modelId: string): ReasoningEffort[] {
const modelInfo = getModelInfo(modelId);
if (!modelInfo?.reasoning) return [];
if (modelInfo.multiAgent) return ["low", "medium", "high", "xhigh"];
if (modelInfo.responsesOnly) return ["low", "medium", "high"];
if (!modelInfo?.supportsReasoningEffort) return [];
// Currently only grok-3-mini supports reasoning_effort per xAI docs
// It supports "low" and "high" efforts
return ["low", "high"];
}
+1
View File
@@ -123,6 +123,7 @@ export interface ModelInfo {
supportsClientTools?: boolean;
supportsMaxOutputTokens?: boolean;
defaultReasoningEffort?: ReasoningEffort;
supportsReasoningEffort?: boolean;
}
export type AgentMode = "agent" | "plan" | "ask";