File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ // Twitch outbound must strip assistant internal tool-trace scaffolding before
2+ // delivery (#90684). The hook runs in core delivery before chunk planning, so
3+ // the 500-char Twitch chunker only ever sees sanitized text.
4+ import { describe , expect , it } from "vitest" ;
5+ import { twitchPlugin } from "./plugin.js" ;
6+
7+ function sanitizeOutboundText ( text : string ) : string {
8+ const sanitizeText = twitchPlugin . outbound ?. sanitizeText ;
9+ if ( ! sanitizeText ) {
10+ throw new Error ( "Expected Twitch outbound sanitizeText hook" ) ;
11+ }
12+ return sanitizeText ( { text, payload : { text } } ) ;
13+ }
14+
15+ describe ( "twitch outbound sanitizeText" , ( ) => {
16+ it ( "strips internal tool-trace banners before outbound delivery" , ( ) => {
17+ const text = "Done.\n⚠️ 🛠️ `search repos (agent)` failed" ;
18+
19+ expect ( sanitizeOutboundText ( text ) ) . toBe ( "Done." ) ;
20+ } ) ;
21+
22+ it ( "strips XML tool-call scaffolding leaked into assistant text" , ( ) => {
23+ const text = '<tool_call>{"name":"exec"}</tool_call>Stream is live.' ;
24+
25+ expect ( sanitizeOutboundText ( text ) ) . toBe ( "Stream is live." ) ;
26+ } ) ;
27+
28+ it ( "preserves ordinary assistant prose while sanitizing" , ( ) => {
29+ const text = "The pipeline has 3 open deals." ;
30+
31+ expect ( sanitizeOutboundText ( text ) ) . toBe ( text ) ;
32+ } ) ;
33+ } ) ;
Original file line number Diff line number Diff line change @@ -12,6 +12,7 @@ import {
1212 type MessageReceiptPartKind ,
1313} from "openclaw/plugin-sdk/channel-outbound" ;
1414import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime" ;
15+ import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking" ;
1516import { resolveTwitchAccountContext } from "./config.js" ;
1617import { sendMessageTwitchInternal } from "./send.js" ;
1718import type {
@@ -43,6 +44,9 @@ export const twitchOutbound: ChannelOutboundAdapter = {
4344 /** Twitch chat message limit is 500 characters */
4445 textChunkLimit : 500 ,
4546
47+ /** Strip internal assistant tool-trace scaffolding before delivery */
48+ sanitizeText : ( { text } ) => sanitizeAssistantVisibleText ( text ) ,
49+
4650 /** Word-boundary chunker with markdown stripping */
4751 chunker : chunkTextForTwitch ,
4852
You can’t perform that action at this time.
0 commit comments