11import { EmbeddedBlockChunker } from "openclaw/plugin-sdk/agent-runtime" ;
22import {
3+ createChannelProgressDraftGate ,
34 formatChannelProgressDraftText ,
5+ isChannelProgressDraftWorkToolName ,
46 resolveChannelProgressDraftMaxLines ,
57 resolveChannelStreamingBlockEnabled ,
68 resolveChannelStreamingPreviewToolProgress ,
@@ -70,7 +72,6 @@ export function createDiscordDraftPreviewController(params: {
7072 let hasStreamedMessage = false ;
7173 let finalizedViaPreviewMessage = false ;
7274 let finalDeliveryHandled = false ;
73- let progressDraftStarted = false ;
7475 const previewToolProgressEnabled =
7576 Boolean ( draftStream ) && resolveChannelStreamingPreviewToolProgress ( params . discordConfig ) ;
7677 const suppressDefaultToolProgressMessages =
@@ -83,6 +84,32 @@ export function createDiscordDraftPreviewController(params: {
8384 let previewToolProgressLines : string [ ] = [ ] ;
8485 const progressSeed = `${ params . accountId } :${ params . deliverChannelId } ` ;
8586
87+ const renderProgressDraft = async ( options ?: { flush ?: boolean } ) => {
88+ if ( ! draftStream || discordStreamMode !== "progress" ) {
89+ return ;
90+ }
91+ const previewText = formatChannelProgressDraftText ( {
92+ entry : params . discordConfig ,
93+ lines : previewToolProgressLines ,
94+ seed : progressSeed ,
95+ } ) ;
96+ if ( ! previewText || previewText === lastPartialText ) {
97+ return ;
98+ }
99+ lastPartialText = previewText ;
100+ draftText = previewText ;
101+ hasStreamedMessage = true ;
102+ draftChunker ?. reset ( ) ;
103+ draftStream . update ( previewText ) ;
104+ if ( options ?. flush ) {
105+ await draftStream . flush ( ) ;
106+ }
107+ } ;
108+
109+ const progressDraftGate = createChannelProgressDraftGate ( {
110+ onStart : ( ) => renderProgressDraft ( { flush : true } ) ,
111+ } ) ;
112+
86113 const resetProgressState = ( ) => {
87114 lastPartialText = "" ;
88115 draftText = "" ;
@@ -106,6 +133,9 @@ export function createDiscordDraftPreviewController(params: {
106133 get isProgressMode ( ) {
107134 return discordStreamMode === "progress" ;
108135 } ,
136+ get hasProgressDraftStarted ( ) {
137+ return progressDraftGate . hasStarted ;
138+ } ,
109139 get finalizedViaPreviewMessage ( ) {
110140 return finalizedViaPreviewMessage ;
111141 } ,
@@ -120,50 +150,55 @@ export function createDiscordDraftPreviewController(params: {
120150 if ( ! draftStream || discordStreamMode !== "progress" ) {
121151 return ;
122152 }
123- if ( progressDraftStarted ) {
124- return ;
125- }
126- const previewText = formatChannelProgressDraftText ( {
127- entry : params . discordConfig ,
128- lines : [ ] ,
129- seed : progressSeed ,
130- } ) ;
131- if ( ! previewText || previewText === lastPartialText ) {
153+ await progressDraftGate . startNow ( ) ;
154+ } ,
155+ async pushToolProgress ( line ?: string , options ?: { toolName ?: string } ) {
156+ if ( ! draftStream ) {
132157 return ;
133158 }
134- progressDraftStarted = true ;
135- lastPartialText = previewText ;
136- draftText = previewText ;
137- hasStreamedMessage = true ;
138- draftChunker ?. reset ( ) ;
139- draftStream . update ( previewText ) ;
140- await draftStream . flush ( ) ;
141- } ,
142- pushToolProgress ( line ?: string ) {
143- if ( ! draftStream || ! previewToolProgressEnabled || previewToolProgressSuppressed ) {
159+ if (
160+ options ?. toolName !== undefined &&
161+ ! isChannelProgressDraftWorkToolName ( options . toolName )
162+ ) {
144163 return ;
145164 }
146165 const normalized = line ?. replace ( / \s + / g, " " ) . trim ( ) ;
147- if ( ! normalized ) {
166+ if ( discordStreamMode !== "progress" ) {
167+ if ( ! previewToolProgressEnabled || previewToolProgressSuppressed || ! normalized ) {
168+ return ;
169+ }
170+ const previous = previewToolProgressLines . at ( - 1 ) ;
171+ if ( previous === normalized ) {
172+ return ;
173+ }
174+ previewToolProgressLines = [ ...previewToolProgressLines , normalized ] . slice (
175+ - resolveChannelProgressDraftMaxLines ( params . discordConfig ) ,
176+ ) ;
177+ const previewText = formatChannelProgressDraftText ( {
178+ entry : params . discordConfig ,
179+ lines : previewToolProgressLines ,
180+ seed : progressSeed ,
181+ } ) ;
182+ lastPartialText = previewText ;
183+ draftText = previewText ;
184+ hasStreamedMessage = true ;
185+ draftChunker ?. reset ( ) ;
186+ draftStream . update ( previewText ) ;
148187 return ;
149188 }
150- const previous = previewToolProgressLines . at ( - 1 ) ;
151- if ( previous === normalized ) {
152- return ;
189+ if ( previewToolProgressEnabled && ! previewToolProgressSuppressed && normalized ) {
190+ const previous = previewToolProgressLines . at ( - 1 ) ;
191+ if ( previous !== normalized ) {
192+ previewToolProgressLines = [ ...previewToolProgressLines , normalized ] . slice (
193+ - resolveChannelProgressDraftMaxLines ( params . discordConfig ) ,
194+ ) ;
195+ }
196+ }
197+ const alreadyStarted = progressDraftGate . hasStarted ;
198+ await progressDraftGate . noteWork ( ) ;
199+ if ( alreadyStarted && progressDraftGate . hasStarted ) {
200+ await renderProgressDraft ( ) ;
153201 }
154- previewToolProgressLines = [ ...previewToolProgressLines , normalized ] . slice (
155- - resolveChannelProgressDraftMaxLines ( params . discordConfig ) ,
156- ) ;
157- const previewText = formatChannelProgressDraftText ( {
158- entry : params . discordConfig ,
159- lines : previewToolProgressLines ,
160- seed : progressSeed ,
161- } ) ;
162- lastPartialText = previewText ;
163- draftText = previewText ;
164- hasStreamedMessage = true ;
165- draftChunker ?. reset ( ) ;
166- draftStream . update ( previewText ) ;
167202 } ,
168203 resolvePreviewFinalText ( text ?: string ) {
169204 if ( typeof text !== "string" ) {
@@ -281,6 +316,7 @@ export function createDiscordDraftPreviewController(params: {
281316 } ,
282317 async cleanup ( ) {
283318 try {
319+ progressDraftGate . cancel ( ) ;
284320 if ( ! finalDeliveryHandled ) {
285321 await draftStream ?. discardPending ( ) ;
286322 }
0 commit comments