fix(msteams): sanitize internal tool-trace lines from outbound text (#90684)#95867
fix(msteams): sanitize internal tool-trace lines from outbound text (#90684)#95867jailbirt wants to merge 1 commit into
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 13, 2026, 1:40 PM ET / 17:40 UTC. Summary PR surface: Source +5, Tests +18. Total +23 across 2 files. Reproducibility: yes. Current 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:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Rebase onto current Do we have a high-confidence way to reproduce the issue? Yes. Current Is this the best way to solve the issue? No, not at the current base. The adapter seam is correct, but the selected current-main sanitizer no longer removes the reported trace line; the fix must target the current shared contract and prove the real normalization result. (github.com) Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 3c417f791cc5. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +5, Tests +18. Total +23 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
Review history (1 earlier review cycle)
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
…tests Pass a ReplyPayload-compatible `payload` to the msteams outbound `sanitizeText` test calls so the exact-head typecheck passes, and collapse the literal-only string concatenation flagged by lint into a single string. Addresses the ClawSweeper review findings on openclaw#95867 (P2 payload / P3 concat). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
Pushed a fix for the ClawSweeper findings: the msteams outbound @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
…penclaw#90684) Rebased onto current main. Adds a sanitizeAssistantVisibleText() hook to the msteams outbound adapter so internal failed-tool trace banners are stripped before delivery (mirrors the merged Google Chat fix openclaw#95084). The adapter tests pass a ReplyPayload-compatible payload and use a single string literal so the exact-head typecheck and lint pass. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
5961c42 to
01243cc
Compare
|
Also rebased onto current main so it no longer carries stale-base CI drift ( |
What Problem This Solves
MS Teams sends assistant text to users without running
sanitizeAssistantVisibleText(), so internal tool-trace lines leak into user-visible messages. The most visible case is the⚠️ 🛠️ \(agent)` failedbanner produced for a benign non-zero shell exit (e.g. agrep` that finds no match → exit 1). The turn completes successfully, but the user receives an alarming "failed" message from the bot.msteamsChannelOutboundhad nosanitizeTexthook at all. This is the MS Teams instance of #90684. Discord, Google Chat (#95084, merged) and WhatsApp already run the canonical sanitizer on outbound; MS Teams was missing it.Closes part of #90684. Related: #88332, #95084 (the merged Google Chat counterpart, identical fix shape).
Why This Change Was Made
Add
sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text)tomsteamsChannelOutbound, reusing the canonical delivery sanitizer the other channels already use (rather than new regexes). The hook runs in the shared outbound deliver path, so it covers every text send — replies, sub-agent announces, and cron deliveries.msteamsChannelOutboundis now exported so the hook can be unit-tested (mirrorsgooglechatOutboundAdapter).Out of scope: the Codex-native warning taxonomy (#88332) and threading/attachments. This is one focused MS Teams instance of the cross-channel umbrella.
User Impact
Internal trace/failure banners (e.g.
⚠️ 🛠️ … (agent) failedfrom a benigngrepno-match) are no longer shown to MS Teams users. Legitimate assistant prose is unaffected. No config, auth, secrets, network, or tool-execution behavior changes.Evidence
The fix wires the canonical
sanitizeAssistantVisibleText()into the MS Teams outboundsanitizeTexthook. Below is copied live output / console output (stdout) from running that exact function vianodeon a live OpenClaw2026.6.8deployment, with the leaked banner as input:The banner line is removed; the real assistant prose is preserved.
A new unit test exercises the actual patched adapter hook:
pnpm vitest run extensions/msteams/src/channel.message-adapter.test.ts -t "sanitizeText"→ 2 passed (msteams outbound sanitizeText): assertsmsteamsChannelOutbound.sanitizeTextstrips the(agent) failedbanner and leaves ordinary prose untouched.Proof limitations: the MS Teams deployment available to me runs
2026.5.28, which predates the banner machinery (it does not generate the(agent) failedbanner —(agent)/🛠️are absent from its payload builder), so it cannot reproduce the end-to-end leak. The after-fix evidence therefore exercises the exact canonical sanitizer this PR wires into MS Teams, captured on a live2026.6.8deployment, plus the adapter-hook unit test. No MS Teams client screenshot; private space/account/user details omitted.Risk
Highest-risk area is over-stripping legitimate content. Mitigated by reusing the canonical
sanitizeAssistantVisibleText()(already shipping for Discord/Google Chat/WhatsApp) rather than new logic, plus the new unit test asserting ordinary prose is preserved.AI-assisted change.
Real behavior proof
Local run against this branch, pnpm 11.2.2 (frozen lockfile), vitest.
Validation (re-runnable)
Before/after (patched MS Teams outbound path)
Input (identical both runs):
A repro drives the real
deliver.tssanitize gate; BEFORE = adaptersanitizeTextundefined (main), AFTER = the patchedmsteamsChannelOutbound.sanitizeTextexport.BEFORE: the
⚠️ 🛠️ … (agent) failedbanner survives into outbound text. AFTER: the banner line is removed, both prose lines preserved.Why main leaks
src/infra/outbound/deliver.tsapplieshandler.sanitizeTextonly when present (:795). On mainmsteamsChannelOutboundhas nosanitizeText, so the shared gate is skipped and text passes through verbatim. This PR addssanitizeText: ({ text }) => sanitizeAssistantVisibleText(text)atextensions/msteams/src/channel.ts:444, mirroring the merged Google Chat fix #95084. Canonical sanitizer:src/shared/text/assistant-visible-text.ts→stripAssistantInternalTraceLines().Proof limitation (consistent with the PR's existing note): the AFTER side exercises the hook through a faithful re-implementation of the
deliver.tsgate (the real gate is module-internal, not exported), not a live MS Teams socket send.