Skip to content

stop the CoS runner rebuilding OpenCode's config from an identity-only provider view - #6140

Merged
atomantic merged 1 commit into
mainfrom
cos/task-mtm40kd2/agent-d0a65718
Sep 3, 2026
Merged

stop the CoS runner rebuilding OpenCode's config from an identity-only provider view#6140
atomantic merged 1 commit into
mainfrom
cos/task-mtm40kd2/agent-d0a65718

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Every runner-owned OpenCode agent was silently running on a hosted OpenCode Zen model instead of the local model it was dispatched with. Reported against agent-eac37dd4, which was launched on opencode-ollama-tui / qwen3-coder:30b and ran on Zen's default.

The cause is a second, non-idempotent env-composition pass over a partial provider view:

  • PortOS composes the CLI child-env delta from the full provider record and POSTs it to the CoS runner as before, alongside cliProviderAuthDescriptor's identity-only view — { id, command, ollamaBacked }, no envVars, no models, no defaultModel.
  • The runner re-runs buildCliChildEnv with that partial view as provider. Every generative layer in composeProviderEnv sits above before, so the rebuild overwrote the complete value it was layered onto.
  • For an OpenCode wrapper that meant OPENCODE_CONFIG_CONTENT rebuilt with an empty models map. --model ollama/<id> then resolved to nothing, and OpenCode fell back to the first model in its own catalog rather than failing — so the run looked healthy while answering from the wrong model.

Reproduced directly: with the good config, opencode models lists the ten ollama/* ids; with the rebuilt one it lists only the hosted opencode/* catalog.

The fix is at the seam, not in the OpenCode builder. cliProviderAuthDescriptor now stamps authOnly: true, and composeProviderEnv short-circuits on it — an identity-only view contributes no env at all. buildSafeCliBaseEnv still receives the descriptor, since selecting that provider's ambient-auth allowlist is the whole reason it is POSTed. Guarding here rather than inside buildOpencodeEnvVars also covers the next generative layer added to composeProviderEnv, instead of special-casing the one symptom that surfaced.

Both runner call sites (/spawn and /spawn-tui) are fixed by the same change, so headless runner-CLI OpenCode agents were affected too, not just the TUI path.

Test plan

  • New cliChildEnv.test.js case drives the real two-hop shape — compose from the full record, then re-layer with the descriptor — and asserts the whole composed env equals the POSTed delta (plus PATH/PWD), so a future generative layer is covered rather than just OPENCODE_CONFIG_CONTENT. Verified it fails without the fix.
  • The pre-existing ambient-auth test is kept as the descriptor's other half: inert for composition, still the input the auth allowlist is picked from.
  • Full server suite: 1917 files / 38708 tests passing.

…y provider view

PortOS composes a CLI child-env delta from the full provider record and POSTs it
to the CoS runner alongside cliProviderAuthDescriptor's non-secret identity
({ id, command, ollamaBacked }). The runner then re-ran composeProviderEnv with
that partial view as `provider` — and every generative layer there sits ABOVE
`before`, so the rebuild overwrote the complete value it was layered onto.

For an OpenCode wrapper that meant a config with an EMPTY models map replacing
the good one: `--model ollama/<id>` stopped resolving, and OpenCode silently fell
back to the first model in its own catalog (a hosted OpenCode Zen model) rather
than failing. Every runner-owned OpenCode agent ran on a model nobody chose.

Mark the descriptor `authOnly` and short-circuit composeProviderEnv on it, so an
identity-only view contributes no env at all. buildSafeCliBaseEnv still receives
it — selecting that provider's ambient-auth allowlist is why it is POSTed — but
it can no longer generate config. Guarding the seam rather than the OpenCode
builder also covers the next layer added to composeProviderEnv.
@atomantic
atomantic merged commit 0d39708 into main Sep 3, 2026
7 checks passed
@atomantic
atomantic deleted the cos/task-mtm40kd2/agent-d0a65718 branch September 3, 2026 23:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant