diff --git a/packages/ai/src/providers/xai.ts b/packages/ai/src/providers/xai.ts index 281a106357..246a1be62b 100644 --- a/packages/ai/src/providers/xai.ts +++ b/packages/ai/src/providers/xai.ts @@ -1,25 +1,29 @@ import { AuthOptions, type ProviderAuthOption } from "../route/auth-options" import type { RouteDefaultsInput } from "../route/client" -import { HttpOptions, ProviderID, type ModelID } from "../schema" +import { HttpOptions, ProviderID, mergeProviderOptions, type ModelID, type ProviderOptions } from "../schema" import * as OpenAICompatibleProfiles from "./openai-compatible-profile" import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat" import * as OpenAIResponses from "../protocols/openai-responses" import { XAIImages } from "../protocols/xai-images" -import type { OpenAIProviderOptionsInput } from "./openai-options" +import type { OpenAIOptionsInput } from "./openai-options" import type { ProviderPackage } from "../provider-package" export const id = ProviderID.make("xai") +export type XAIProviderOptionsInput = ProviderOptions & { + readonly xai?: OpenAIOptionsInput +} + export type ModelOptions = Omit & ProviderAuthOption<"optional"> & { readonly baseURL?: string - readonly providerOptions?: OpenAIProviderOptionsInput + readonly providerOptions?: XAIProviderOptionsInput } export interface Settings extends ProviderPackage.Settings { readonly apiKey?: string readonly baseURL?: string - readonly providerOptions?: OpenAIProviderOptionsInput + readonly providerOptions?: XAIProviderOptionsInput } export type { XAIImageOptions } from "../protocols/xai-images" @@ -33,8 +37,10 @@ const configuredResponsesRoute = (input: ModelOptions) => { return OpenAIResponses.route.with({ ...rest, provider: id, + providerMetadataKey: "xai", endpoint: { baseURL: baseURL ?? OpenAICompatibleProfiles.profiles.xai.baseURL }, auth: auth(input), + providerOptions: mergeProviderOptions({ xai: { store: false } }, input.providerOptions), }) } @@ -43,6 +49,7 @@ const configuredChatRoute = (input: ModelOptions) => { return OpenAICompatibleChat.route.with({ ...rest, provider: id, + providerMetadataKey: "xai", endpoint: { baseURL: baseURL ?? OpenAICompatibleProfiles.profiles.xai.baseURL }, auth: auth(input), }) @@ -51,8 +58,8 @@ const configuredChatRoute = (input: ModelOptions) => { export const configure = (input: ModelOptions = {}) => { const responsesRoute = configuredResponsesRoute(input) const chatRoute = configuredChatRoute(input) - const responses = (modelID: string | ModelID) => responsesRoute.model({ id: modelID }) - const chat = (modelID: string | ModelID) => chatRoute.model({ id: modelID }) + const responses = (modelID: string | ModelID) => responsesRoute.model({ id: modelID }) + const chat = (modelID: string | ModelID) => chatRoute.model({ id: modelID }) const image = (modelID: string | ModelID) => XAIImages.model({ id: modelID, @@ -72,7 +79,7 @@ export const configure = (input: ModelOptions = {}) => { } export const provider = configure() -export const model: ProviderPackage.Definition["model"] = (modelID, settings) => +export const model: ProviderPackage.Definition["model"] = (modelID, settings) => configure({ apiKey: settings.apiKey, baseURL: settings.baseURL, diff --git a/packages/ai/test/provider-options/xai.types.ts b/packages/ai/test/provider-options/xai.types.ts index 619f543083..ab1a99c46b 100644 --- a/packages/ai/test/provider-options/xai.types.ts +++ b/packages/ai/test/provider-options/xai.types.ts @@ -3,11 +3,11 @@ import { XAI } from "../../src/providers" const model = XAI.provider.model("grok-4") -LLM.request({ model, prompt: "Hello", providerOptions: { openai: { reasoningEffort: "high" } } }) +LLM.request({ model, prompt: "Hello", providerOptions: { xai: { reasoningEffort: "high" } } }) LLM.request({ model, prompt: "Hello", // @ts-expect-error xAI's OpenAI-compatible reasoning effort must be a string. - providerOptions: { openai: { reasoningEffort: true } }, + providerOptions: { xai: { reasoningEffort: true } }, }) diff --git a/packages/ai/test/provider-package.test.ts b/packages/ai/test/provider-package.test.ts index 0bb1b1441b..9748289b80 100644 --- a/packages/ai/test/provider-package.test.ts +++ b/packages/ai/test/provider-package.test.ts @@ -47,7 +47,7 @@ describe("provider package entrypoints", () => { }) const xai = XAI.model("grok-4", { ...settings, - providerOptions: { openai: { reasoningEffort: "high" } }, + providerOptions: { xai: { reasoningEffort: "high" } }, }) for (const selected of [openrouter, xai]) { @@ -57,7 +57,7 @@ describe("provider package entrypoints", () => { expect(selected.route.defaults.limits).toEqual(settings.limits) } expect(openrouter.route.defaults.providerOptions).toEqual({ openrouter: { usage: true } }) - expect(xai.route.defaults.providerOptions).toEqual({ openai: { reasoningEffort: "high", store: false } }) + expect(xai.route.defaults.providerOptions).toMatchObject({ xai: { reasoningEffort: "high", store: false } }) }) test("maps package settings onto the executable model", () => { diff --git a/packages/core/src/model-resolver.ts b/packages/core/src/model-resolver.ts index 5cce0e4362..04c737e914 100644 --- a/packages/core/src/model-resolver.ts +++ b/packages/core/src/model-resolver.ts @@ -242,7 +242,7 @@ const nativeProviderOptions = (packageName: string | undefined, settings: Readon if (Object.keys(values).length === 0) return undefined if (packageName === "@ai-sdk/google") return { gemini: values } if (packageName === "@openrouter/ai-sdk-provider") return { openrouter: values } - if (packageName === "@ai-sdk/xai") return { openai: values } + if (packageName === "@ai-sdk/xai") return { xai: values } return undefined } diff --git a/packages/core/test/model-resolver.test.ts b/packages/core/test/model-resolver.test.ts index d48db827d0..2f67a60b43 100644 --- a/packages/core/test/model-resolver.test.ts +++ b/packages/core/test/model-resolver.test.ts @@ -552,7 +552,7 @@ describe("ModelResolver", () => { const packages = [ ["@ai-sdk/google", "@opencode-ai/ai/providers/google", "gemini"], ["@openrouter/ai-sdk-provider", "@opencode-ai/ai/providers/openrouter", "openrouter"], - ["@ai-sdk/xai", "@opencode-ai/ai/providers/xai", "openai"], + ["@ai-sdk/xai", "@opencode-ai/ai/providers/xai", "xai"], ] as const yield* Effect.forEach(packages, ([catalogPackage, nativePackage, optionKey]) => @@ -611,7 +611,8 @@ describe("ModelResolver", () => { expect(openrouter.route.defaults.providerOptions).toEqual({ openrouter: { reasoning: { effort: "high" } } }) expect(xai.route.id).toBe("openai-responses") expect(xai.route.defaults.providerOptions).toEqual({ - openai: { reasoningEffort: "high", store: false }, + openai: { store: false }, + xai: { reasoningEffort: "high", store: false }, }) }), )