mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 17:54:47 +00:00
Fix subagent default model precedence (#81783)
* fix subagent default model precedence * docs changelog for subagent default fix
This commit is contained in:
@@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
|
||||
- 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.
|
||||
- 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`.
|
||||
- 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.
|
||||
- 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.
|
||||
- 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.
|
||||
- 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.
|
||||
- Telegram: resolve plugin native commands with the active runtime config so commands like `/codex ...` stay on the native command path.
|
||||
|
||||
@@ -2,6 +2,7 @@ import { describe, it, expect, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.js";
|
||||
import { resetLogger, setLoggerOverride } from "../logging/logger.js";
|
||||
import { createWarnLogCapture } from "../logging/test-helpers/warn-log-capture.js";
|
||||
import { resolveAgentHarnessPolicy } from "./harness/policy.js";
|
||||
import { migrateLegacyRuntimeModelRef } from "./model-runtime-aliases.js";
|
||||
import { isModelKeyAllowedBySet, providerWildcardModelKey } from "./model-selection-shared.js";
|
||||
import {
|
||||
@@ -2186,7 +2187,7 @@ describe("normalizeModelSelection", () => {
|
||||
});
|
||||
|
||||
describe("resolveSubagentConfiguredModelSelection", () => {
|
||||
it("prefers the agent primary model over agents.defaults.subagents.model", () => {
|
||||
it("prefers agents.defaults.subagents.model over the agent primary model", () => {
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
@@ -2203,7 +2204,7 @@ describe("resolveSubagentConfiguredModelSelection", () => {
|
||||
} as OpenClawConfig;
|
||||
|
||||
expect(resolveSubagentConfiguredModelSelection({ cfg, agentId: "research" })).toBe(
|
||||
"anthropic/claude-opus-4-6",
|
||||
"openai/gpt-5.4",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2228,6 +2229,34 @@ describe("resolveSubagentConfiguredModelSelection", () => {
|
||||
"google/gemini-2.5-pro",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps runtime policy attached to the configured default subagent model", () => {
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: { model: "anthropic/claude-sonnet-4-6" },
|
||||
models: {
|
||||
"anthropic/claude-sonnet-4-6": { agentRuntime: { id: "claude-cli" } },
|
||||
},
|
||||
},
|
||||
list: [{ id: "research", model: "anthropic/claude-opus-4-7" }],
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const resolved = resolveSubagentConfiguredModelSelection({ cfg, agentId: "research" });
|
||||
|
||||
expect(resolved).toBe("anthropic/claude-sonnet-4-6");
|
||||
expect(
|
||||
resolveAgentHarnessPolicy({
|
||||
provider: "anthropic",
|
||||
modelId: "claude-sonnet-4-6",
|
||||
config: cfg,
|
||||
}),
|
||||
).toEqual({
|
||||
runtime: "claude-cli",
|
||||
runtimeSource: "model",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveSubagentSpawnModelSelection", () => {
|
||||
|
||||
@@ -322,8 +322,8 @@ export function resolveSubagentConfiguredModelSelection(params: {
|
||||
const agentConfig = resolveAgentConfig(params.cfg, params.agentId);
|
||||
return (
|
||||
normalizeModelSelection(agentConfig?.subagents?.model) ??
|
||||
normalizeModelSelection(agentConfig?.model) ??
|
||||
normalizeModelSelection(params.cfg.agents?.defaults?.subagents?.model)
|
||||
normalizeModelSelection(params.cfg.agents?.defaults?.subagents?.model) ??
|
||||
normalizeModelSelection(agentConfig?.model)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,29 @@ describe("subagent spawn model + thinking plan", () => {
|
||||
expect(plan.initialSessionPatch.modelOverrideSource).toBe("auto");
|
||||
});
|
||||
|
||||
it("prefers default subagent model over target agent primary model", () => {
|
||||
const cfg = createConfig({
|
||||
agents: {
|
||||
defaults: { subagents: { model: "minimax/MiniMax-M2.7" } },
|
||||
list: [{ id: "research", model: { primary: "opencode/claude" } }],
|
||||
},
|
||||
});
|
||||
const targetAgentConfig = {
|
||||
id: "research",
|
||||
model: { primary: "opencode/claude" },
|
||||
};
|
||||
const plan = expectOkPlan(
|
||||
resolveSubagentModelAndThinkingPlan({
|
||||
cfg,
|
||||
targetAgentId: "research",
|
||||
targetAgentConfig,
|
||||
}),
|
||||
);
|
||||
expect(plan.resolvedModel).toBe("minimax/MiniMax-M2.7");
|
||||
expect(plan.initialSessionPatch.model).toBe("minimax/MiniMax-M2.7");
|
||||
expect(plan.initialSessionPatch.modelOverrideSource).toBe("auto");
|
||||
});
|
||||
|
||||
it("prefers target agent primary model over global default", () => {
|
||||
const cfg = createConfig({
|
||||
agents: {
|
||||
|
||||
Reference in New Issue
Block a user