@@ -6,6 +6,22 @@ import {
66 readSpeakableRealtimeVoiceToolResult ,
77} from "./consult-question.js" ;
88
9+ function hasLoneSurrogate ( value : string ) : boolean {
10+ for ( let index = 0 ; index < value . length ; index += 1 ) {
11+ const code = value . charCodeAt ( index ) ;
12+ if ( code >= 0xd800 && code <= 0xdbff ) {
13+ const next = value . charCodeAt ( index + 1 ) ;
14+ if ( next < 0xdc00 || next > 0xdfff ) {
15+ return true ;
16+ }
17+ index += 1 ;
18+ } else if ( code >= 0xdc00 && code <= 0xdfff ) {
19+ return true ;
20+ }
21+ }
22+ return false ;
23+ }
24+
925describe ( "realtime voice consult question helpers" , ( ) => {
1026 it ( "reads common provider question fields" , ( ) => {
1127 expect ( readRealtimeVoiceConsultQuestion ( { question : " check status " } ) ) . toBe ( "check status" ) ;
@@ -40,4 +56,15 @@ describe("realtime voice consult question helpers", () => {
4056 ) ,
4157 ) . toBe ( "abcdefgh [truncated]" ) ;
4258 } ) ;
59+
60+ it ( "does not split a boundary emoji in truncated speakable text" , ( ) => {
61+ const result = readSpeakableRealtimeVoiceToolResult (
62+ { text : `${ "a" . repeat ( 7 ) } 😀${ "b" . repeat ( 20 ) } ` } ,
63+ { maxChars : 23 } ,
64+ ) ;
65+
66+ expect ( result ) . toBe ( `${ "a" . repeat ( 7 ) } [truncated]` ) ;
67+ expect ( result ) . toContain ( "[truncated]" ) ;
68+ expect ( hasLoneSurrogate ( result ?? "" ) ) . toBe ( false ) ;
69+ } ) ;
4370} ) ;
0 commit comments