feat(provider): load catalog request variants

This commit is contained in:
Aiden Cline 2026-07-21 22:58:11 -05:00
commit 75ab5ceae9
11 changed files with 207 additions and 243 deletions

View file

@ -69,6 +69,7 @@ export const Model = Schema.Struct({
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
variants: Schema.optional(Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.MutableJson))),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
@ -109,7 +110,13 @@ export const Model = Schema.Struct({
),
status: Schema.optional(CatalogModelStatus),
provider: Schema.optional(
Schema.Struct({ npm: Schema.optional(Schema.String), api: Schema.optional(Schema.String) }),
Schema.Struct({
npm: Schema.optional(Schema.String),
api: Schema.optional(Schema.String),
variant: Schema.optional(Schema.String),
body: Schema.optional(Schema.Record(Schema.String, Schema.MutableJson)),
headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),
}),
),
})
export type Model = Schema.Schema.Type<typeof Model>

View file

@ -3,6 +3,7 @@ import type { ModelV2Info } from "@opencode-ai/sdk/v2/types"
import { Effect, Stream } from "effect"
import { EventV2 } from "../event"
import { ModelsDev } from "../models-dev"
import { ModelV2 } from "../model"
import { ProviderV2 } from "../provider"
function released(date: string) {
@ -102,7 +103,11 @@ function applyModel(
input: [...(model.modalities?.input ?? [])],
output: [...(model.modalities?.output ?? [])],
}
draft.variants = []
draft.variants = Object.entries(model.variants ?? {}).map(([id, body]) => ({
id: ModelV2.VariantID.make(id),
headers: {},
body: { ...body },
}))
draft.time.released = released(model.release_date)
draft.cost = input.cost ?? cost(model.cost)
draft.status = model.status ?? "active"
@ -112,6 +117,9 @@ function applyModel(
input: model.limit.input,
output: model.limit.output,
}
if (model.provider?.variant !== undefined) draft.request.variant = ModelV2.VariantID.make(model.provider.variant)
Object.assign(draft.request.headers, model.provider?.headers ?? {})
Object.assign(draft.request.body, model.provider?.body ?? {})
Object.assign(draft.request.headers, input.request?.headers ?? {})
Object.assign(draft.request.body, input.request?.body ?? {})
}

View file

@ -48,8 +48,13 @@ describe("ModelsDevPlugin", () => {
release_date: "2026-01-01",
attachment: false,
reasoning: true,
reasoning_options: [{ type: "toggle" }],
temperature: true,
tool_call: true,
variants: {
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
},
cost: {
input: 2.5,
output: 15,
@ -64,6 +69,11 @@ describe("ModelsDevPlugin", () => {
context_over_200k: { input: 5, output: 22.5, cache_read: 0.5 },
},
limit: { context: 1_050_000, input: 922_000, output: 128_000 },
provider: {
variant: "thinking",
body: { thinking: { type: "adaptive" } },
headers: { "x-model": "gpt-5.4" },
},
experimental: {
modes: {
fast: {
@ -93,18 +103,29 @@ describe("ModelsDevPlugin", () => {
const base = yield* catalog.model.get(providerID, ModelV2.ID.make("gpt-5.4"))
const fast = yield* catalog.model.get(providerID, ModelV2.ID.make("gpt-5.4-fast"))
expect(base?.variants).toEqual([])
expect(base?.request.body).toEqual({})
expect(base?.variants).toEqual([
{ id: ModelV2.VariantID.make("none"), headers: {}, body: { thinking: { type: "disabled" } } },
{ id: ModelV2.VariantID.make("thinking"), headers: {}, body: { thinking: { type: "adaptive" } } },
])
expect(base?.request).toEqual({
variant: ModelV2.VariantID.make("thinking"),
headers: { "x-model": "gpt-5.4" },
body: { thinking: { type: "adaptive" } },
})
expect(fast).toMatchObject({
id: "gpt-5.4-fast",
providerID: "acme",
name: "GPT-5.4 Fast",
api: { id: "gpt-5.4" },
request: {
headers: { "x-mode": "fast" },
body: { service_tier: "priority" },
variant: ModelV2.VariantID.make("thinking"),
headers: { "x-model": "gpt-5.4", "x-mode": "fast" },
body: { thinking: { type: "adaptive" }, service_tier: "priority" },
},
variants: [],
variants: [
{ id: ModelV2.VariantID.make("none"), headers: {}, body: { thinking: { type: "disabled" } } },
{ id: ModelV2.VariantID.make("thinking"), headers: {}, body: { thinking: { type: "adaptive" } } },
],
})
expect(fast?.cost).toEqual([
{ input: 5, output: 30, cache: { read: 0.5, write: 0 } },

View file

@ -22,7 +22,7 @@ type Api =
}
| { readonly type: "native"; readonly url?: string; readonly settings: Record<string, unknown> }
const model = (api: Api, variants: ModelV2.Info["variants"] = []) =>
const model = (api: Api, variants: ModelV2.Info["variants"] = [], variant?: ModelV2.VariantID) =>
ModelV2.Info.make({
id: ModelV2.ID.make("test-model"),
providerID: ProviderV2.ID.make("test-provider"),
@ -32,6 +32,7 @@ const model = (api: Api, variants: ModelV2.Info["variants"] = []) =>
request: {
headers: { "x-test": "header" },
body: { apiKey: "secret", custom_extension: { enabled: true } },
...(variant ? { variant } : {}),
},
variants,
time: { released: 0 },
@ -175,6 +176,44 @@ describe("SessionRunnerModel", () => {
}),
)
it.effect("uses the catalog default Session variant", () =>
Effect.gen(function* () {
const catalog = model(
{ type: "aisdk", package: "@ai-sdk/anthropic", url: "https://anthropic.example/v1" },
[
{
id: ModelV2.VariantID.make("none"),
headers: {},
body: { thinking: { type: "disabled" } },
},
{
id: ModelV2.VariantID.make("thinking"),
headers: {},
body: { thinking: { type: "adaptive" } },
},
],
ModelV2.VariantID.make("thinking"),
)
const session = SessionV2.Info.make({
id: SessionV2.ID.make("ses_default_variant"),
projectID: ProjectV2.ID.global,
title: "test",
model: { id: catalog.id, providerID: catalog.providerID },
cost: 0,
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
time: { created: DateTime.makeUnsafe(0), updated: DateTime.makeUnsafe(0) },
location: { directory: AbsolutePath.make("/project") },
})
const resolved = yield* SessionRunnerModel.resolve(session, catalog)
expect(resolved.route.defaults.http?.body).toEqual({
custom_extension: { enabled: true },
thinking: { type: "adaptive" },
})
}),
)
it.effect("rejects an explicit unavailable Session variant during model resolution", () =>
Effect.gen(function* () {
const catalog = model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" })

View file

@ -55,7 +55,6 @@ const PROTOCOL_BODY_OVERLAY_DENYLIST = new Set([
"systemInstruction",
"system_instruction",
"temperature",
"thinking",
"toolChoice",
"toolConfig",
"tool_choice",

View file

@ -156,6 +156,32 @@ describe("request option precedence", () => {
}),
)
it.effect("allows provider thinking body overlays", () =>
LLMClient.generate(
LLM.request({
model: OpenAIChat.route
.with({
endpoint: { baseURL: "https://api.provider.test/v1/" },
auth: Auth.bearer("test"),
http: { body: { thinking: { type: "adaptive" } } },
})
.model({ id: "minimax-m3" }),
prompt: "Say hello.",
}),
).pipe(
Effect.provide(
dynamicResponse((input) => {
expect(decodeJson(input.text)).toMatchObject({ thinking: { type: "adaptive" } })
return Effect.succeed(
input.respond(sseEvents(deltaChunk({}, "stop")), {
headers: { "content-type": "text/event-stream" },
}),
)
}),
),
),
)
it.effect("uses model output limits after route limits and before call maxTokens", () =>
Effect.gen(function* () {
const route = AnthropicMessages.route.with({

View file

@ -1041,6 +1041,7 @@ export const Model = Schema.Struct({
options: Schema.Record(Schema.String, Schema.Any),
headers: Schema.Record(Schema.String, Schema.String),
release_date: Schema.String,
variant: optional(ModelV2.VariantID),
variants: optional(Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Any))),
}).annotate({ identifier: "Model" })
export type Model = Types.DeepMutable<Schema.Schema.Type<typeof Model>>
@ -1216,8 +1217,8 @@ function fromModelsDevModel(provider: ModelsDev.Provider, model: ModelsDev.Model
npm: model.provider?.npm ?? provider.npm ?? "@ai-sdk/openai-compatible",
},
status: model.status ?? "active",
headers: {},
options: {},
headers: { ...(model.provider?.headers ?? {}) },
options: { ...(model.provider?.body ?? {}) },
cost: cost(model.cost),
limit: {
context: model.limit.context,
@ -1246,10 +1247,12 @@ function fromModelsDevModel(provider: ModelsDev.Provider, model: ModelsDev.Model
interleaved: model.interleaved ?? false,
},
release_date: model.release_date ?? "",
variant: model.provider?.variant ? ModelV2.VariantID.make(model.provider.variant) : undefined,
variants: {},
}
const variants = ProviderTransform.reasoningVariants(model, base) ?? ProviderTransform.variants(base)
const variants =
model.variants ?? ProviderTransform.reasoningVariants(model, base) ?? ProviderTransform.variants(base)
return {
...base,
@ -1498,6 +1501,7 @@ const layer = Layer.effect(
headers: mergeDeep(existingModel?.headers ?? {}, model.headers ?? {}),
family: model.family ?? existingModel?.family ?? "",
release_date: model.release_date ?? existingModel?.release_date ?? "",
variant: existingModel?.variant,
variants: {},
}
const variants =

View file

@ -682,21 +682,6 @@ function googleThinkingVariants(model: Provider.Model): Record<string, Record<st
)
}
function minimaxM3ThinkingVariants(model: Provider.Model): Provider.Model["variants"] {
if (!model.api.id.toLowerCase().includes("minimax-m3")) return
if (!["@ai-sdk/anthropic", "@ai-sdk/openai-compatible"].includes(model.api.npm)) return
if (["nvidia", "lilac"].includes(model.providerID)) {
return {
none: { chat_template_kwargs: { thinking_mode: "disabled" } },
thinking: { chat_template_kwargs: { thinking_mode: "enabled" } },
}
}
return {
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
}
}
export function variants(model: Provider.Model): Record<string, Record<string, any>> {
if (!model.capabilities.reasoning) return {}
@ -704,8 +689,6 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
const glm52 = ["glm-5.2", "glm-5-2", "glm-5p2"].some(
(name) => id.includes(name) || model.api.id.toLowerCase().includes(name),
)
const minimaxM3 = minimaxM3ThinkingVariants(model)
if (minimaxM3) return minimaxM3
const adaptiveThinkingOmitted = anthropicOmitsThinking(model.api.id)
const adaptiveEfforts = anthropicAdaptiveEfforts(model.api.id)
if (glm52 && model.api.npm === "@openrouter/ai-sdk-provider") {
@ -1196,11 +1179,6 @@ export function options(input: {
const modelId = input.model.api.id.toLowerCase()
// MiniMax's Anthropic interface defaults thinking off, unlike Chat Completions.
if (modelId.includes("minimax-m3") && input.model.api.npm === "@ai-sdk/anthropic") {
result["thinking"] = { type: "adaptive" }
}
// Moonshot's Anthropic-compatible API uses adaptive effort rather than token budgets.
// Request summaries so thinking content survives replay on subsequent turns.
if (
@ -1313,21 +1291,15 @@ const SLUG_OVERRIDES: Record<string, string> = {
}
export function providerOptions(model: Provider.Model, options: { [x: string]: any }) {
const cleaned =
model.api.id.toLowerCase().includes("minimax-m3") &&
["nvidia", "lilac"].includes(model.providerID) &&
options.chat_template_kwargs?.thinking_mode !== undefined
? Object.fromEntries(Object.entries(options).filter(([key]) => key !== "thinking"))
: options
const usesOpenAIReasoningGate =
model.api.npm === "@ai-sdk/openai" ||
model.api.npm === "@ai-sdk/azure" ||
model.api.npm === "@ai-sdk/amazon-bedrock/mantle"
const normalized =
usesOpenAIReasoningGate &&
(model.capabilities.reasoning || cleaned.reasoningEffort !== undefined || cleaned.reasoningSummary !== undefined)
? { ...cleaned, forceReasoning: true }
: cleaned
(model.capabilities.reasoning || options.reasoningEffort !== undefined || options.reasoningSummary !== undefined)
? { ...options, forceReasoning: true }
: options
if (model.api.npm === "@ai-sdk/gateway") {
// Gateway providerOptions are split across two namespaces:
@ -1666,8 +1638,6 @@ function nonEmptyVariants(variants: NonNullable<Provider.Model["variants"]>): Pr
}
function reasoningToggle(model: Provider.Model): NonNullable<Provider.Model["variants"]> {
const minimaxM3 = minimaxM3ThinkingVariants(model)
if (minimaxM3) return minimaxM3
if (model.api.npm === "@ai-sdk/alibaba")
return {
none: { enableThinking: false },

View file

@ -77,10 +77,9 @@ export const prepare = Effect.fn("LLMRequestPrep.prepare")(function* (input: Pre
system.push(header, rest.join("\n"))
}
const variant =
!input.small && input.model.variants && input.user.model.variant
? input.model.variants[input.user.model.variant]
: {}
const variantID =
input.user.model.variant === "default" ? input.model.variant : (input.user.model.variant ?? input.model.variant)
const variant = !input.small && input.model.variants && variantID ? input.model.variants[variantID] : {}
const base = input.small
? ProviderTransform.smallOptions(input.model)
: ProviderTransform.options({

View file

@ -1522,6 +1522,23 @@ test("models.dev reasoning options replace generated variants and unsupported to
provider: { npm: "@ai-sdk/anthropic" },
limit: { context: 1_048_576, output: 131_072 },
},
providerVariants: {
id: "minimax-m3",
name: "Provider Variants",
reasoning: true,
reasoning_options: [{ type: "toggle" }],
variants: {
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
},
provider: {
npm: "@ai-sdk/anthropic",
variant: "thinking",
body: { thinking: { type: "adaptive" } },
headers: { "x-model": "minimax-m3" },
},
limit: { context: 1_000_000, output: 128_000 },
},
},
} as unknown as ModelsDev.Provider
@ -1539,6 +1556,13 @@ test("models.dev reasoning options replace generated variants and unsupported to
high: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
})
expect(models.anthropicCompatible.variants).toEqual({ max: { effort: "max" } })
expect(models.providerVariants.options).toEqual({ thinking: { type: "adaptive" } })
expect(models.providerVariants.headers).toEqual({ "x-model": "minimax-m3" })
expect(models.providerVariants.variant).toBe(ModelV2.VariantID.make("thinking"))
expect(models.providerVariants.variants).toEqual({
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
})
expect(models["gemini-3-pro-fast"].variants).toEqual(models.override.variants)
})

View file

@ -5,8 +5,7 @@ import { LLMRequestPrep } from "@/session/llm/request"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { ModelV2 } from "@opencode-ai/core/model"
import { ModelsDev } from "@opencode-ai/core/models-dev"
import { generateText, jsonSchema } from "ai"
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
import { jsonSchema } from "ai"
describe("ProviderTransform.options - setCacheKey", () => {
const sessionID = "test-session-123"
@ -279,23 +278,57 @@ describe("ProviderTransform.options - minimax m3 thinking", () => {
limit: { output: 64_000 },
}) as any
test("explicitly enables adaptive thinking with the anthropic SDK", () => {
test.each(["@ai-sdk/anthropic", "@ai-sdk/openai-compatible"])("does not synthesize options for %s", (npm) => {
expect(
ProviderTransform.options({
model: createModel("@ai-sdk/anthropic"),
sessionID: "test-session-123",
}).thinking,
).toEqual({ type: "adaptive" })
})
test("uses the native default with the openai-compatible SDK", () => {
expect(
ProviderTransform.options({
model: createModel("@ai-sdk/openai-compatible"),
model: createModel(npm),
sessionID: "test-session-123",
}).thinking,
).toBeUndefined()
})
test("applies the model default variant without changing small requests", async () => {
const model = {
...createModel("@ai-sdk/anthropic"),
variant: "thinking",
variants: {
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
},
}
const prepare = (small: boolean) =>
Effect.runPromise(
LLMRequestPrep.prepare({
user: {
id: "msg_user-test",
sessionID: "test-session-123",
role: "user",
time: { created: Date.now() },
agent: "test",
model: { providerID: "minimax", modelID: "minimax-m3" },
} as any,
sessionID: "test-session-123",
model,
agent: { name: "test", mode: "primary", options: {}, permission: [] } as any,
system: [],
messages: [{ role: "user", content: "Hello" }],
small,
tools: {},
provider: { id: "minimax", options: {} } as any,
auth: undefined,
plugin: {
trigger: (_name: string, _input: unknown, output: unknown) => Effect.succeed(output),
list: () => Effect.succeed([]),
init: () => Effect.void,
} as any,
flags: { outputTokenMax: 32_000, client: "test" } as any,
isWorkflow: false,
}),
)
expect((await prepare(false)).params.options.thinking).toEqual({ type: "adaptive" })
expect((await prepare(true)).params.options.thinking).toEqual({ type: "disabled" })
})
})
describe("ProviderTransform.options - google thinkingConfig gating", () => {
@ -3078,10 +3111,10 @@ describe("ProviderTransform.temperature - Cohere North", () => {
describe("ProviderTransform.reasoningVariants", () => {
const model = (reasoning_options: ModelsDev.Model["reasoning_options"]) => ({ reasoning_options }) as ModelsDev.Model
const target = (npm: string, id = "test-model", providerID = "test") =>
const target = (npm: string, id = "test-model") =>
({
id,
providerID,
providerID: "test",
api: { id, npm, url: "" },
capabilities: { reasoning: true },
limit: { output: 64_000 },
@ -3091,12 +3124,6 @@ describe("ProviderTransform.reasoningVariants", () => {
expect(ProviderTransform.reasoningVariants(model([]), target("@ai-sdk/openai"))).toEqual({})
})
test("preserves fixed reasoning for the paid OpenCode MiniMax M3 route", () => {
expect(
ProviderTransform.reasoningVariants(model([]), target("@ai-sdk/openai-compatible", "minimax-m3", "opencode")),
).toEqual({})
})
test.each([
["@openrouter/ai-sdk-provider", { reasoning: { effort: "high" } }],
["@ai-sdk/anthropic", { thinking: { type: "adaptive" }, effort: "high" }, "claude-opus-4-6"],
@ -3260,75 +3287,6 @@ describe("ProviderTransform.reasoningVariants", () => {
expect(ProviderTransform.reasoningVariants(model([{ type: "toggle" }]), target(npm))).toEqual(expected)
})
test.each([
[
"minimax",
"@ai-sdk/anthropic",
{
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
},
],
[
"crossmodel",
"@ai-sdk/openai-compatible",
{
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
},
],
[
"opencode",
"@ai-sdk/anthropic",
{
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
},
],
[
"opencode-go",
"@ai-sdk/anthropic",
{
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
},
],
[
"nvidia",
"@ai-sdk/openai-compatible",
{
none: { chat_template_kwargs: { thinking_mode: "disabled" } },
thinking: { chat_template_kwargs: { thinking_mode: "enabled" } },
},
],
[
"lilac",
"@ai-sdk/openai-compatible",
{
none: { chat_template_kwargs: { thinking_mode: "disabled" } },
thinking: { chat_template_kwargs: { thinking_mode: "enabled" } },
},
],
[
"kilo",
"@ai-sdk/openai-compatible",
{
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
},
],
])("maps MiniMax M3 toggle options for %s", (providerID, npm, expected) => {
expect(
ProviderTransform.reasoningVariants(model([{ type: "toggle" }]), target(npm, "minimaxai/minimax-m3", providerID)),
).toEqual(expected)
})
test("preserves unsupported Vercel MiniMax M3 toggle behavior", () => {
const vercel = target("@ai-sdk/gateway", "minimax/minimax-m3", "vercel")
expect(ProviderTransform.reasoningVariants(model([{ type: "toggle" }]), vercel)).toBeUndefined()
expect(ProviderTransform.variants(vercel)).toEqual({})
})
test("combines Cohere toggle and budget options", () => {
expect(
ProviderTransform.reasoningVariants(
@ -3511,112 +3469,21 @@ describe("ProviderTransform.variants", () => {
expect(result).toEqual({})
})
test("minimax m3 using anthropic returns thinking toggles", () => {
const model = createMockModel({
id: "minimax/minimax-m3",
providerID: "minimax",
api: {
id: "MiniMax-M3",
url: "https://api.minimax.com/anthropic/v1",
npm: "@ai-sdk/anthropic",
},
})
const result = ProviderTransform.variants(model)
expect(result).toEqual({
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
})
})
test("minimax m3 using openai-compatible returns thinking toggles", () => {
const model = createMockModel({
id: "minimax/minimax-m3",
providerID: "minimax",
api: {
id: "minimax-m3",
url: "https://api.minimax.com/v1",
npm: "@ai-sdk/openai-compatible",
},
})
expect(ProviderTransform.variants(model)).toEqual({
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
})
})
test.each([
["nvidia", "https://integrate.api.nvidia.com/v1"],
["lilac", "https://api.getlilac.com/v1"],
])("%s minimax m3 sends chat template thinking toggles", async (providerID, baseURL) => {
const model = createMockModel({
id: `${providerID}/minimaxai/minimax-m3`,
providerID,
api: {
id: "minimaxai/minimax-m3",
url: baseURL,
npm: "@ai-sdk/openai-compatible",
},
})
const variants = ProviderTransform.variants(model)
expect(variants).toEqual({
none: { chat_template_kwargs: { thinking_mode: "disabled" } },
thinking: { chat_template_kwargs: { thinking_mode: "enabled" } },
})
const bodies: Record<string, unknown>[] = []
const captureFetch: typeof fetch = Object.assign(
async (_url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => {
bodies.push(JSON.parse(String(init?.body)))
return new Response(
JSON.stringify({
id: "test",
object: "chat.completion",
created: 0,
model: model.api.id,
choices: [{ index: 0, message: { role: "assistant", content: "ok" }, finish_reason: "stop" }],
usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 },
}),
{ headers: { "content-type": "application/json" } },
)
},
{ preconnect: fetch.preconnect.bind(fetch) },
)
const provider = createOpenAICompatible({
name: providerID,
baseURL,
apiKey: "test",
fetch: captureFetch,
})
const call = async (options: Record<string, unknown>) => {
await generateText({
model: provider(model.api.id),
prompt: "test",
providerOptions: ProviderTransform.providerOptions(model, options),
test.each(["@ai-sdk/anthropic", "@ai-sdk/openai-compatible"])(
"does not synthesize minimax m3 variants for %s",
(npm) => {
const model = createMockModel({
id: "minimax/minimax-m3",
providerID: "minimax",
api: {
id: "minimax-m3",
url: "https://api.minimax.com/v1",
npm,
},
})
return bodies.at(-1)
}
const defaults = await call({})
expect(defaults?.chat_template_kwargs).toBeUndefined()
expect(defaults?.thinking).toBeUndefined()
const legacy = await call({ thinking: { type: "adaptive" } })
expect(legacy?.chat_template_kwargs).toBeUndefined()
expect(legacy?.thinking).toEqual({ type: "adaptive" })
const none = await call({
thinking: { type: "adaptive" },
...variants.none,
})
expect(none?.chat_template_kwargs).toEqual({ thinking_mode: "disabled" })
expect(none?.thinking).toBeUndefined()
const thinking = await call({
thinking: { type: "disabled" },
...variants.thinking,
})
expect(thinking?.chat_template_kwargs).toEqual({ thinking_mode: "enabled" })
expect(thinking?.thinking).toBeUndefined()
})
expect(ProviderTransform.variants(model)).toEqual({})
},
)
test("glm returns empty object", () => {
const model = createMockModel({