fix(agents): restore global subagent model default priority over agent own model#58823
fix(agents): restore global subagent model default priority over agent own model#58823joeykrug wants to merge 35 commits into
Conversation
Greptile SummaryThis PR fixes a model-selection precedence regression introduced in PR #58003. It restores the correct priority order in both
Confidence Score: 5/5Safe to merge — minimal, targeted fix with good regression-test coverage and no collateral changes. All findings are P2 or lower. The logic change is a correct two-line swap applied consistently across both code paths, the updated and new tests directly cover the regression and the full priority matrix, and no unrelated code is touched. No files require special attention. Reviews (1): Last reviewed commit: "fix(agents): restore global subagent mod..." | Re-trigger Greptile |
155066c to
d588fb4
Compare
|
Codex review: keeping this open for maintainer follow-up; there is still a little grit to resolve. Keep this PR open. Current main still implements and tests the opposite subagent model precedence, while the docs support the reporter's expectation that Best possible solution: Keep this PR open for maintainer review. If the documented contract is intended, land this PR or a narrow equivalent, ideally with explicit allowlist validation for resolved subagent defaults and What I checked:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 7120f5b25487. |
9a24cf6 to
0cc6234
Compare
…t own model PR openclaw#58003 reordered resolveSubagentConfiguredModelSelection to prefer agentConfig.model over agents.defaults.subagents.model. This caused the main agent's own model to shadow the global subagent default — e.g. when the main agent runs Opus and defaults.subagents.model is GPT-5.4, subagents incorrectly inherited Opus instead of GPT-5.4. Restore the correct precedence: 1. agentConfig.subagents.model (explicit per-agent subagent config) 2. agents.defaults.subagents.model (global subagent default) 3. agentConfig.model (agent own model, last-resort fallback) Apply the same fix to the cron isolated-agent model selection path. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add regression tests for resolveSubagentSpawnModelSelection covering the no-subagents-config 3-tier precedence: 1. session-level modelOverride wins over everything 2. agents.list[].model wins over agents.defaults.model 3. agents.defaults.model is used when neither override is set These complement the resolveSubagentConfiguredModelSelection tests added in the prior fix commit by pinning the spawn-time resolution path. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
4645342 to
5f5e960
Compare
|
Codex review: needs maintainer review before merge. Reviewed July 12, 2026, 12:13 AM ET / 04:13 UTC. Summary PR surface: Source +7, Tests +251, Other +127. Total +385 across 7 files. Reproducibility: yes. at source level: current main contains two deterministic selectors with opposite precedence for the same configured agent primary and global subagent default. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Adopt global-default-first as one documented contract across spawn planning, shared cron selection, and fallback policy, then assess the broader runtime-session PR only for its distinct persistence and parent-override fixes. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main contains two deterministic selectors with opposite precedence for the same configured agent primary and global subagent default. Is this the best way to solve the issue? Yes mechanically: reordering the shared helper is the narrowest maintainable fix for the remaining inconsistency, provided maintainers approve global-default-first as the compatibility contract. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 86b10ffb8e93. Label changesLabel justifications:
Evidence reviewedPR surface: Source +7, Tests +251, Other +127. Total +385 across 7 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (6 earlier review cycles)
|
…precedence-global-default
…ack tests PR openclaw#58823's subagent-precedence fallback tests (agent-scope + cron isolated-agent) asserted legacy 'openai-codex/gpt-5.x', but their configs use 'openai/gpt-5.x' and the resolver returns the configured fallbacks verbatim (no aliasing) — so the expected value cannot be openai-codex. Per AGENTS.md, openai-codex is folded into openai (legacy input only), so the canonical runtime value is openai/*. The flip behavior (global defaults.subagents.model fallbacks win over the agent's own model) is correctly implemented in agent-scope.ts; only the test expectations were wrong. Fixes the 2 failing CI shards (agentic-agents-core-runtime, core-runtime-cron-isolated-agent).
|
Refreshed the canonical branch with upstream |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
Final shared-upstream synchronization is exact head @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Summary
Current exact-head refresh
262baedcf7fa3d66dc35cce7d0253e0a31f0cc0einto exact branch head49b4d13321fcda6e3ca3ef2744f17a0dca52749a.Fixes #58822.
resolveSubagentConfiguredModelSelection: globalagents.defaults.subagents.modelnow takes priority over the parent agent's ownmodel.primary, with the agent's own model only used as a last-resort fallbacksrc/cron/isolated-agent/model-selection.ts) and the sharedresolveSubagentModelConfigSelectionResulthelper insrc/agents/agent-scope.tsBackground
PR #58003 reordered
resolveSubagentConfiguredModelSelectionto preferagentConfig.modeloveragents.defaults.subagents.model. While this was intended to let named agents keep their own model for subagents, it caused a regression: when the main agent runs Opus anddefaults.subagents.modelis GPT-5.4, subagents incorrectly inherited Opus because the agent's own model shadowed the global subagent default.The correct precedence is:
agentConfig.subagents.model— explicit per-agent subagent config (highest)agents.defaults.subagents.model— global subagent defaultagentConfig.model— agent's own model (last-resort fallback)Test plan
pnpm test src/agents/model-selection.test.ts— 105 tests passpnpm test src/cron/isolated-agent.model-formatting.test.ts— 32 tests passpnpm test src/agents/openclaw-tools.subagents.sessions-spawn.model.test.ts— 11 tests passpnpm test src/agents/subagent-spawn.model-session.test.ts— 1 test passespnpm test src/gateway/session-utils.test.ts— 84 tests passpnpm test src/gateway/sessions-patch.test.ts— 34 tests passReal behavior proof
Behavior addressed: Subagent model resolution for a main agent whose own
modeldiffers fromagents.defaults.subagents.model. Before this PR, an Opus-running agent withdefaults.subagents.model = openai/gpt-5still produced Opus subagents because the agent's ownmodelshadowed the global subagent default inresolveSubagentConfiguredModelSelection, in the sharedresolveSubagentModelConfigSelectionResulthelper, and in the cron isolated-agent path. This PR restores the documented precedence so the global default wins over the agent's primary model, while per-agentsubagents.modelstill takes the very top slot.Real environment tested: Linux x86_64 (Node v24.15.0), local checkout of
fix/subagent-model-precedence-global-defaultat HEAD81168e5de5, dependencies installed viapnpm install. Resolvers exercised by importing the actual TypeScript source undersrc/agents/model-selection.tsandsrc/agents/agent-scope.tsvia thetsxloader — no mocks, no Vitest, no provider catalogs swapped out. The cron isolated-agent path uses the sameresolveSubagentModelConfigSelectionResulthelper, so the asserted source values cover that resolver too.Exact steps or command run after this patch:
The script (
scripts/proof/pr-58823-subagent-precedence.mjs, committed in this PR for reviewer reproducibility) constructs three realOpenClawConfigshapes, callsresolveSubagentModelConfigSelectionResult,resolveSubagentConfiguredModelSelection, andresolveSubagentSpawnModelSelectionon each, and asserts both the resolved model ref and the selectionsourcelabel (subagent/default-subagent/agent).Evidence after fix: Verbatim terminal stdout (runtime log) from the live
node --import tsxrun above against the patched sources:For completeness, the Vitest suites listed in Test plan also pass on this branch (
pnpm test src/agents/model-selection.test.ts→ 105 passed;pnpm test src/cron/isolated-agent.model-formatting.test.ts→ 32 passed; etc.), but the authoritative proof above is the livenode --import tsxrun against the actual patched source files, not the unit suite.Observed result after fix:
defaults.subagents.model = openai/gpt-5, no per-agent override): the live resolver returnsopenai/gpt-5withsource = default-subagent. Before this PR it returnedanthropic/claude-opuswithsource = agent— the exact bug from fix(agents): subagent model precedence — global default shadowed by parent agent's own model #58822.subagents.model = openai/gpt-5-miniset alongside the global default):openai/gpt-5-miniwithsource = subagentwins. Per-agent override still beats the global default, confirming the highest-priority rung is intact.subagents.modelnordefaults.subagents.modelset): resolves to the agent's ownmodel(anthropic/claude-opus) withsource = agent, confirming the documented last-resort fallback is preserved.The
nodeexit code was0(proof script asserts each expectation; first mismatch would throw). Theagent-scopesource labels are produced by the sharedresolveSubagentModelConfigSelectionResulthelper used by bothsrc/agents/model-selection.tsandsrc/cron/isolated-agent/model-selection.ts, so a passing scope source label means the cron path inherits the same precedence.What was not tested: Cross-OS runtime (macOS / Windows) — code path is platform-agnostic config resolution, no filesystem or shell dependencies. Live spawn of an actual subagent process against a remote model provider — the resolver returns the same model ref regardless of whether the downstream spawn succeeds, and the spawn path is exercised by
src/agents/openclaw-tools.subagents.sessions-spawn.model.test.ts(11 passing). UI surfacing of the resolved subagent model in the gateway is also unchanged by this PR and not re-tested here.🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 [email protected]