* fix(heartbeat): unblock beads cadence — parallel broadcast, agent-scoped busy check, full HEARTBEAT.md prompt, connect-timeout, doctor warning
* docs(changelog): note heartbeat cadence fixes
* fix(heartbeat): address review feedback
* fix(heartbeat): append HEARTBEAT.md directives to commitment-only task dispatch (review feedback)
* docs(changelog): extend heartbeat fix entry — commitment-only task dispatch path (review feedback)
* fix(heartbeat): clear connect timer on synchronous baseFn throw (review feedback)
When the provider stream function passed to streamWithIdleTimeout throws
synchronously during setup, the connect watchdog timer was left armed
and could fire onIdleTimeout later with a stale error, keeping the
process open past the real failure. Wrap the synchronous baseFn(...)
invocation in a try/catch that clears the connect timer before
rethrowing, and add a regression test that asserts onIdleTimeout is
not invoked after the synchronous throw.
* docs(changelog): note round-4 heartbeat fix (review feedback)
Bump the heartbeat fixes list from six to seven and document the
synchronous-baseFn-throw connect-timer cleanup added in the prior
commit.
* fix(heartbeat): honor omitted doctor target (review feedback)
* fix(heartbeat): merge doctor heartbeat defaults (review feedback)
Teach the heartbeat session-target doctor warning to enumerate the same agents as the runtime heartbeat runner and merge agents.defaults.heartbeat with per-agent overrides before checking pinned sessions.
Add regression coverage for default-only heartbeat.session pins and explicit agent heartbeat entries that inherit the default session.
Validation:
- pnpm test src/commands/doctor-heartbeat-session-target.test.ts
- pnpm tsgo:core
- pnpm tsgo:core:test
- pnpm config:schema:check
- pnpm exec oxlint src/commands/doctor-heartbeat-session-target.ts src/commands/doctor-heartbeat-session-target.test.ts
- pnpm exec oxfmt --check src/commands/doctor-heartbeat-session-target.ts src/commands/doctor-heartbeat-session-target.test.ts
- git diff --check
Beads: openclaw-8zp
* test(heartbeat): avoid redundant doctor assertion (review feedback)
The CI lint shard flags the non-null assertion in the heartbeat doctor regression test. Keep the same test setup while using an explicit guard so the test still narrows the fixture before mutating the heartbeat entry.
Validation:
- pnpm exec oxlint src/commands/doctor-heartbeat-session-target.test.ts
- pnpm test src/commands/doctor-heartbeat-session-target.test.ts
- pnpm tsgo:core:test
- git diff --check
Beads: openclaw-8zp
* docs(config): refresh baseline after heartbeat branch update
* fix(heartbeat): narrow doctor session warnings (review feedback)
`session_end` was only fired when a session was replaced, reset, deleted, or
compacted -- the gateway shutdown/restart paths closed the process without
enumerating active sessions, so downstream `session_end` plugins
(e.g. claude-mem) accumulated ghost rows in `active` state across restarts.
Issue reporter saw 11 orphaned sessions cause 63 timeouts/day from agent
pool exhaustion.
Add an in-memory active-session tracker
(`src/gateway/active-sessions-shutdown-tracker.ts`) populated by
`emitGatewaySessionStartPluginHook` and forgotten unconditionally by
`emitGatewaySessionEndPluginHook` (even when no plugin listens), so any
session that has already been finalized through the normal lifecycle is
never re-fired by the shutdown drain. The close handler then calls a new
`drainActiveSessionsForShutdown({ reason })` in `session-reset-service.ts`
between the `gateway:shutdown`/`gateway:pre-restart` lifecycle hooks and
the subsystem teardown steps; the drain races a bounded 2 s total timeout
so a slow plugin cannot block SIGTERM/SIGINT, surfacing the timeout as a
`session-end-drain` warning on the shutdown result.
Extend `PluginHookSessionEndReason` with `"shutdown"` and `"restart"` so
plugins can distinguish a graceful close from a planned restart; the close
handler picks `restart` when `restartExpectedMs` is set and `shutdown`
otherwise. Update `emitGatewaySessionStartPluginHook` to also accept
`storePath`, `sessionFile`, and `agentId` so the shutdown drain can build
the same `session_end` payload shape the normal lifecycle path emits, and
update the existing call sites in `session-reset-service.ts` and
`server-methods/sessions.ts` to pass those fields through.
Tests:
- `src/gateway/active-sessions-shutdown-tracker.test.ts` (new) -- tracker
insert/forget/clear semantics, idempotent re-noting, empty-id guard,
snapshot isolation.
- `src/gateway/drain-active-sessions-for-shutdown.test.ts` (new) -- drain
fires `session_end` with the right reason for every tracked session,
skips sessions already finalized via reset/delete/compaction, and still
forgets sessions even when no `session_end` plugin is registered.
- `src/gateway/server-close.test.ts` -- four new cases covering the
shutdown/restart drain wiring, the bounded timeout warning, and the
drain-skipped-when-no-helper case.
Docs:
- `docs/plugins/hooks.md` documents the new `shutdown`/`restart` values
on `PluginHookSessionEndReason`.
- `docs/automation/hooks.md` documents the post-`gateway:shutdown`
`session_end` drain step and its bounded execution guarantee.
Fixes#57790.
Route group/channel task, subagent, and media completions through one requester-session delivery policy, including plugin legacy session keys.
Also keeps current Zalo lifecycle test typing green on CI after the latest main changes.
Co-authored-by: Merlin <merlin@funcracker.net>
When an automatic compaction happens mid-turn, chat users currently see a long stall and the run can finish without a final visible answer.
This adds an optional bundled compaction notifier hook and a one-shot compacted-transcript continuation retry when a compaction produced no user-visible final payload.
Keep async music generation completions on the requester-session wake path even when direct-send completion is enabled.
Also aligns config help, generated schema text, public docs, and the changelog so tools.media.asyncCompletion.directSend no longer claims to direct-send music completions.
Verification:
- pnpm test src/agents/tools/music-generate-background.test.ts src/agents/tools/video-generate-background.test.ts
- pnpm exec oxfmt --check --threads=1 src/agents/tools/media-generate-background-shared.ts src/agents/tools/music-generate-background.ts src/agents/tools/music-generate-background.test.ts src/config/schema.help.ts src/config/types.tools.ts docs/automation/tasks.md docs/gateway/config-tools.md CHANGELOG.md
- pnpm config:schema:check
- pnpm config:docs:check
- pnpm check:changelog-attributions
- git diff --check
- OPENCLAW_TESTBOX=1 pnpm check:changed
- start/openclaw: workspace-as-memory Tip component
- automation/tasks: drop 'this page covers' filler in Note
- automation/auth-monitoring, clawflow, cron-vs-heartbeat: collapse 'this page moved... See X' redirects to single direct sentences