diff --git a/CHANGELOG.md b/CHANGELOG.md index 042b5711e5e..cf33ae7d512 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/agents/bash-tools.exec-runtime.ts b/src/agents/bash-tools.exec-runtime.ts index c092f064148..f56addac4d0 100644 --- a/src/agents/bash-tools.exec-runtime.ts +++ b/src/agents/bash-tools.exec-runtime.ts @@ -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) { diff --git a/src/agents/bash-tools.test.ts b/src/agents/bash-tools.test.ts index 5828b2f48ad..2bf9e8f368e 100644 --- a/src/agents/bash-tools.test.ts +++ b/src/agents/bash-tools.test.ts @@ -559,12 +559,12 @@ describe("exec notifyOnExit", () => { wakeHandler as unknown as Parameters[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[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();