fix(tlon): strip internal tool-trace banners from outbound text#102211
fix(tlon): strip internal tool-trace banners from outbound text#102211masatohoshino wants to merge 1 commit into
Conversation
Part of openclaw#90684 Wire sanitizeAssistantVisibleText into the tlon outbound adapter's sanitizeText hook, matching the merged sibling channel fixes (Feishu openclaw#98705, Mattermost openclaw#98693, Slack, Signal, Matrix, IRC). Without the hook, shared delivery passes internal tool-call/reasoning scaffolding verbatim to Tlon end users.
|
Codex review: needs maintainer review before merge. Reviewed July 8, 2026, 11:32 AM ET / 15:32 UTC. Summary PR surface: Source +2, Tests +21. Total +23 across 2 files. Reproducibility: yes. at source level: current main's Tlon outbound adapter lacks Review metrics: 1 noteworthy metric.
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 Tlon hook after exact-head validation while keeping #90684 open for remaining channel slices or a future shared sanitizer-default decision. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main's Tlon outbound adapter lacks Is this the best way to solve the issue? Yes for the narrow Tlon slice: the PR uses the existing channel-owned SDK AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against c69724ef3b50. Label changesLabel justifications:
Evidence reviewedPR surface: Source +2, Tests +21. 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 (3 earlier review cycles) |
|
Thank you, @masatohoshino — this fix is now landed on I preserved your contribution with the original commit author name/email in The original branch could not be updated after syncing to current Exact replacement-head CI passed, along with the focused before/after boundary proof, all 143 Tlon tests, the changed-surface gate, and a clean structured autoreview. Closing this PR as superseded by the credited landed replacement. The umbrella #90684 remains open for other channels. |
Related: #90684 (Tlon slice)
What Problem This Solves
Addresses the Tlon slice of #90684: Tlon users can see internal assistant
tool-call/tool-trace markup — XML tool-call tags and banners such as
⚠️ 🛠️ \search repos (agent)` failed` — verbatim in their DMs and groupchats when an agent reply carries leftover internal markup.
The shared delivery pipeline applies the assistant-visible sanitizer only
when a channel adapter defines the outbound
sanitizeTexthook. The Tlonadapter does not define it, so Tlon delivers raw text while sibling adapters
(most recently Feishu #98705 and Mattermost #98693) already strip this
markup. I did not find an open PR covering the Tlon adapter during
pre-submit review.
Why This Change Was Made
tlonChannelOutboundwas missing thesanitizeTexthook, and the sharedpipeline only sanitizes when that hook exists. This wires
sanitizeAssistantVisibleTextinto the hook; the single adapter object feedsboth the plugin
outboundsurface and the channel message adapter, so onewiring point covers both delivery routes.
This follows the per-channel hook pattern established by the merged sibling
fixes and fills an adapter that has no candidate PR. It takes no position on
the per-channel vs. shared-default design question discussed on #90684, and
does not close that umbrella. Inbound sanitization and
sanitizeAssistantVisibleTextitself are unchanged.User Impact
Tlon users no longer receive internal tool-call/tool-trace markup in
outbound messages; ordinary prose and markdown pass through unchanged. No
config changes, no behavior change for any other channel.
Evidence
extensions/tlon/src/outbound-tool-trace-sanitize.test.ts:tool-trace banner is stripped before delivery; ordinary assistant prose
passes through unchanged (over-strip negative control). Assertions run
against the real plugin adapter export (no mocks of the sanitizer itself).
node scripts/run-vitest.mjs extensions/tlon→ 17 files / 143 tests passed (includes the new file).
oxfmt --checkandscripts/run-oxlint.mjsclean on both touched files.Live behavior proof (production send path, captured at the ship HTTP boundary)
Captured with
node --import tsxagainst the real production pipeline — noproduct code mocked:
deliverOutboundPayloads(src/infra/outbound/deliver.ts)→ tlon plugin bootstrap → OpenClaw's real Urbit login request flow
(
POST /~/login) → realchat-dm-actionpokePUT /~/channel/<id>. Thesubstitution is at the network boundary: a local HTTP capture server stands in
for the Urbit ship and records the exact poke bytes OpenClaw would send to a
ship. This is boundary-capture proof, not a live hosted ship run (declared
below). Isolated
OPENCLAW_STATE_DIR; ship~zodwith its well-knowndevelopment code and a loopback URL (no private ships, endpoints, or
credentials involved).
Input payload 1:
"Done.\n⚠️ 🛠️ \search repos (agent)` failed"(tool-trace banner). Input payload 2:"The pipeline has 3 open deals."` (ordinary prose).With this fix (head 370326f) the outgoing memo is banner-free:
Negative control — same script with
extensions/tlon/src/channel.tsrevertedto the base commit (fc05a81), everything else identical: the internal
banner leaves OpenClaw verbatim in the outgoing poke:
Both runs completed with OpenClaw's own per-payload delivery receipts from
the exercised send path (not hosted-ship acknowledgements), so sanitization
happens in the send path itself, not via a dropped or failed payload.
The capture above exercises the full OpenClaw send path up to the ship's
HTTP interface.