anomalyco / anomalyco/opencode
Resuming a session after switching the global default model still uses the old recorded model (session.model) — blocks continuation when old model is unavailable
@kitlangton is already working on this.
Since Aug 26, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
When I switch the global default model in opencode.json (e.g. from xiaomi/mimo-v2.5-pro to whalecloud/g-deepseek-v4-flash) and then resume an existing session that was created under the old model, opencode still uses the old recorded model for that session instead of the new global default.
This becomes a hard blocker when the old model is no longer available (quota exhausted / invalid API key): the resumed session immediately fails with AI_APICallError and the in-flight task cannot continue under the new model.
Root cause is in packages/opencode/src/session/prompt.ts, the currentModel helper:
const currentModel = Effect.fnUntraced(function* (sessionID) {
const current = yield* db
.select({ model: SessionTable.model })
.from(SessionTable)
.where(eq(SessionTable.id, sessionID))
.get()
if (current?.model) {
// 1. session.model (stored old model) wins — never falls back to global default
return { providerID: ..., modelID: ... }
}
const match = yield* sessions
.findMessage(sessionID, (m) => m.info.role === "user" && !!m.info.model)
if (Option.isSome(match) && match.value.info.role === "user") return match.value.info.model // 2. last user message model
return yield* provider.defaultModel().pipe(Effect.orDie) // 3. global default — only when neither exists
})
So the selection order on resume is:
session.model(the stored old model) — always used if present- last user message's recorded model — fallback, still the old model
provider.defaultModel()(readsopencode.jsonmodel) — only reached when neither 1 nor 2 exists
Since every session that ever ran stores a session.model, resuming after a model switch always keeps the old model and never falls back to the new global default.
Plugins
oh-my-openagent (which manages subagent model config via ~/.omo/omo.jsonc)
OpenCode version
1.18.23
Steps to reproduce
- Configure global
"model": "providerA/model-old"inopencode.json. - Start a session under
providerA/model-oldand do some work. - Switch global
"model"to"providerB/model-new"(e.g. because providerA quota/API key expired). - Resume the old session (
/sessions→ pick it, oropencode --continue). - Observe: the session still uses
providerA/model-oldand fails with an API error if that model is unavailable. The task cannot continue underproviderB/model-new.
Expected behavior
A session resumed after a global model switch should be able to continue under the new default model, especially when the previously-recorded model is no longer available. At minimum there should be a way to make a stuck session fall back to the current default, and a clear signal when the recorded model is stale/unavailable.
Suggested direction (similar to the proposal in #43179): distinguish a session model that is following the default from one pinned by the user. When a recorded model is missing/unauthorized and it wasn't explicitly pinned, fall back to the current global default instead of hard-failing.
Related issues
- #38165 — same root cause (
session.modeloverwritten / stale on resume), triggered by a command model - #43179 — session model silently preserved on agent switch (V2)
- #33044 — stale continuation rows can overwrite the session model
- #44680 — subagent sessions inherit parent session model instead of agent-configured model
Operating System
WSL2 / Ubuntu (Linux)
Terminal
Windows Terminal (via WSL)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.