openclaw - ✅(Solved) Fix tool_call/tool_result XML blocks leak into Discord messages despite verboseDefault: off [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#61688Fetched 2026-04-08 02:55:52
View on GitHub
Comments
1
Participants
2
Timeline
3
Reactions
0
Participants
Timeline (top)
closed ×1commented ×1cross-referenced ×1

Raw <tool_call> and <tool_result> XML blocks are visible in Discord messages even with verboseDefault: "off" set in agents.defaults. The blocks appear inline before the assistant's formatted response text.

Root Cause

Raw <tool_call> and <tool_result> XML blocks are visible in Discord messages even with verboseDefault: "off" set in agents.defaults. The blocks appear inline before the assistant's formatted response text.

Fix Action

Fixed

PR fix notes

PR #61729: fix(Gateway): strip tool_call and tool_result XML blocks from assistant visible text

Description (problem / solution / changelog)

Summary

  • Problem: In Discord and other gateway-managed channels, raw <tool_call> and <tool_result> XML blocks leak into the assistant's visible messages even when verboseDefault: "off" is set. This occurs because the gateway layer sometimes emits tool results wrapped in XML (e.g., <tool_result>...</tool_result> or even mismatched <tool_result>...</tool_call>), and the core message delivery pipeline fails to strip these tags.
  • Root Cause: There are two separate sanitization pipelines in the codebase. PR #60619 added stripToolCallXmlTags() to stripAssistantInternalScaffolding() in assistant-visible-text.ts, but this function is only exported for the plugin SDK and is never called in the main message delivery path. The actual delivery pipeline uses sanitizeAssistantText() in pi-embedded-utils.ts, which strips <think> tags, downgraded [Tool Call: ...] text, and Minimax XML, but completely misses standard <tool_call> and <tool_result> XML tags. Furthermore, the TOOL_CALL_TAG_NAMES set did not include tool_result, meaning even if the function was called, <tool_result> blocks would still leak.
  • Fix:
    1. Exported stripToolCallXmlTags from assistant-visible-text.ts and integrated it into the core sanitizeAssistantText() pipeline in pi-embedded-utils.ts.
    2. Added tool_result to TOOL_CALL_TAG_NAMES and TOOL_CALL_QUICK_RE so that tool result XML blocks are properly identified and stripped. This ensures that all assistant text is properly sanitized of tool XML before being chunked and delivered to any channel, fixing the root cause of the leak.
  • What changed:
    • src/shared/text/assistant-visible-text.ts: Added tool_result to tag names and regex; exported stripToolCallXmlTags.
    • src/agents/pi-embedded-utils.ts: Imported and called stripToolCallXmlTags inside sanitizeAssistantText().
    • src/shared/text/assistant-visible-text.test.ts: Added tests for <tool_result> stripping.
    • src/agents/pi-embedded-utils.test.ts: Added regression tests for <tool_call> and <tool_result> stripping in extractAssistantText.
  • What did NOT change (scope boundary): The logic for determining when to emit tool results (the verbose flag logic) remains unchanged. We are strictly fixing the text sanitization pipeline to ensure XML scaffolding never reaches the user-facing text buffer. The stripAssistantInternalScaffolding behavior for plugins remains functionally identical (just with added tool_result support).

Reproduction

  1. Set agents.defaults.verboseDefault: "off" in openclaw.json.
  2. Use /verbose off in a Discord channel.
  3. Send a message that triggers a tool call (e.g., "Read the file test.txt").
  4. Observe that the assistant's reply no longer contains raw <tool_call> or <tool_result> XML blocks inline.

Risk / Mitigation

  • Risk: Stripping <tool_result> or <tool_call> might accidentally remove legitimate user-facing text if the assistant is trying to teach the user about these XML tags.
  • Mitigation: The stripToolCallXmlTags function is already stateful and carefully designed to preserve literal XML-style examples in prose (e.g., when wrapped in backticks or when used as lone mentions). We added comprehensive unit tests in pi-embedded-utils.test.ts to ensure both the stripping of raw blocks and the preservation of legitimate text work as expected.

Change Type (select all)

  • Bug fix

Scope (select all touched areas)

  • Gateway
  • Agents

Linked Issue/PR

Fixes #61688

Changed files

  • CHANGELOG.md (modified, +2/-0)
  • src/agents/pi-embedded-utils.test.ts (modified, +110/-0)
  • src/agents/pi-embedded-utils.ts (modified, +8/-218)
  • src/agents/tools/chat-history-text.ts (modified, +3/-13)
  • src/agents/tools/sessions.test.ts (modified, +7/-0)
  • src/shared/text/assistant-visible-text.test.ts (modified, +55/-1)
  • src/shared/text/assistant-visible-text.ts (modified, +220/-4)

Code Example

<tool_call>
{"name": "exec", "arguments": {"command": "cd ~/.openclaw/workspace && python3 scripts/preflight.py --status", "timeout": 30}}
</tool_call>

<tool_result>
{"stdout": "...", "stderr": "", "exitCode": 0, "duration": 556}
</tool_call>

Crescent Moon Skull — render picks pending...
RAW_BUFFERClick to expand / collapse

Description

Raw <tool_call> and <tool_result> XML blocks are visible in Discord messages even with verboseDefault: "off" set in agents.defaults. The blocks appear inline before the assistant's formatted response text.

Example Discord output

<tool_call>
{"name": "exec", "arguments": {"command": "cd ~/.openclaw/workspace && python3 scripts/preflight.py --status", "timeout": 30}}
</tool_call>

<tool_result>
{"stdout": "...", "stderr": "", "exitCode": 0, "duration": 556}
</tool_call>

Crescent Moon Skull — render picks pending...

Expected: only the final response text ("Crescent Moon Skull — render picks pending...") should appear when verbose is off.

Steps to reproduce

  1. Set agents.defaults.verboseDefault: "off" in openclaw.json
  2. Use /verbose off in Discord channel
  3. Reset session (/reset)
  4. Send a message that triggers a tool call (e.g. "run preflight")
  5. Tool call and result XML blocks appear inline in the Discord message

Environment

  • OpenClaw 2026.4.5 (3e72c03)
  • macOS Darwin 24.6.0 (arm64, Mac mini M4)
  • Primary model: anthropic/claude-opus-4-6 (reasoning: false)
  • Discord channel: gateway-managed bot
  • LCM plugin: @martian-engineering/[email protected]

Notes

  • Upgraded from 2026.4.2 to 2026.4.5 specifically for #60619 (outbound sanitizer for leaked tool_call XML), but the issue persists
  • verboseDefault is confirmed in config and validated via openclaw config validate
  • Session reset and /verbose off command have no effect on the XML block display
  • The <tool_result> blocks are sometimes closed with </tool_call> instead of </tool_result>, suggesting these are gateway-generated XML rather than model output

extent analysis

TL;DR

Disable verbose mode at the gateway level or adjust the XML parsing logic to exclude tool call and result blocks when verboseDefault is set to "off".

Guidance

  • Verify that the verboseDefault setting is correctly propagated to the gateway-managed bot and the LCM plugin.
  • Check the gateway's configuration to see if there's an override for verbose mode that's causing the XML blocks to appear.
  • Investigate the XML parsing logic to determine why the </tool_call> closing tag is sometimes used for tool_result blocks, and adjust the logic to correctly handle these blocks.
  • Consider adding a feature to explicitly exclude tool call and result blocks from Discord messages when verboseDefault is "off".

Example

No code snippet is provided as the issue does not contain sufficient information about the codebase.

Notes

The issue may be related to the gateway-managed bot or the LCM plugin, and further investigation is needed to determine the root cause. The fact that the <tool_result> blocks are sometimes closed with </tool_call> suggests that the issue may be related to the gateway-generated XML.

Recommendation

Apply workaround: adjust the XML parsing logic to exclude tool call and result blocks when verboseDefault is set to "off", as the root cause of the issue is unclear and may require further investigation.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING