Repository navigation
Description
What happened
I run opencode headless in fresh sandboxes every day (eval harness, 180 tasks/day) with a single gateway provider configured and no model set. Every single run picks google/gemini-3-pro-preview. That model is a generation behind and it never changes, so I dug into why. Verified on 1.18.7 (current npm latest).
The cause
packages/opencode/src/provider/provider.ts (dev branch):
const priority = ["gpt-5", "claude-sonnet-4", "big-pickle", "gemini-3-pro"]
export function sort<T extends { id: string }>(models: T[]) {
return sortBy(
models,
[(model) => priority.findIndex((filter) => model.id.includes(filter)), "desc"],
[(model) => (model.id.includes("latest") ? 0 : 1), "asc"],
[(model) => model.id, "desc"],
)
}defaultModel falls through cfg.model -> recents in state/model.json -> sort(provider.models)[0]. With no config and no state, the priority list decides, and it has gone stale in a few compounding ways:
- Substring pins don't survive model generations.
"gemini-3-pro"doesn't matchgoogle/gemini-3.1-pro-preview(that id containsgemini-3.1-pro), so the successor can never win. Meanwhilegpt-5.5andclaude-sonnet-4.6do match their pins, but at lower priority indexes, so they lose to the older gemini pin. findIndex+"desc"means the last array entry is the highest priority. Easy to misread as first-wins. Either way the top preference is whatever was appended last, back when gemini-3-pro was current.- The final tie-break is reverse-alphabetical id, which is the only reason
-previewbeats-image(p > i). Nothing checks capabilities at this point. If the catalog gained a-visionor-realtimesibling it would sort above-previewand become the default. - Only
status: deprecated/alphaget filtered before the sort, so a superseded-but-active preview model stays eligible forever.
Repro
Clean machine (no state/model.json), opencode.json with just a gateway provider and no model:
{
"provider": {
"vercel": { "options": { "apiKey": "{env:AI_GATEWAY_API_KEY}" } }
}
}opencode run "hello" picks google/gemini-3-pro-preview. Emulating sort() over that provider's catalog (499 models in the 1.18.7 build) ranks:
google/gemini-3-pro-previewgoogle/gemini-3-pro-imageanthropic/claude-sonnet-4
Why nobody notices
The recents fallback shadows this for anyone who has ever picked a model interactively. Ephemeral environments hit the cold-start path every time - CI, sandboxes, containers, eval harnesses - and they're all quietly running on gemini-3-pro-preview today.
Suggested fix
Any of these kills the staleness class rather than today's instance:
- Use
release_datein the ranking. It's already on every model andgetSmallModelalready sorts by it -defaultModelcould prefer the newest model within a preferred family/capability set. - Match on the catalog's
familymetadata (e.g.gemini-pro) instead of raw id substrings, so successor generations inherit the preference. - At minimum, filter for
toolcall+ text output ahead of the id tie-break so an image variant can't become the default by alphabetical accident.
Happy to PR whichever direction you prefer.
Environment: opencode 1.18.7 (npm opencode-ai, also confirmed in 1.17.0), single gateway provider via opencode.json, no model configured, clean state.
Activity
molebox commentedon Sep 19, 2026
Is there any chance this will be fixed? Or shall we close this out? If not its not going to be fixed, we can just select the model i guess
neriousy commentedon Oct 19, 2026
This is fixed in v2: the stale model-name substring priority list is gone. The fallback now uses release-date ordering and selects a model that supports text, with a separate preference for certain free models when only free models are available. To get v2, run
npm i -g @opencode/cli@latest. If you still see this on v2, please open a new issue with the details.