Skip to content

Agents: fix subagent model precedence#58003

Merged
obviyus merged 1 commit into
openclaw:mainfrom
neeravmakwana:fix/subagent-model-precedence
Mar 31, 2026
Merged

Agents: fix subagent model precedence#58003
obviyus merged 1 commit into
openclaw:mainfrom
neeravmakwana:fix/subagent-model-precedence

Conversation

@neeravmakwana

Copy link
Copy Markdown
Contributor

Summary

  • Problem: sessions_spawn and related subagent model resolution preferred agents.defaults.subagents.model over a named agent's own model.primary, so per-agent model defaults were ignored.
  • Why it matters: named agents could not reliably keep their configured primary model for spawned subagents unless every spawn call repeated an explicit model override.
  • What changed: reordered subagent model precedence to prefer agents.list[].subagents.model, then agents.list[].model.primary, then agents.defaults.subagents.model, and mirrored that precedence in isolated cron model resolution.
  • What did NOT change (scope boundary): explicit spawn/job model overrides still win, and no broader agent/default model resolution behavior was changed.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause / Regression History (if applicable)

  • Root cause: resolveSubagentConfiguredModelSelection in src/agents/model-selection.ts placed agents.defaults.subagents.model ahead of the target agent's own model, so the global subagent default masked the per-agent primary model.
  • Missing detection / guardrail: there was no regression test asserting that a named agent's model.primary beats the global subagent default when subagents.model is unset.
  • Prior context (git blame, prior PR, issue, or refactor if known): issue [Bug]: agents.list[].model.primary ignored - agents.defaults.subagents.model always wins #57993 reported the precedence mismatch with a direct repro.
  • Why this regressed now: the precedence chain encoded the wrong specificity order.
  • If unknown, what was ruled out: N/A.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/model-selection.test.ts, src/cron/isolated-agent.subagent-model.test.ts, and src/gateway/sessions-patch.test.ts
  • Scenario the test should lock in: named agent model.primary is used for subagents unless a more specific agents.list[].subagents.model or explicit runtime override is present.
  • Why this is the smallest reliable guardrail: it locks the precedence helper directly and covers the two mirrored runtime consumers that depended on the old order.
  • Existing test that already covers this (if any): src/gateway/sessions-patch.test.ts already covered adjacent allowlist behavior and was updated to stay aligned with the corrected precedence.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

  • Named agents now keep their own model.primary for spawned subagents when agents.list[].subagents.model is unset, even if agents.defaults.subagents.model is configured.
  • Isolated cron runs now apply the same precedence when targeting a named agent.

Diagram (if applicable)

Before:
subagent spawn -> global defaults.subagents.model -> agent model.primary ignored

After:
subagent spawn -> agent subagents.model (if set) -> else agent model.primary -> else global defaults.subagents.model

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS 15 / Darwin 25.x
  • Runtime/container: local Node 22+ / pnpm workspace
  • Model/provider: config-driven subagent model selection
  • Integration/channel (if any): N/A
  • Relevant config (redacted): agents.defaults.subagents.model, agents.list[].model.primary, optional agents.list[].subagents.model

Steps

  1. Configure agents.defaults.subagents.model and a named agent with a different model.primary.
  2. Spawn a subagent for that named agent without an explicit model override.
  3. Inspect the resolved subagent model.

Expected

  • The named agent's model.primary is used unless agents.list[].subagents.model is configured.

Actual

  • Before this fix, agents.defaults.subagents.model won and masked the named agent's model.primary.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: reproduced the precedence issue in code inspection, updated the precedence helper, ran targeted regression tests for model selection, cron isolated-agent subagent resolution, and gateway sessions patch behavior; also ran pnpm check and pnpm build.
  • Edge cases checked: agent subagents.model still outranks agent model.primary; explicit runtime/job model overrides still outrank config defaults; global defaults.subagents.model still applies when the agent has no explicit model.
  • What you did not verify: I did not change or validate unrelated CLI help output; repo-wide pnpm test still reports the existing unrelated failure in src/cli/config-cli.test.ts about --container examples in help text.

AI Assistance

  • AI-assisted: yes

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: another runtime path could still encode a different subagent model precedence order.
    • Mitigation: the helper and isolated cron path now match, and regression tests cover both direct helper precedence and mirrored runtime usage.

