fix(#2256): pass per-agent model overrides through Codex/OpenCode transport (#2628)

The Codex and OpenCode install paths read `model_overrides` only from
`~/.gsd/defaults.json` (global). A per-project override set in
`.planning/config.json` — the reporter's exact setup for
`gsd-codebase-mapper` — was silently dropped, so the child agent inherited
the runtime's default model regardless of `model_overrides`.

Neither runtime has an inline `model` parameter on its spawn API
(Codex `spawn_agent(agent_type, message)`, OpenCode `task(description,
prompt, subagent_type, task_id, command)`), so the per-agent model must
reach the child via the static config GSD writes at install time. That
config was being populated from the wrong source.

Fix: add `readGsdEffectiveModelOverrides(targetDir)` which merges
`~/.gsd/defaults.json` with per-project `.planning/config.json`, with
per-project keys winning on conflict. Both install sites now call it and
walk up from the install root to locate `.planning/` — matching the
precedence `readGsdRuntimeProfileResolver` already uses for #2517.

Also update the Codex Task()->spawn_agent mapping block so it no longer
says "omit" without context: it now documents that per-agent overrides
are embedded in the agent TOML and notes the restriction that Codex
only permits `spawn_agent` when the user explicitly requested sub-agents
(do the work inline otherwise).

Regression tests (`tests/bug-2256-model-overrides-transport.test.cjs`)
cover: global-only, project-only, project-wins-on-conflict, walking up
from a nested `targetDir`, Codex TOML `model =` emission, and OpenCode
frontmatter `model:` emission.

Closes #2256

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-23 11:58:06 -04:00
committed by GitHub
parent bdba40cc3d
commit 5a8a6fb511
3 changed files with 242 additions and 5 deletions

View File

@@ -609,6 +609,17 @@ Override specific agents without changing the entire profile:
Valid override values: `opus`, `sonnet`, `haiku`, `inherit`, or any fully-qualified model ID (e.g., `"openai/o3"`, `"google/gemini-2.5-pro"`).
`model_overrides` can be set in either `.planning/config.json` (per-project)
or `~/.gsd/defaults.json` (global). Per-project entries win on conflict and
non-conflicting global entries are preserved, so you can tune a single
agent's model in one repo without re-setting global defaults. This applies
uniformly across Claude Code, Codex, OpenCode, Kilo, and the other
supported runtimes. On Codex and OpenCode, the resolved model is embedded
into each agent's static config at install time — `spawn_agent` and
OpenCode's `task` interface do not accept an inline `model` parameter, so
running `gsd install <runtime>` after editing `model_overrides` is required
for the change to take effect. See issue #2256.
### Non-Claude Runtimes (Codex, OpenCode, Gemini CLI, Kilo)
When GSD is installed for a non-Claude runtime, the installer automatically sets `resolve_model_ids: "omit"` in `~/.gsd/defaults.json`. This causes GSD to return an empty model parameter for all agents, so each agent uses whatever model the runtime is configured with. No additional setup is needed for the default case.