openclaw - ✅(Solved) Fix [Bug]: msteams proactive send path hardcodes replyStyle top-level, ignoring thread config [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#78298Fetched 2026-05-07 03:38:36
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
2
Author
Timeline (top)
cross-referenced ×2closed ×1commented ×1referenced ×1

The proactive send path in extensions/msteams/src/send.ts hardcodes replyStyle: "top-level" when calling sendMSTeamsMessages(), causing all proactive/CLI-sent messages to land as new top-level channel posts regardless of whether the conversation has thread context available.

Error Message

  1. extensions/msteams/src/messenger.ts line 575 — throw new Error("Missing context for replyStyle=thread") blocks the proactive path from threading even if the hardcode were removed

Root Cause

Root cause in code:

Fix Action

Fix / Workaround

The inbound reply-dispatcher path (reply-dispatcher.ts) handles threading correctly when a live turn context is available. The bug is specifically in the proactive/outbound send path which never has a turn context.

PR fix notes

PR #78299: fix(msteams): respect thread context in proactive send path

Description (problem / solution / changelog)

Summary

  • Problem: The proactive send path in send.ts hardcodes replyStyle: "top-level", causing all proactive/CLI messages to land as new top-level channel posts regardless of thread context.
  • Why it matters: Channel thread replies never thread correctly when sent via the message tool or CLI, breaking conversational continuity for users.
  • What changed: send.ts resolves replyStyle dynamically from conversation context; messenger.ts falls back to proactive send with thread targeting instead of throwing.
  • What did NOT change (scope boundary): DM and group chat behavior unchanged. The inbound reply-dispatcher path (which already threads correctly) is untouched.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #78298
  • This PR fixes a bug or regression

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: Proactive sends to channel conversations always create top-level posts instead of threading into the existing conversation thread.
  • Real environment tested: Local test suite exercising the real sendTextWithMediasendMSTeamsMessagessendProactively chain with mocked Bot Framework adapter.
  • Exact steps or command run after this patch: pnpm test extensions/msteams/src/send.test.ts and pnpm test extensions/msteams/src/messenger.test.ts
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output): 13/13 send tests pass (4 new), 31/31 messenger tests pass (2 new). New tests assert replyStyle: "thread" is passed for channel+threadId conversations and that the proactive fallback constructs ;messageid=<threadRootId> conversation IDs.
  • Observed result after fix: Channel conversations with thread context route to sendProactively(messages, 0, resolvedThreadId) which builds 19:[email protected];messageid=thread-root-msg — proven by captured adapter reference in test.
  • What was not tested: Live Teams environment (requires bot registration + tenant). The adapter mock faithfully replicates the continueConversation contract.
  • Before evidence (optional but encouraged): Before this fix, sendMSTeamsMessages was always called with replyStyle: "top-level" (hardcoded at old line 399 of send.ts).

Root Cause (if applicable)

  • Root cause: sendTextWithMedia() hardcoded replyStyle: "top-level" instead of resolving from conversation context. Additionally, sendMSTeamsMessages() threw when replyStyle === "thread" with no turn context, blocking the proactive path from threading.
  • Missing detection / guardrail: No test asserted the replyStyle value passed to sendMSTeamsMessages from the proactive send path.
  • Contributing context (if known): The proactive send path was written before channel thread support was added; the hardcode was never updated.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/msteams/src/send.test.ts, extensions/msteams/src/messenger.test.ts
  • Scenario the test should lock in: Channel conversations with thread root resolve to replyStyle: "thread"; no-context thread sends fall back to proactive with thread targeting.
  • Why this is the smallest reliable guardrail: Tests exercise the routing decision and the fallback path at the seam boundary (mocked adapter), covering all 4 conversation scenarios.
  • Existing test that already covers this (if any): None existed before this PR.

User-visible / Behavior Changes

  • Proactive messages (message tool, CLI sends) to Teams channels now thread into the correct conversation thread instead of creating new top-level posts.

Diagram (if applicable)

Before:
[proactive send to channel] -> replyStyle: "top-level" (hardcoded) -> new top-level post

After:
[proactive send to channel] -> isChannelThread? -> replyStyle: "thread" -> sendProactively(msgs, 0, resolvedThreadId) -> ;messageid=<threadRoot> -> threaded reply
[proactive send to DM]      -> !isChannelThread -> replyStyle: "top-level" -> top-level (unchanged)

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: Linux
  • Runtime/container: Node 22
  • Integration/channel (if any): MS Teams

Steps

  1. Configure msteams plugin with a channel conversation that has a stored threadId
  2. Send a proactive message via the message tool to that conversation
  3. Observe the message lands in the thread (after fix) vs. top-level post (before fix)

Expected

  • Message threads into the existing channel thread

Actual

  • Before: Message creates a new top-level post
  • After: Message threads correctly

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: Channel+threadId → thread, channel+activityId → thread, personal → top-level, channel without thread root → top-level, no-context fallback → proactive with thread suffix
  • Edge cases checked: activityId fallback when threadId absent; channel with neither threadId nor activityId stays top-level
  • What you did not verify: Live Teams tenant delivery (requires bot registration)

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: Stored conversation references without threadId or activityId could miss the thread routing.
    • Mitigation: Falls back to "top-level" when neither field is present — same behavior as before this fix.

Changed files

  • extensions/msteams/src/messenger.test.ts (modified, +94/-0)
  • extensions/msteams/src/messenger.ts (modified, +5/-1)
  • extensions/msteams/src/send.test.ts (modified, +100/-0)
  • extensions/msteams/src/send.ts (modified, +8/-1)

PR #78387: fix(msteams): preserve proactive thread replies

Description (problem / solution / changelog)

Summary

  • Resolve the Microsoft Teams proactive send replyStyle from stored conversation context and the existing Teams channel/team/global policy instead of hardcoding top-level.
  • Allow no-context threaded proactive sends to use the existing proactive thread-targeting path, so channel sends with threadId or legacy activityId build the ;messageid=<threadRoot> conversation id.
  • Add focused regression coverage for proactive reply-style resolution, send-path forwarding, no-context thread fallback, and configured top-level channel overrides.
  • Add an unreleased changelog entry.

Closes #78298.

Root Cause

The proactive text/media send path always passed replyStyle: "top-level" into sendMSTeamsMessages(), so CLI/message-tool sends ignored stored Teams channel thread roots. Switching that path to thread was previously blocked because sendMSTeamsMessages() threw when no live turn context was present.

Manual CLI Repro Proof

I exercised the actual CLI command path with a temp OpenClaw config/state directory and a network shim that only replaced AAD token acquisition and the Bot Framework service URL. The command under test was:

openclaw message send --channel msteams --target conversation:19:[email protected] --message "CLI proactive reply" --json
  • Local before/after CLI proof: origin/main sent to https://service.example.com/v3/conversations/19:[email protected]/activities; this branch sent to https://service.example.com/v3/conversations/19:[email protected];messageid=thread-root-msg-id/activities.
  • Hetzner Crabbox cbx_2a5cfab75860 (coral-crab): same CLI command passed before/after proof with HETZNER_CLI_SUMMARY beforeStatus=0 beforeId=19:[email protected] afterStatus=0 afterId=19:[email protected];messageid=thread-root-msg-id afterRef=93b8a7c9848e3eadaf2f3e03ddcc22f72e5446d2.
  • Lease was released after the Hetzner run.

No live Teams tenant send was run; no Teams/Microsoft/Azure credentials were present in env or ~/.profile.

Additional Manual Adapter Proof

A throwaway harness also exercised the Bot Framework proactive adapter boundary directly with a stored channel reference containing threadId: "thread-root-msg-id" and no live turn context.

  • Hetzner Crabbox cbx_2c7ac22b6281 (crimson-krill): before patch on origin/main failed with {"ok":false,"name":"Error","message":"Missing context for replyStyle=thread"}.
  • Same Hetzner Crabbox run after patch on 93b8a7c9848e3eadaf2f3e03ddcc22f72e5446d2 succeeded with {"ok":true,"ids":["id:manual proactive reply"],"sent":["manual proactive reply"],"proactiveConversationId":"19:[email protected];messageid=thread-root-msg-id","proactiveActivityId":null}.
  • Lease was released after the run.

