@@ -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 ,
@@ -1154,6 +1155,15 @@ export async function dispatchReplyFromConfig(
11541155 return await normalizeReplyMediaPayloadPaths ( payload ) ;
11551156 } ;
11561157
1158+ const sanitizeVisibleBlockPayload = ( payload : ReplyPayload ) : ReplyPayload | null => {
1159+ if ( ! payload . text ) {
1160+ return payload ;
1161+ }
1162+ const text = sanitizeUserFacingText ( payload . text , { errorContext : Boolean ( payload . isError ) } ) ;
1163+ const nextPayload = { ...payload , text : text . trim ( ) ? text : undefined } ;
1164+ return hasOutboundReplyContent ( nextPayload , { trimText : true } ) ? nextPayload : null ;
1165+ } ;
1166+
11571167 const routeReplyToOriginating = async (
11581168 payload : ReplyPayload ,
11591169 options ?: { abortSignal ?: AbortSignal ; mirror ?: boolean } ,
@@ -2245,30 +2255,34 @@ export async function dispatchReplyFromConfig(
22452255 if ( payload . isReasoning === true ) {
22462256 return ;
22472257 }
2258+ const sanitizedPayload = sanitizeVisibleBlockPayload ( payload ) ;
2259+ if ( ! sanitizedPayload ) {
2260+ return ;
2261+ }
22482262 // Accumulate block text for TTS generation after streaming.
22492263 // Exclude status notices — they are informational UI signals
22502264 // and must not be synthesised into the spoken reply.
2251- const isStatusNotice = isReplyPayloadStatusNotice ( payload ) ;
2252- if ( payload . text && ! isStatusNotice ) {
2265+ const isStatusNotice = isReplyPayloadStatusNotice ( sanitizedPayload ) ;
2266+ if ( sanitizedPayload . text && ! isStatusNotice ) {
22532267 const joinsBufferedTtsDirective =
22542268 cleanBlockTtsDirectiveText ?. hasBufferedDirectiveText ( ) === true ;
22552269 if ( accumulatedBlockText . length > 0 ) {
22562270 accumulatedBlockText += "\n" ;
22572271 }
2258- accumulatedBlockText += payload . text ;
2272+ accumulatedBlockText += sanitizedPayload . text ;
22592273 if ( accumulatedBlockTtsText . length > 0 && ! joinsBufferedTtsDirective ) {
22602274 accumulatedBlockTtsText += "\n" ;
22612275 }
2262- accumulatedBlockTtsText += payload . text ;
2276+ accumulatedBlockTtsText += sanitizedPayload . text ;
22632277 blockCount ++ ;
22642278 }
22652279 const visiblePayload =
2266- payload . text && cleanBlockTtsDirectiveText && ! isStatusNotice
2280+ sanitizedPayload . text && cleanBlockTtsDirectiveText && ! isStatusNotice
22672281 ? ( ( ) => {
2268- const text = cleanBlockTtsDirectiveText . push ( payload . text ) ;
2269- return { ...payload , text : text . trim ( ) ? text : undefined } ;
2282+ const text = cleanBlockTtsDirectiveText . push ( sanitizedPayload . text ) ;
2283+ return { ...sanitizedPayload , text : text . trim ( ) ? text : undefined } ;
22702284 } ) ( )
2271- : payload ;
2285+ : sanitizedPayload ;
22722286 if ( ! hasOutboundReplyContent ( visiblePayload , { trimText : true } ) ) {
22732287 return ;
22742288 }
0 commit comments