fix(feishu): strip internal tool-trace banners from outbound text#98705
Conversation
Part of openclaw#90684 Co-authored-by: Cursor <[email protected]>
|
Codex review: needs maintainer review before merge. Reviewed July 1, 2026, 12:17 PM ET / 16:17 UTC. Summary PR surface: Source +2, Tests +20. Total +22 across 2 files. Reproducibility: yes. source inspection gives a high-confidence reproduction path: current main Feishu lacks Review metrics: none identified. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the narrow Feishu hook after required CI and maintainer review, then keep the broader cross-channel cleanup tracked on #90684. Do we have a high-confidence way to reproduce the issue? Yes, source inspection gives a high-confidence reproduction path: current main Feishu lacks Is this the best way to solve the issue? Yes, this is the best narrow fix for the Feishu slice because it uses the existing plugin SDK sanitizer seam and matches accepted sibling channel implementations without adding config or a parallel sanitizer. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against a5e11c0083c5. Label changesLabel justifications:
Evidence reviewedPR surface: Source +2, Tests +20. Total +22 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
6378d5e
into
openclaw:main
* origin/main: (1287 commits) fix(android): block loopback canvas navigation (openclaw#99874) fix(hooks): suppress unhandled stdout/stderr stream errors in gmail watcher (openclaw#100519) fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout (openclaw#98381) fix(build): fall back to tsx for build TypeScript scripts (openclaw#91262) feat(skills): suggest saving detected reusable workflows by default (openclaw#95477) (openclaw#100692) docs(changelog): remove generated release-note entries feat(telegram): offer BotFather web app flow in setup help and docs (openclaw#100540) fix(ios): unify Talk and Settings row typography on one branded detail row (openclaw#100515) feat(gateway): add persisted crash-loop breaker and fatal-config exit contract refactor(macos): lock and unify PortGuardian tunnel record persistence so concurrent app instances cannot lose orphan records (openclaw#100601) fix: stop reconnecting on protocol mismatch (openclaw#98414) fix(maint): reuse recent hosted gates after rebase (openclaw#100663) fix(ui): reopen web terminals without stale content (openclaw#100665) fix(browser): diagnose empty WSL2 Chrome replies (openclaw#100590) fix(ios): chat snaps back to bottom when scrolling to top via status-bar tap (openclaw#100502) Treat already-compacted CLI compaction as no-op (openclaw#99136) docs(changelog): remove direct main fix entry fix(feishu): strip internal tool-trace banners from outbound text (openclaw#98705) fix(message): thread --limit through to CLI formatter and surface provider pagination hints (openclaw#99089) fix(voyage): close response body stream when batch output JSONL parsing throws (openclaw#98840) ... # Conflicts: # extensions/memory-wiki/package.json
…enclaw#98705) Part of openclaw#90684 Co-authored-by: Cursor <[email protected]>
…enclaw#98705) Part of openclaw#90684 Co-authored-by: Cursor <[email protected]>
…text The Nextcloud Talk outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered chat messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (mattermost openclaw#98693, feishu openclaw#98705, twitch openclaw#103109, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound base adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <[email protected]>
Part of #90684
What Problem This Solves
Fixes an issue where Feishu users receiving bot replies would see internal assistant tool-trace scaffolding lines (e.g.
⚠️ 🛠️ \search repos (agent)` failed`) leaked into outbound messages. These banners are internal runtime diagnostics that should not reach end users.Why This Change Was Made
The Feishu outbound adapter lacked a
sanitizeTexthook, so corestripInternalRuntimeScaffoldingwas the only sanitization layer — and it does not remove tool-trace failure banners. AddingsanitizeAssistantVisibleTexton the outboundsanitizeTexthook matches the accepted sibling pattern already shipped for Slack, Signal, Matrix, Telegram, Google Chat, QQBot, IRC, and SMS.User Impact
Feishu users no longer see internal tool-trace failure banners in bot replies. Normal assistant prose and markdown formatting are preserved.
Evidence
Negative control — core strip keeps banner (pre-fix behavior):
After fix — feishuPlugin.outbound.sanitizeText strips banner:
Focused test:
What was not tested: No live Feishu round-trip — credentials were not available in this checkout. The bug is in the sanitization layer before network delivery, so the proof above covers the affected boundary without a live channel.
AI-assisted: Cursor (Claude). Proof run manually.
Made with Cursor