CodeNomad may persist and resend stale session.agent / session.model, causing invalid subagent model selection
Summary
During debugging of repeated subagent failures in an OpenCode + OMO setup, I found a strong correlation between CodeNomad being in the loop and subagent failures.
When CodeNomad is not used and the same workflow is continued from pure CLI, previously failing subagent_type="explore" smoke tests succeed.
At the same time, CodeNomad source shows it is not a passive client: it stores session.agent and session.model locally, updates them when the agent changes, and resends both values in subsequent session.promptAsync() requests.
That means stale or incorrect client-side session state can be fed back into OpenCode and keep poisoning later requests.
Observed behavior
With CodeNomad involved
- background subagent tasks frequently failed
- failures were not uniform; examples included:
Model not found: opencode/gpt-5-nano
- requests reaching the LLM proxy with
model: "minimax-m2.7" and failing because that provider was not configured in the proxy
Without CodeNomad (pure CLI)
category="quick" smoke test succeeded
subagent_type="explore" smoke test also succeeded
This strongly suggests CodeNomad is at least one of the variables that can corrupt the session state.
Source evidence from CodeNomad
1. CodeNomad resends locally stored session.agent and session.model
File: packages/ui/src/stores/session-actions.ts
const requestBody = {
parts: requestParts,
...(session.agent && { agent: session.agent }),
...(session.model.providerId &&
session.model.modelId && {
model: {
providerID: session.model.providerId,
modelID: session.model.modelId,
},
}),
}
await client.session.promptAsync({
sessionID: sessionId,
...(requestBody as any),
})
This means CodeNomad is not just forwarding user text. It actively resends local session state back to OpenCode.
2. Switching agent mutates session.model
File: packages/ui/src/stores/session-actions.ts
const nextModel = await getDefaultModel(instanceId, agent)
const shouldApplyModel = isModelValid(instanceId, nextModel)
withSession(instanceId, sessionId, (current) => {
current.agent = agent
if (shouldApplyModel) {
current.model = nextModel
}
})
This means CodeNomad actively rewrites the session model whenever it thinks the active agent changed.
3. Default model resolution prefers cached agent.model
File: packages/ui/src/stores/session-models.ts
if (agentName) {
const agent = instanceAgents.find((a) => a.name === agentName)
if (agent && agent.model && isModelValid(instanceId, agent.model)) {
return {
providerId: agent.model.providerId,
modelId: agent.model.modelId,
}
}
const stored = await getAgentModelPreference(instanceId, agentName)
if (isModelValid(instanceId, stored)) {
return stored
}
}
Priority is:
agent.model
- stored preference
- recent/default provider model
So if agent.model or stored preference is stale, it can be written back into the session and resent later.
4. CodeNomad caches agent -> model
File: packages/ui/src/stores/session-api.ts
const agentList = (response.data ?? []).map((agent) => ({
name: agent.name,
...
model: agent.model?.modelID
? {
providerID: agent.model.providerID || "",
modelID: agent.model.modelID,
}
: undefined,
}))
So the client maintains its own agent/model mapping and uses it to drive later session behavior.
Why this looks problematic
This creates a feedback loop:
- fetch agents from OpenCode
- cache
agent.model locally
- switch agent -> compute
nextModel
- overwrite local
session.model
- next message -> resend both
session.agent and session.model
If any part of that local state becomes stale or mismatched, the client can keep replaying the wrong model selection.
Request
Please review whether CodeNomad should:
- stop auto-overwriting
session.model when changing session.agent, or
- stop resending cached
session.model unless the user explicitly changed model, or
- distinguish server-authoritative session state from client preference state, or
- log
session.promptAsync request bodies in a way that is easier to inspect when this happens.
Notes from my environment
- OpenCode client is used against a local AI proxy
- removing CodeNomad from the loop made the previously failing
explore subagent smoke test succeed
- another independent issue also existed in the LLM proxy (
minimax-m2.7 had no configured provider), but that does not explain why the same OpenCode/OMO workflow succeeds once CodeNomad is removed from the path
Repro idea
- Start with a session whose agent/model was previously changed in UI
- Trigger subagent workflows from CodeNomad
- Compare:
- CodeNomad UI path
- pure CLI path
- Inspect whether
session.agent / session.model in the outgoing session.promptAsync body differ between the two
CodeNomad may persist and resend stale
session.agent/session.model, causing invalid subagent model selectionSummary
During debugging of repeated subagent failures in an OpenCode + OMO setup, I found a strong correlation between CodeNomad being in the loop and subagent failures.
When CodeNomad is not used and the same workflow is continued from pure CLI, previously failing
subagent_type="explore"smoke tests succeed.At the same time, CodeNomad source shows it is not a passive client: it stores
session.agentandsession.modellocally, updates them when the agent changes, and resends both values in subsequentsession.promptAsync()requests.That means stale or incorrect client-side session state can be fed back into OpenCode and keep poisoning later requests.
Observed behavior
With CodeNomad involved
Model not found: opencode/gpt-5-nanomodel: "minimax-m2.7"and failing because that provider was not configured in the proxyWithout CodeNomad (pure CLI)
category="quick"smoke test succeededsubagent_type="explore"smoke test also succeededThis strongly suggests CodeNomad is at least one of the variables that can corrupt the session state.
Source evidence from CodeNomad
1. CodeNomad resends locally stored
session.agentandsession.modelFile:
packages/ui/src/stores/session-actions.tsThis means CodeNomad is not just forwarding user text. It actively resends local session state back to OpenCode.
2. Switching agent mutates
session.modelFile:
packages/ui/src/stores/session-actions.tsThis means CodeNomad actively rewrites the session model whenever it thinks the active agent changed.
3. Default model resolution prefers cached
agent.modelFile:
packages/ui/src/stores/session-models.tsPriority is:
agent.modelSo if
agent.modelor stored preference is stale, it can be written back into the session and resent later.4. CodeNomad caches
agent -> modelFile:
packages/ui/src/stores/session-api.tsSo the client maintains its own agent/model mapping and uses it to drive later session behavior.
Why this looks problematic
This creates a feedback loop:
agent.modellocallynextModelsession.modelsession.agentandsession.modelIf any part of that local state becomes stale or mismatched, the client can keep replaying the wrong model selection.
Request
Please review whether CodeNomad should:
session.modelwhen changingsession.agent, orsession.modelunless the user explicitly changed model, orsession.promptAsyncrequest bodies in a way that is easier to inspect when this happens.Notes from my environment
exploresubagent smoke test succeedminimax-m2.7had no configured provider), but that does not explain why the same OpenCode/OMO workflow succeeds once CodeNomad is removed from the pathRepro idea
session.agent/session.modelin the outgoingsession.promptAsyncbody differ between the two