From f92f995b48c579256f1acb102474e1bf62678d9a Mon Sep 17 00:00:00 2001 From: Den <2119348+dzianisv@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:15:13 -0700 Subject: [PATCH] fix: let server decide model when no user selection exists (#37) Registry defaults unreliable for deployed models; return null so server uses its configured model. Fixes #35. --- src/lib/model-selection.test.ts | 20 +++++++++++--------- src/lib/model-selection.ts | 32 +++++++++++++++++--------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/lib/model-selection.test.ts b/src/lib/model-selection.test.ts index 1afde1b..4bc0746 100644 --- a/src/lib/model-selection.test.ts +++ b/src/lib/model-selection.test.ts @@ -5,7 +5,7 @@ import { chooseModelSelection } from "./model-selection.ts" const providers = [ { id: "azure", - models: [{ id: "gpt-5.4" }, { id: "gpt-5.2" }], + models: [{ id: "gpt-5.4" }, { id: "gpt-5.2" }, { id: "claude-sonnet-4-6" }], }, ] @@ -14,29 +14,31 @@ test("keeps existing selection when still available", () => { providers, defaults: { azure: "gpt-5.4" }, existing: { providerID: "azure", modelID: "gpt-5.2" }, - agentModel: { providerID: "azure", modelID: "claude-sonnet-4-6" }, + agentModel: null, }) assert.deepEqual(selected, { providerID: "azure", modelID: "gpt-5.2" }) }) -test("prefers provider default over unavailable agent model", () => { +test("returns null when no existing selection (let server decide)", () => { + // Even though defaults and providers exist, we return null to let + // the server use its own configured model from opencode.json const selected = chooseModelSelection({ providers, - defaults: { azure: "gpt-5.4" }, + defaults: { azure: "claude-sonnet-4-6" }, existing: null, agentModel: { providerID: "azure", modelID: "claude-sonnet-4-6" }, }) - assert.deepEqual(selected, { providerID: "azure", modelID: "gpt-5.4" }) + assert.equal(selected, null) }) -test("falls back to first connected provider model when default missing", () => { +test("returns null when existing selection no longer available", () => { const selected = chooseModelSelection({ providers, - defaults: {}, - existing: null, + defaults: { azure: "gpt-5.4" }, + existing: { providerID: "azure", modelID: "nonexistent-model" }, agentModel: null, }) - assert.deepEqual(selected, { providerID: "azure", modelID: "gpt-5.4" }) + assert.equal(selected, null) }) test("returns null when no connected providers", () => { diff --git a/src/lib/model-selection.ts b/src/lib/model-selection.ts index a0729ed..37396f6 100644 --- a/src/lib/model-selection.ts +++ b/src/lib/model-selection.ts @@ -22,29 +22,31 @@ export function isModelAvailable( return provider.models.some((m) => m.id === selection.modelID) } +/** + * Chooses a model selection for the session. + * + * Returns `null` when there is no prior user-explicit choice. A null model + * means the server's configured default (opencode.json `"model"` field) will + * be used — which is the correct behavior for first-launch and CI where the + * provider registry's "default" model may not be deployed on the user's + * resource. + * + * Only returns a non-null value when the user previously made an explicit + * selection that is still valid (model available on a connected provider). + */ export function chooseModelSelection(params: { providers: ProviderRef[] defaults: Record existing: ModelSelection | null agentModel: ModelSelection | null }): ModelSelection | null { - const { providers, defaults, existing, agentModel } = params + const { providers, existing } = params + // Keep existing user-chosen selection if it's still reachable if (isModelAvailable(providers, existing)) return existing - for (const provider of providers) { - const defaultModelID = defaults[provider.id] - if (!defaultModelID) continue - if (provider.models.some((m) => m.id === defaultModelID)) { - return { providerID: provider.id, modelID: defaultModelID } - } - } - - if (providers.length > 0 && providers[0].models.length > 0) { - return { providerID: providers[0].id, modelID: providers[0].models[0].id } - } - - if (isModelAvailable(providers, agentModel)) return agentModel - + // Otherwise return null — let the server decide via its own config. + // The provider registry's "defaults" map is unreliable (it lists the + // upstream registry default, not what's deployed on the user's resource). return null }