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:
Mitch McAlister
2026-02-23 17:25:08 +00:00
committed by Peter Steinberger
parent 803e02d8df
commit 5710d72527
5 changed files with 162 additions and 3 deletions

View File

@@ -193,14 +193,22 @@ export async function spawnSubagentDirect(
threadId: ctx.agentThreadId,
});
const hookRunner = getGlobalHookRunner();
const cfg = loadConfig();
// When agent omits runTimeoutSeconds, use the config default.
// Falls back to 0 (no timeout) if config key is also unset,
// preserving current behavior for existing deployments.
const cfgSubagentTimeout =
typeof cfg?.agents?.defaults?.subagents?.runTimeoutSeconds === "number" &&
Number.isFinite(cfg.agents.defaults.subagents.runTimeoutSeconds)
? Math.max(0, Math.floor(cfg.agents.defaults.subagents.runTimeoutSeconds))
: 0;
const runTimeoutSeconds =
typeof params.runTimeoutSeconds === "number" && Number.isFinite(params.runTimeoutSeconds)
? Math.max(0, Math.floor(params.runTimeoutSeconds))
: 0;
: cfgSubagentTimeout;
let modelApplied = false;
let threadBindingReady = false;
const cfg = loadConfig();
const { mainKey, alias } = resolveMainSessionAlias(cfg);
const requesterSessionKey = ctx.agentSessionKey;
const requesterInternalKey = requesterSessionKey