fix(core): load and spell reasoning for every native provider package (#55789)

This commit is contained in:
Aiden Cline
2026-10-15 15:34:08 -05:00
committed by GitHub
Unverified
parent fe87944b6a
commit 412b2b1d85
7 changed files with 195 additions and 55 deletions
+16 -21
View File
@@ -32,15 +32,12 @@ export function rewrite<ID extends string>(
const replacement = resolve(input.specifier, { ...input, settings }) ?? plain
const translated = options(replacement, input.modelID, settings)
if (target.package !== undefined || replacement !== input.specifier) target.package = replacement
target.settings =
target.settings === undefined
? undefined
: {
...translated.settings,
...(!NATIVE.has(input.specifier) && replacement === "@opencode/ai/providers/openai-compatible"
? { provider: input.canonical ?? input.providerID }
: {}),
}
// Without `provider`, the native compatible package reports every AI SDK-mapped host as `openai-compatible`.
const identity =
replacement === "@opencode/ai/providers/openai-compatible" && !Provider.builtinPackages.has(input.specifier)
? { provider: input.canonical ?? input.providerID }
: {}
target.settings = target.settings === undefined ? undefined : { ...translated.settings, ...identity }
target.headers = Provider.mergeHeaders(translated.headers, target.headers)
target.body = Provider.mergeOverlay(translated.body, target.body)
target.variants = target.variants?.map((variant) => {
@@ -122,15 +119,6 @@ const HOSTS: Readonly<Record<string, Readonly<Record<string, string>>>> = {
"zhipuai-coding-plan": protocols("zai-coding-plan"),
}
const NATIVE = new Set([
...Object.values(PACKAGES),
...Object.values(HOSTS).flatMap((host) => Object.values(host)),
"@opencode/ai/providers/azure/chat",
"@opencode/ai/providers/amazon-bedrock/mantle",
"@opencode/ai/providers/amazon-bedrock/mantle/chat",
"@opencode/ai/providers/amazon-bedrock/mantle/responses",
])
export function native(npm: string, context: Context & { readonly settings?: Provider.Settings }): string | undefined {
const host = HOSTS[context.providerID]?.[npm]
if (host) return host
@@ -142,8 +130,10 @@ export function native(npm: string, context: Context & { readonly settings?: Pro
const azureChat = (context: Context & { readonly settings?: Provider.Settings }) =>
context.shape === "completions" || context.settings?.useCompletionUrls === true
// Mantle serves Claude only through Anthropic Messages and GPT-OSS only through Chat.
const mantle = (modelID: string | undefined) => {
if (modelID === undefined) return "@opencode/ai/providers/amazon-bedrock/mantle"
if (modelID.includes("anthropic.")) return "@opencode/ai/providers/amazon-bedrock/mantle/messages"
return `@opencode/ai/providers/amazon-bedrock/mantle/${modelID.includes("gpt-oss") ? "chat" : "responses"}`
}
@@ -151,9 +141,14 @@ function resolve(specifier: string, context: Context & { readonly settings?: Pro
const npm = Provider.packageName(specifier)
if (Provider.isAISDK(specifier) || npm in PACKAGES || npm in (HOSTS[context.providerID] ?? {}))
return native(npm, context)
if (npm === "@opencode/ai/providers/amazon-bedrock/mantle") return mantle(context.modelID)
if (npm === "@opencode/ai/providers/azure/responses" && azureChat(context)) return "@opencode/ai/providers/azure/chat"
return NATIVE.has(npm) ? npm : undefined
if (npm === "@opencode/ai/providers/amazon-bedrock/mantle" || npm === "@opencode/ai/providers/amazon-bedrock-mantle")
return mantle(context.modelID)
if (
(npm === "@opencode/ai/providers/azure" || npm === "@opencode/ai/providers/azure/responses") &&
azureChat(context)
)
return "@opencode/ai/providers/azure/chat"
return Provider.builtinPackages.has(npm) ? npm : undefined
}
type Overlay = {
+36 -5
View File
@@ -46,19 +46,25 @@ export type ProviderPackage = ProviderPackageDefinition
const packages = new Map<string, Promise<unknown>>()
const builtins = new Map<string, () => Promise<unknown>>([
["@opencode/ai/providers/alibaba", () => import("@opencode/ai/providers/alibaba")],
["@opencode/ai/providers/alibaba/chat", () => import("@opencode/ai/providers/alibaba/chat")],
["@opencode/ai/providers/alibaba/messages", () => import("@opencode/ai/providers/alibaba/messages")],
["@opencode/ai/providers/alibaba/responses", () => import("@opencode/ai/providers/alibaba/responses")],
["@opencode/ai/providers/amazon-bedrock", () => import("@opencode/ai/providers/amazon-bedrock")],
["@opencode/ai/providers/amazon-bedrock/mantle", () => import("@opencode/ai/providers/amazon-bedrock/mantle")],
[
"@opencode/ai/providers/amazon-bedrock/mantle/chat",
() => import("@opencode/ai/providers/amazon-bedrock/mantle/chat"),
],
[
"@opencode/ai/providers/amazon-bedrock/mantle/messages",
() => import("@opencode/ai/providers/amazon-bedrock/mantle/messages"),
],
[
"@opencode/ai/providers/amazon-bedrock/mantle/responses",
() => import("@opencode/ai/providers/amazon-bedrock/mantle/responses"),
],
["@opencode/ai/providers/alibaba/chat", () => import("@opencode/ai/providers/alibaba/chat")],
["@opencode/ai/providers/alibaba/messages", () => import("@opencode/ai/providers/alibaba/messages")],
["@opencode/ai/providers/alibaba/responses", () => import("@opencode/ai/providers/alibaba/responses")],
["@opencode/ai/providers/amazon-bedrock-mantle", () => import("@opencode/ai/providers/amazon-bedrock-mantle")],
["@opencode/ai/providers/anthropic", () => import("@opencode/ai/providers/anthropic")],
["@opencode/ai/providers/anthropic-compatible", () => import("@opencode/ai/providers/anthropic-compatible")],
["@opencode/ai/providers/azure", () => import("@opencode/ai/providers/azure")],
@@ -77,23 +83,34 @@ const builtins = new Map<string, () => Promise<unknown>>([
["@opencode/ai/providers/google", () => import("@opencode/ai/providers/google")],
["@opencode/ai/providers/google/interactions", () => import("@opencode/ai/providers/google/interactions")],
["@opencode/ai/providers/google-vertex", () => import("@opencode/ai/providers/google-vertex")],
["@opencode/ai/providers/google-vertex/chat", () => import("@opencode/ai/providers/google-vertex/chat")],
["@opencode/ai/providers/google-vertex/gemini", () => import("@opencode/ai/providers/google-vertex/gemini")],
[
"@opencode/ai/providers/google-vertex/interactions",
() => import("@opencode/ai/providers/google-vertex/interactions"),
],
["@opencode/ai/providers/google-vertex/chat", () => import("@opencode/ai/providers/google-vertex/chat")],
["@opencode/ai/providers/google-vertex/responses", () => import("@opencode/ai/providers/google-vertex/responses")],
["@opencode/ai/providers/google-vertex/messages", () => import("@opencode/ai/providers/google-vertex/messages")],
["@opencode/ai/providers/google-vertex/mistral", () => import("@opencode/ai/providers/google-vertex/mistral")],
["@opencode/ai/providers/google-vertex/responses", () => import("@opencode/ai/providers/google-vertex/responses")],
["@opencode/ai/providers/google-vertex-chat", () => import("@opencode/ai/providers/google-vertex-chat")],
[
"@opencode/ai/providers/google-vertex-interactions",
() => import("@opencode/ai/providers/google-vertex-interactions"),
],
["@opencode/ai/providers/google-vertex-messages", () => import("@opencode/ai/providers/google-vertex-messages")],
["@opencode/ai/providers/google-vertex-mistral", () => import("@opencode/ai/providers/google-vertex-mistral")],
["@opencode/ai/providers/google-vertex-responses", () => import("@opencode/ai/providers/google-vertex-responses")],
["@opencode/ai/providers/groq", () => import("@opencode/ai/providers/groq")],
["@opencode/ai/providers/meta", () => import("@opencode/ai/providers/meta")],
["@opencode/ai/providers/meta/chat", () => import("@opencode/ai/providers/meta/chat")],
["@opencode/ai/providers/meta/messages", () => import("@opencode/ai/providers/meta/messages")],
["@opencode/ai/providers/meta/responses", () => import("@opencode/ai/providers/meta/responses")],
["@opencode/ai/providers/minimax", () => import("@opencode/ai/providers/minimax")],
["@opencode/ai/providers/minimax/chat", () => import("@opencode/ai/providers/minimax/chat")],
["@opencode/ai/providers/minimax/messages", () => import("@opencode/ai/providers/minimax/messages")],
["@opencode/ai/providers/minimax/responses", () => import("@opencode/ai/providers/minimax/responses")],
["@opencode/ai/providers/mistral", () => import("@opencode/ai/providers/mistral")],
["@opencode/ai/providers/moonshot", () => import("@opencode/ai/providers/moonshot")],
["@opencode/ai/providers/moonshot/chat", () => import("@opencode/ai/providers/moonshot/chat")],
["@opencode/ai/providers/moonshot/messages", () => import("@opencode/ai/providers/moonshot/messages")],
["@opencode/ai/providers/moonshot/responses", () => import("@opencode/ai/providers/moonshot/responses")],
@@ -113,8 +130,19 @@ const builtins = new Map<string, () => Promise<unknown>>([
["@opencode/ai/providers/togetherai", () => import("@opencode/ai/providers/togetherai")],
["@opencode/ai/providers/venice", () => import("@opencode/ai/providers/venice")],
["@opencode/ai/providers/vercel-ai-gateway", () => import("@opencode/ai/providers/vercel-ai-gateway")],
["@opencode/ai/providers/vercel-ai-gateway/chat", () => import("@opencode/ai/providers/vercel-ai-gateway/chat")],
[
"@opencode/ai/providers/vercel-ai-gateway/messages",
() => import("@opencode/ai/providers/vercel-ai-gateway/messages"),
],
[
"@opencode/ai/providers/vercel-ai-gateway/responses",
() => import("@opencode/ai/providers/vercel-ai-gateway/responses"),
],
["@opencode/ai/providers/xai", () => import("@opencode/ai/providers/xai")],
["@opencode/ai/providers/zai", () => import("@opencode/ai/providers/zai")],
["@opencode/ai/providers/zai/chat", () => import("@opencode/ai/providers/zai/chat")],
["@opencode/ai/providers/zai-coding-plan", () => import("@opencode/ai/providers/zai-coding-plan")],
["@opencode/ai/providers/zai-coding-plan/chat", () => import("@opencode/ai/providers/zai-coding-plan/chat")],
["@opencode/ai/providers/zai-coding-plan/messages", () => import("@opencode/ai/providers/zai-coding-plan/messages")],
[
@@ -123,6 +151,9 @@ const builtins = new Map<string, () => Promise<unknown>>([
],
])
/** Native `@opencode/ai/providers/*` entrypoints bundled with Core and loadable by name from config. */
export const builtinPackages: ReadonlySet<string> = new Set(builtins.keys())
export const loadPackage = Effect.fn("Provider.loadPackage")(function* (input: string, npm?: Npm.Interface) {
const specifier = packageName(input)
const builtin = builtins.get(specifier)
+51 -7
View File
@@ -99,11 +99,18 @@ const responsesEffort = (effort: string): Overlay => ({
settings: { reasoningEffort: effort, reasoningSummary: "auto", include: ENCRYPTED_REASONING },
})
const xaiResponses: Protocol = (_, support) => {
const openResponses: Protocol = (_, support) => {
if (support.type !== "effort") return []
return efforts(support.values ?? EFFORTS, responsesEffort)
}
const googleInteractions: Protocol = (_, support) => {
if (support.type !== "effort") return []
return efforts(support.values ?? EFFORTS, (effort) => ({
settings: { thinkingLevel: effort, thinkingSummaries: "auto" },
}))
}
const cloudflareAIGateway: Protocol = (model, support) => {
const id = modelID(model)
if (id.startsWith("openai/")) return openaiResponses(model, support)
@@ -466,8 +473,17 @@ const cohere: Protocol = (model, support) => {
const vercelGateway: Protocol = (model, support) => {
const id = modelID(model)
if (id.startsWith("openai/gpt-")) return openaiResponses(model, support)
if (id.startsWith("spacexai/grok-")) return xaiResponses(model, support)
if (id.startsWith("anthropic/")) return anthropicMessages(model, support)
if (id.startsWith("spacexai/grok-")) return openResponses(model, support)
return vercelMessages(model, support)
}
const vercelResponses: Protocol = (model, support) =>
modelID(model).startsWith("openai/gpt-") ? openaiResponses(model, support) : openResponses(model, support)
const vercelMessages: Protocol = (model, support) =>
modelID(model).startsWith("anthropic/") ? anthropicMessages(model, support) : vercelChat(model, support)
const vercelChat: Protocol = (model, support) => {
switch (support.type) {
case "effort":
return openaiChat(model, support)
@@ -478,7 +494,7 @@ const vercelGateway: Protocol = (model, support) => {
model,
support,
(tokens) => ({ settings: { thinking: { type: "enabled", budgetTokens: tokens } } }),
id.startsWith("alibaba/") ? ALIBABA_THINKING_BUDGET_MAX : model.limit.output,
modelID(model).startsWith("alibaba/") ? ALIBABA_THINKING_BUDGET_MAX : model.limit.output,
)
}
}
@@ -576,18 +592,32 @@ const gitlab: Protocol = (model, support) => {
const PROTOCOLS: Readonly<Record<string, Protocol>> = {
"@opencode/ai/providers/openai": openaiResponses,
"@opencode/ai/providers/openai/responses": openaiResponses,
"@opencode/ai/providers/azure": openaiResponses,
"@opencode/ai/providers/azure/responses": openaiResponses,
"@opencode/ai/providers/amazon-bedrock/mantle/chat": openaiResponses,
"@opencode/ai/providers/amazon-bedrock/mantle": openaiResponses,
"@opencode/ai/providers/amazon-bedrock/mantle/responses": openaiResponses,
"@opencode/ai/providers/amazon-bedrock-mantle": openaiResponses,
"@opencode/ai/providers/alibaba/responses": openaiResponses,
"@opencode/ai/providers/meta": openaiResponses,
"@opencode/ai/providers/meta/responses": openaiResponses,
"@opencode/ai/providers/minimax/responses": openaiResponses,
"@opencode/ai/providers/moonshot/responses": openaiResponses,
"@opencode/ai/providers/zai-coding-plan/responses": openaiResponses,
"@opencode/ai/providers/openai-compatible/responses": openResponses,
"@opencode/ai/providers/openai-compatible-responses": openResponses,
"@opencode/ai/providers/google-vertex/responses": openResponses,
"@opencode/ai/providers/google-vertex-responses": openResponses,
"@opencode/ai/providers/xai": openResponses,
"@opencode/ai/providers/openai-compatible": openaiCompatible,
"@opencode/ai/providers/openai/chat": openaiChat,
"@opencode/ai/providers/azure/chat": openaiChat,
"@opencode/ai/providers/amazon-bedrock/mantle/chat": openaiChat,
"@opencode/ai/providers/google-vertex/chat": vertexChat,
"@opencode/ai/providers/google-vertex-chat": vertexChat,
"@opencode/ai/providers/alibaba": alibabaChat,
"@opencode/ai/providers/alibaba/chat": alibabaChat,
"@opencode/ai/providers/baseten": basetenChat,
"@opencode/ai/providers/cerebras": openaiChat,
@@ -601,24 +631,35 @@ const PROTOCOLS: Readonly<Record<string, Protocol>> = {
"@opencode/ai/providers/meta/chat": openaiChat,
"@opencode/ai/providers/minimax/chat": openaiChat,
"@opencode/ai/providers/mistral": openaiChat,
"@opencode/ai/providers/google-vertex/mistral": openaiChat,
"@opencode/ai/providers/google-vertex-mistral": openaiChat,
"@opencode/ai/providers/moonshot": moonshotChat,
"@opencode/ai/providers/moonshot/chat": moonshotChat,
"@opencode/ai/providers/togetherai": openaiChat,
"@opencode/ai/providers/venice": veniceChat,
"@opencode/ai/providers/xai": xaiResponses,
"@opencode/ai/providers/zai": zaiChat,
"@opencode/ai/providers/zai/chat": zaiChat,
"@opencode/ai/providers/zai-coding-plan": zaiChat,
"@opencode/ai/providers/zai-coding-plan/chat": zaiChat,
"@opencode/ai/providers/anthropic": anthropicMessages,
"@opencode/ai/providers/anthropic-compatible": anthropicMessages,
"@opencode/ai/providers/amazon-bedrock/mantle/messages": anthropicMessages,
"@opencode/ai/providers/google-vertex/messages": anthropicMessages,
"@opencode/ai/providers/google-vertex/mistral": openaiChat,
"@opencode/ai/providers/google-vertex-messages": anthropicMessages,
"@opencode/ai/providers/alibaba/messages": alibabaMessages,
"@opencode/ai/providers/meta/messages": anthropicMessages,
"@opencode/ai/providers/minimax": minimaxMessages,
"@opencode/ai/providers/minimax/messages": minimaxMessages,
"@opencode/ai/providers/moonshot/messages": moonshotMessages,
"@opencode/ai/providers/zai-coding-plan/messages": zaiMessages,
"@opencode/ai/providers/google": gemini,
"@opencode/ai/providers/google-vertex": gemini,
"@opencode/ai/providers/google-vertex/gemini": gemini,
"@opencode/ai/providers/google/interactions": googleInteractions,
"@opencode/ai/providers/google-vertex/interactions": googleInteractions,
"@opencode/ai/providers/google-vertex-interactions": googleInteractions,
"@opencode/ai/providers/amazon-bedrock": bedrockConverse,
"@opencode/ai/providers/cohere": cohere,
@@ -627,6 +668,9 @@ const PROTOCOLS: Readonly<Record<string, Protocol>> = {
[Provider.aisdk("venice-ai-sdk-provider")]: veniceChat,
"@opencode/ai/providers/cloudflare-ai-gateway": cloudflareAIGateway,
"@opencode/ai/providers/vercel-ai-gateway": vercelGateway,
"@opencode/ai/providers/vercel-ai-gateway/chat": vercelChat,
"@opencode/ai/providers/vercel-ai-gateway/messages": vercelMessages,
"@opencode/ai/providers/vercel-ai-gateway/responses": vercelResponses,
[Provider.aisdk("@ai-sdk/gateway")]: vercelGateway,
[Provider.aisdk("@jerome-benoit/sap-ai-provider-v2")]: sapAICore,
[Provider.aisdk("gitlab-ai-provider")]: gitlab,
+30
View File
@@ -1,5 +1,6 @@
import { describe, expect, test } from "bun:test"
import { AISDKNative } from "@opencode/core/aisdk-native"
import { Provider } from "@opencode/core/provider"
function map(
packageName: string,
@@ -225,6 +226,35 @@ describe("AISDKNative", () => {
package: "@opencode/ai/providers/amazon-bedrock/mantle/chat",
settings: { region: "us-east-1" },
})
expect(
map("@ai-sdk/amazon-bedrock/mantle", { region: "us-east-1", profile: "sso" }, "anthropic.claude-opus-4-8"),
).toEqual({
package: "@opencode/ai/providers/amazon-bedrock/mantle/messages",
settings: { region: "us-east-1", profile: "sso" },
})
})
test("translates settings for every bundled native package named in config", () => {
const rewrite = (specifier: string, settings: Record<string, unknown>, modelID = "test-model") => {
const target: { package?: string; settings?: Record<string, unknown>; headers?: Record<string, string> } = {
package: specifier,
settings,
}
AISDKNative.rewrite(target, { specifier, providerID: "test-provider", modelID })
return target
}
for (const specifier of Provider.builtinPackages)
expect(rewrite(specifier, { headers: { "x-test": "value" } }).headers).toEqual({ "x-test": "value" })
expect(
rewrite("@opencode/ai/providers/amazon-bedrock/mantle", { bearerToken: "token" }, "anthropic.claude-opus-4-8"),
).toMatchObject({
package: "@opencode/ai/providers/amazon-bedrock/mantle/messages",
settings: { apiKey: "token" },
})
expect(rewrite("@opencode/ai/providers/azure", { useCompletionUrls: true }).package).toBe(
"@opencode/ai/providers/azure/chat",
)
})
test("maps Azure deployments and settings to native routes", () => {
+13 -22
View File
@@ -1,31 +1,22 @@
import { describe, expect, test } from "bun:test"
import path from "node:path"
import { Effect } from "effect"
import { Provider } from "@opencode/core/provider"
describe("Provider", () => {
test("loads bundled native provider entrypoints", async () => {
const packages = [
"@opencode/ai/providers/baseten",
"@opencode/ai/providers/cerebras",
"@opencode/ai/providers/cloudflare-ai-gateway",
"@opencode/ai/providers/cloudflare-workers-ai",
"@opencode/ai/providers/cohere",
"@opencode/ai/providers/cohere/chat",
"@opencode/ai/providers/deepinfra",
"@opencode/ai/providers/deepseek",
"@opencode/ai/providers/fireworks",
"@opencode/ai/providers/google-vertex",
"@opencode/ai/providers/google-vertex/gemini",
"@opencode/ai/providers/google-vertex/interactions",
"@opencode/ai/providers/google-vertex/chat",
"@opencode/ai/providers/google-vertex/responses",
"@opencode/ai/providers/google-vertex/messages",
"@opencode/ai/providers/groq",
"@opencode/ai/providers/mistral",
"@opencode/ai/providers/togetherai",
"@opencode/ai/providers/vercel-ai-gateway",
]
test("bundles every native provider entrypoint that exports model()", async () => {
const providers = path.join(import.meta.dir, "../../ai/src/providers")
const entrypoints = await Promise.all(
Array.from(new Bun.Glob("**/*.ts").scanSync(providers)).map(async (file) => {
const specifier = `@opencode/ai/providers/${file.replace(/\.ts$/, "")}`
const module = await import(specifier)
return typeof module.model === "function" ? specifier : undefined
}),
)
const packages = entrypoints.filter((specifier) => specifier !== undefined).toSorted()
expect(packages.filter((specifier) => !Provider.builtinPackages.has(specifier))).toEqual([])
expect(Array.from(Provider.builtinPackages).toSorted()).toEqual(packages)
for (const specifier of packages) {
const loaded = await Effect.runPromise(Provider.loadPackage(specifier))
expect(loaded.model).toBeFunction()
+48
View File
@@ -164,6 +164,17 @@ test("spells Vercel AI Gateway variants for their selected routes", () => {
{ id: "high", settings: { thinking: { type: "enabled", budgetTokens: 19_456 } } },
{ id: "max", settings: { thinking: { type: "enabled", budgetTokens: 38_911 } } },
])
expect(resolve(model(`${pkg}/chat`, "anthropic/claude-sonnet-4.6"), [{ type: "effort", values: ["high"] }])).toEqual([
{ id: "high", settings: { reasoningEffort: "high" } },
])
expect(
resolve(model(`${pkg}/messages`, "anthropic/claude-sonnet-4.6"), [{ type: "effort", values: ["high"] }]),
).toEqual([{ id: "high", settings: { effort: "high", thinking: { type: "adaptive", display: "summarized" } } }])
expect(resolve(model(`${pkg}/responses`, "spacexai/grok-4.7"), [{ type: "effort" }]).map((item) => item.id)).toEqual([
"low",
"medium",
"high",
])
})
test("spells xAI Responses variants with catalog effort levels", () => {
@@ -496,3 +507,40 @@ test("spells GitLab Duo variants for gitlab-ai-provider routes", () => {
expect(resolve(gitlab("duo-chat-gpt-5-4"), [])).toEqual([])
expect(resolve(gitlab("duo-workflow-opus-5-5"), [{ type: "effort" }])).toEqual([])
})
test("spells reasoning variants for every bundled native package", () => {
const supports: Variant.Support[] = [{ type: "toggle" }, { type: "effort" }, { type: "budget_tokens" }]
const missing = Array.from(Provider.builtinPackages).filter(
(packageName) => Variant.resolve(model(packageName, "test-model", 32_000), supports).length === 0,
)
expect(missing).toEqual([])
})
test("spells Mantle variants for the API each model is routed through", () => {
expect(
resolve(model("@opencode/ai/providers/amazon-bedrock/mantle/messages", "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/amazon-bedrock/mantle/chat", "openai.gpt-oss-120b"), [{ type: "effort" }]),
).toEqual([
{ id: "low", settings: { reasoningEffort: "low" } },
{ id: "medium", settings: { reasoningEffort: "medium" } },
{ id: "high", settings: { reasoningEffort: "high" } },
])
})
test("spells Google Interactions variants as thinking levels", () => {
for (const packageName of [
"@opencode/ai/providers/google/interactions",
"@opencode/ai/providers/google-vertex/interactions",
])
expect(resolve(model(packageName, "gemini-3.5-pro"), [{ type: "effort", values: ["low", "high"] }])).toEqual([
{ id: "low", settings: { thinkingLevel: "low", thinkingSummaries: "auto" } },
{ id: "high", settings: { thinkingLevel: "high", thinkingSummaries: "auto" } },
])
})
@@ -218,6 +218,7 @@ Native package options include:
- `@opencode/ai/providers/amazon-bedrock`
- `@opencode/ai/providers/amazon-bedrock/mantle`
- `@opencode/ai/providers/amazon-bedrock/mantle/chat`
- `@opencode/ai/providers/amazon-bedrock/mantle/messages`
- `@opencode/ai/providers/amazon-bedrock/mantle/responses`
- `@opencode/ai/providers/openrouter`
- `@opencode/ai/providers/xai`