fix: ensure variants can be disabled

This commit is contained in:
Aiden Cline
2025-12-30 16:12:01 -06:00
parent 5e1986c0bc
commit 938a53b5a2
8 changed files with 87 additions and 25 deletions

View File

@@ -8,6 +8,27 @@
"provider": {
"opencode": {
"options": {},
"models": {
"claude-haiku-4-5": {
"variants": {
"high": {
"disabled": true,
},
"max": {
"disabled": true,
},
},
},
"custom-model": {
"variants": {
"special": {
"This is special": {
"so": true,
},
},
},
},
},
},
},
"mcp": {},

View File

@@ -2,6 +2,10 @@
- To test opencode in the `packages/opencode` directory you can run `bun dev`
## SDK
To regenerate the javascript SDK, run ./packages/sdk/js/script/build.ts
## Tool Calling
- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE.

View File

@@ -620,7 +620,24 @@ export namespace Config {
.extend({
whitelist: z.array(z.string()).optional(),
blacklist: z.array(z.string()).optional(),
models: z.record(z.string(), ModelsDev.Model.partial()).optional(),
models: z
.record(
z.string(),
ModelsDev.Model.partial().extend({
variants: z
.record(
z.string(),
z
.object({
disabled: z.boolean().optional().describe("Disable this variant for the model"),
})
.catchall(z.any()),
)
.optional()
.describe("Variant-specific configuration"),
}),
)
.optional(),
options: z
.object({
apiKey: z.string().optional(),

View File

@@ -60,6 +60,7 @@ export namespace ModelsDev {
options: z.record(z.string(), z.any()),
headers: z.record(z.string(), z.string()).optional(),
provider: z.object({ npm: z.string() }).optional(),
variants: z.record(z.string(), z.record(z.string(), z.any())).optional(),
})
export type Model = z.infer<typeof Model>

View File

@@ -1,7 +1,7 @@
import z from "zod"
import fuzzysort from "fuzzysort"
import { Config } from "../config/config"
import { mapValues, mergeDeep, sortBy } from "remeda"
import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda"
import { NoSuchModelError, type Provider as SDK } from "ai"
import { Log } from "../util/log"
import { BunProc } from "../bun"
@@ -405,16 +405,6 @@ export namespace Provider {
},
}
export const Variant = z
.object({
disabled: z.boolean(),
})
.catchall(z.any())
.meta({
ref: "Variant",
})
export type Variant = z.infer<typeof Variant>
export const Model = z
.object({
id: z.string(),
@@ -478,7 +468,7 @@ export namespace Provider {
options: z.record(z.string(), z.any()),
headers: z.record(z.string(), z.string()),
release_date: z.string(),
variants: z.record(z.string(), Variant).optional(),
variants: z.record(z.string(), z.record(z.string(), z.any())).optional(),
})
.meta({
ref: "Model",
@@ -561,7 +551,7 @@ export namespace Provider {
variants: {},
}
m.variants = mapValues(ProviderTransform.variants(m), (v) => ({ disabled: false, ...v }))
m.variants = mapValues(ProviderTransform.variants(m), (v) => v)
return m
}
@@ -699,7 +689,11 @@ export namespace Provider {
release_date: model.release_date ?? existingModel?.release_date ?? "",
variants: {},
}
parsedModel.variants = mapValues(ProviderTransform.variants(parsedModel), (v) => ({ disabled: false, ...v }))
const merged = mergeDeep(ProviderTransform.variants(parsedModel), model.variants ?? {})
parsedModel.variants = mapValues(
pickBy(merged, (v) => !v.disabled),
(v) => omit(v, ["disabled"]),
)
parsed.models[modelID] = parsedModel
}
database[providerID] = parsed
@@ -824,6 +818,16 @@ export namespace Provider {
(configProvider?.whitelist && !configProvider.whitelist.includes(modelID))
)
delete provider.models[modelID]
// Filter out disabled variants from config
const configVariants = configProvider?.models?.[modelID]?.variants
if (configVariants && model.variants) {
const merged = mergeDeep(model.variants, configVariants)
model.variants = mapValues(
pickBy(merged, (v) => !v.disabled),
(v) => omit(v, ["disabled"]),
)
}
}
if (Object.keys(provider.models).length === 0) {

View File

@@ -246,7 +246,7 @@ export namespace ProviderTransform {
const WIDELY_SUPPORTED_EFFORTS = ["low", "medium", "high"]
const OPENAI_EFFORTS = ["none", "minimal", ...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
export function variants(model: Provider.Model) {
export function variants(model: Provider.Model): Record<string, Record<string, any>> {
if (!model.capabilities.reasoning) return {}
const id = model.id.toLowerCase()

View File

@@ -82,13 +82,14 @@ export namespace LLM {
}
const provider = await Provider.getProvider(input.model.providerID)
const variant = input.model.variants && input.user.variant ? input.model.variants[input.user.variant] : undefined
const small = input.small ? ProviderTransform.smallOptions(input.model) : {}
const variant = input.model.variants && input.user.variant ? input.model.variants[input.user.variant] : {}
const options = pipe(
ProviderTransform.options(input.model, input.sessionID, provider.options),
mergeDeep(input.small ? ProviderTransform.smallOptions(input.model) : {}),
mergeDeep(small),
mergeDeep(input.model.options),
mergeDeep(input.agent.options),
mergeDeep(variant && !variant.disabled ? variant : {}),
mergeDeep(variant),
)
const params = await Plugin.trigger(

View File

@@ -1309,6 +1309,18 @@ export type ProviderConfig = {
provider?: {
npm: string
}
/**
* Variant-specific configuration
*/
variants?: {
[key: string]: {
/**
* Disable this variant for the model
*/
disabled?: boolean
[key: string]: unknown | boolean | undefined
}
}
}
}
whitelist?: Array<string>
@@ -1717,11 +1729,6 @@ export type Command = {
subtask?: boolean
}
export type Variant = {
disabled: boolean
[key: string]: unknown | boolean
}
export type Model = {
id: string
providerID: string
@@ -1786,7 +1793,9 @@ export type Model = {
}
release_date: string
variants?: {
[key: string]: Variant
[key: string]: {
[key: string]: unknown
}
}
}
@@ -3497,6 +3506,11 @@ export type ProviderListResponses = {
provider?: {
npm: string
}
variants?: {
[key: string]: {
[key: string]: unknown
}
}
}
}
}>