mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-17 12:11:20 +00:00
155 lines
4.5 KiB
TypeScript
155 lines
4.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { OpenClawConfig } from "../config/config.js";
|
|
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js";
|
|
import {
|
|
resolveConfiguredSubagentRunTimeoutSeconds,
|
|
resolveSubagentModelAndThinkingPlan,
|
|
} from "./subagent-spawn-plan.js";
|
|
|
|
function createConfig(overrides?: Record<string, unknown>): OpenClawConfig {
|
|
return {
|
|
session: { mainKey: "main", scope: "per-sender" },
|
|
...overrides,
|
|
} as OpenClawConfig;
|
|
}
|
|
|
|
describe("subagent spawn model + thinking plan", () => {
|
|
it("includes explicit model overrides in the initial patch", () => {
|
|
const plan = resolveSubagentModelAndThinkingPlan({
|
|
cfg: createConfig(),
|
|
targetAgentId: "research",
|
|
modelOverride: "claude-haiku-4-5",
|
|
});
|
|
expect(plan).toMatchObject({
|
|
status: "ok",
|
|
resolvedModel: "claude-haiku-4-5",
|
|
modelApplied: true,
|
|
initialSessionPatch: {
|
|
model: "claude-haiku-4-5",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("normalizes thinking overrides into the initial patch", () => {
|
|
const plan = resolveSubagentModelAndThinkingPlan({
|
|
cfg: createConfig(),
|
|
targetAgentId: "research",
|
|
thinkingOverrideRaw: "high",
|
|
});
|
|
expect(plan).toMatchObject({
|
|
status: "ok",
|
|
thinkingOverride: "high",
|
|
initialSessionPatch: {
|
|
thinkingLevel: "high",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("rejects invalid thinking levels before any runtime work", () => {
|
|
const plan = resolveSubagentModelAndThinkingPlan({
|
|
cfg: createConfig(),
|
|
targetAgentId: "research",
|
|
thinkingOverrideRaw: "banana",
|
|
});
|
|
expect(plan).toMatchObject({
|
|
status: "error",
|
|
});
|
|
if (plan.status === "error") {
|
|
expect(plan.error).toMatch(/Invalid thinking level/i);
|
|
}
|
|
});
|
|
|
|
it("applies default subagent model from defaults config", () => {
|
|
const plan = resolveSubagentModelAndThinkingPlan({
|
|
cfg: createConfig({
|
|
agents: { defaults: { subagents: { model: "minimax/MiniMax-M2.7" } } },
|
|
}),
|
|
targetAgentId: "research",
|
|
});
|
|
expect(plan).toMatchObject({
|
|
status: "ok",
|
|
resolvedModel: "minimax/MiniMax-M2.7",
|
|
initialSessionPatch: { model: "minimax/MiniMax-M2.7" },
|
|
});
|
|
});
|
|
|
|
it("falls back to runtime default model when no model config is set", () => {
|
|
const plan = resolveSubagentModelAndThinkingPlan({
|
|
cfg: createConfig(),
|
|
targetAgentId: "research",
|
|
});
|
|
expect(plan).toMatchObject({
|
|
status: "ok",
|
|
resolvedModel: `${DEFAULT_PROVIDER}/${DEFAULT_MODEL}`,
|
|
initialSessionPatch: { model: `${DEFAULT_PROVIDER}/${DEFAULT_MODEL}` },
|
|
});
|
|
});
|
|
|
|
it("prefers per-agent subagent model over defaults", () => {
|
|
const cfg = createConfig({
|
|
agents: {
|
|
defaults: { subagents: { model: "minimax/MiniMax-M2.7" } },
|
|
list: [{ id: "research", subagents: { model: "opencode/claude" } }],
|
|
},
|
|
});
|
|
const targetAgentConfig = {
|
|
id: "research",
|
|
subagents: { model: "opencode/claude" },
|
|
};
|
|
const plan = resolveSubagentModelAndThinkingPlan({
|
|
cfg,
|
|
targetAgentId: "research",
|
|
targetAgentConfig,
|
|
});
|
|
expect(plan).toMatchObject({
|
|
status: "ok",
|
|
resolvedModel: "opencode/claude",
|
|
initialSessionPatch: { model: "opencode/claude" },
|
|
});
|
|
});
|
|
|
|
it("prefers target agent primary model over global default", () => {
|
|
const cfg = createConfig({
|
|
agents: {
|
|
defaults: { model: { primary: "minimax/MiniMax-M2.7" } },
|
|
list: [{ id: "research", model: { primary: "opencode/claude" } }],
|
|
},
|
|
});
|
|
const targetAgentConfig = {
|
|
id: "research",
|
|
model: { primary: "opencode/claude" },
|
|
};
|
|
const plan = resolveSubagentModelAndThinkingPlan({
|
|
cfg,
|
|
targetAgentId: "research",
|
|
targetAgentConfig,
|
|
});
|
|
expect(plan).toMatchObject({
|
|
status: "ok",
|
|
resolvedModel: "opencode/claude",
|
|
initialSessionPatch: { model: "opencode/claude" },
|
|
});
|
|
});
|
|
|
|
it("uses config default timeout when agent omits runTimeoutSeconds", () => {
|
|
expect(
|
|
resolveConfiguredSubagentRunTimeoutSeconds({
|
|
cfg: createConfig({
|
|
agents: { defaults: { subagents: { runTimeoutSeconds: 120 } } },
|
|
}),
|
|
}),
|
|
).toBe(120);
|
|
});
|
|
|
|
it("explicit runTimeoutSeconds wins over config default", () => {
|
|
expect(
|
|
resolveConfiguredSubagentRunTimeoutSeconds({
|
|
cfg: createConfig({
|
|
agents: { defaults: { subagents: { runTimeoutSeconds: 120 } } },
|
|
}),
|
|
runTimeoutSeconds: 2,
|
|
}),
|
|
).toBe(2);
|
|
});
|
|
});
|