Summary
Forward Action.Submit messageBack activities (type="message" with empty text + value object) to the agent instead of dropping them as empty messages.
Problem to solve
When a user clicks an Action.Submit button on an Adaptive Card in Teams, the click is sent as a messageBack activity (type="message" with empty text and a value object containing the button payload). The msteams plugin strips mentions, finds empty text, and drops the message with "skipping empty message after stripping mentions." The value payload is never forwarded to the agent.
This is distinct from the adaptiveCard/action invoke fixed in #60431 — that PR handles Action.Execute (type="invoke"). However, the majority of Adaptive Cards use Action.Submit, which Teams sends as messageBack, not an invoke.
Without this, interactive cards (confirmations, approvals, form submissions, RAG status updates) cannot work. Bots must fall back to conversational text prompts.
Proposed solution
In the message handler, before dropping empty-text messages, check if activity.value is present:
const text = stripMSTeamsMentionTags(activity.text || '').trim();
if (!text && activity.value && typeof activity.value === 'object') {
// This is a messageBack card action — forward to agent with value payload
// Option A: Serialize value into text: "[CARD_ACTION] {json}"
// Option B: Forward as-is and let the agent framework access activity.value
}
The detection pattern is: activity.type === "message" && !activity.text.trim() && activity.value && typeof activity.value === "object"
This should be checked before the "skipping empty message" branch.
Alternatives considered
Current workaround: We run a sidecar HTTP proxy between the Cloudflare tunnel and OpenClaw that buffers the request body, detects the messageBack pattern, sends HTTP 200 to Teams immediately, rewrites the activity text to include the value payload as [CARD_ACTION] {json}, and forwards it to OpenClaw. This works but adds operational complexity (extra container per gateway).
Action.OpenUrl fallback: Using Action.OpenUrl instead of Action.Submit opens a browser — poor UX and not suitable for inline confirmations.
Conversational fallback: Agent displays options as text, user types a number. Works but defeats the purpose of Adaptive Cards.
Impact
Affected: All Teams bot users using Adaptive Cards with Action.Submit
Severity: High — blocks all interactive card workflows
Frequency: Every button click on every Adaptive Card
Consequence: Interactive cards are unusable; must fall back to text-based prompts or run a sidecar proxy as workaround
Evidence/examples
Related: Issue 55384 / PR 60431 fixed adaptiveCard/action invoke (Action.Execute). This issue covers Action.Submit messageBack, a different and more commonly used activity pattern. Environment: OpenClaw latest, msteams stock plugin, Azure Bot Single Tenant, Adaptive Card schema 1.5.
Additional information
The relevant code is in extensions/msteams/src/monitor-handler.ts. The fix should add a value-object check before the empty-text drop logic. This is the companion issue to 55384 — together they cover both invoke formats Teams uses for Adaptive Card interactions.
Summary
Forward Action.Submit messageBack activities (type="message" with empty text + value object) to the agent instead of dropping them as empty messages.
Problem to solve
When a user clicks an Action.Submit button on an Adaptive Card in Teams, the click is sent as a messageBack activity (type="message" with empty text and a value object containing the button payload). The msteams plugin strips mentions, finds empty text, and drops the message with "skipping empty message after stripping mentions." The value payload is never forwarded to the agent.
This is distinct from the adaptiveCard/action invoke fixed in #60431 — that PR handles Action.Execute (type="invoke"). However, the majority of Adaptive Cards use Action.Submit, which Teams sends as messageBack, not an invoke.
Without this, interactive cards (confirmations, approvals, form submissions, RAG status updates) cannot work. Bots must fall back to conversational text prompts.
Proposed solution
In the message handler, before dropping empty-text messages, check if
activity.valueis present:The detection pattern is:
activity.type === "message" && !activity.text.trim() && activity.value && typeof activity.value === "object"This should be checked before the "skipping empty message" branch.
Alternatives considered
Current workaround: We run a sidecar HTTP proxy between the Cloudflare tunnel and OpenClaw that buffers the request body, detects the messageBack pattern, sends HTTP 200 to Teams immediately, rewrites the activity text to include the value payload as
[CARD_ACTION] {json}, and forwards it to OpenClaw. This works but adds operational complexity (extra container per gateway).Action.OpenUrl fallback: Using Action.OpenUrl instead of Action.Submit opens a browser — poor UX and not suitable for inline confirmations.
Conversational fallback: Agent displays options as text, user types a number. Works but defeats the purpose of Adaptive Cards.
Impact
Affected: All Teams bot users using Adaptive Cards with Action.Submit
Severity: High — blocks all interactive card workflows
Frequency: Every button click on every Adaptive Card
Consequence: Interactive cards are unusable; must fall back to text-based prompts or run a sidecar proxy as workaround
Evidence/examples
Related: Issue 55384 / PR 60431 fixed adaptiveCard/action invoke (Action.Execute). This issue covers Action.Submit messageBack, a different and more commonly used activity pattern. Environment: OpenClaw latest, msteams stock plugin, Azure Bot Single Tenant, Adaptive Card schema 1.5.
Additional information
The relevant code is in extensions/msteams/src/monitor-handler.ts. The fix should add a value-object check before the empty-text drop logic. This is the companion issue to 55384 — together they cover both invoke formats Teams uses for Adaptive Card interactions.