Skip to content

feat(config): add agents.defaults.subagents.timeoutSeconds#109

Merged
dgarson merged 1 commit intodgarson/forkfrom
feat/subagent-default-timeout
Feb 23, 2026
Merged

feat(config): add agents.defaults.subagents.timeoutSeconds#109
dgarson merged 1 commit intodgarson/forkfrom
feat/subagent-default-timeout

Conversation

@dgarson
Copy link
Owner

@dgarson dgarson commented Feb 23, 2026

Problem

Sub-agents spawned without an explicit runTimeoutSeconds in the sessions_spawn call defaulted to unlimited timeout. The existing agents.defaults.timeoutSeconds field had no effect on sub-agents — only on top-level agent sessions.

This caused last night's fleet incident: Barry's deterministic replay workstream and Tim's heartbeat workers ran until the gateway killed them (or didn't), rather than timing out cleanly.

Solution

Adds agents.defaults.subagents.timeoutSeconds — a configurable default timeout that applies to all spawned sub-agents when no per-call override is provided.

{
  "agents": {
    "defaults": {
      "subagents": {
        "timeoutSeconds": 600
      }
    }
  }
}

Changes (3 files, 14 insertions, 2 deletions)

  • src/config/zod-schema.agent-defaults.ts — adds timeoutSeconds to the subagents object schema (required since the schema uses .strict())
  • src/config/types.agent-defaults.ts — adds timeoutSeconds?: number to the AgentDefaultsConfig.subagents interface
  • src/agents/subagent-registry.ts — two one-line changes:
    • registerSubagentRun: falls back to cfg.agents.defaults.subagents.timeoutSeconds before 0 (unlimited)
    • replaceSubagentRunAfterSteer: same fallback so resumed/steered sub-agents also respect the default

Behavior

Scenario Before After
runTimeoutSeconds explicitly passed Uses value (0 = unlimited) Unchanged
runTimeoutSeconds not passed, config unset Unlimited Unchanged (0 fallback)
runTimeoutSeconds not passed, config set to 600 Unlimited 600s
Steer/restart, no new timeout Carries previous value or unlimited Carries previous value or config default

No breaking changes. Existing callers passing runTimeoutSeconds: 0 retain unlimited timeout.

Adds a default timeout for spawned sub-agents, configurable via
agents.defaults.subagents.timeoutSeconds in openclaw.json.

Previously, sub-agents with no explicit runTimeoutSeconds in the
sessions_spawn call defaulted to unlimited (0 = NO_TIMEOUT_MS in
resolveAgentTimeoutMs). This meant the global agents.defaults.timeoutSeconds
had no effect on sub-agents — only top-level sessions.

Changes:
- zod-schema.agent-defaults.ts: add timeoutSeconds to the subagents
  .strict() schema object so the field is accepted and validated
- types.agent-defaults.ts: add timeoutSeconds?: number to the
  AgentDefaultsConfig.subagents interface
- subagent-registry.ts (registerSubagentRun): fall back to
  cfg.agents.defaults.subagents.timeoutSeconds when no per-call
  runTimeoutSeconds is provided, before defaulting to 0 (unlimited)
- subagent-registry.ts (replaceSubagentRunAfterSteer): same fallback
  so resumed/steered sub-agents also respect the default

Explicit per-call runTimeoutSeconds=0 still means unlimited (no
behavior change for existing callers). If the config field is unset,
behavior is identical to before.
@dgarson dgarson merged commit b06d480 into dgarson/fork Feb 23, 2026
2 of 9 checks passed
dgarson added a commit that referenced this pull request Feb 24, 2026
Adds a default timeout for spawned sub-agents, configurable via
agents.defaults.subagents.timeoutSeconds in openclaw.json.

Previously, sub-agents with no explicit runTimeoutSeconds in the
sessions_spawn call defaulted to unlimited (0 = NO_TIMEOUT_MS in
resolveAgentTimeoutMs). This meant the global agents.defaults.timeoutSeconds
had no effect on sub-agents — only top-level sessions.

Changes:
- zod-schema.agent-defaults.ts: add timeoutSeconds to the subagents
  .strict() schema object so the field is accepted and validated
- types.agent-defaults.ts: add timeoutSeconds?: number to the
  AgentDefaultsConfig.subagents interface
- subagent-registry.ts (registerSubagentRun): fall back to
  cfg.agents.defaults.subagents.timeoutSeconds when no per-call
  runTimeoutSeconds is provided, before defaulting to 0 (unlimited)
- subagent-registry.ts (replaceSubagentRunAfterSteer): same fallback
  so resumed/steered sub-agents also respect the default

Explicit per-call runTimeoutSeconds=0 still means unlimited (no
behavior change for existing callers). If the config field is unset,
behavior is identical to before.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant