@@ -10,6 +10,7 @@ import {
1010 resolveSessionAgentId ,
1111} from "../../agents/agent-scope.js" ;
1212import { selectAgentHarness } from "../../agents/harness/selection.js" ;
13+ import { sanitizeUserFacingText } from "../../agents/pi-embedded-helpers/sanitize-user-facing-text.js" ;
1314import {
1415 buildModelAliasIndex ,
1516 resolveDefaultModelForAgent ,
@@ -1155,6 +1156,15 @@ export async function dispatchReplyFromConfig(
11551156 return await normalizeReplyMediaPayloadPaths ( payload ) ;
11561157 } ;
11571158
1159+ const sanitizeVisibleBlockPayload = ( payload : ReplyPayload ) : ReplyPayload | null => {
1160+ if ( ! payload . text ) {
1161+ return payload ;
1162+ }
1163+ const text = sanitizeUserFacingText ( payload . text , { errorContext : Boolean ( payload . isError ) } ) ;
1164+ const nextPayload = { ...payload , text : text . trim ( ) ? text : undefined } ;
1165+ return hasOutboundReplyContent ( nextPayload , { trimText : true } ) ? nextPayload : null ;
1166+ } ;
1167+
11581168 const routeReplyToOriginating = async (
11591169 payload : ReplyPayload ,
11601170 options ?: { abortSignal ?: AbortSignal ; mirror ?: boolean } ,
@@ -2246,30 +2256,34 @@ export async function dispatchReplyFromConfig(
22462256 if ( payload . isReasoning === true ) {
22472257 return ;
22482258 }
2259+ const sanitizedPayload = sanitizeVisibleBlockPayload ( payload ) ;
2260+ if ( ! sanitizedPayload ) {
2261+ return ;
2262+ }
22492263 // Accumulate block text for TTS generation after streaming.
22502264 // Exclude status notices — they are informational UI signals
22512265 // and must not be synthesised into the spoken reply.
2252- const isStatusNotice = isReplyPayloadStatusNotice ( payload ) ;
2253- if ( payload . text && ! isStatusNotice ) {
2266+ const isStatusNotice = isReplyPayloadStatusNotice ( sanitizedPayload ) ;
2267+ if ( sanitizedPayload . text && ! isStatusNotice ) {
22542268 const joinsBufferedTtsDirective =
22552269 cleanBlockTtsDirectiveText ?. hasBufferedDirectiveText ( ) === true ;
22562270 if ( accumulatedBlockText . length > 0 ) {
22572271 accumulatedBlockText += "\n" ;
22582272 }
2259- accumulatedBlockText += payload . text ;
2273+ accumulatedBlockText += sanitizedPayload . text ;
22602274 if ( accumulatedBlockTtsText . length > 0 && ! joinsBufferedTtsDirective ) {
22612275 accumulatedBlockTtsText += "\n" ;
22622276 }
2263- accumulatedBlockTtsText += payload . text ;
2277+ accumulatedBlockTtsText += sanitizedPayload . text ;
22642278 blockCount ++ ;
22652279 }
22662280 const visiblePayload =
2267- payload . text && cleanBlockTtsDirectiveText && ! isStatusNotice
2281+ sanitizedPayload . text && cleanBlockTtsDirectiveText && ! isStatusNotice
22682282 ? ( ( ) => {
2269- const text = cleanBlockTtsDirectiveText . push ( payload . text ) ;
2270- return { ...payload , text : text . trim ( ) ? text : undefined } ;
2283+ const text = cleanBlockTtsDirectiveText . push ( sanitizedPayload . text ) ;
2284+ return { ...sanitizedPayload , text : text . trim ( ) ? text : undefined } ;
22712285 } ) ( )
2272- : payload ;
2286+ : sanitizedPayload ;
22732287 if ( ! hasOutboundReplyContent ( visiblePayload , { trimText : true } ) ) {
22742288 return ;
22752289 }
0 commit comments