Skip to content

Commit 81fef60

Browse files
fix: ensure variants also work for completely custom models (anomalyco#6481)
Co-authored-by: Daniel Smolsky <dannysmo@gmail.com>
1 parent 3fe5d91 commit 81fef60

File tree

10 files changed

+955
-27
lines changed

10 files changed

+955
-27
lines changed

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
- To test opencode in the `packages/opencode` directory you can run `bun dev`
44

5+
## SDK
6+
7+
To regenerate the javascript SDK, run ./packages/sdk/js/script/build.ts
8+
59
## Tool Calling
610

711
- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE.

packages/opencode/src/cli/cmd/tui/context/local.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
319319
const provider = sync.data.provider.find((x) => x.id === m.providerID)
320320
const info = provider?.models[m.modelID]
321321
if (!info?.variants) return []
322-
return Object.entries(info.variants)
323-
.filter(([_, v]) => !v.disabled)
324-
.map(([name]) => name)
322+
return Object.keys(info.variants)
325323
},
326324
set(value: string | undefined) {
327325
const m = currentModel()

packages/opencode/src/config/config.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,24 @@ export namespace Config {
620620
.extend({
621621
whitelist: z.array(z.string()).optional(),
622622
blacklist: z.array(z.string()).optional(),
623-
models: z.record(z.string(), ModelsDev.Model.partial()).optional(),
623+
models: z
624+
.record(
625+
z.string(),
626+
ModelsDev.Model.partial().extend({
627+
variants: z
628+
.record(
629+
z.string(),
630+
z
631+
.object({
632+
disabled: z.boolean().optional().describe("Disable this variant for the model"),
633+
})
634+
.catchall(z.any()),
635+
)
636+
.optional()
637+
.describe("Variant-specific configuration"),
638+
}),
639+
)
640+
.optional(),
624641
options: z
625642
.object({
626643
apiKey: z.string().optional(),

packages/opencode/src/provider/models.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export namespace ModelsDev {
6060
options: z.record(z.string(), z.any()),
6161
headers: z.record(z.string(), z.string()).optional(),
6262
provider: z.object({ npm: z.string() }).optional(),
63+
variants: z.record(z.string(), z.record(z.string(), z.any())).optional(),
6364
})
6465
export type Model = z.infer<typeof Model>
6566

packages/opencode/src/provider/provider.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import z from "zod"
22
import fuzzysort from "fuzzysort"
33
import { Config } from "../config/config"
4-
import { mapValues, mergeDeep, sortBy } from "remeda"
4+
import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda"
55
import { NoSuchModelError, type Provider as SDK } from "ai"
66
import { Log } from "../util/log"
77
import { BunProc } from "../bun"
@@ -405,16 +405,6 @@ export namespace Provider {
405405
},
406406
}
407407

408-
export const Variant = z
409-
.object({
410-
disabled: z.boolean(),
411-
})
412-
.catchall(z.any())
413-
.meta({
414-
ref: "Variant",
415-
})
416-
export type Variant = z.infer<typeof Variant>
417-
418408
export const Model = z
419409
.object({
420410
id: z.string(),
@@ -478,7 +468,7 @@ export namespace Provider {
478468
options: z.record(z.string(), z.any()),
479469
headers: z.record(z.string(), z.string()),
480470
release_date: z.string(),
481-
variants: z.record(z.string(), Variant).optional(),
471+
variants: z.record(z.string(), z.record(z.string(), z.any())).optional(),
482472
})
483473
.meta({
484474
ref: "Model",
@@ -561,7 +551,7 @@ export namespace Provider {
561551
variants: {},
562552
}
563553

564-
m.variants = mapValues(ProviderTransform.variants(m), (v) => ({ disabled: false, ...v }))
554+
m.variants = mapValues(ProviderTransform.variants(m), (v) => v)
565555

566556
return m
567557
}
@@ -697,7 +687,13 @@ export namespace Provider {
697687
headers: mergeDeep(existingModel?.headers ?? {}, model.headers ?? {}),
698688
family: model.family ?? existingModel?.family ?? "",
699689
release_date: model.release_date ?? existingModel?.release_date ?? "",
690+
variants: {},
700691
}
692+
const merged = mergeDeep(ProviderTransform.variants(parsedModel), model.variants ?? {})
693+
parsedModel.variants = mapValues(
694+
pickBy(merged, (v) => !v.disabled),
695+
(v) => omit(v, ["disabled"]),
696+
)
701697
parsed.models[modelID] = parsedModel
702698
}
703699
database[providerID] = parsed
@@ -822,6 +818,16 @@ export namespace Provider {
822818
(configProvider?.whitelist && !configProvider.whitelist.includes(modelID))
823819
)
824820
delete provider.models[modelID]
821+
822+
// Filter out disabled variants from config
823+
const configVariants = configProvider?.models?.[modelID]?.variants
824+
if (configVariants && model.variants) {
825+
const merged = mergeDeep(model.variants, configVariants)
826+
model.variants = mapValues(
827+
pickBy(merged, (v) => !v.disabled),
828+
(v) => omit(v, ["disabled"]),
829+
)
830+
}
825831
}
826832

827833
if (Object.keys(provider.models).length === 0) {

packages/opencode/src/provider/transform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export namespace ProviderTransform {
246246
const WIDELY_SUPPORTED_EFFORTS = ["low", "medium", "high"]
247247
const OPENAI_EFFORTS = ["none", "minimal", ...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
248248

249-
export function variants(model: Provider.Model) {
249+
export function variants(model: Provider.Model): Record<string, Record<string, any>> {
250250
if (!model.capabilities.reasoning) return {}
251251

252252
const id = model.id.toLowerCase()

packages/opencode/src/session/llm.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,14 @@ export namespace LLM {
8282
}
8383

8484
const provider = await Provider.getProvider(input.model.providerID)
85-
const variant = input.model.variants && input.user.variant ? input.model.variants[input.user.variant] : undefined
85+
const small = input.small ? ProviderTransform.smallOptions(input.model) : {}
86+
const variant = input.model.variants && input.user.variant ? input.model.variants[input.user.variant] : {}
8687
const options = pipe(
8788
ProviderTransform.options(input.model, input.sessionID, provider.options),
88-
mergeDeep(input.small ? ProviderTransform.smallOptions(input.model) : {}),
89+
mergeDeep(small),
8990
mergeDeep(input.model.options),
9091
mergeDeep(input.agent.options),
91-
mergeDeep(variant && !variant.disabled ? variant : {}),
92+
mergeDeep(variant),
9293
)
9394

9495
const params = await Plugin.trigger(

0 commit comments

Comments
 (0)