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.
This commit is contained in:
@@ -5,7 +5,7 @@ import { chooseModelSelection } from "./model-selection.ts"
|
|||||||
const providers = [
|
const providers = [
|
||||||
{
|
{
|
||||||
id: "azure",
|
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,
|
providers,
|
||||||
defaults: { azure: "gpt-5.4" },
|
defaults: { azure: "gpt-5.4" },
|
||||||
existing: { providerID: "azure", modelID: "gpt-5.2" },
|
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" })
|
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({
|
const selected = chooseModelSelection({
|
||||||
providers,
|
providers,
|
||||||
defaults: { azure: "gpt-5.4" },
|
defaults: { azure: "claude-sonnet-4-6" },
|
||||||
existing: null,
|
existing: null,
|
||||||
agentModel: { providerID: "azure", modelID: "claude-sonnet-4-6" },
|
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({
|
const selected = chooseModelSelection({
|
||||||
providers,
|
providers,
|
||||||
defaults: {},
|
defaults: { azure: "gpt-5.4" },
|
||||||
existing: null,
|
existing: { providerID: "azure", modelID: "nonexistent-model" },
|
||||||
agentModel: null,
|
agentModel: null,
|
||||||
})
|
})
|
||||||
assert.deepEqual(selected, { providerID: "azure", modelID: "gpt-5.4" })
|
assert.equal(selected, null)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("returns null when no connected providers", () => {
|
test("returns null when no connected providers", () => {
|
||||||
|
|||||||
@@ -22,29 +22,31 @@ export function isModelAvailable(
|
|||||||
return provider.models.some((m) => m.id === selection.modelID)
|
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: {
|
export function chooseModelSelection(params: {
|
||||||
providers: ProviderRef[]
|
providers: ProviderRef[]
|
||||||
defaults: Record<string, string>
|
defaults: Record<string, string>
|
||||||
existing: ModelSelection | null
|
existing: ModelSelection | null
|
||||||
agentModel: ModelSelection | null
|
agentModel: ModelSelection | null
|
||||||
}): 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
|
if (isModelAvailable(providers, existing)) return existing
|
||||||
|
|
||||||
for (const provider of providers) {
|
// Otherwise return null — let the server decide via its own config.
|
||||||
const defaultModelID = defaults[provider.id]
|
// The provider registry's "defaults" map is unreliable (it lists the
|
||||||
if (!defaultModelID) continue
|
// upstream registry default, not what's deployed on the user's resource).
|
||||||
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
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user