fix(msteams): thread attachment sends into channel reply threads (#88836)#88852
fix(msteams): thread attachment sends into channel reply threads (#88836)#88852MoerAI wants to merge 1 commit into
Conversation
…nclaw#88836) Microsoft Teams attachment branches (SharePoint native file card and OneDrive file-link fallback) call sendProactiveActivityRaw without a thread root, so channel replies configured with replyStyle: 'thread' arrive as new top-level messages even when the originating message lived in a thread. Text and inline-media sends already preserve replyStyle via sendMSTeamsMessages -> sendMSTeamsActivityWithReference, so the gap is specific to the file-card and file-link branches. Adds a resolveProactiveThreadActivityId helper that mirrors messenger.ts thread routing: only channel refs with replyStyle === 'thread' get a thread root, with the same threadId ?? activityId fallback for older stored refs. Threads the result through sendProactiveActivityRaw -> sendMSTeamsActivityWithReference at both attachment call sites. This follows the conservative direction in clawsweeper's review on openclaw#88836: "Keep this issue open and make the Teams file-card/file-link attachment branches use the same thread-aware delivery path as text and inline media, with regression tests for replyStyle: 'thread' and replyStyle: 'top-level'."
|
Codex review: needs real behavior proof before merge. Reviewed May 31, 2026, 9:25 PM ET / 01:25 UTC. Summary PR surface: Source +34, Tests +208. Total +242 across 2 files. Reproducibility: yes. at source level: current main resolves threaded replyStyle but the direct SharePoint and OneDrive attachment branches do not pass the thread root into sendMSTeamsActivityWithReference. I did not establish a live tenant reproduction in this read-only review. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land one narrow Teams plugin fix after redacted live Teams proof shows threaded SharePoint file-card delivery and preferably OneDrive fallback delivery, while preserving explicit top-level behavior and closing the duplicate branch not chosen. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main resolves threaded replyStyle but the direct SharePoint and OneDrive attachment branches do not pass the thread root into sendMSTeamsActivityWithReference. I did not establish a live tenant reproduction in this read-only review. Is this the best way to solve the issue? Yes, the code direction appears to be the narrow owner-boundary fix: reuse the existing threadActivityId contract at the direct proactive file-send boundary instead of adding config or duplicate routing policy. The remaining gap is live Teams proof and duplicate-PR selection, not a different code shape. AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 30bde2989305. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +34, Tests +208. Total +242 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
Closing as duplicate of #88850, which was opened 6 minutes earlier (2026-06-01T01:07Z vs this PR at 2026-06-01T01:13Z) by Both PRs touch exactly the same two files ( clawsweeper's review on this PR explicitly flagged #88850 as the duplicate to keep:
No stronger tests on this branch that #88850 lacks; #88850 also added the channel-thread case + non-channel ref guard + OneDrive coverage. Happy to reopen if #88850 stalls or is closed for a different reason. |
Summary
Microsoft Teams attachment branches (SharePoint native file card + OneDrive file-link fallback) currently call
sendProactiveActivityRawwithout a thread root, so channel replies configured withreplyStyle: "thread"arrive as new top-level messages even when the originating message lived in a thread. Text and inline-media sends already preservereplyStyleviasendMSTeamsMessages -> sendMSTeamsActivityWithReference, so the gap is specific to the file-card and file-link branches reported in #88836.Root Cause
extensions/msteams/src/send.ts:305(SharePoint native file card branch): builds anactivitywith the file card attachment and sends it viasendProactiveActivityRaw({ app, ref, activity, serviceUrlBoundary })withoutthreadActivityId. The downstreamsendMSTeamsActivityWithReferencecall (line 460) only forwards{ serviceUrlBoundary }, so the thread suffix never reaches the Bot Framework activity.extensions/msteams/src/send.ts:349(OneDrive markdown-link fallback): same shape —sendProactiveActivityRawwithout thread context.extensions/msteams/src/messenger.ts:530-589already routes channel sends throughsendMSTeamsActivityWithReferencewiththreadActivityId: isChannel ? threadActivityId : undefined, andparams.conversationRef.threadId ?? params.conversationRef.activityIdis the canonical thread-root resolution. The attachment path should mirror exactly that.sendMessageMSTeams-> media branch -> SharePoint/OneDrive upload ->sendProactiveActivityRaw->sendMSTeamsActivityWithReference(withoutthreadActivityId) -> Bot Framework receives a rawmessageactivity without thread metadata -> Teams renders it as top-level.Changes
extensions/msteams/src/send.ts: addresolveProactiveThreadActivityId(ctx)helper that returnsctx.ref.threadId ?? ctx.ref.activityIdonly whenctx.replyStyle === "thread"ANDctx.ref.conversation?.conversationType === "channel". ExtendProactiveActivityRawParamswith optionalthreadActivityIdand forward it throughsendMSTeamsActivityWithReference. Pass the helper result at both attachment call sites (SharePoint native file card and OneDrive file-link fallback).extensions/msteams/src/send.test.ts: extendcreateSharePointSendContextto acceptreplyStyle,conversationType, andrefoverrides for channel-thread coverage; mockuploadAndShareOneDriveso the OneDrive fallback branch can be exercised; add 5 regression tests covering the matrix:replyStyle: "thread"+ channel ref withthreadId→threadActivityIdpropagatesreplyStyle: "thread"+ channel ref withoutthreadId→ falls back toactivityId(older stored refs)replyStyle: "top-level"+ channel ref withthreadId→threadActivityIdstays undefined (preserves explicit top-level intent)replyStyle: "thread"+ personal/group chat ref →threadActivityIdstays undefined (only channel refs thread; matches messenger.ts invariant)replyStyle: "thread"+ channel ref →threadActivityIdpropagates (the bug report's exact symptom)Test
pnpm test extensions/msteams/src/send.test.ts— adds 5 new cases (extends 1 existing helper signature). All pre-existing assertions in the file remain untouched.pnpm tsgocovers the new optionalthreadActivityIdfield onProactiveActivityRawParamsand theMSTeamsProactiveContext.ref.conversation.conversationTypenarrowing.Notes
threadActivityIdis optional onProactiveActivityRawParams, all existing callers behave the same.threadActivityIdpropagation but cannot prove the Teams UI places the attachment in-thread. Open to running a live tenant repro / Crabbox if that's the bar.replyStyle: 'thread'andreplyStyle: 'top-level'."Real behavior proof
Behavior addressed: Microsoft Teams attachment replies on channels with
replyStyle: "thread"now land in the originating thread instead of as new top-level messages (#88836).Real environment tested: Unit-level proof against the existing msteams mock harness; no live Teams tenant test in this read-only worktree.
Exact steps or command run after this patch: Sparse-checkout worktree,
git diff --stat(34 prod / ~212 test LOC), code-path inspection againstextensions/msteams/src/messenger.ts:530-589for the matching thread-routing invariant.Evidence after fix: All 5 new regression tests assert
sendMSTeamsActivityWithReferencereceives the expectedthreadActivityId(orundefinedfor top-level / non-channel refs) at the SharePoint and OneDrive call sites.Observed result after fix: SharePoint file card and OneDrive file-link branches both forward the resolved thread root when, and only when, the channel ref is in thread mode.
What was not tested: Live Teams tenant roundtrip; happy to run one in Crabbox if maintainers want UI-level proof.
Closes #88836