Skip to content

[Bug]: Assistant text preceding a tool call in the same turn is silently dropped on Signal channel (Anthropic/Sonnet, non-streaming) #101793

Description

@musubi1893

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

When an assistant response contains text followed by a tool call in the same turn (stopReason: "toolUse"), the text portion is not delivered to the Signal channel — only a subsequent, separate turn that ends cleanly (stopReason: "stop") actually reaches the user. The dropped text is fully present in the session transcript/JSONL as if it had been sent, with no indication to the agent or any log-visible error that delivery failed. This caused a real data-integrity incident: a required user-confirmation question was never delivered, and the agent proceeded as if a later, unrelated reply had confirmed it.

This appears closely related to #9983 ("Minimax: Text before tool calls not sent to chat"), but that report attributes the cause specifically to Minimax's non-streaming text+tool_call bundling behavior, implying Claude/Sonnet emits these as separate streamed events and is unaffected. This report shows the same symptom occurring with Anthropic claude-sonnet-5 on the Signal channel, so the issue is not Minimax-specific.

Steps to reproduce

  1. Configure an agent on the Signal channel with a workflow that asks the user a confirmation question and then, in the same response, calls a tool (e.g., checking whether a file exists, querying a database) before continuing.
  2. Send a message that triggers this flow.
  3. Observe the assistant's response in the session transcript (agents//sessions/.jsonl): the response contains a text block asking the confirmation question, immediately followed by a toolCall block, with "stopReason":"toolUse".
  4. Compare against what actually arrives on the Signal client. The text portion is never delivered — only a later, subsequent assistant message (one that ends with "stopReason":"stop" and has no attached tool call) is received.
  5. The user, having never seen the question, replies to whatever was actually delivered. The agent — relying on its own transcript, which shows the question as sent — treats the reply as an answer to the undelivered question.

Expected behavior

Text content generated in the same turn as a tool call should either:

  • Be delivered to the channel before or alongside the tool call executing (matching what the session transcript records as having happened), or
  • If intentionally suppressed by design (per the discussion in Expose stopReason in message_sending plugin hook metadata #66235), the agent should be made aware — via a system-level signal, injected note, or the tool result itself — that its preceding text was not delivered, so it does not proceed as though the user received and could have responded to it.

Actual behavior

The text is recorded as sent in the transcript, is invisible to the end user, and the agent has no way to detect the discrepancy without a manual line-by-line comparison against the user's actual client.

OpenClaw version

2026.6.11 (e085fa1)

Operating system

Ubuntu Server 26.04

Install method

npm

Model

anthropic/claude-sonnet-5

Provider / routing chain

openclaw -> anthropic (direct)

Additional provider/model setup details

Direct route is openclaw -> api.anthropic.com (anthropic-messages API), no proxy, gateway, or router in between — confirmed via gateway logs showing requests going straight to https://api.anthropic.com/v1/messages.

Model registered manually under models.providers.anthropic.models[] in openclaw.json, since OpenClaw's built-in catalog did not yet include claude-sonnet-5 at the time of setup.

Relevant config lives in openclaw.json under models.providers.anthropic.

Logs

Screenshots, recordings, and evidence

Raw transcript excerpt (session file, redacted only where noted) — the assistant message containing the confirmation question, ending in toolUse:
{
"type": "message",
"id": "ffff22e6",
"message": {
"role": "assistant",
"content": [
{
"type": "text",
"text": "...Also confirming: property is [PROPERTY_ADDRESS], personal card, owed to [PERSON_NAME] — same as your standing instruction, correct? And I still need to move the staged file to shared storage before logging — doing that now."
},
{
"type": "toolCall",
"id": "toolu_[REDACTED_TOOL_CALL_ID]",
"name": "exec",
"arguments": { "command": "ls -la media/inbound/[REDACTED_FILENAME].jpg 2>&1" }
}
],
"api": "anthropic-messages",
"provider": "anthropic",
"model": "claude-sonnet-5",
"stopReason": "toolUse"
}
}
The only message that actually reached the Signal client at this point in the conversation (confirmed via screenshot of the Signal app) was a separate, later assistant turn:
{
"type": "message",
"id": "45b0f614",
"message": {
"role": "assistant",
"content": [
{
"type": "text",
"text": "File confirmed staged in my workspace — holding the move until you confirm categorization and property/payment details above, then I'll move it and log everything in one pass."
}
],
"stopReason": "stop"
}
}

Note this second message references "details above" (i.e., the property/payment question) as if the user had already seen it — but the user's Signal client never received the message containing those details at all. Only this second, self-contained "stop" turn was delivered.

(Message/session IDs shown above are internal identifiers only; the property address, payment-recipient name, and filename UUID in the original transcript have been replaced with placeholders for privacy.)

Impact and severity

Affected users/systems/channels: Confirmed on the Signal channel with anthropic/claude-sonnet-5 (non-streaming), OpenClaw 2026.6.11, self-hosted deployment. Whether this affects other channels or models is NOT_ENOUGH_INFO — only Signal/Sonnet was directly observed.

Severity: Data risk. The dropped message was a required user-confirmation question (property/payment details) for a financial record-keeping workflow. Because the drop is silent and undetectable from the agent's own transcript, the agent proceeded to log a database record based on an unrelated later reply, treating it as if it had answered the undelivered question. The record was written with unconfirmed data as a direct result.

Frequency: NOT_ENOUGH_INFO on general frequency (always/intermittent/edge case) — this was observed and confirmed once in our deployment via direct transcript-to-Signal-client comparison. We have not run repeated trials to determine how often it recurs under the same conditions (text + tool call in the same turn).

Consequence: A financial record (a retail receipt, $224.37) was logged with owner-confirmed property and payment/reimbursement fields that the owner had never actually seen or approved, because the confirmation question that should have preceded logging was silently dropped. The incorrect data was caught and corrected only through manual comparison of the raw session transcript against the user's actual Signal message history — there was no automated way to detect the discrepancy.

Additional information

  1. Flush/deliver assistant text to the channel as soon as it's generated, before a subsequent tool call executes in the same turn.
  2. At minimum, surface the drop to the agent so it can be instructed to re-send.
  3. Document this behavior explicitly in the Signal/Messages docs.

Related Issues
#9983 — same symptom (text before tool call dropped from chat), attributed to Minimax-specific streaming behavior. This report shows the same symptom on Anthropic/Sonnet via Signal, suggesting the root cause may be broader than provider-specific streaming differences, or that non-streaming delivery paths generally have this gap regardless of provider.
#66235 — feature request to explicitly suppress stopReason: toolUse text via a plugin hook, describing this drop as consistent/expected in non-streaming mode. If this is intentional, it should be documented clearly and the agent-side blind spot described above should be addressed regardless.
#25592 — related but distinct: concerns intermediate text leaking to channels when it shouldn't; this report concerns the opposite — text that should reach the user being dropped.
#76915 (closed) — related but distinct: that issue concerns assistant text generated AFTER a message-tool call completes (trailing commentary dropped from Telegram), whereas this report concerns text generated BEFORE a tool call in the same turn (stopReason: toolUse), across arbitrary tool types (not just the message tool), on Signal rather than Telegram.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.bugSomething isn't workingbug:behaviorIncorrect behavior without a crashclawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.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.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.maturity:stableIssue affects a taxonomy feature currently scored M4/M5.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions