Files
opencode/packages/core/test/variant.test.ts

378 lines
16 KiB
TypeScript

import { expect, test } from "bun:test"
import { Model } from "@opencode/core/model"
import { Provider } from "@opencode/core/provider"
import { Variant } from "@opencode/core/variant"
const model = (packageName: string, modelID: string, output?: number, providerID = "test") => {
const result = Model.Info.default(Provider.ID.make(providerID), Model.ID.make(modelID)) as Model.MutableInfo
result.package = packageName
result.modelID = Model.ID.make(modelID)
if (output !== undefined) result.limit = { ...result.limit, output }
return Model.Info.make(result)
}
const resolve = (input: Model.Info, supports: readonly Variant.Support[]) =>
Variant.resolve(input, supports).map((item) => ({ ...item, id: String(item.id) }))
test("spells Messages variants for each provider", () => {
expect(
resolve(model("@opencode/ai/providers/anthropic", "claude-opus-4-5"), [
{ type: "effort", values: ["low", "high"] },
{ type: "budget_tokens", min: 1024 },
]),
).toEqual([
{
id: "low",
settings: { effort: "low", thinking: { type: "enabled", budgetTokens: 16_000 } },
},
{
id: "high",
settings: { effort: "high", thinking: { type: "enabled", budgetTokens: 16_000 } },
},
])
expect(
resolve(model("@opencode/ai/providers/anthropic", "claude-opus-4-8"), [{ type: "effort", values: ["low", "max"] }]),
).toEqual([
{ id: "low", settings: { effort: "low", thinking: { type: "adaptive", display: "summarized" } } },
{ id: "max", settings: { effort: "max", thinking: { type: "adaptive", display: "summarized" } } },
])
expect(resolve(model("@opencode/ai/providers/minimax/messages", "MiniMax-M3"), [{ type: "toggle" }])).toEqual([
{ id: "none", settings: { thinking: { type: "disabled" } } },
{ id: "thinking", settings: { thinking: { type: "adaptive" } } },
])
expect(
resolve(model("@opencode/ai/providers/moonshot/messages", "k3"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "high", "max"] },
]),
).toEqual([
{ id: "low", settings: { effort: "low" } },
{ id: "high", settings: { effort: "high" } },
{ id: "max", settings: { effort: "max" } },
])
expect(
resolve(model("@opencode/ai/providers/alibaba/messages", "qwen3.8-max"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "medium", "xhigh"] },
{ type: "budget_tokens", min: 1024, max: 262_144 },
]),
).toEqual([
{ id: "none", settings: { thinking: { type: "disabled" } } },
{ id: "low", settings: { effort: "low", thinking: { type: "enabled" } } },
{ id: "medium", settings: { effort: "medium", thinking: { type: "enabled" } } },
{ id: "xhigh", settings: { effort: "xhigh", thinking: { type: "enabled" } } },
])
expect(
resolve(model("@opencode/ai/providers/zai-coding-plan/messages", "glm-5.3"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "high", "max"] },
{ type: "budget_tokens", min: 1024 },
]),
).toEqual([
{ id: "low", settings: { effort: "low", thinking: { type: "enabled" } } },
{ id: "high", settings: { effort: "high", thinking: { type: "enabled" } } },
{ id: "max", settings: { effort: "max", thinking: { type: "enabled" } } },
])
})
test("recognizes Claude version spellings and future models", () => {
for (const id of ["claude-sonnet-3.7", "claude-sonnet-3-7", "claude-3.7-sonnet", "claude-3-7-sonnet"])
expect(resolve(model("@opencode/ai/providers/anthropic", id), [{ type: "effort" }])).toEqual([
{ id: "high", settings: { thinking: { type: "enabled", budgetTokens: 16000 } } },
{ id: "max", settings: { thinking: { type: "enabled", budgetTokens: 31999 } } },
])
expect(resolve(model("@opencode/ai/providers/anthropic", "claude-opus-6"), [{ type: "effort" }])).toEqual(
["low", "medium", "high", "xhigh", "max"].map((effort) => ({
id: effort,
settings: { effort, thinking: { type: "adaptive", display: "summarized" } },
})),
)
expect(
resolve(model("@opencode/ai/providers/anthropic", "claude-haiku-4-5", 64_000), [
{ type: "budget_tokens", min: 1_024, max: 64_000 },
]),
).toEqual([
{ id: "high", settings: { thinking: { type: "enabled", budgetTokens: 16_000 } } },
{ id: "max", settings: { thinking: { type: "enabled", budgetTokens: 31_999 } } },
])
})
test("spells Cloudflare AI Gateway variants for their upstream routes", () => {
const pkg = "@opencode/ai/providers/cloudflare-ai-gateway"
expect(resolve(model(pkg, "openai/gpt-5.4"), [{ type: "effort", values: ["low", "xhigh"] }])).toEqual([
{
id: "low",
settings: { reasoningEffort: "low", reasoningSummary: "auto", include: ["reasoning.encrypted_content"] },
},
{
id: "xhigh",
settings: { reasoningEffort: "xhigh", reasoningSummary: "auto", include: ["reasoning.encrypted_content"] },
},
])
expect(resolve(model(pkg, "anthropic/claude-sonnet-4-6"), [{ type: "effort", values: ["low", "high"] }])).toEqual([
{ id: "low", settings: { effort: "low", thinking: { type: "adaptive", display: "summarized" } } },
{ id: "high", settings: { effort: "high", thinking: { type: "adaptive", display: "summarized" } } },
])
expect(resolve(model(pkg, "xai/grok-4.6"), [{ type: "effort", values: ["low", "high"] }])).toEqual([
{ id: "low", settings: { reasoningEffort: "low" } },
{ id: "high", settings: { reasoningEffort: "high" } },
])
})
test("spells xAI Responses variants with catalog effort levels", () => {
const supports: Variant.Support[] = [{ type: "effort", values: ["low", "medium", "high", "xhigh"] }]
expect(resolve(model("@opencode/ai/providers/xai", "grok-4.6"), supports)).toEqual(
["low", "medium", "high", "xhigh"].map((effort) => ({
id: effort,
settings: { reasoningEffort: effort, reasoningSummary: "auto", include: ["reasoning.encrypted_content"] },
})),
)
expect(resolve(model("@opencode/ai/providers/xai", "grok-4.3"), [{ type: "effort", values: ["none", "low"] }])).toEqual([
{
id: "none",
settings: { reasoningEffort: "none", reasoningSummary: "auto", include: ["reasoning.encrypted_content"] },
},
{ id: "low", settings: { reasoningEffort: "low", reasoningSummary: "auto", include: ["reasoning.encrypted_content"] } },
])
expect(resolve(model("@opencode/ai/providers/xai", "grok-4.6"), [{ type: "effort" }]).map((item) => item.id)).toEqual([
"low", "medium", "high",
])
})
test("spells Chat Completions variants for direct providers", () => {
expect(
resolve(model("@opencode/ai/providers/deepseek", "deepseek-v4-flash"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "high", "max"] },
]),
).toEqual([
{ id: "none", body: { thinking: { type: "disabled" } } },
{ id: "low", settings: { reasoningEffort: "low" }, body: { thinking: { type: "enabled" } } },
{ id: "high", settings: { reasoningEffort: "high" }, body: { thinking: { type: "enabled" } } },
{ id: "max", settings: { reasoningEffort: "max" }, body: { thinking: { type: "enabled" } } },
])
expect(
resolve(model("@opencode/ai/providers/moonshot/chat", "kimi-k3"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "high", "max"] },
]),
).toEqual([
{ id: "low", settings: { reasoningEffort: "low" } },
{ id: "high", settings: { reasoningEffort: "high" } },
{ id: "max", settings: { reasoningEffort: "max" } },
])
expect(resolve(model("@opencode/ai/providers/moonshot/chat", "kimi-k2.6"), [{ type: "toggle" }])).toEqual([
{ id: "none", settings: { thinking: { type: "disabled" } } },
{ id: "thinking", settings: { thinking: { type: "enabled" } } },
])
expect(
resolve(model("@opencode/ai/providers/alibaba/chat", "qwen3.8-max"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "medium", "xhigh"] },
{ type: "budget_tokens", min: 0, max: 262_144 },
]),
).toEqual([
{ id: "none", settings: { enableThinking: false } },
{ id: "low", settings: { enableThinking: true, reasoningEffort: "low" } },
{ id: "medium", settings: { enableThinking: true, reasoningEffort: "medium" } },
{ id: "xhigh", settings: { enableThinking: true, reasoningEffort: "xhigh" } },
])
expect(
resolve(model("@opencode/ai/providers/alibaba/chat", "qwen3.7-plus", 300_000), [
{ type: "toggle" },
{ type: "budget_tokens", min: 0, max: 262_144 },
]),
).toEqual([
{ id: "none", settings: { enableThinking: false } },
{ id: "high", settings: { enableThinking: true, thinkingBudget: 32_000 } },
{ id: "max", settings: { enableThinking: true, thinkingBudget: 63_999 } },
])
expect(
resolve(model("@opencode/ai/providers/zai/chat", "glm-5.3"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "high", "max"] },
]),
).toEqual([
{ id: "low", settings: { thinking: { type: "enabled", clear_thinking: false }, reasoningEffort: "low" } },
{ id: "high", settings: { thinking: { type: "enabled", clear_thinking: false }, reasoningEffort: "high" } },
{ id: "max", settings: { thinking: { type: "enabled", clear_thinking: false }, reasoningEffort: "max" } },
])
expect(resolve(model("@opencode/ai/providers/zai/chat", "glm-4.7"), [{ type: "toggle" }])).toEqual([
{ id: "none", settings: { thinking: { type: "disabled" } } },
{ id: "thinking", settings: { thinking: { type: "enabled", clear_thinking: false } } },
])
})
test("spells Bedrock Converse Claude budgets as a thinking setting", () => {
expect(
resolve(model("@opencode/ai/providers/amazon-bedrock", "us.anthropic.claude-haiku-4-5-20251001-v1:0", 64_000), [
{ type: "budget_tokens", min: 1024 },
]),
).toEqual([
{ id: "high", settings: { thinking: { type: "enabled", budgetTokens: 16_000 } } },
{ id: "max", settings: { thinking: { type: "enabled", budgetTokens: 31_999 } } },
])
})
test("spells Bedrock Converse effort for Grok and Nova", () => {
const supports: Variant.Support[] = [{ type: "effort", values: ["low", "xhigh"] }]
expect(resolve(model("@opencode/ai/providers/amazon-bedrock", "us.xai.grok-4.6"), supports)).toEqual([
{ id: "low", body: { additionalModelRequestFields: { reasoning: { effort: "low" } } } },
{ id: "xhigh", body: { additionalModelRequestFields: { reasoning: { effort: "xhigh" } } } },
])
expect(resolve(model("@opencode/ai/providers/amazon-bedrock", "us.amazon.nova-2-lite-v1:0"), supports)).toEqual([
{
id: "low",
body: { additionalModelRequestFields: { reasoningConfig: { type: "enabled", maxReasoningEffort: "low" } } },
},
{
id: "xhigh",
body: { additionalModelRequestFields: { reasoningConfig: { type: "enabled", maxReasoningEffort: "xhigh" } } },
},
])
})
test("caps Alibaba thinking budget variants at 64k", () => {
const supports: Variant.Support[] = [{ type: "toggle" }, { type: "budget_tokens" }]
expect(resolve(model("@opencode/ai/providers/alibaba/chat", "kimi-k2.6", 262_144), supports)).toEqual([
{ id: "none", settings: { enableThinking: false } },
{ id: "high", settings: { enableThinking: true, thinkingBudget: 32_000 } },
{ id: "max", settings: { enableThinking: true, thinkingBudget: 63_999 } },
])
expect(resolve(model("@opencode/ai/providers/alibaba/messages", "kimi-k2.6", 262_144), supports)).toEqual([
{ id: "none", settings: { thinking: { type: "disabled" } } },
{ id: "high", settings: { thinking: { type: "enabled", budgetTokens: 32_000 } } },
{ id: "max", settings: { thinking: { type: "enabled", budgetTokens: 63_999 } } },
])
expect(resolve(model("@opencode/ai/providers/alibaba/chat", "kimi-k2.5", 32_768), supports)).toEqual([
{ id: "none", settings: { enableThinking: false } },
{ id: "high", settings: { enableThinking: true, thinkingBudget: 16_384 } },
{ id: "max", settings: { enableThinking: true, thinkingBudget: 32_767 } },
])
})
test("spells Workers AI thinking controls through the chat template", () => {
const pkg = "@opencode/ai/providers/cloudflare-workers-ai"
const off = { body: { chat_template_kwargs: { enable_thinking: false, thinking: false } } }
const on = { body: { chat_template_kwargs: { enable_thinking: true, thinking: true } } }
expect(
resolve(model(pkg, "@cf/deepseek-ai/deepseek-v4-flash-0731"), [
{ type: "effort", values: ["none", "low", "high", "max"] },
]),
).toEqual([
{ id: "none", ...off },
{ id: "low", settings: { reasoningEffort: "low" } },
{ id: "high", settings: { reasoningEffort: "high" } },
{ id: "max", settings: { reasoningEffort: "max" } },
])
expect(resolve(model(pkg, "@cf/zai-org/glm-4.7-flash"), [{ type: "toggle" }])).toEqual([
{ id: "none", ...off },
{ id: "thinking", ...on },
])
expect(
resolve(model(pkg, "@cf/qwen/qwen3.8-27b"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "medium", "xhigh"] },
]),
).toEqual([
{ id: "none", ...off },
{ id: "low", settings: { reasoningEffort: "low" } },
{ id: "medium", settings: { reasoningEffort: "medium" } },
{ id: "xhigh", settings: { reasoningEffort: "xhigh" } },
])
})
test("spells Chat Completions variants for hosting providers", () => {
expect(
resolve(model("@opencode/ai/providers/openai-compatible", "deepseek-ai/deepseek-v4-pro", undefined, "nvidia"), [
{ type: "effort", values: ["none", "high", "max"] },
]),
).toEqual([
{ id: "none", body: { chat_template_kwargs: { thinking: false } } },
{ id: "high", body: { chat_template_kwargs: { thinking: true, reasoning_effort: "high" } } },
{ id: "max", body: { chat_template_kwargs: { thinking: true, reasoning_effort: "max" } } },
])
expect(
resolve(model("@opencode/ai/providers/openai-compatible", "moonshotai/kimi-k2.6", undefined, "nvidia"), [
{ type: "effort", values: ["none", "low", "high", "max"] },
]),
).toEqual([
{ id: "none", body: { chat_template_kwargs: { thinking: false } } },
{ id: "thinking", body: { chat_template_kwargs: { thinking: true } } },
])
expect(
resolve(model("@opencode/ai/providers/openai-compatible", "moonshotai/kimi-k3", undefined, "nvidia"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "high", "max"] },
]),
).toEqual([
{ id: "none", body: { chat_template_kwargs: { thinking: false } } },
{ id: "low", settings: { reasoningEffort: "low" } },
{ id: "high", settings: { reasoningEffort: "high" } },
{ id: "max", settings: { reasoningEffort: "max" } },
])
expect(
resolve(model("@opencode/ai/providers/openai-compatible", "minimaxai/minimax-m3", undefined, "nvidia"), [
{ type: "toggle" },
]),
).toEqual([
{ id: "none", body: { chat_template_kwargs: { thinking_mode: "disabled" } } },
{ id: "thinking", body: { chat_template_kwargs: { thinking_mode: "enabled" } } },
])
expect(
resolve(model("@opencode/ai/providers/baseten", "zai-org/GLM-5.2"), [
{ type: "effort", values: ["none", "high", "max"] },
]),
).toEqual([
{
id: "none",
settings: { reasoningEffort: "none" },
body: { chat_template_args: { enable_thinking: false } },
},
{
id: "high",
settings: { reasoningEffort: "high" },
body: { chat_template_args: { enable_thinking: true } },
},
{
id: "max",
settings: { reasoningEffort: "max" },
body: { chat_template_args: { enable_thinking: true } },
},
])
expect(resolve(model("@opencode/ai/providers/baseten", "moonshotai/Kimi-K2.6"), [{ type: "toggle" }])).toEqual([
{ id: "none", body: { chat_template_args: { enable_thinking: false } } },
{ id: "thinking", body: { chat_template_args: { enable_thinking: true } } },
])
expect(
resolve(model("@opencode/ai/providers/deepinfra", "zai-org/GLM-5.2"), [
{ type: "toggle" },
{ type: "effort", values: ["low", "high", "xhigh"] },
]),
).toEqual([
{ id: "none", body: { reasoning: { enabled: false } } },
{ id: "low", settings: { reasoningEffort: "low" } },
{ id: "high", settings: { reasoningEffort: "high" } },
{ id: "xhigh", settings: { reasoningEffort: "xhigh" } },
])
})