mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 01:18:28 +00:00
feat(agents): configurable default runTimeoutSeconds for subagent spawns
When sessions_spawn is called without runTimeoutSeconds, subagents previously defaulted to 0 (no timeout). This adds a config key at agents.defaults.subagents.runTimeoutSeconds so operators can set a global default timeout for all subagent runs. The agent-provided value still takes precedence when explicitly passed. When neither the agent nor the config specifies a timeout, behavior is unchanged (0 = no timeout), preserving backwards compatibility. Updated for the subagent-spawn.ts refactor (logic moved from sessions-spawn-tool.ts to spawnSubagentDirect). Closes #19288 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Peter Steinberger
parent
803e02d8df
commit
5710d72527
@@ -0,0 +1,69 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createSessionsSpawnTool } from "./tools/sessions-spawn-tool.js";
|
||||
|
||||
vi.mock("../config/config.js", async () => {
|
||||
const actual = await vi.importActual("../config/config.js");
|
||||
return {
|
||||
...actual,
|
||||
loadConfig: () => ({
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
maxConcurrent: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
routing: {
|
||||
sessions: {
|
||||
mainKey: "agent:test:main",
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../gateway/call.js", () => {
|
||||
return {
|
||||
callGateway: vi.fn(async ({ method }: { method: string }) => {
|
||||
if (method === "agent") {
|
||||
return { runId: "run-456" };
|
||||
}
|
||||
return {};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../plugins/hook-runner-global.js", () => ({
|
||||
getGlobalHookRunner: () => null,
|
||||
}));
|
||||
|
||||
type GatewayCall = { method: string; params?: Record<string, unknown> };
|
||||
|
||||
async function getGatewayCalls(): Promise<GatewayCall[]> {
|
||||
const { callGateway } = await import("../gateway/call.js");
|
||||
return (callGateway as unknown as ReturnType<typeof vi.fn>).mock.calls.map(
|
||||
(call) => call[0] as GatewayCall,
|
||||
);
|
||||
}
|
||||
|
||||
function findLastCall(calls: GatewayCall[], predicate: (call: GatewayCall) => boolean) {
|
||||
for (let i = calls.length - 1; i >= 0; i -= 1) {
|
||||
const call = calls[i];
|
||||
if (call && predicate(call)) {
|
||||
return call;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
describe("sessions_spawn default runTimeoutSeconds (config absent)", () => {
|
||||
it("falls back to 0 (no timeout) when config key is absent", async () => {
|
||||
const tool = createSessionsSpawnTool({ agentSessionKey: "agent:test:main" });
|
||||
const result = await tool.execute("call-1", { task: "hello" });
|
||||
expect(result.details).toMatchObject({ status: "accepted" });
|
||||
|
||||
const calls = await getGatewayCalls();
|
||||
const agentCall = findLastCall(calls, (call) => call.method === "agent");
|
||||
expect(agentCall?.params?.timeout).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user