diff --git a/src/agents/openclaw-tools.subagents.sessions-spawn.model.e2e.test.ts b/src/agents/openclaw-tools.subagents.sessions-spawn.model.e2e.test.ts index 6427e7b6d4..c0e67858fd 100644 --- a/src/agents/openclaw-tools.subagents.sessions-spawn.model.e2e.test.ts +++ b/src/agents/openclaw-tools.subagents.sessions-spawn.model.e2e.test.ts @@ -12,6 +12,7 @@ import { SUBAGENT_SPAWN_ACCEPTED_NOTE } from "./subagent-spawn.js"; const callGatewayMock = getCallGatewayMock(); type GatewayCall = { method?: string; params?: unknown }; +type SessionsSpawnConfigOverride = Parameters[0]; function mockLongRunningSpawnFlow(params: { calls: GatewayCall[]; @@ -60,6 +61,39 @@ function mockPatchAndSingleAgentRun(params: { calls: GatewayCall[]; runId: strin }); } +async function expectSpawnUsesConfiguredModel(params: { + config: SessionsSpawnConfigOverride; + runId: string; + callId: string; + expectedModel: string; +}) { + resetSubagentRegistryForTests(); + callGatewayMock.mockReset(); + setSessionsSpawnConfigOverride(params.config); + const calls: GatewayCall[] = []; + mockPatchAndSingleAgentRun({ calls, runId: params.runId }); + + const tool = await getSessionsSpawnTool({ + agentSessionKey: "agent:research:main", + agentChannel: "discord", + }); + + const result = await tool.execute(params.callId, { + task: "do thing", + }); + expect(result.details).toMatchObject({ + status: "accepted", + modelApplied: true, + }); + + const patchCall = calls.find( + (call) => call.method === "sessions.patch" && (call.params as { model?: string })?.model, + ); + expect(patchCall?.params).toMatchObject({ + model: params.expectedModel, + }); +} + describe("openclaw-tools: subagents (sessions_spawn model + thinking)", () => { beforeEach(() => { resetSessionsSpawnConfigOverride(); @@ -222,70 +256,32 @@ describe("openclaw-tools: subagents (sessions_spawn model + thinking)", () => { }); it("sessions_spawn prefers per-agent subagent model over defaults", async () => { - resetSubagentRegistryForTests(); - callGatewayMock.mockReset(); - setSessionsSpawnConfigOverride({ - session: { mainKey: "main", scope: "per-sender" }, - agents: { - defaults: { subagents: { model: "minimax/MiniMax-M2.1" } }, - list: [{ id: "research", subagents: { model: "opencode/claude" } }], + await expectSpawnUsesConfiguredModel({ + config: { + session: { mainKey: "main", scope: "per-sender" }, + agents: { + defaults: { subagents: { model: "minimax/MiniMax-M2.1" } }, + list: [{ id: "research", subagents: { model: "opencode/claude" } }], + }, }, - }); - const calls: GatewayCall[] = []; - mockPatchAndSingleAgentRun({ calls, runId: "run-agent-model" }); - - const tool = await getSessionsSpawnTool({ - agentSessionKey: "agent:research:main", - agentChannel: "discord", - }); - - const result = await tool.execute("call-agent-model", { - task: "do thing", - }); - expect(result.details).toMatchObject({ - status: "accepted", - modelApplied: true, - }); - - const patchCall = calls.find( - (call) => call.method === "sessions.patch" && (call.params as { model?: string })?.model, - ); - expect(patchCall?.params).toMatchObject({ - model: "opencode/claude", + runId: "run-agent-model", + callId: "call-agent-model", + expectedModel: "opencode/claude", }); }); it("sessions_spawn prefers target agent primary model over global default", async () => { - resetSubagentRegistryForTests(); - callGatewayMock.mockReset(); - setSessionsSpawnConfigOverride({ - session: { mainKey: "main", scope: "per-sender" }, - agents: { - defaults: { model: { primary: "minimax/MiniMax-M2.1" } }, - list: [{ id: "research", model: { primary: "opencode/claude" } }], + await expectSpawnUsesConfiguredModel({ + config: { + session: { mainKey: "main", scope: "per-sender" }, + agents: { + defaults: { model: { primary: "minimax/MiniMax-M2.1" } }, + list: [{ id: "research", model: { primary: "opencode/claude" } }], + }, }, - }); - const calls: GatewayCall[] = []; - mockPatchAndSingleAgentRun({ calls, runId: "run-agent-primary-model" }); - - const tool = await getSessionsSpawnTool({ - agentSessionKey: "agent:research:main", - agentChannel: "discord", - }); - - const result = await tool.execute("call-agent-primary-model", { - task: "do thing", - }); - expect(result.details).toMatchObject({ - status: "accepted", - modelApplied: true, - }); - - const patchCall = calls.find( - (call) => call.method === "sessions.patch" && (call.params as { model?: string })?.model, - ); - expect(patchCall?.params).toMatchObject({ - model: "opencode/claude", + runId: "run-agent-primary-model", + callId: "call-agent-primary-model", + expectedModel: "opencode/claude", }); });