fix(cron): cancel timed-out runs before side effects (openclaw#22411) thanks @Takhoffman

Verified:
- pnpm check
- pnpm vitest run src/memory/qmd-manager.test.ts src/cron/service.issue-regressions.test.ts src/cron/isolated-agent.delivers-response-has-heartbeat-ok-but-includes.test.ts --maxWorkers=1

Co-authored-by: Takhoffman <781889+Takhoffman@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Tak Hoffman
2026-02-22 15:45:27 -06:00
committed by GitHub
parent 64b273a71c
commit 556af3f08b
5 changed files with 195 additions and 8 deletions

View File

@@ -556,7 +556,11 @@ async function maybeQueueSubagentAnnounce(params: {
triggerMessage: string;
summaryLine?: string;
requesterOrigin?: DeliveryContext;
signal?: AbortSignal;
}): Promise<"steered" | "queued" | "none"> {
if (params.signal?.aborted) {
return "none";
}
const { cfg, entry } = loadRequesterSessionEntry(params.requesterSessionKey);
const canonicalKey = resolveRequesterStoreKey(cfg, params.requesterSessionKey);
const sessionId = entry?.sessionId;
@@ -637,7 +641,14 @@ async function sendSubagentAnnounceDirectly(params: {
completionDirectOrigin?: DeliveryContext;
directOrigin?: DeliveryContext;
requesterIsSubagent: boolean;
signal?: AbortSignal;
}): Promise<SubagentAnnounceDeliveryResult> {
if (params.signal?.aborted) {
return {
delivered: false,
path: "none",
};
}
const cfg = loadConfig();
const announceTimeoutMs = resolveSubagentAnnounceTimeoutMs(cfg);
const canonicalRequesterSessionKey = resolveRequesterStoreKey(
@@ -691,6 +702,12 @@ async function sendSubagentAnnounceDirectly(params: {
completionDirectOrigin?.threadId != null && completionDirectOrigin.threadId !== ""
? String(completionDirectOrigin.threadId)
: undefined;
if (params.signal?.aborted) {
return {
delivered: false,
path: "none",
};
}
await callGateway({
method: "send",
params: {
@@ -717,6 +734,12 @@ async function sendSubagentAnnounceDirectly(params: {
directOrigin?.threadId != null && directOrigin.threadId !== ""
? String(directOrigin.threadId)
: undefined;
if (params.signal?.aborted) {
return {
delivered: false,
path: "none",
};
}
await callGateway({
method: "agent",
params: {
@@ -761,7 +784,14 @@ async function deliverSubagentAnnouncement(params: {
completionRouteMode?: "bound" | "fallback" | "hook";
spawnMode?: SpawnSubagentMode;
directIdempotencyKey: string;
signal?: AbortSignal;
}): Promise<SubagentAnnounceDeliveryResult> {
if (params.signal?.aborted) {
return {
delivered: false,
path: "none",
};
}
// Non-completion mode mirrors historical behavior: try queued/steered delivery first,
// then (only if not queued) attempt direct delivery.
if (!params.expectsCompletionMessage) {
@@ -771,6 +801,7 @@ async function deliverSubagentAnnouncement(params: {
triggerMessage: params.triggerMessage,
summaryLine: params.summaryLine,
requesterOrigin: params.requesterOrigin,
signal: params.signal,
});
const queued = queueOutcomeToDeliveryResult(queueOutcome);
if (queued.delivered) {
@@ -791,6 +822,7 @@ async function deliverSubagentAnnouncement(params: {
directOrigin: params.directOrigin,
requesterIsSubagent: params.requesterIsSubagent,
expectsCompletionMessage: params.expectsCompletionMessage,
signal: params.signal,
});
if (direct.delivered || !params.expectsCompletionMessage) {
return direct;
@@ -804,6 +836,7 @@ async function deliverSubagentAnnouncement(params: {
triggerMessage: params.triggerMessage,
summaryLine: params.summaryLine,
requesterOrigin: params.requesterOrigin,
signal: params.signal,
});
if (queueOutcome === "steered" || queueOutcome === "queued") {
return queueOutcomeToDeliveryResult(queueOutcome);
@@ -956,6 +989,7 @@ export async function runSubagentAnnounceFlow(params: {
announceType?: SubagentAnnounceType;
expectsCompletionMessage?: boolean;
spawnMode?: SpawnSubagentMode;
signal?: AbortSignal;
}): Promise<boolean> {
let didAnnounce = false;
const expectsCompletionMessage = params.expectsCompletionMessage === true;
@@ -1216,6 +1250,7 @@ export async function runSubagentAnnounceFlow(params: {
completionRouteMode: completionResolution.routeMode,
spawnMode: params.spawnMode,
directIdempotencyKey,
signal: params.signal,
});
didAnnounce = delivery.delivered;
if (!delivery.delivered && delivery.path === "direct" && delivery.error) {