Verification

  • Manual local CLI before/after proof: passed as described above.
  • Manual Hetzner Crabbox CLI before/after proof on cbx_2a5cfab75860: passed as described above.
  • Manual local adapter before/after harness: before origin/main failed with Missing context for replyStyle=thread; after branch succeeded with threaded proactive conversation id.
  • Manual Hetzner Crabbox adapter before/after harness on cbx_2c7ac22b6281: passed as described above.
  • pnpm test extensions/msteams/src/send-context.test.ts extensions/msteams/src/send.test.ts extensions/msteams/src/messenger.test.ts locally: 3 files, 47 tests passed.
  • pnpm exec oxfmt --check --threads=1 extensions/msteams/src/send-context.ts extensions/msteams/src/send.ts extensions/msteams/src/messenger.ts extensions/msteams/src/send-context.test.ts extensions/msteams/src/send.test.ts extensions/msteams/src/messenger.test.ts CHANGELOG.md
  • git diff --check
  • Crabbox/Testbox focused test on tbx_01kqy8brzxk1e58fhcdggmkdfs: 3 files, 47 tests passed; lease stopped.
  • Crabbox/Testbox pnpm check:changed on tbx_01kqy8k9cb8300643vamz6d3ss: passed; lease stopped.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/msteams/src/messenger.test.ts (modified, +88/-0)
  • extensions/msteams/src/messenger.ts (modified, +1/-1)
  • extensions/msteams/src/send-context.test.ts (added, +93/-0)
  • extensions/msteams/src/send-context.ts (modified, +38/-0)
  • extensions/msteams/src/send.test.ts (modified, +58/-0)
  • extensions/msteams/src/send.ts (modified, +2/-1)
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

The proactive send path in extensions/msteams/src/send.ts hardcodes replyStyle: "top-level" when calling sendMSTeamsMessages(), causing all proactive/CLI-sent messages to land as new top-level channel posts regardless of whether the conversation has thread context available.

Steps to reproduce

  1. Configure msteams plugin with a channel where the bot has been @mentioned in a thread (so a stored conversation reference with threadId exists).
  2. Send a proactive message to that conversation via the message tool or openclaw send.
  3. Observe the message lands as a new top-level post instead of in the thread.

Expected behavior

When sending a proactive message to a channel conversation that has a known thread root (threadId or activityId on the stored conversation reference), the message should be delivered into the correct channel thread.

Actual behavior

All proactive messages (from the message tool, CLI, or any code path through sendTextWithMedia()) create new top-level posts in the channel, breaking conversational threading. The replyStyle: "top-level" hardcode at extensions/msteams/src/send.ts:399 bypasses any thread context.

OpenClaw version

2026.5.5

Operating system

Linux (reproduced on Ubuntu 24.04)

Install method

pnpm dev

Model

N/A (channel routing issue, model-independent)

Provider / routing chain

N/A (issue is in the msteams channel plugin send path, not provider routing)

Additional provider/model setup details

N/A

Logs, screenshots, and evidence

Root cause in code:

  1. extensions/msteams/src/send.ts line 399 — replyStyle: "top-level" hardcoded in sendTextWithMedia()
  2. extensions/msteams/src/messenger.ts line 575 — throw new Error("Missing context for replyStyle=thread") blocks the proactive path from threading even if the hardcode were removed

Impact and severity

  • Affected: All MS Teams channel users receiving proactive messages (message tool, CLI sends)
  • Severity: High (breaks thread reply routing for all proactive sends to channels)
  • Frequency: Always (100% of proactive channel sends)
  • Consequence: Conversations fragment into disconnected top-level posts instead of threading, confusing users and breaking context

Additional information

The inbound reply-dispatcher path (reply-dispatcher.ts) handles threading correctly when a live turn context is available. The bug is specifically in the proactive/outbound send path which never has a turn context.

Fix submitted in #78299.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

When sending a proactive message to a channel conversation that has a known thread root (threadId or activityId on the stored conversation reference), the message should be delivered into the correct channel thread.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING