Skip to content

[Bug]: Reasoning tokens leak to chat channels when models stream interleaved text/thinking blocks #89473

Description

@zax0rz

Summary

Models that stream interleaved text and thinking blocks within tool_call_thinking/reasoning tags can leak reasoning tokens to user-facing chat channels (Discord, etc.), even when reasoningDefault is set to "off". The built-in stripThinkingTagsFromText sanitizer is not wired into the sanitizeAssistantText pipeline, so any thinking tags that survive chunk-level parsing pass through as visible text.

Steps to reproduce

  1. Configure a model that streams interleaved thinking/text blocks (e.g., MiniMax M3 via OpenAI-compatible proxy such as LiteLLM).
  2. Set reasoningDefault: "off" on the agent.
  3. Send a message to the agent via any chat channel (Discord, Telegram, etc.).
  4. Observe that internal reasoning text (wrapped in reasoning tags) appears inline in the agent's visible response.

Expected behavior

All reasoning/thinking content should be stripped before delivery to chat channels, regardless of whether the model is classified as a reasoning model in openclaw.json. stripThinkingTagsFromText exists as a utility but is not applied as a safety net in the final sanitization stage.

Actual behavior

Reasoning tokens appear verbatim in the chat channel. The chunk-level thinking_delta parsing correctly separates explicit thinking blocks, but interleaved text blocks within the same reasoning tag sequence pass through sanitizeAssistantVisibleText unstripped because stripThinkingTagsFromText is never called.

Fix

In src/embedded-agent-utils.ts, sanitizeAssistantText should apply stripThinkingTagsFromText as a final safety net:

- function sanitizeAssistantText(text) {
-   return sanitizeAssistantVisibleText(text);
- }
+ function sanitizeAssistantText(text) {
+   return stripThinkingTagsFromText(sanitizeAssistantVisibleText(text));
- }

This is a one-line change that ensures any reasoning-tagged content surviving earlier stream parsing is caught before delivery.

Verified working against the compiled output (dist/embedded-agent-utils-CjcypG6C.js line 21-22) after manual hotfix.

OpenClaw version

2026.5.28 (e932160)

Operating system

macOS 15.3 (arm64)

Install method

npm global

Model

MiniMax M3 (via LiteLLM proxy). Also reproducible with any model that streams interleaved text/thinking blocks within reasoning tags.

Additional context

Setting "reasoning": true on the model definition in openclaw.json partially mitigates this by enabling the chunk-level thinking_delta parsing, but does not fully prevent leaks when the model's streaming behavior interleaves text and thinking blocks within the same tag sequence. The sanitizer should be defense-in-depth regardless of model classification.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.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:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.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