Skip to content

[Bug]: msteams implicit mention fails — replyToId unreliable, conversation.id threadRootId not used as fallback #38629

@vongohren

Description

@vongohren

Description

Thread replies to bot messages in MS Teams channels do not trigger implicit mention detection, even though the Groups documentation states:

"Replying to a bot message counts as an implicit mention (when the channel supports reply metadata)."

The current implementation at extensions/msteams/src/monitor-handler/message-handler.ts:680-682 relies solely on activity.replyToId to detect implicit mentions:

const implicitMention = Boolean(
  conversationId && replyToId && wasMSTeamsMessageSent(conversationId, replyToId),
);

However, Microsoft Teams does not reliably send replyToId for thread replies:

  • Desktop client: returns null
  • Mobile (iOS/Android): returns string "0"
  • Channel thread replies: frequently omitted entirely

This is a confirmed platform limitation documented in MicrosoftDocs/msteams-docs#4530 and Microsoft Q&A.

Root Cause

Three compounding issues:

  1. replyToId is unreliable — Teams doesn't consistently include it for thread replies
  2. conversation.id thread signal is discarded — Teams encodes the thread root message ID as ;messageid=XXX in conversation.id for thread replies, and the plugin already parses this via extractMSTeamsConversationMessageId() in inbound.ts:13-20, but it's not used for implicit mention detection
  3. Sent-message cache is in-memory only — lost on process restart, breaking implicit mention until the bot sends new messages

Proposed Fix

Use conversation.id's ;messageid= suffix as a fallback when replyToId is absent or invalid. The function extractMSTeamsConversationMessageId() already exists and extracts this ID — it just needs to be wired into the implicit mention check:

const rawConversationId = activity.conversation?.id ?? "";
const conversationId = normalizeMSTeamsConversationId(rawConversationId);
const replyToId = activity.replyToId ?? undefined;
const threadRootId = extractMSTeamsConversationMessageId(rawConversationId);
const implicitMention = Boolean(
  conversationId && (
    (replyToId && wasMSTeamsMessageSent(conversationId, replyToId)) ||
    (threadRootId && wasMSTeamsMessageSent(conversationId, threadRootId))
  ),
);

This is a 7-line change (5 insertions, 2 modifications) with no new dependencies.

How conversation.id thread detection works

// Top-level channel post (no thread):
"conversation": { "id": "19:[email protected]" }

// Thread reply (messageid = root message of the thread):
"conversation": { "id": "19:[email protected];messageid=1481567603816" }

If ;messageid= is present → it's a thread reply. The root message ID can be looked up in the existing sent-message cache.

Comparison with Other Plugins

  • Discord (message-handler.preflight.ts:609-614): Stateless detection via message.referencedMessage.author.id === botId — Discord provides the replied-to message's author in the payload
  • Telegram: Has had implicit mention fixes (e.g., forum system message exclusion) showing the pattern is actively maintained
  • Slack: Issue Slack: implicitMention should check thread participation, not just parent_user_id #25760 (completed) added participation-based implicit mention checking

The msteams plugin is the only one where implicit mention silently fails due to platform metadata unreliability.

Steps to Reproduce

  1. Configure msteams channel with requireMention: true (the default)
  2. @mention the bot in a Teams channel — bot responds in thread
  3. Reply to the bot's message in the thread without @mentioning it
  4. Expected: Bot detects implicit mention and responds
  5. Actual: Bot ignores the reply (logged as "skipping message (mention required)")

Additional Context

  • Sent-message cache (sent-message-cache.ts): In-memory Map with 24h TTL, lost on restart. A separate enhancement to persist this cache would further improve reliability.
  • Proactive messages sent via send.ts are never recorded in the cache, so replies to proactive bot messages also won't trigger implicit mention (separate issue).
  • Version: Tested on @openclaw/msteams 2026.3.3

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions