From f17fd735efd96429b35d26d59170fc21973af3ba Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 12 Apr 2026 13:18:10 +0100 Subject: [PATCH] fix(agents): avoid kill-recovery hook bootstrap race --- src/agents/subagent-registry-run-manager.ts | 31 +++++++++++++-------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/agents/subagent-registry-run-manager.ts b/src/agents/subagent-registry-run-manager.ts index df196fcc829..d7f27daa7c1 100644 --- a/src/agents/subagent-registry-run-manager.ts +++ b/src/agents/subagent-registry-run-manager.ts @@ -2,6 +2,7 @@ import { loadConfig } from "../config/config.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { callGateway } from "../gateway/call.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; +import { getGlobalHookRunner } from "../plugins/hook-runner-global.js"; import { createRunningTaskRun } from "../tasks/task-executor.js"; import { type DeliveryContext, normalizeDeliveryContext } from "../utils/delivery-context.js"; import { waitForAgentRun } from "./run-wait.js"; @@ -419,6 +420,17 @@ export function createSubagentRunManager(params: { if (updated > 0) { params.persist(); for (const entry of entriesByChildSessionKey.values()) { + const emitEndedHook = () => + emitSubagentEndedHookOnce({ + entry, + reason: SUBAGENT_ENDED_REASON_KILLED, + sendFarewell: true, + accountId: entry.requesterOrigin?.accountId, + outcome: SUBAGENT_ENDED_OUTCOME_KILLED, + error: reason, + inFlightRunIds: params.endedHookInFlightRunIds, + persist: () => params.persist(), + }); void persistSubagentSessionTiming(entry).catch((err) => { log.warn("failed to persist killed subagent session timing", { err, @@ -435,6 +447,12 @@ export function createSubagentRunManager(params: { cleanup: entry.cleanup, completedAt: now, }); + if (getGlobalHookRunner()) { + void emitEndedHook().catch(() => { + // Hook failures should not break termination flow. + }); + continue; + } const cfg = params.loadConfig(); void Promise.resolve( params.ensureRuntimePluginsLoaded({ @@ -443,18 +461,7 @@ export function createSubagentRunManager(params: { allowGatewaySubagentBinding: true, }), ) - .then(() => - emitSubagentEndedHookOnce({ - entry, - reason: SUBAGENT_ENDED_REASON_KILLED, - sendFarewell: true, - accountId: entry.requesterOrigin?.accountId, - outcome: SUBAGENT_ENDED_OUTCOME_KILLED, - error: reason, - inFlightRunIds: params.endedHookInFlightRunIds, - persist: () => params.persist(), - }), - ) + .then(emitEndedHook) .catch(() => { // Hook failures should not break termination flow. });