fix(exec): keep notifyOnExit heartbeat wakes on exec-event (#41479)

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
rstar327 2026-04-05 11:25:12 +03:00 committed by GitHub
parent 8be017fae6
commit 43fe68f9ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 6 additions and 7 deletions

View File

@ -133,6 +133,7 @@ Docs: https://docs.openclaw.ai
- Amazon Bedrock/aws-sdk auth: stop injecting the fake `AWS_PROFILE` apiKey marker when no AWS auth env vars exist, so instance-role and other default-chain setups keep working without poisoning provider config. (#61194) Thanks @wirjo.
- Providers/Google: add model-level `cacheRetention` support for direct Gemini system prompts by creating, reusing, and refreshing `cachedContents` automatically on Google AI Studio runs. (#51372) Thanks @rafaelmariano-glitch.
- Windows/restart: fall back to the installed Startup-entry launcher when the scheduled task was never registered, so `/restart` can relaunch the gateway on Windows setups where `schtasks` install fell back during onboarding. (#58943) Thanks @imechZhangLY.
- Exec/heartbeat: use the canonical `exec-event` wake reason for `notifyOnExit` so background exec completions still trigger follow-up turns when `HEARTBEAT.md` is empty or comments-only. (#41479) Thanks @rstar327.
## 2026.4.2

View File

@ -331,9 +331,7 @@ function maybeNotifyOnExit(session: ProcessSession, status: "completed" | "faile
? `Exec ${status} (${session.id.slice(0, 8)}, ${exitLabel}) :: ${output}`
: `Exec ${status} (${session.id.slice(0, 8)}, ${exitLabel})`;
enqueueSystemEvent(summary, { sessionKey });
requestHeartbeatNow(
scopedHeartbeatWakeOptions(sessionKey, { reason: `exec:${session.id}:exit` }),
);
requestHeartbeatNow(scopedHeartbeatWakeOptions(sessionKey, { reason: "exec-event" }));
}
export function createApprovalSlug(id: string) {

View File

@ -559,12 +559,12 @@ describe("exec notifyOnExit", () => {
wakeHandler as unknown as Parameters<typeof setHeartbeatWakeHandler>[0],
);
try {
const sessionId = await startBackgroundCommand(tool, echoAfterDelay("notify"));
const _sessionId = await startBackgroundCommand(tool, echoAfterDelay("notify"));
await expect
.poll(() => wakeHandler.mock.calls[0]?.[0], NOTIFY_POLL_OPTIONS)
.toMatchObject({
reason: `exec:${sessionId}:exit`,
reason: "exec-event",
sessionKey: DEFAULT_NOTIFY_SESSION_KEY,
});
} finally {
@ -579,12 +579,12 @@ describe("exec notifyOnExit", () => {
wakeHandler as unknown as Parameters<typeof setHeartbeatWakeHandler>[0],
);
try {
const sessionId = await startBackgroundCommand(tool, echoAfterDelay("notify"));
const _sessionId = await startBackgroundCommand(tool, echoAfterDelay("notify"));
await expect
.poll(() => wakeHandler.mock.calls[0]?.[0], NOTIFY_POLL_OPTIONS)
.toEqual({
reason: `exec:${sessionId}:exit`,
reason: "exec-event",
});
} finally {
dispose();