44 */
55import fsp from "node:fs/promises" ;
66import path from "node:path" ;
7+ import { truncateUtf16Safe , sliceUtf16Safe } from "@openclaw/normalization-core/utf16-slice" ;
78import {
89 resolveSessionFilePath ,
910 resolveSessionFilePathOptions ,
@@ -214,8 +215,8 @@ export function buildCliSessionHistoryPrompt(params: {
214215 0 ,
215216 maxHistoryChars - truncationMarker . length - separatorBudget - tailBudget ,
216217 ) ;
217- const summaryTruncated = renderedSummary . slice ( 0 , summaryBudget ) . trimEnd ( ) ;
218- const tailTruncated = tailBudget > 0 ? tailRaw . slice ( - tailBudget ) . trimStart ( ) : "" ;
218+ const summaryTruncated = truncateUtf16Safe ( renderedSummary , summaryBudget ) . trimEnd ( ) ;
219+ const tailTruncated = tailBudget > 0 ? sliceUtf16Safe ( tailRaw , - tailBudget ) . trimStart ( ) : "" ;
219220 return [ truncationMarker , summaryTruncated , tailTruncated ] . filter ( Boolean ) . join ( "\n" ) ;
220221 } ;
221222
@@ -242,7 +243,7 @@ export function buildCliSessionHistoryPrompt(params: {
242243 // reserved tail budget instead of being dropped wholesale.
243244 renderedHistory = renderTruncatedSummaryWithTail ( summaryRendered ) ;
244245 } else if ( tailRaw . length > remainingBudget ) {
245- renderedHistory = `${ summaryBlock } ${ truncationMarker } \n${ tailRaw . slice ( - remainingBudget ) . trimStart ( ) } ` ;
246+ renderedHistory = `${ summaryBlock } ${ truncationMarker } \n${ sliceUtf16Safe ( tailRaw , - remainingBudget ) . trimStart ( ) } ` ;
246247 } else {
247248 renderedHistory = `${ summaryBlock } ${ tailRaw } ` ;
248249 }
@@ -253,7 +254,7 @@ export function buildCliSessionHistoryPrompt(params: {
253254 // (older turns dropped, recent tail retained).
254255 renderedHistory =
255256 tailRaw . length > maxHistoryChars
256- ? `${ truncationMarker } \n${ tailRaw . slice ( - maxHistoryChars ) . trimStart ( ) } `
257+ ? `${ truncationMarker } \n${ sliceUtf16Safe ( tailRaw , - maxHistoryChars ) . trimStart ( ) } `
257258 : tailRaw ;
258259 }
259260
0 commit comments