@@ -511,6 +511,160 @@ test("range-mode nudges append to existing text parts before tool outputs", () =
511511 assert . equal ( ( toolOutput as any ) . state . output , "task output body" )
512512} )
513513
514+ test ( "range-mode nudges inject only once for assistant messages with multiple text parts" , ( ) => {
515+ const sessionID = "ses_range_nudge_multi_text"
516+ const messages : WithParts [ ] = [
517+ buildMessage ( "msg-user-1" , "user" , sessionID , "Hello" , 1 ) ,
518+ {
519+ info : {
520+ id : "msg-assistant-1" ,
521+ role : "assistant" ,
522+ sessionID,
523+ agent : "assistant" ,
524+ time : { created : 2 } ,
525+ } as WithParts [ "info" ] ,
526+ parts : [
527+ textPart ( "msg-assistant-1" , sessionID , "assistant-text-1" , "First chunk." ) ,
528+ textPart ( "msg-assistant-1" , sessionID , "assistant-text-2" , "Second chunk." ) ,
529+ ] ,
530+ } ,
531+ ]
532+ const state = createSessionState ( )
533+ const config = buildConfig ( "range" )
534+
535+ assignMessageRefs ( state , messages )
536+ state . nudges . contextLimitAnchors . add ( "msg-assistant-1" )
537+
538+ applyAnchoredNudges ( state , config , messages , {
539+ system : "" ,
540+ compressRange : "" ,
541+ compressMessage : "" ,
542+ contextLimitNudge : "<dcp-system-reminder>Base context nudge</dcp-system-reminder>" ,
543+ turnNudge : "<dcp-system-reminder>Base turn nudge</dcp-system-reminder>" ,
544+ iterationNudge : "<dcp-system-reminder>Base iteration nudge</dcp-system-reminder>" ,
545+ } )
546+
547+ assert . match ( ( messages [ 1 ] ?. parts [ 0 ] as any ) . text , / B a s e c o n t e x t n u d g e / )
548+ assert . doesNotMatch ( ( messages [ 1 ] ?. parts [ 1 ] as any ) . text , / B a s e c o n t e x t n u d g e / )
549+ } )
550+
551+ test ( "range-mode nudges skip empty assistant messages to avoid prefill (issue #463)" , ( ) => {
552+ const sessionID = "ses_range_nudge_empty_assistant"
553+ const messages : WithParts [ ] = [
554+ buildMessage ( "msg-user-1" , "user" , sessionID , "Hello" , 1 ) ,
555+ {
556+ info : {
557+ id : "msg-assistant-empty" ,
558+ role : "assistant" ,
559+ sessionID,
560+ agent : "assistant" ,
561+ time : { created : 2 } ,
562+ } as WithParts [ "info" ] ,
563+ parts : [ ] ,
564+ } ,
565+ ]
566+ const state = createSessionState ( )
567+ const config = buildConfig ( "range" )
568+
569+ assignMessageRefs ( state , messages )
570+ state . nudges . contextLimitAnchors . add ( "msg-assistant-empty" )
571+
572+ applyAnchoredNudges ( state , config , messages , {
573+ system : "" ,
574+ compressRange : "" ,
575+ compressMessage : "" ,
576+ contextLimitNudge : "<dcp-system-reminder>Base context nudge</dcp-system-reminder>" ,
577+ turnNudge : "<dcp-system-reminder>Base turn nudge</dcp-system-reminder>" ,
578+ iterationNudge : "<dcp-system-reminder>Base iteration nudge</dcp-system-reminder>" ,
579+ } )
580+
581+ assert . equal ( messages [ 1 ] ?. parts . length , 0 )
582+ } )
583+
584+ test ( "range-mode nudges skip assistant with only pending tool parts (issue #463)" , ( ) => {
585+ const sessionID = "ses_range_nudge_pending_tool"
586+ const messages : WithParts [ ] = [
587+ buildMessage ( "msg-user-1" , "user" , sessionID , "Hello" , 1 ) ,
588+ {
589+ info : {
590+ id : "msg-assistant-pending" ,
591+ role : "assistant" ,
592+ sessionID,
593+ agent : "assistant" ,
594+ time : { created : 2 } ,
595+ } as WithParts [ "info" ] ,
596+ parts : [
597+ {
598+ id : "pending-tool-part" ,
599+ messageID : "msg-assistant-pending" ,
600+ sessionID,
601+ type : "tool" as const ,
602+ tool : "bash" ,
603+ callID : "call-pending-1" ,
604+ state : {
605+ status : "pending" as const ,
606+ input : { command : "ls" } ,
607+ } ,
608+ } as any ,
609+ ] ,
610+ } ,
611+ ]
612+ const state = createSessionState ( )
613+ const config = buildConfig ( "range" )
614+
615+ assignMessageRefs ( state , messages )
616+ state . nudges . contextLimitAnchors . add ( "msg-assistant-pending" )
617+
618+ applyAnchoredNudges ( state , config , messages , {
619+ system : "" ,
620+ compressRange : "" ,
621+ compressMessage : "" ,
622+ contextLimitNudge : "<dcp-system-reminder>Base context nudge</dcp-system-reminder>" ,
623+ turnNudge : "<dcp-system-reminder>Base turn nudge</dcp-system-reminder>" ,
624+ iterationNudge : "<dcp-system-reminder>Base iteration nudge</dcp-system-reminder>" ,
625+ } )
626+
627+ assert . equal ( messages [ 1 ] ?. parts . length , 1 )
628+ assert . equal ( messages [ 1 ] ?. parts [ 0 ] ?. type , "tool" )
629+ } )
630+
631+ test ( "range-mode nudges append to an assistant empty text part (issue #463)" , ( ) => {
632+ const sessionID = "ses_range_nudge_empty_text"
633+ const messages : WithParts [ ] = [
634+ buildMessage ( "msg-user-1" , "user" , sessionID , "Hello" , 1 ) ,
635+ {
636+ info : {
637+ id : "msg-assistant-empty-text" ,
638+ role : "assistant" ,
639+ sessionID,
640+ agent : "assistant" ,
641+ time : { created : 2 } ,
642+ } as WithParts [ "info" ] ,
643+ parts : [ textPart ( "msg-assistant-empty-text" , sessionID , "empty-text-part" , "" ) ] ,
644+ } ,
645+ ]
646+ const state = createSessionState ( )
647+ const config = buildConfig ( "range" )
648+
649+ assignMessageRefs ( state , messages )
650+ state . nudges . contextLimitAnchors . add ( "msg-assistant-empty-text" )
651+
652+ applyAnchoredNudges ( state , config , messages , {
653+ system : "" ,
654+ compressRange : "" ,
655+ compressMessage : "" ,
656+ contextLimitNudge : "<dcp-system-reminder>Base context nudge</dcp-system-reminder>" ,
657+ turnNudge : "<dcp-system-reminder>Base turn nudge</dcp-system-reminder>" ,
658+ iterationNudge : "<dcp-system-reminder>Base iteration nudge</dcp-system-reminder>" ,
659+ } )
660+
661+ assert . equal ( messages [ 1 ] ?. parts . length , 1 )
662+ assert . match (
663+ ( messages [ 1 ] ?. parts [ 0 ] as any ) . text ,
664+ / < d c p - s y s t e m - r e m i n d e r > B a s e c o n t e x t n u d g e [ \s \S ] * C o m p r e s s e d b l o c k c o n t e x t : / ,
665+ )
666+ } )
667+
514668test ( "message-mode rendered compressed summaries mark block IDs as BLOCKED" , ( ) => {
515669 const sessionID = "ses_message_blocked_blocks"
516670 const messages : WithParts [ ] = [
0 commit comments