#6582: fix(steer): prevent cross-thread reply contamination in queue mode
channel: whatsapp-web
commands
agents
Cluster:
Agent Messaging Enhancements
## Summary
Fixes cross-thread reply contamination when using queue mode with steering enabled (#5615).
When an agent is actively streaming a response, the fast "steer" path injects new messages directly into the running conversation via `queueEmbeddedPiMessage()`. However, this path only passes the prompt text—it doesn't carry the `originatingThreadId` that determines where replies should be routed.
**The bug:** If User A sends a message in Thread A while the agent is responding to Thread B, User A's message gets steered into Thread B's conversation, and the reply goes to Thread B instead of Thread A.
## Changes
- Add `ACTIVE_RUN_THREAD_CONTEXT` map to track thread context for each active run
- `setActiveEmbeddedRun()` now accepts and stores thread context (wired through from `params.messageThreadId` in attempt.ts)
- `hasActiveRunThreadContext()` checks if context is registered AND run is active, cleaning up stale entries if run ended
- `getActiveRunThreadContext()` only returns context if run is active
- Update `runReplyAgent()` to compare threads before fast steering:
- Require `hasThreadContext` for ALL fast-steer cases
- If context not registered → fall back to queue (conservative)
- Use strict equality (no type coercion) to avoid false positives
- Added clarifying comments: `undefined` thread value means "unthreaded/DM", not "unknown"
## Test plan
- [x] Added 6 test cases covering all thread routing scenarios
- [x] All 806+ test files pass
- [x] `pnpm lint` passes
- [x] `pnpm build` passes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR fixes cross-thread reply contamination in queue+steer mode by tracking the originating thread for an active embedded run and requiring an exact thread match before using the fast `queueEmbeddedPiMessage()` steering path.
The core change is in `src/agents/pi-embedded-runner/runs.ts`, which now stores a per-session thread context alongside the active run handle and exposes `hasActiveRunThreadContext()`/`getActiveRunThreadContext()` helpers. `runReplyAgent()` (`src/auto-reply/reply/agent-runner.ts`) uses these helpers to gate fast steering: if thread context isn’t registered, or if the incoming message’s `originatingThreadId` doesn’t exactly match the active run’s thread ID (including type), it falls back to enqueuing the follow-up run to preserve per-message routing.
A dedicated test suite (`src/auto-reply/reply/agent-runner.steer-thread-routing.test.ts`) covers same-thread steering, cross-thread rejection, unregistered context conservatism, and type-mismatch cases.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- The change is tightly scoped, adds conservative guards to prevent misrouting, and includes focused test coverage for the new thread-routing behavior. The thread-context lifecycle is cleaned up on run completion and defensively on stale entries.
- No files require special attention
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#22982: fix: prevent stale threadId from routing subagent announces to wron...
by unboxed-ai · 2026-02-21
75.4%
#16893: fix(threads): inject thread starter context on every turn, not just...
by battman21 · 2026-02-15
75.1%
#21790: fix(msteams): deliver thread replies via continueConversation to su...
by BinHPdev · 2026-02-20
74.6%
#4749: fix: handle string thread IDs in queue drain for Slack
by nvonpentz · 2026-01-30
74.5%
#23320: fix(slack): respect replyToMode when incomingThreadTs is auto-created
by dorukardahan · 2026-02-22
73.7%
#23804: fix(slack): preserve string thread context in queue + DM route
by vincentkoc · 2026-02-22
72.6%
#20406: fix(slack): respect replyToMode when computing statusThreadTs in DMs
by QuinnYates · 2026-02-18
72.2%
#16223: feat(slack): sticky thread routing — bypass @mention in active threads
by iamfuntime · 2026-02-14
72.1%
#11194: fix(slack): queue drain drops string thread_ts — replies leak to ma...
by Lukavyi · 2026-02-07
72.1%
#19274: feat(mattermost): enable threaded replies in channels
by rockinyp · 2026-02-17
71.9%