← Back to PRs

#21790: fix(msteams): deliver thread replies via continueConversation to survive proxy expiry

by BinHPdev open 2026-02-20 11:11 View on GitHub →
channel: msteams size: S
## Summary Closes #18636 When an MS Teams agent runs tool calls that take longer than ~15 s, the Bot Framework `TurnContext` proxy expires. The previous `thread` reply path called `ctx.sendActivity()` directly on the original `TurnContext`, which threw: ``` TypeError: Cannot perform 'set' on a proxy that has been revoked ``` The response was silently lost even though the agent had completed successfully. ## Root cause `sendMSTeamsMessages` had two separate code paths: - **thread** — used `ctx.sendActivity()` on the live, expiring `TurnContext` - **top-level** — used `adapter.continueConversation()` (not affected by proxy expiry) ## Fix Route **all** replies — both `thread` and `top-level` — through `adapter.continueConversation()`, which opens a fresh Bot Framework turn and is not bound to the original request context. For `thread`-style replies, `replyToId` is set on each outgoing activity to the `activityId` stored in the conversation reference, so Teams still threads the messages under the original post. The now-unused `context` parameter is removed from `sendMSTeamsMessages` and callers are updated accordingly. ## Changes - `extensions/msteams/src/messenger.ts` — unify both reply paths under `continueConversation`; set `replyToId` for thread-style replies; remove unused `context` parameter - `extensions/msteams/src/reply-dispatcher.ts` — remove `context` from `sendMSTeamsMessages` call - `extensions/msteams/src/messenger.test.ts` — update thread-reply tests to verify `continueConversation` is called and `replyToId` is set; remove stale `context` arguments ## Test plan - [x] `pnpm vitest run extensions/msteams/src/` — 144/144 pass - [x] `pnpm build` — TypeScript + lint + format clean - [x] Thread-reply test verifies `continueConversation` is called, `activityId` is preserved in the reference, and `replyToId` is set on every activity - [x] Retry tests (429 throttle, 400 no-retry) updated and passing - [ ] Manual: send a message that triggers >15 s tool calls and confirm the thread reply arrives <!-- greptile_comment --> <h3>Greptile Summary</h3> Unified MS Teams message delivery to use `adapter.continueConversation()` for both thread and top-level replies instead of routing thread replies through the original `TurnContext`. This prevents message loss when the Bot Framework proxy expires after ~15 seconds during long-running tool calls. **Key changes:** - Removed the separate thread reply code path that used `ctx.sendActivity()` directly - Both thread and top-level replies now use `continueConversation()` which opens a fresh Bot Framework turn - Thread replies preserve threading by setting `replyToId` on each outgoing activity - Removed the now-unused `context` parameter from `sendMSTeamsMessages()` and updated all callers - Updated tests to verify `continueConversation` is called and `replyToId` is properly set The fix correctly addresses the root cause: the original `TurnContext` proxy becomes revoked after the ~15 second timeout, causing "Cannot perform 'set' on a proxy that has been revoked" errors. By using `continueConversation()` for all replies, messages are delivered through a fresh context that isn't bound to the original request lifecycle. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk - The implementation is clean, well-tested, and addresses a specific bug with a targeted fix. All tests pass (144/144), the code unifies both reply paths under a single, more robust mechanism, and the change is backwards-compatible. The fix correctly uses Bot Framework's `continueConversation()` API and sets `replyToId` appropriately to preserve threading behavior. - No files require special attention <sub>Last reviewed commit: 515fbc4</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs