← Back to PRs

#19406: fix(heartbeat): filter error payloads from heartbeat reply selection

by namabile open 2026-02-17 19:24 View on GitHub →
size: S
Closes #19302 ## Problem `resolveHeartbeatReplyPayload` iterates the reply payload array **backwards** and returns the last non-empty payload. When `buildFinalReplyPayloads` appends an `isError: true` tool error summary after the agent's `HEARTBEAT_OK` text, the error payload shadows the valid response and gets delivered to the channel as a spurious alert. **Sequence:** 1. Heartbeat fires → agent processes it 2. Agent calls a tool (e.g. `exec`) that fails 3. Agent responds with `HEARTBEAT_OK` 4. `buildFinalReplyPayloads` appends `{ text: "⚠️ 🛠️ Exec: ...", isError: true }` 5. `resolveHeartbeatReplyPayload` iterates backwards → picks the error payload (last in array) over `HEARTBEAT_OK` 6. Error is delivered to channel instead of being suppressed ## Fix Skip payloads with `isError: true` during backward iteration in `resolveHeartbeatReplyPayload`. Error payloads are tool diagnostic summaries that should never be selected for heartbeat delivery. When all non-error payloads are empty/absent, the function returns `undefined`, which triggers normal `HEARTBEAT_OK` suppression in the caller. ## Test plan - [x] 10 new unit tests covering: - Normal payload selection (single, array, empty) - `isError` payloads skipped in favor of earlier valid payload - Multiple trailing errors skipped - All-error array returns `undefined` - Media payloads preserved when errors are skipped - Single (non-array) error payload passes through unchanged - [x] `pnpm format:check` passes - [x] `pnpm tsgo` passes - [x] `pnpm lint` passes <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes a bug where `resolveHeartbeatReplyPayload` could return an `isError: true` tool error summary instead of the agent's `HEARTBEAT_OK` text, causing spurious error messages to be delivered to the channel during heartbeat runs. **Changes:** - `src/auto-reply/heartbeat-reply-payload.ts`: Adds a 4-line guard in the backward iteration loop to skip payloads with `isError: true`, so tool error summaries (appended after the agent's response by `buildEmbeddedRunPayloads`) can never shadow a valid `HEARTBEAT_OK` reply. The fix is minimal, correctly placed before the content check, and well-commented. - `src/auto-reply/heartbeat-reply-payload.test.ts`: New test file with 10 regression tests covering the primary fix scenario plus boundary cases (empty array, all-error array, media payloads, single non-array passthrough). The fix is straightforward and correctly scoped. Both the source comment and the test JSDoc reference `buildFinalReplyPayloads` as the source of the error payloads, but this function does not exist in the codebase — the actual culprit is `buildEmbeddedRunPayloads` in `src/agents/pi-embedded-runner/run/payloads.ts`. <h3>Confidence Score: 5/5</h3> - Safe to merge — the fix is minimal, targeted, and well-tested with no risk of regression. - The change is a 4-line guard in a single function, directly addresses the documented bug, is backed by 10 new unit tests, and doesn't affect any non-heartbeat code paths. The only findings are cosmetic comment inaccuracies (stale function name). - No files require special attention. <sub>Last reviewed commit: c2cee78</sub> <!-- greptile_other_comments_section --> <sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub> <!-- /greptile_comment -->

Most Similar PRs