Made with Cursor

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime agents Agent runtime and tooling size: S labels Mar 31, 2026
@greptile-apps

greptile-apps Bot commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a subagent model precedence bug where agents.defaults.subagents.model was incorrectly winning over a named agent's own model.primary. The fix reorders the resolution chain in both resolveSubagentConfiguredModelSelection (the shared helper) and resolveCronModelSelection (isolated cron path) so that per-agent config always outranks global defaults, matching the expected specificity order.

  • Core fix (src/agents/model-selection.ts): swapped agentConfig.model and defaults.subagents.model in the ?? chain — correct and minimal.
  • Cron mirror (src/cron/isolated-agent/model-selection.ts): added agentConfigOverride.model as a middle fallback and added model?: unknown to the param type so normalizeModelSelection (which already handles { primary: "..." } objects) can unwrap it — consistent with the shared helper.
  • Tests (model-selection.test.ts, isolated-agent.subagent-model.test.ts, sessions-patch.test.ts): new unit and integration tests directly lock in both the helper precedence and the cron runtime path; the sessions-patch test was updated to cover the no-agent-model case cleanly by making agentPrimaryModel optional.
  • No behavior is changed for explicit runtime/job model overrides, and the global default still applies when the agent has no model configured.

Confidence Score: 5/5

  • Safe to merge — the change is minimal, correctly targeted, and well-covered by new regression tests.
  • All changes are P2 or lower. The precedence reorder is logically correct: normalizeModelSelection already handles both string and { primary: "..." } object formats, so the new agentConfigOverride?.model fallback in the cron path extracts the primary model correctly. Explicit overrides still win, the global default still applies as a last resort, and three new tests lock in the fixed behaviour at both the unit and integration level.
  • No files require special attention.

Reviews (1): Last reviewed commit: "Agents: fix subagent model precedence" | Re-trigger Greptile

@byungsker

This comment was marked as spam.

@obviyus obviyus self-assigned this Mar 31, 2026
@obviyus obviyus force-pushed the fix/subagent-model-precedence branch from afd1490 to 40feb69 Compare March 31, 2026 02:56

@obviyus obviyus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed latest changes; landing now.

@obviyus obviyus merged commit e394262 into openclaw:main Mar 31, 2026
33 of 35 checks passed
@obviyus

obviyus commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

Landed on main.

Thanks @neeravmakwana.

joeykrug added a commit to joeykrug/openclaw that referenced this pull request Apr 26, 2026
…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 <noreply@anthropic.com>
martingarramon added a commit to martingarramon/openclaw that referenced this pull request May 20, 2026
…gentModelConfigSelectionResult

PR openclaw#58003 (e394262) introduced a regression in agent-scope.ts: agentConfig.model
(the agent's own model) was placed before cfg.agents.defaults.subagents.model (the
global subagent default) in the candidates array. This shadowed the global default
for any agent that has its own model configured — the common case.

openclaw#81783 fixed the same regression in model-selection.ts but the agent-scope.ts path
was missed. This path is used by the cron isolation runner and resolveSubagentModel-
FallbacksOverride.

Correct precedence:
  1. agentConfig.subagents.model (per-agent subagent config)
  2. cfg.agents.defaults.subagents.model (global subagent default)
  3. agentConfig.model (agent's own model — last resort only)

Closes openclaw#58822.
martingarramon added a commit to martingarramon/openclaw that referenced this pull request May 23, 2026
…gentModelConfigSelectionResult

PR openclaw#58003 (e394262) introduced a regression in agent-scope.ts: agentConfig.model
(the agent's own model) was placed before cfg.agents.defaults.subagents.model (the
global subagent default) in the candidates array. This shadowed the global default
for any agent that has its own model configured — the common case.

openclaw#81783 fixed the same regression in model-selection.ts but the agent-scope.ts path
was missed. This path is used by the cron isolation runner and resolveSubagentModel-
FallbacksOverride.

Correct precedence:
  1. agentConfig.subagents.model (per-agent subagent config)
  2. cfg.agents.defaults.subagents.model (global subagent default)
  3. agentConfig.model (agent's own model — last resort only)

Closes openclaw#58822.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling gateway Gateway runtime size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: agents.list[].model.primary ignored - agents.defaults.subagents.model always wins

3 participants