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:
4 files changed
+121
-7
No files matched your search
@@ -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
@@ -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
@@ -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"];
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ export interface ModelInfo {
|
||||
supportsClientTools?: boolean;
|
||||
supportsMaxOutputTokens?: boolean;
|
||||
defaultReasoningEffort?: ReasoningEffort;
|
||||
supportsReasoningEffort?: boolean;
|
||||
}
|
||||
|
||||
export type AgentMode = "agent" | "plan" | "ask";
|
||||
|
||||
Reference in new issue
Block a user