@@ -923,6 +923,105 @@ export const MultiSessionApp: React.FC = () => {
923923 setStreamRecoveryVisible ( false ) ;
924924 } ) ) ;
925925
926+ // 🎯 监听手动 /compress 的状态推送(start → done/error/skipped)。
927+ // 目标:用户敲 /compress 后不再面对空白干等 —— 在对话流里插入一条
928+ // 持久的 in-chat 通知(带 spinner),压缩结束后原地更新为最终结果,
929+ // 同时复用底部 compression-progress-bar 作为全局进度提示。
930+ cleanups . push ( messageService . onExtensionMessage ( 'compress_status' , ( payload : any ) => {
931+ console . log ( '🗜️ [MultiSessionApp] Received compress_status:' , payload ) ;
932+ const targetSessionId : string | undefined =
933+ payload ?. sessionId || stateRef . current . currentSessionId || undefined ;
934+ if ( ! targetSessionId ) {
935+ console . warn ( '🗜️ [MultiSessionApp] compress_status without resolvable sessionId, ignoring' ) ;
936+ return ;
937+ }
938+ // 用 statusId 派生稳定的消息 id,保证 start/done/error 落到同一条通知。
939+ const statusId : string = payload ?. statusId || `compress-${ Date . now ( ) } ` ;
940+ const notificationId = `notif-${ statusId } ` ;
941+
942+ const fmt = ( n : any ) => ( typeof n === 'number' ? n . toLocaleString ( ) : String ( n ) ) ;
943+
944+ if ( payload ?. phase === 'start' ) {
945+ // 底部进度条
946+ setIsCompressing ( true ) ;
947+ // in-chat 持久通知(进行中)
948+ addMessage ( targetSessionId , {
949+ id : notificationId ,
950+ type : 'notification' ,
951+ content : createTextMessageContent ( '' ) ,
952+ timestamp : Date . now ( ) ,
953+ notificationType : 'compression' ,
954+ notificationTitle : t ( 'compression.manualTitle' , { } , 'Context Compression' ) ,
955+ notificationDescription : t (
956+ 'compression.manualInProgressDesc' ,
957+ { } ,
958+ 'Summarizing older messages while preserving recent context. This may take a moment.'
959+ ) ,
960+ severity : 'info' ,
961+ notificationInProgress : true ,
962+ statusId,
963+ } as any ) ;
964+ return ;
965+ }
966+
967+ // 任何结束态都要收起底部进度条
968+ setIsCompressing ( false ) ;
969+
970+ if ( payload ?. phase === 'done' ) {
971+ const original = Number ( payload ?. originalTokenCount ) ;
972+ const compressed = Number ( payload ?. newTokenCount ) ;
973+ const saved =
974+ Number . isFinite ( original ) && Number . isFinite ( compressed )
975+ ? Math . max ( 0 , original - compressed )
976+ : undefined ;
977+ const percent =
978+ Number . isFinite ( original ) && original > 0 && saved !== undefined
979+ ? `-${ Math . round ( ( saved / original ) * 100 ) } %`
980+ : '' ;
981+ updateMessage ( targetSessionId , notificationId , {
982+ notificationInProgress : false ,
983+ notificationTitle : t ( 'compression.manualDone' , { } , 'Context compressed' ) ,
984+ notificationDescription : t (
985+ 'compression.manualDoneDesc' ,
986+ {
987+ original : fmt ( original ) ,
988+ compressed : fmt ( compressed ) ,
989+ saved : fmt ( saved ) ,
990+ percent,
991+ } ,
992+ `Reduced from ${ fmt ( original ) } to ${ fmt ( compressed ) } tokens.`
993+ ) ,
994+ severity : 'info' ,
995+ } as any ) ;
996+ return ;
997+ }
998+
999+ if ( payload ?. phase === 'skipped' ) {
1000+ updateMessage ( targetSessionId , notificationId , {
1001+ notificationInProgress : false ,
1002+ notificationTitle : t ( 'compression.manualSkipped' , { } , 'Compression skipped' ) ,
1003+ notificationDescription : t (
1004+ 'compression.manualSkippedDesc' ,
1005+ { } ,
1006+ 'The conversation history is already small enough — nothing to compress.'
1007+ ) ,
1008+ severity : 'info' ,
1009+ } as any ) ;
1010+ return ;
1011+ }
1012+
1013+ if ( payload ?. phase === 'error' ) {
1014+ updateMessage ( targetSessionId , notificationId , {
1015+ notificationInProgress : false ,
1016+ notificationType : 'warning' ,
1017+ notificationTitle : t ( 'compression.manualFailed' , { } , 'Compression failed' ) ,
1018+ notificationDescription : String ( payload ?. error || 'Compression failed.' ) ,
1019+ severity : 'error' ,
1020+ } as any ) ;
1021+ return ;
1022+ }
1023+ } ) ) ;
1024+
9261025 // 🔐 监听认证过期通知(服务端返回 HTTP 401 时由 extension 主动推送)
9271026 cleanups . push ( messageService . onAuthExpired ( ( { reason } ) => {
9281027 console . log ( '🔐 [MultiSessionApp] Auth expired notification received:' , reason ) ;
0 commit comments