@@ -167,42 +167,33 @@ describe("truncateToolResultText", () => {
167167 expect ( result . length ) . toBeGreaterThan ( 250 ) ;
168168 } ) ;
169169
170- it ( "does not split surrogate pairs when truncating at a char boundary" , ( ) => {
171- // Emoji 😀 is U+1F600, a surrogate pair (2 UTF-16 code units).
172- const text = "a" . repeat ( 100 ) + "😀" . repeat ( 10 ) + "b" . repeat ( 100 ) ;
173- const result = truncateToolResultText ( text , 50 ) ;
174- expect ( result . length ) . toBeLessThan ( text . length ) ;
175- expect ( hasLoneSurrogate ( result ) ) . toBe ( false ) ;
170+ it ( "keeps direct and suffix-only cuts on complete code points" , ( ) => {
171+ expect (
172+ truncateToolResultText ( "aaa😀z" , 5 , {
173+ suffix : "!" ,
174+ minKeepChars : 0 ,
175+ } ) ,
176+ ) . toBe ( "aaa!" ) ;
177+ expect (
178+ truncateToolResultText ( "abcdef" , 1 , {
179+ suffix : "😀" ,
180+ minKeepChars : 0 ,
181+ } ) ,
182+ ) . toBe ( "" ) ;
176183 } ) ;
177184
178- it ( "does not split surrogate pairs in head+tail error-preserving truncation " , ( ) => {
179- const head = "line\n" . repeat ( 500 ) ;
180- const middle = " x". repeat ( 10_000 ) ;
181- // Place an emoji so it sits right at the tail budget boundary.
182- const tail = "\nError: process failed 😀\n" ;
183- const text = head + middle + tail ;
184- const result = truncateToolResultText ( text , 5_000 ) ;
185- expect ( result ) . toContain ( "Error: process failed" ) ;
186- expect ( hasLoneSurrogate ( result ) ) . toBe ( false ) ;
185+ it ( "keeps both head and tail cuts on complete code points " , ( ) => {
186+ const marker = "\n\n⚠️ [... middle content omitted — showing head and tail ...]\n\n" ;
187+ const text = ` ${ "a" . repeat ( 6 ) } 😀 ${ "m" . repeat ( 100 ) } 😀 ${ " x". repeat ( 22 ) } Error` ;
188+ expect (
189+ truncateToolResultText ( text , 100 , {
190+ suffix : "!" ,
191+ minKeepChars : 1 ,
192+ } ) ,
193+ ) . toBe ( ` ${ "a" . repeat ( 6 ) } ${ marker } ${ "x" . repeat ( 22 ) } Error!` ) ;
187194 } ) ;
188195} ) ;
189196
190- function hasLoneSurrogate ( value : string ) : boolean {
191- for ( let index = 0 ; index < value . length ; index ++ ) {
192- const code = value . charCodeAt ( index ) ;
193- if ( code >= 0xd800 && code <= 0xdbff ) {
194- const next = value . charCodeAt ( index + 1 ) ;
195- if ( next < 0xdc00 || next > 0xdfff ) {
196- return true ;
197- }
198- index ++ ;
199- } else if ( code >= 0xdc00 && code <= 0xdfff ) {
200- return true ;
201- }
202- }
203- return false ;
204- }
205-
206197describe ( "getToolResultTextLength" , ( ) => {
207198 it ( "sums all text blocks in tool results" , ( ) => {
208199 const msg : ToolResultMessage = {
0 commit comments