Skip to content

Commit 2b04ced

Browse files
authored
Fix subagent default model precedence (#81783)
* fix subagent default model precedence * docs changelog for subagent default fix
1 parent d25bece commit 2b04ced

4 files changed

Lines changed: 57 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
2727
- macOS/Gateway: fail managed LaunchAgent stop and restart when the configured gateway port remains busy after cleanup instead of reporting success while a listener survives. Fixes #73132. Thanks @BunsDev.
2828
- Telegram: ship the isolated polling worker at the root dist path used by the bundled worker loader, avoiding startup failures looking for `dist/telegram-ingress-worker.runtime.js`.
2929
- Security/sandbox: include Windows `USERPROFILE` in the sandbox blocked home roots so credential-bearing binds (such as `.codex`, `.openclaw`, or `.ssh` under the Windows user profile) are denied even when `HOME` points at a different shell home. (#63074) Thanks @luoyanglang.
30+
- Agents/subagents: apply `agents.defaults.subagents.model` before target agent primary models during `sessions_spawn`, so model-scoped runtimes such as `claude-cli` stay attached to default child runs. Fixes #81395. (#81783) Thanks @joshavant.
3031
- Gateway/OpenAI-compatible HTTP: parse shared JSON endpoint paths without trusting malformed Host headers, avoiding 500s before `/v1/chat/completions`, `/v1/responses`, and `/v1/embeddings` request handling.
3132
- Telegram: keep Bot API polling alive during main event-loop stalls by moving ingress to an isolated worker with a durable local spool. Fixes #81132. (#81746) Thanks @joshavant.
3233
- Telegram: resolve plugin native commands with the active runtime config so commands like `/codex ...` stay on the native command path.

src/agents/model-selection.test.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { describe, it, expect, vi } from "vitest";
22
import type { OpenClawConfig } from "../config/types.js";
33
import { resetLogger, setLoggerOverride } from "../logging/logger.js";
44
import { createWarnLogCapture } from "../logging/test-helpers/warn-log-capture.js";
5+
import { resolveAgentHarnessPolicy } from "./harness/policy.js";
56
import { migrateLegacyRuntimeModelRef } from "./model-runtime-aliases.js";
67
import { isModelKeyAllowedBySet, providerWildcardModelKey } from "./model-selection-shared.js";
78
import {
@@ -2186,7 +2187,7 @@ describe("normalizeModelSelection", () => {
21862187
});
21872188

21882189
describe("resolveSubagentConfiguredModelSelection", () => {
2189-
it("prefers the agent primary model over agents.defaults.subagents.model", () => {
2190+
it("prefers agents.defaults.subagents.model over the agent primary model", () => {
21902191
const cfg = {
21912192
agents: {
21922193
defaults: {
@@ -2203,7 +2204,7 @@ describe("resolveSubagentConfiguredModelSelection", () => {
22032204
} as OpenClawConfig;
22042205

22052206
expect(resolveSubagentConfiguredModelSelection({ cfg, agentId: "research" })).toBe(
2206-
"anthropic/claude-opus-4-6",
2207+
"openai/gpt-5.4",
22072208
);
22082209
});
22092210

@@ -2228,6 +2229,34 @@ describe("resolveSubagentConfiguredModelSelection", () => {
22282229
"google/gemini-2.5-pro",
22292230
);
22302231
});
2232+
2233+
it("keeps runtime policy attached to the configured default subagent model", () => {
2234+
const cfg = {
2235+
agents: {
2236+
defaults: {
2237+
subagents: { model: "anthropic/claude-sonnet-4-6" },
2238+
models: {
2239+
"anthropic/claude-sonnet-4-6": { agentRuntime: { id: "claude-cli" } },
2240+
},
2241+
},
2242+
list: [{ id: "research", model: "anthropic/claude-opus-4-7" }],
2243+
},
2244+
} as OpenClawConfig;
2245+
2246+
const resolved = resolveSubagentConfiguredModelSelection({ cfg, agentId: "research" });
2247+
2248+
expect(resolved).toBe("anthropic/claude-sonnet-4-6");
2249+
expect(
2250+
resolveAgentHarnessPolicy({
2251+
provider: "anthropic",
2252+
modelId: "claude-sonnet-4-6",
2253+
config: cfg,
2254+
}),
2255+
).toEqual({
2256+
runtime: "claude-cli",
2257+
runtimeSource: "model",
2258+
});
2259+
});
22312260
});
22322261

22332262
describe("resolveSubagentSpawnModelSelection", () => {

src/agents/model-selection.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,8 @@ export function resolveSubagentConfiguredModelSelection(params: {
322322
const agentConfig = resolveAgentConfig(params.cfg, params.agentId);
323323
return (
324324
normalizeModelSelection(agentConfig?.subagents?.model) ??
325-
normalizeModelSelection(agentConfig?.model) ??
326-
normalizeModelSelection(params.cfg.agents?.defaults?.subagents?.model)
325+
normalizeModelSelection(params.cfg.agents?.defaults?.subagents?.model) ??
326+
normalizeModelSelection(agentConfig?.model)
327327
);
328328
}
329329

src/agents/openclaw-tools.subagents.sessions-spawn.model.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,29 @@ describe("subagent spawn model + thinking plan", () => {
121121
expect(plan.initialSessionPatch.modelOverrideSource).toBe("auto");
122122
});
123123

124+
it("prefers default subagent model over target agent primary model", () => {
125+
const cfg = createConfig({
126+
agents: {
127+
defaults: { subagents: { model: "minimax/MiniMax-M2.7" } },
128+
list: [{ id: "research", model: { primary: "opencode/claude" } }],
129+
},
130+
});
131+
const targetAgentConfig = {
132+
id: "research",
133+
model: { primary: "opencode/claude" },
134+
};
135+
const plan = expectOkPlan(
136+
resolveSubagentModelAndThinkingPlan({
137+
cfg,
138+
targetAgentId: "research",
139+
targetAgentConfig,
140+
}),
141+
);
142+
expect(plan.resolvedModel).toBe("minimax/MiniMax-M2.7");
143+
expect(plan.initialSessionPatch.model).toBe("minimax/MiniMax-M2.7");
144+
expect(plan.initialSessionPatch.modelOverrideSource).toBe("auto");
145+
});
146+
124147
it("prefers target agent primary model over global default", () => {
125148
const cfg = createConfig({
126149
agents: {

0 commit comments

Comments
 (0)