Bug Description
When an agent produces multiple text blocks in a single turn (text → tool calls → text), only the first text block is delivered to the Teams user. All subsequent text blocks are silently dropped — no error, no retry, no log entry.
This means if the agent says "Let me check..." before running tools, the user sees that filler text but never receives the actual answer.
Steps to Reproduce
- Configure OpenClaw with MS Teams plugin (
@openclaw/msteams v2026.2.23)
- Send a message to the bot that triggers tool use (e.g., a database lookup)
- The agent outputs:
- Text block 1: "Good question, let me look that up..."
- Tool call(s)
- Text block 2: (the actual detailed answer)
- User only receives Text block 1 in Teams. Text block 2 never arrives.
Expected Behavior
All text blocks should be delivered to the user, either as separate messages or coalesced into a single message.
Actual Behavior
Only the first text block per turn is delivered. Subsequent blocks are silently dropped. No errors in gateway logs. The session log shows the full response was generated correctly.
Environment
- OpenClaw: v2026.2.26
- MS Teams plugin: @openclaw/msteams v2026.2.23
replyStyle: "top-level"
blockStreamingDefault: off (default)
- Conversation type: personal (1:1 DM)
- Single-tenant Azure Bot
Analysis
The deliver() callback in reply-dispatcher.ts is called once per text block. The first call succeeds via continueConversation() in messenger.ts. Subsequent calls appear to fail silently — possibly because the proactive messaging context (continueConversation with activityId: undefined) becomes invalid after the first send, or the webhook response cycle has already completed.
The sendMSTeamsMessages() function in messenger.ts handles multiple chunks within a single delivery correctly (iterating in a loop inside one continueConversation call). But multiple deliveries (separate deliver() invocations from the reply dispatcher) each create independent continueConversation calls, and only the first one succeeds.
Workaround
Instruct the agent to never output intermediate text between tool calls — run all tools silently, then respond once. This ensures only one deliver() call per turn.
Related
Possibly related to the block streaming delivery path. With blockStreamingDefault: on, the behavior may differ.
Bug Description
When an agent produces multiple text blocks in a single turn (text → tool calls → text), only the first text block is delivered to the Teams user. All subsequent text blocks are silently dropped — no error, no retry, no log entry.
This means if the agent says "Let me check..." before running tools, the user sees that filler text but never receives the actual answer.
Steps to Reproduce
@openclaw/msteamsv2026.2.23)Expected Behavior
All text blocks should be delivered to the user, either as separate messages or coalesced into a single message.
Actual Behavior
Only the first text block per turn is delivered. Subsequent blocks are silently dropped. No errors in gateway logs. The session log shows the full response was generated correctly.
Environment
replyStyle: "top-level"blockStreamingDefault: off(default)Analysis
The
deliver()callback inreply-dispatcher.tsis called once per text block. The first call succeeds viacontinueConversation()inmessenger.ts. Subsequent calls appear to fail silently — possibly because the proactive messaging context (continueConversationwithactivityId: undefined) becomes invalid after the first send, or the webhook response cycle has already completed.The
sendMSTeamsMessages()function inmessenger.tshandles multiple chunks within a single delivery correctly (iterating in a loop inside onecontinueConversationcall). But multiple deliveries (separatedeliver()invocations from the reply dispatcher) each create independentcontinueConversationcalls, and only the first one succeeds.Workaround
Instruct the agent to never output intermediate text between tool calls — run all tools silently, then respond once. This ensures only one
deliver()call per turn.Related
Possibly related to the block streaming delivery path. With
blockStreamingDefault: on, the behavior may differ.