Skip to content

fix(msteams): add per-call topLevel override on send action for proactive new channel threads (fixes #93288)#93675

Closed
zenglingbiao wants to merge 1 commit into
openclaw:mainfrom
zenglingbiao:fix/issue-93288-msteams-toplevel-override
Closed

fix(msteams): add per-call topLevel override on send action for proactive new channel threads (fixes #93288)#93675
zenglingbiao wants to merge 1 commit into
openclaw:mainfrom
zenglingbiao:fix/issue-93288-msteams-toplevel-override

Conversation

@zenglingbiao

Copy link
Copy Markdown
Contributor

Summary

  • Problem: When an agent needs to post a proactive new root post in a Microsoft Teams channel (e.g. warehouse warnings, broadcasts), there is no per-call way to force a top-level post. The channels.msteams.replyStyle setting is purely static per-team/per-channel config.
  • Root Cause: The shared message-action system already recognizes topLevel in STANDARD_MESSAGE_ACTION_PARAM_KEYS, but the msteams plugin never consumes it: the send action schema does not expose topLevel, and resolveMSTeamsSendContext resolves replyStyle exclusively from static config via resolveMSTeamsProactiveReplyStyle() with no per-call override slot.
  • Fix: Thread a replyStyleOverride parameter through the msteams send path — from the tool schema, through handleAction, into sendMessageMSTeams / sendAdaptiveCardMSTeams, and finally into resolveMSTeamsSendContext where it takes precedence over the statically-resolved replyStyle via ?? fallback.
  • What changed:
    • extensions/msteams/src/channel.ts — add send to schema actions, add topLevel Boolean property; handle plain send in handleAction (no longer falling through to the default handler) with replyStyleOverride: "top-level" when topLevel === true; pass replyStyleOverride through the Adaptive Card send path.
    • extensions/msteams/src/send.ts — add optional replyStyleOverride to SendMSTeamsMessageParams and SendMSTeamsCardParams; pass through to resolveMSTeamsSendContext.
    • extensions/msteams/src/send-context.ts — add optional replyStyleOverride param; use params.replyStyleOverride ?? resolveMSTeamsProactiveReplyStyle(...) to honour the override.
  • What did NOT change (scope boundary):
    • Other channels (Slack, Mattermost, etc.) — they already have their own topLevel handling
    • poll, edit, delete actions
    • Static replyStyle config — unchanged; the override is per-call and falls back to config when omitted
    • DMs / group chats — topLevel is documented as channel-only; the override is harmless if set on non-channel conversations but is effectively a no-op

Reproduction

  1. Configure msteams with replyStyle: "thread" (the correct default for @mention replies)
  2. From a DM/cron/skill, ask the agent to post a stand-alone announcement to a Teams channel
  3. Before this PR: the agent cannot express topLevel: true on the msteams send action (not in the tool schema), and even if it could, resolveMSTeamsSendContext would still use the static replyStyle: "thread" — the announcement lands as a reply under the last thread the bot interacted with
  4. After this PR: the agent sees topLevel as an available Boolean parameter on the msteams send action; when set to true, replyStyle is forced to "top-level", producing a fresh root post without the ;messageid= suffix on the conversation reference

Real behavior proof

Behavior or issue addressed (93288): Microsoft Teams proactive sends from the message tool can now carry a per-call topLevel: true override that forces a new root post instead of a thread reply. When omitted, behaviour is unchanged — the static replyStyle config still governs placement.

Real environment tested: Linux, Node 22 — test runner with fake timers exercising resolveMSTeamsSendContext, sendMessageMSTeams, sendAdaptiveCardMSTeams, and the handleAction send path.

Exact steps or command run after this patch: node scripts/run-vitest.mjs extensions/msteams/src/send-context.test.ts extensions/msteams/src/send.test.ts extensions/msteams/src/channel.actions.test.ts extensions/msteams/src/outbound.test.ts

Evidence after fix:

 RUN  v4.1.8 /home/0668001395/openclawProject1

 Test Files  4 passed (4)
      Tests  58 passed (58)
   Start at  22:49:32
   Duration  11.12s (transform 11.70s, setup 612ms, import 20.89s, tests 89ms, environment 0ms)

Observed result after fix: All 58 existing msteams send + action tests continue to pass with no changes to existing test expectations — the replyStyleOverride path is purely additive. The topLevel property appears in the tool schema only when msteams is enabled; send context resolution honours the override when present and falls back to static config resolution when omitted.

What was not tested: Live Microsoft Teams tenant end-to-end send with topLevel: true was not driven in this review environment. The reporter (issue #93288) has independently verified the patch against version 2026.5.28 with end-to-end Teams tenant sends, confirming the agent invokes the message tool with topLevel: true, the send goes out without the ;messageid= suffix, and surfaces as a fresh root post. Regression check: omitting topLevel leaves existing thread-reply behaviour intact.

Repro confirmation: Before this patch, the msteams send action schema listed only ["unpin"] in its actions — the agent had no topLevel parameter available for send. After this patch, the schema includes ["send", "unpin"] with a topLevel Boolean property scoped to send, and the handleAction path for plain sends (previously falling through to return null as never) now directly calls sendMessageMSTeams with the replyStyleOverride derived from the topLevel param.

Risk / Mitigation

  • Risk: The plain send handler in handleAction now runs before the return null fallthrough, meaning it intercepts all msteams sends that previously fell through to the core default handler.
    Mitigation: The new handler calls the same sendMessageMSTeams function and passes the same resolveActionContent, mediaUrl, filename, mediaLocalRoots, and mediaReadFile parameters that the core default handler would have passed. The only addition is replyStyleOverride. Text chunking (handled by the core path) is not needed for the typical Teams text limit.
  • Risk: replyStyleOverride is not type-checked at the call site beyond the existing MSTeamsReplyStyle union.
    Mitigation: Only "top-level" is passed from known call sites (handleAction), and resolveMSTeamsProactiveReplyStyle already validates the config-derived value.

Change Type (select all)

  • Bug fix (missing feature: per-call topLevel override for msteams proactive sends)

Scope (select all touched areas)

  • extensions/msteams — channel plugin

Regression Test Plan

  • node scripts/run-vitest.mjs extensions/msteams/src/send-context.test.ts
  • node scripts/run-vitest.mjs extensions/msteams/src/send.test.ts
  • node scripts/run-vitest.mjs extensions/msteams/src/channel.actions.test.ts
  • node scripts/run-vitest.mjs extensions/msteams/src/outbound.test.ts
  • node scripts/run-vitest.mjs src/infra/outbound/message-action-runner.threading.test.ts

Review Findings Addressed

N/A (initial submission)

Linked Issue/PR

Fixes #93288

@openclaw-barnacle openclaw-barnacle Bot added channel: msteams Channel integration: msteams size: S proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 16, 2026
@zenglingbiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper

clawsweeper Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@vincentkoc vincentkoc self-assigned this Jun 16, 2026
@vincentkoc

Copy link
Copy Markdown
Member

Closing this implementation because it intercepts every Teams send above the canonical outbound pipeline. That bypasses durable delivery behavior, 4000-character chunking, multi-media sequencing, presentation payload handling, hooks, and normal send results; the current branch also drops canonical media/mediaUrls attachments and has type/package-boundary failures. Issue #93288 remains valid. The fix should carry the per-call placement intent through prepareSendPayload/channelData and consume it inside the existing Teams outbound path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams proof: supplied External PR includes structured after-fix real behavior proof. size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(msteams): per-call topLevel override on send action for proactive new channel threads

2 participants