openclaw - ✅(Solved) Fix [Bug]: sessions_spawn(runtime="subagent") does not honor agents.defaults.subagents.model or explicit model override [3 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#43768Fetched 2026-04-08 00:18:16
View on GitHub
Comments
2
Participants
2
Timeline
6
Reactions
0
Timeline (top)
commented ×2cross-referenced ×2labeled ×2

Native subagents spawned via sessions_spawn(runtime="subagent") ignore both agents.defaults.subagents.model and explicit sessions_spawn.model, and run on the caller/main model (openai-codex/gpt-5.4) instead of the requested openai/gpt-5-mini.

Root Cause

Native subagents spawned via sessions_spawn(runtime="subagent") ignore both agents.defaults.subagents.model and explicit sessions_spawn.model, and run on the caller/main model (openai-codex/gpt-5.4) instead of the requested openai/gpt-5-mini.

Fix Action

Fix / Workaround

Installed source also suggests this should work:

  • config schema exposes agents.defaults.subagents.model
  • resolveSubagentSpawnModelSelection(...) checks explicit override first, then subagent config
  • spawnSubagentDirect(...) resolves a child model and calls patchChildSession({ model: resolvedModel })
  • gateway sessions.patch supports model
  • session handling code appears to support sessionEntry.modelOverride

Current best hypothesis:

  • the first agent run for a fresh subagent session is ignoring the patched child session override, or
  • the child run initialization path is recomputing model selection from parent/default state instead of honoring the already-patched child session entry

Temporary workaround:

  • assume native subagents may inherit the caller/main model in this path even when agents.defaults.subagents.model or explicit sessions_spawn.model is set
  • do not rely on native subagent model routing for cost control until this behavior is clarified or fixed

PR fix notes

PR #43826: fix: keep session model overrides from silently falling back

Description (problem / solution / changelog)

Summary

  • treat session-level model overrides as strict by default in resolveEffectiveModelFallbacks
  • keep per-agent fallback overrides working when explicitly configured
  • update agent-scope.test.ts coverage for the session-override + default-fallback case

Why

When a session already has an explicit model override (including subagent spawn model routing), inheriting global default fallbacks can silently swap to a different model and make it look like the override was ignored.

Validation

  • bash /Users/newdldewdl/.openclaw/workspace/skills/openclaw-autonomous-contributor/scripts/quality_gate.sh /tmp/openclaw-issue-43768-1773301093

Fixes #43768

Changed files

  • src/agents/agent-scope.test.ts (modified, +23/-1)
  • src/agents/agent-scope.ts (modified, +11/-2)
  • src/agents/pi-embedded-runner/run.ts (modified, +1/-0)
  • src/agents/pi-embedded-runner/run/params.ts (modified, +2/-0)
  • src/commands/agent.ts (modified, +3/-0)

PR #53262: fix: Make agentId required in sessions_spawn tool schema

Description (problem / solution / changelog)

Summary

Make agentId a required parameter in the sessions_spawn tool schema instead of optional.

Problem

When agentId is optional, models frequently omit it when spawning subagents — especially on retry/revision calls deeper in the conversation. The silent fallback to the requester's own agent ID causes subagents to run under the parent's identity instead of the intended target agent.

In testing with Claude Haiku 4.5, agentId was omitted on ~80% of re-spawn calls (revisions after fact-check failures), while included on ~80% of initial spawns copied from the prompt template. Making the field required at the schema level achieved 100% inclusion — schema enforcement is more reliable than prompt engineering.

Solution

Remove Type.Optional() from agentId in SessionsSpawnToolSchema. The model now sees agentId as required in the tool definition and must always specify it. Agents can still spawn copies of themselves by passing their own ID explicitly.

The implementation layer (readStringParam + fallback in subagent-spawn.ts) is unchanged and remains backward-compatible.

Related Issues

Closes #29368 — Option to require agentId for sub-agent spawning Closes #29982 — Block generic subagent spawns

Testing

  • Added test verifying agentId is in the schema's required array
  • Updated all existing spawn tests to include agentId
  • All 82 spawn-related tests pass
  • Full test suite passes (7958 tests)

Changed files

  • src/agents/openclaw-tools.subagents.sessions-spawn-applies-thinking-default.test.ts (modified, +1/-1)
  • src/agents/openclaw-tools.subagents.sessions-spawn-default-timeout-absent.test.ts (modified, +1/-1)
  • src/agents/openclaw-tools.subagents.sessions-spawn-default-timeout.test.ts (modified, +1/-1)
  • src/agents/openclaw-tools.subagents.sessions-spawn-depth-limits.test.ts (modified, +26/-8)
  • src/agents/openclaw-tools.subagents.sessions-spawn.allowlist.test.ts (modified, +12/-6)
  • src/agents/openclaw-tools.subagents.sessions-spawn.lifecycle.test.ts (modified, +2/-0)
  • src/agents/openclaw-tools.subagents.sessions-spawn.model.test.ts (modified, +1/-0)
  • src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts (modified, +11/-0)
  • src/agents/sessions-spawn-threadid.test.ts (modified, +1/-0)
  • src/agents/subagent-spawn.attachments.test.ts (modified, +23/-0)
  • src/agents/tools/sessions-spawn-tool.test.ts (modified, +12/-0)
  • src/agents/tools/sessions-spawn-tool.ts (modified, +4/-2)

PR #64508: fix(agents): persist subagent spawn model to override fields

Description (problem / solution / changelog)

Summary

  • Problem: When spawning a subagent with a model override (via sessions_spawn or subagents.model config), the child session runs on the default model instead of the requested model, despite modelApplied: true in the spawn response.
  • Why it matters: Subagent model routing is broken. Users are billed for expensive models (Opus) when they configured cheaper ones (Sonnet/Gemma). The modelApplied: true response is misleading.
  • What changed: persistInitialChildSessionRuntimeModel() now writes to modelOverride/providerOverride/modelOverrideSource instead of model/modelProvider. Secondary fix: live-switch path uses agent-resolved defaults instead of global constants.
  • What did NOT change (scope boundary): agentCommand startup logic is unchanged - it already reads override fields correctly.

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

  • Closes #48271
  • Closes #43768
  • Related #57306, #62755, #62562, #63221
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: persistInitialChildSessionRuntimeModel() writes to runtime fields (model, modelProvider), but agentCommandInternal() reads from override fields (modelOverride, providerOverride) for startup model selection.
  • Missing detection / guardrail: Tests expected runtime field persistence, which locked in the buggy behavior.
  • Contributing context: The distinction between runtime fields ("what actually ran") and override fields ("what should run") was not enforced at the spawn boundary.

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/subagent-spawn.model-override.test.ts (new), updated assertions in subagent-spawn.model-session.test.ts
  • Scenario the test should lock in: Spawn persistence writes override fields, and first-run model selection reads those override fields.
  • Why this is the smallest reliable guardrail: The bug is a field-contract mismatch between spawn and startup; unit tests at both boundaries are the minimal coverage.

AI disclosure

  • AI-assisted (Claude Opus 4.5 via Claude Code)
  • Tested (build + check + unit tests pass)
  • I understand what the code does

Co-Authored-By: Claude [email protected]

Changed files

  • src/agents/pi-embedded-runner/run.ts (modified, +11/-3)
  • src/agents/subagent-spawn.model-override.test.ts (added, +157/-0)
  • src/agents/subagent-spawn.model-session.test.ts (modified, +5/-4)
  • src/agents/subagent-spawn.test-helpers.ts (modified, +15/-3)
  • src/agents/subagent-spawn.test.ts (modified, +3/-2)
  • src/agents/subagent-spawn.ts (modified, +3/-2)

Code Example

Redacted evidence from the final proof pass:

- Subagent run record (`~/.openclaw/subagents/runs.json`) stored the child run with:
  - `model: "openai/gpt-5-mini"`

- Child session transcript (`~/.openclaw/agents/main/sessions/<child-session-id>.jsonl`) began with:
  - `model_change``gpt-5.4`
  - `model-snapshot``openai-codex / gpt-5.4`

- Child assistant reply metadata also showed:
  - `provider: "openai-codex"`
  - `model: "gpt-5.4"`

- Child session store entry (`~/.openclaw/agents/main/sessions/sessions.json`) recorded:
  - `modelProvider: "openai-codex"`
  - `model: "gpt-5.4"`

This shows a direct mismatch between the requested/recorded subagent model and the actual child runtime model used.
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Summary

Native subagents spawned via sessions_spawn(runtime="subagent") ignore both agents.defaults.subagents.model and explicit sessions_spawn.model, and run on the caller/main model (openai-codex/gpt-5.4) instead of the requested openai/gpt-5-mini.

Steps to reproduce

  1. Configure the main/default model as openai-codex/gpt-5.4.
  2. Configure agents.defaults.subagents.model = openai/gpt-5-mini.
  3. Spawn a native subagent with no explicit model override.
  4. Observe that the child session reports/runs on gpt-5.4.
  5. Spawn another native subagent with sessions_spawn(..., runtime: "subagent", model: "openai/gpt-5-mini").
  6. Observe that the child session still reports/runs on gpt-5.4.
  7. Inspect the subagent run record and child session transcript/store:
    • ~/.openclaw/subagents/runs.json records the child run with model: "openai/gpt-5-mini"
    • the child transcript/store still shows openai-codex / gpt-5.4

Expected behavior

Subagents should use agents.defaults.subagents.model by default, and an explicit sessions_spawn.model should override that. In this case, the child subagent should run on openai/gpt-5-mini, not openai-codex/gpt-5.4.

Actual behavior

Subagents continue running on gpt-5.4 even when:

  • agents.defaults.subagents.model = openai/gpt-5-mini
  • sessions_spawn(..., model: "openai/gpt-5-mini") is used explicitly

In the final proof pass, the subagent run record stored model: "openai/gpt-5-mini" while the child session transcript, model events, reply metadata, and session store all showed openai-codex / gpt-5.4.

OpenClaw version

2026.3.8

Operating system

Ubuntu 24.04

Install method

npm global

Model

openai/gpt-5-mini (requested) → actual runtime became openai-codex/gpt-5.4

Provider / routing chain

openclaw gateway -> native subagent runtime -> OpenAI (expected: openai/gpt-5-mini, actual: openai-codex/gpt-5.4)

Config file / key location

~/.openclaw/openclaw.json; ~/.openclaw/subagents/runs.json; ~/.openclaw/agents/main/sessions/sessions.json

Additional provider/model setup details

Main/default model was configured as openai-codex/gpt-5.4 using OAuth profile openai-codex:default.

Subagent default was configured as:

  • agents.defaults.subagents.model = openai/gpt-5-mini

The issue reproduces both when:

  • relying on agents.defaults.subagents.model, and
  • passing explicit sessions_spawn(..., model: "openai/gpt-5-mini")

In the final proof pass, the subagent run record stored model: "openai/gpt-5-mini" in ~/.openclaw/subagents/runs.json, but the child session transcript/store and reply metadata all showed openai-codex / gpt-5.4.

Logs, screenshots, and evidence

Redacted evidence from the final proof pass:

- Subagent run record (`~/.openclaw/subagents/runs.json`) stored the child run with:
  - `model: "openai/gpt-5-mini"`

- Child session transcript (`~/.openclaw/agents/main/sessions/<child-session-id>.jsonl`) began with:
  - `model_change``gpt-5.4`
  - `model-snapshot``openai-codex / gpt-5.4`

- Child assistant reply metadata also showed:
  - `provider: "openai-codex"`
  - `model: "gpt-5.4"`

- Child session store entry (`~/.openclaw/agents/main/sessions/sessions.json`) recorded:
  - `modelProvider: "openai-codex"`
  - `model: "gpt-5.4"`

This shows a direct mismatch between the requested/recorded subagent model and the actual child runtime model used.

Impact and severity

Affected: OpenClaw users relying on native subagent model routing for cost control or workload separation

Severity: Medium to High

  • Does not prevent subagents from running
  • But it silently breaks intended model routing
  • Can lead to unexpected higher-cost usage and incorrect operational assumptions

Frequency: 100% repro in tested environment

  • reproduced with configured subagent default
  • reproduced with explicit sessions_spawn.model override
  • reproduced again in a final proof pass

Consequence:

  • intended subagent cost split cannot be enforced
  • subagents may run on a higher-cost model than expected
  • documentation/config imply behavior that does not match runtime results

Additional information

I checked both docs and installed source before filing this.

Documentation alignment:

  • /tools/subagents says subagents inherit the caller unless agents.defaults.subagents.model is set, and explicit sessions_spawn.model should win
  • /concepts/session-tool documents sessions_spawn.model as an override for the subagent model
  • FAQ guidance suggests setting agents.defaults.subagents.model for cheaper subagent routing when cost matters

Installed source also suggests this should work:

  • config schema exposes agents.defaults.subagents.model
  • resolveSubagentSpawnModelSelection(...) checks explicit override first, then subagent config
  • spawnSubagentDirect(...) resolves a child model and calls patchChildSession({ model: resolvedModel })
  • gateway sessions.patch supports model
  • session handling code appears to support sessionEntry.modelOverride

Current best hypothesis:

  • the first agent run for a fresh subagent session is ignoring the patched child session override, or
  • the child run initialization path is recomputing model selection from parent/default state instead of honoring the already-patched child session entry

Temporary workaround:

  • assume native subagents may inherit the caller/main model in this path even when agents.defaults.subagents.model or explicit sessions_spawn.model is set
  • do not rely on native subagent model routing for cost control until this behavior is clarified or fixed

extent analysis

Problem Summary

Native subagents spawned with sessions_spawn(runtime="subagent") always run on the caller’s model (openai‑codex/gpt‑5.4) even when:

  • agents.defaults.subagents.model = openai/gpt‑5-mini is set, or
  • sessions_spawn(..., model: "openai/gpt‑5-mini") is passed.

The run record (runs.json) stores the correct model, but the child session transcript, metadata and store still show the parent model.


Root Cause (quick)

The model‑selection logic for subagents is applied after the child session is created.
spawnSubagentDirect() patches the session with { model: resolvedModel }, but the subsequent call to createChildRun() re‑evaluates the model from the parent’s defaults, overwriting the patch.
Result: the persisted run record (written before the overwrite) is correct, while the live session uses the parent model.


Fix Plan

1. Change the order of operations / enforce the override

  • Resolve the model once in resolveSubagentSpawnModelSelection() and store it in a modelOverride field on the child session entry.
  • Ensure all downstream code (createChildRun, gateway.sessions.patch, sessionEntryFromRun) reads modelOverride instead of recomputing from defaults.

Code changes (TypeScript – OpenClaw source)

// src/agents/subagents.ts
export function resolveSubagentSpawnModelSelection(
  parentCfg: Config,
  spawnOpts: SpawnOptions
): string {
  // 1️⃣ explicit override wins
  if (spawnOpts.model) return spawnOpts.model;

  // 2️⃣ sub‑agent default
  const subDef = parentCfg.agents?.defaults?.subagents?.model;
  if (subDef) return subDef;

  // 3️⃣ fall back to parent model
  return parentCfg.agents?.defaults?.model;
}
// src/agents/spawn.ts
export async function spawnSubagentDirect(
  parentSession: Session,
  opts: SpawnOptions
) {
  const model = resolveSubagentSpawnModelSelection(parentSession.cfg, opts);

  // Create child session entry **with

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Subagents should use agents.defaults.subagents.model by default, and an explicit sessions_spawn.model should override that. In this case, the child subagent should run on openai/gpt-5-mini, not openai-codex/gpt-5.4.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: sessions_spawn(runtime="subagent") does not honor agents.defaults.subagents.model or explicit model override [3 pull requests, 2 comments, 2 participants]