Skip to content

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

Description

@leen109

Use case

When the bot needs to post a proactive new root post / new thread in a Microsoft Teams channel — e.g. for warehouse warnings, broadcasts, cross-team announcements — there is currently no way to do this on a per-call basis. The channels.msteams.replyStyle setting is purely static (per-team / per-channel config). Setting it globally to "top-level" is not desirable: regular @mention replies in existing threads must still land inside their thread.

Two distinct behaviours are needed in the same channel:

  1. Reply path (existing): bot is @mentioned inside a thread → reply lands inside the same thread. (Currently works via replyStyle: "thread".)
  2. Proactive new-thread path (missing): bot is asked, via DM/cron/skill, to post a stand-alone announcement → must surface as a fresh root post, not as a reply under whichever thread happened to last seed the conversation reference.

Why the static config is insufficient

In dist/probe-<hash>.js resolveMSTeamsSendContext() the replyStyle is resolved strictly from cfg:

const replyStyle = resolveMSTeamsProactiveReplyStyle({
  cfg: msteamsCfg,
  conversationId,
  ref: safeRef,
  conversationType
});

There is no override slot. In dist/channel-<hash>.js describeMSTeamsMessageTool() the send action exposes no topLevel / replyStyle schema property either, so the agent has no signal it could set. The Standard message-action param allowlist already lists topLevel (in dist/channel-target-<hash>.js STANDARD_MESSAGE_ACTION_PARAM_KEYS), but the msteams plugin never consumes it. The Telegram plugin treats thread-create as topic-create; there is no msteams equivalent.

Proposal

  1. Add topLevel: Type.Optional(Type.Boolean(...)) to the schema returned by describeMSTeamsMessageTool(), with action scope including send. Description should make clear that it forces a new root post (channel only) and is ignored for DMs / group chats.

  2. In handleAction for action === "send", when params.topLevel === true, call sendMessageMSTeams({ ..., replyStyleOverride: "top-level" }) (and analogously for sendAdaptiveCardMSTeams if presentation is set).

  3. In sendMessageMSTeams and sendAdaptiveCardMSTeams, accept an optional replyStyleOverride param and forward it to resolveMSTeamsSendContext.

  4. In resolveMSTeamsSendContext, honour params.replyStyleOverride before falling back to the config-derived resolveMSTeamsProactiveReplyStyle():

const replyStyle = params.replyStyleOverride ?? resolveMSTeamsProactiveReplyStyle({ ... });

Net change is ~10 lines in two files. Backwards compatible: when topLevel is omitted, behaviour is unchanged.

Workaround in place

We have applied this exact patch locally against version 2026.5.28 (msteams plugin install path ~/.openclaw/npm/projects/openclaw-msteams-*/node_modules/@openclaw/msteams/dist/) and verified end-to-end: agent invokes the message tool with topLevel: true, send goes out without the ;messageid= suffix on the conversation reference, surfaces as a fresh root post with its own thread. Regression check: omitting topLevel leaves the existing thread-reply behaviour intact.

A re-apply script restores the patch after openclaw plugins install @openclaw/msteams. Happy to open a PR from a fork (versando-it) once you confirm the proposal direction.

Sample usage

// agent message tool call
{
  "channel": "msteams",
  "action": "send",
  "target": "conversation:19:[email protected]",
  "topLevel": true,
  "message": "⚠️ Warehouse alert: incoming delivery delayed for article 12345."
}

Environment

  • OpenClaw 2026.5.28
  • @openclaw/msteams 2026.5.28
  • Windows Server (SVR-APP2), Node 24.15.0
  • Bot Framework public cloud
  • Channel: classic “Posts” style (so replyStyle: "thread" is the correct default for replies)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions