#17340: fix(auto-reply): prevent duplicate transcript entries for followup queue messages
size: XS
Cluster:
Heartbeat Message Filtering
## Summary
- **Bug**: When messages arrive while the agent is busy (followup queue), the assistant response is written to the session transcript twice — once by the embedded agent during its normal run, and once by the delivery-mirror mechanism in `routeReply`. This produces duplicate assistant messages in the transcript, which can confuse the model on subsequent interactions.
- **Fix**: Add `mirror: false` to the `routeReply` call inside `sendFollowupPayloads` in `src/auto-reply/reply/followup-runner.ts`. Since the agent already persists its response in the session transcript, the delivery-mirror copy is redundant for followup queue messages.
- **Change**: One-line addition — `mirror: false` parameter to the existing `routeReply({ ... })` call at line 97.
## Details
`routeReply` accepts an optional `mirror` parameter (defined in `src/auto-reply/reply/route-reply.ts`). When `mirror` is not explicitly `false` and a `sessionKey` is provided, the reply is mirrored into the session transcript. For followup queue runs, `sessionKey` is always provided (line 94: `sessionKey: queued.run.sessionKey`), so the mirror fires unconditionally. But the embedded agent that processes the followup already saves the response to the transcript as part of its normal execution, creating the duplicate.
Setting `mirror: false` disables only the delivery-mirror copy; the agent's own transcript persistence is unaffected.
## Test plan
- [ ] Send a message while the agent is processing another request (trigger followup queue)
- [ ] Verify the assistant response appears exactly once in the session transcript
- [ ] Verify the reply is still delivered to the originating channel
- [ ] Verify that non-followup `routeReply` calls (which do not set `mirror: false`) continue to mirror as before
## Contribution checklist
- [x] Local validation: `pnpm build && pnpm check && pnpm test` — all passing
- [x] Focused scope: single bug fix, one-line change
- [x] Clear "what" + "why" in description
- [x] AI-assisted (Claude Code) — fully tested, code reviewed and understood by author
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds `mirror: false` parameter to `routeReply` call in followup queue handler to prevent duplicate assistant responses in session transcripts. The embedded agent already persists its response during execution, so the delivery-mirror copy is redundant for followup messages.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- Single-line focused fix that addresses a clear duplication bug. The change is well-documented, has existing test coverage for the `mirror: false` behavior (route-reply.test.ts:380-395), and doesn't affect other call sites. The embedded agent's transcript persistence is independent of the mirror mechanism.
- No files require special attention
<sub>Last reviewed commit: 5c74271</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
#19486: fix(gateway): mirror delivered agent replies into routed target ses...
by kite010kite · 2026-02-17
81.7%
#10677: fix(heartbeat): mirror outbound messages to session transcript
by PatrickBauer · 2026-02-06
78.7%
#8205: fix: flush followup messages incrementally
by hanxiao · 2026-02-03
73.0%
#21828: fix: acquire session write lock in delivery mirror and gateway chat...
by inkolin · 2026-02-20
72.8%
#13104: fix: persist user command message in chat transcript
by mcaxtr · 2026-02-10
72.0%
#19452: fix: skip stale responses in interrupt queue mode via generationId
by kisjovan · 2026-02-17
71.9%
#7758: fix: prevent opts closure reuse across messages in shared followup ...
by Alexwang-sol · 2026-02-03
71.8%
#3045: [AI-Assisted] fix: preserve pending tasks when subagent completes
by sid1943 · 2026-01-28
71.0%
#20490: fix(queue): partition followup routing safety (rebased on latest main)
by Jackten · 2026-02-19
70.9%
#15792: fix: pass agentId to resolveSessionFilePath in additional call sites
by MisterGuy420 · 2026-02-13
70.5%