Heartbeat routing now stays on main session
Heartbeat background checks no longer accidentally overwrite subagent task results — the system now consistently routes to the main session, preventing corrupted responses.
When agents run background heartbeat checks while subagents are active, those checks could land in the wrong session. A subagent dispatched to do actual work might return a heartbeat status instead of its task result — losing the user's data in the process. The bug occurred because session resolution had three code paths where a subagent session key could slip through, bypassing the intended main-session default.
The fix adds guards at every entry point where a session key gets determined. Any subagent key gets stripped, falling back to the main session. Legitimate main session keys still route correctly.
This touches the heartbeat infrastructure in the agents system. Users running multiple subagents will see reliable task completion instead of corrupted HEARTBEAT_OK responses.
View Original GitHub DescriptionFact Check
What this fixes (plain English)
When background heartbeat checks ran while sub-agents were active, they could accidentally target a sub-agent's session instead of the main one — corrupting the sub-agent's task results by overwriting them with a heartbeat status. This fix ensures heartbeats always route to the main session.
Technical details
Root cause: resolveHeartbeatSession() had three code paths where a subagent session key could slip through:
- Via
opts.sessionKey(forced session key) - Via
heartbeat.sessionconfig value - Via post-canonicalization (where canonicalization transforms a key into a subagent format)
Fix: Added isSubagentSessionKey() guards to all three paths in resolveHeartbeatSession. Any subagent session key is now stripped at every entry point, falling back to mainSessionKey.
Files changed:
src/infra/heartbeat-runner.ts— importisSubagentSessionKey, add guards to all three resolution paths, simplify agent ID resolutionsrc/infra/heartbeat-runner.returns-default-unset.test.ts— parameterized regression test covering both entry vectors
Related
- Fixes #58878
- Recreated from clean branch (previous PR #61526 closed as dirty)
- Parent initiative: #25592
- Companion PRs: #61829, #61463, #61801
Test plan
- 32/32 tests pass
- Subagent session keys via opts.sessionKey are rejected -> falls back to mainSessionKey
- Subagent session keys via heartbeat.session config are rejected -> falls back to mainSessionKey
- Post-canonicalization subagent keys are rejected
- Legitimate main session keys still route correctly