@@ -11,6 +11,7 @@ const prepareSimpleCompletionModelForAgentMock =
1111const extractAssistantTextMock = vi . fn < typeof agentRuntimeModule . extractAssistantText > ( ) ;
1212
1313let generateThreadTitle : typeof import ( "./thread-title.js" ) . generateThreadTitle ;
14+ let buildThreadTitleCompletionUserMessage : typeof import ( "./thread-title.js" ) . buildThreadTitleCompletionUserMessage ;
1415
1516function firstCompletionArgs ( ) : Parameters <
1617 typeof agentRuntimeModule . completeWithPreparedSimpleCompletionModel
@@ -41,7 +42,9 @@ function hasLoneSurrogate(value: string): boolean {
4142}
4243
4344beforeAll ( async ( ) => {
44- ( { generateThreadTitle } = await import ( "./thread-title.js" ) ) ;
45+ ( { buildThreadTitleCompletionUserMessage, generateThreadTitle } = await import (
46+ "./thread-title.js"
47+ ) ) ;
4548} ) ;
4649
4750beforeEach ( ( ) => {
@@ -236,6 +239,19 @@ describe("generateThreadTitle", () => {
236239 expect ( content ) . toContain ( `${ "d" . repeat ( 319 ) } ...` ) ;
237240 } ) ;
238241
242+ it ( "builds prompt text without lone surrogates at truncation boundaries" , ( ) => {
243+ const content = buildThreadTitleCompletionUserMessage ( {
244+ sourceText : `${ "m" . repeat ( 599 ) } 😀tail` ,
245+ channelName : `${ "n" . repeat ( 119 ) } 😀tail` ,
246+ channelDescription : `${ "d" . repeat ( 319 ) } 😀tail` ,
247+ } ) ;
248+
249+ expect ( hasLoneSurrogate ( content ) ) . toBe ( false ) ;
250+ expect ( content ) . toContain ( `${ "m" . repeat ( 599 ) } ...` ) ;
251+ expect ( content ) . toContain ( `${ "n" . repeat ( 119 ) } ...` ) ;
252+ expect ( content ) . toContain ( `${ "d" . repeat ( 319 ) } ...` ) ;
253+ } ) ;
254+
239255 it ( "clamps completion budget to the selected model output cap" , async ( ) => {
240256 prepareSimpleCompletionModelForAgentMock . mockResolvedValueOnce ( {
241257 selection : {
0 commit comments