@@ -160,182 +160,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
160160 vscode . postMessage ( { type : "playTts" , text } )
161161 }
162162
163- useDeepCompareEffect ( ( ) => {
164- // if last message is an ask, show user ask UI
165- // if user finished a task, then start a new task with a new conversation history since in this moment that the extension is waiting for user response, the user could close the extension and the conversation history would be lost.
166- // basically as long as a task is active, the conversation history will be persisted
167- if ( lastMessage ) {
168- switch ( lastMessage . type ) {
169- case "ask" :
170- const isPartial = lastMessage . partial === true
171- switch ( lastMessage . ask ) {
172- case "api_req_failed" :
173- playSound ( "progress_loop" )
174- setTextAreaDisabled ( true )
175- setClineAsk ( "api_req_failed" )
176- setEnableButtons ( true )
177- setPrimaryButtonText ( t ( "chat:retry.title" ) )
178- setSecondaryButtonText ( t ( "chat:startNewTask.title" ) )
179- break
180- case "mistake_limit_reached" :
181- playSound ( "progress_loop" )
182- setTextAreaDisabled ( false )
183- setClineAsk ( "mistake_limit_reached" )
184- setEnableButtons ( true )
185- setPrimaryButtonText ( t ( "chat:proceedAnyways.title" ) )
186- setSecondaryButtonText ( t ( "chat:startNewTask.title" ) )
187- break
188- case "followup" :
189- if ( ! isPartial ) {
190- playSound ( "notification" )
191- }
192- setTextAreaDisabled ( isPartial )
193- setClineAsk ( "followup" )
194- // setting enable buttons to `false` would trigger a focus grab when
195- // the text area is enabled which is undesirable.
196- // We have no buttons for this tool, so no problem having them "enabled"
197- // to workaround this issue. See #1358.
198- setEnableButtons ( true )
199- setPrimaryButtonText ( undefined )
200- setSecondaryButtonText ( undefined )
201- break
202- case "tool" :
203- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
204- playSound ( "notification" )
205- }
206- setTextAreaDisabled ( isPartial )
207- setClineAsk ( "tool" )
208- setEnableButtons ( ! isPartial )
209- const tool = JSON . parse ( lastMessage . text || "{}" ) as ClineSayTool
210- switch ( tool . tool ) {
211- case "editedExistingFile" :
212- case "appliedDiff" :
213- case "newFileCreated" :
214- case "insertContent" :
215- setPrimaryButtonText ( t ( "chat:save.title" ) )
216- setSecondaryButtonText ( t ( "chat:reject.title" ) )
217- break
218- case "finishTask" :
219- setPrimaryButtonText ( t ( "chat:completeSubtaskAndReturn" ) )
220- setSecondaryButtonText ( undefined )
221- break
222- default :
223- setPrimaryButtonText ( t ( "chat:approve.title" ) )
224- setSecondaryButtonText ( t ( "chat:reject.title" ) )
225- break
226- }
227- break
228- case "browser_action_launch" :
229- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
230- playSound ( "notification" )
231- }
232- setTextAreaDisabled ( isPartial )
233- setClineAsk ( "browser_action_launch" )
234- setEnableButtons ( ! isPartial )
235- setPrimaryButtonText ( t ( "chat:approve.title" ) )
236- setSecondaryButtonText ( t ( "chat:reject.title" ) )
237- break
238- case "command" :
239- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
240- playSound ( "notification" )
241- }
242- setTextAreaDisabled ( isPartial )
243- setClineAsk ( "command" )
244- setEnableButtons ( ! isPartial )
245- setPrimaryButtonText ( t ( "chat:runCommand.title" ) )
246- setSecondaryButtonText ( t ( "chat:reject.title" ) )
247- break
248- case "command_output" :
249- setTextAreaDisabled ( false )
250- setClineAsk ( "command_output" )
251- setEnableButtons ( true )
252- setPrimaryButtonText ( t ( "chat:proceedWhileRunning.title" ) )
253- setSecondaryButtonText ( t ( "chat:killCommand.title" ) )
254- break
255- case "use_mcp_server" :
256- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
257- playSound ( "notification" )
258- }
259- setTextAreaDisabled ( isPartial )
260- setClineAsk ( "use_mcp_server" )
261- setEnableButtons ( ! isPartial )
262- setPrimaryButtonText ( t ( "chat:approve.title" ) )
263- setSecondaryButtonText ( t ( "chat:reject.title" ) )
264- break
265- case "completion_result" :
266- // extension waiting for feedback. but we can just present a new task button
267- if ( ! isPartial ) {
268- playSound ( "celebration" )
269- }
270- setTextAreaDisabled ( isPartial )
271- setClineAsk ( "completion_result" )
272- setEnableButtons ( ! isPartial )
273- setPrimaryButtonText ( t ( "chat:startNewTask.title" ) )
274- setSecondaryButtonText ( undefined )
275- break
276- case "resume_task" :
277- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
278- playSound ( "notification" )
279- }
280- setTextAreaDisabled ( false )
281- setClineAsk ( "resume_task" )
282- setEnableButtons ( true )
283- setPrimaryButtonText ( t ( "chat:resumeTask.title" ) )
284- setSecondaryButtonText ( t ( "chat:terminate.title" ) )
285- setDidClickCancel ( false ) // special case where we reset the cancel button state
286- break
287- case "resume_completed_task" :
288- if ( ! isPartial ) {
289- playSound ( "celebration" )
290- }
291- setTextAreaDisabled ( false )
292- setClineAsk ( "resume_completed_task" )
293- setEnableButtons ( true )
294- setPrimaryButtonText ( t ( "chat:startNewTask.title" ) )
295- setSecondaryButtonText ( undefined )
296- setDidClickCancel ( false )
297- break
298- }
299- break
300- case "say" :
301- // Don't want to reset since there could be a "say" after
302- // an "ask" while ask is waiting for response.
303- switch ( lastMessage . say ) {
304- case "api_req_retry_delayed" :
305- setTextAreaDisabled ( true )
306- break
307- case "api_req_started" :
308- if ( secondLastMessage ?. ask === "command_output" ) {
309- // If the last ask is a command_output, and we
310- // receive an api_req_started, then that means
311- // the command has finished and we don't need
312- // input from the user anymore (in every other
313- // case, the user has to interact with input
314- // field or buttons to continue, which does the
315- // following automatically).
316- setInputValue ( "" )
317- setTextAreaDisabled ( true )
318- setSelectedImages ( [ ] )
319- setClineAsk ( undefined )
320- setEnableButtons ( false )
321- }
322- break
323- case "api_req_finished" :
324- case "error" :
325- case "text" :
326- case "browser_action" :
327- case "browser_action_result" :
328- case "command_output" :
329- case "mcp_server_request_started" :
330- case "mcp_server_response" :
331- case "completion_result" :
332- break
333- }
334- break
335- }
336- }
337- } , [ lastMessage , secondLastMessage ] )
338-
339163 useEffect ( ( ) => {
340164 if ( messages . length === 0 ) {
341165 setTextAreaDisabled ( false )
@@ -850,6 +674,182 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
850674 ] ,
851675 )
852676
677+ useEffect ( ( ) => {
678+ // if last message is an ask, show user ask UI
679+ // if user finished a task, then start a new task with a new conversation history since in this moment that the extension is waiting for user response, the user could close the extension and the conversation history would be lost.
680+ // basically as long as a task is active, the conversation history will be persisted
681+ if ( lastMessage ) {
682+ switch ( lastMessage . type ) {
683+ case "ask" :
684+ const isPartial = lastMessage . partial === true
685+ switch ( lastMessage . ask ) {
686+ case "api_req_failed" :
687+ playSound ( "progress_loop" )
688+ setTextAreaDisabled ( true )
689+ setClineAsk ( "api_req_failed" )
690+ setEnableButtons ( true )
691+ setPrimaryButtonText ( t ( "chat:retry.title" ) )
692+ setSecondaryButtonText ( t ( "chat:startNewTask.title" ) )
693+ break
694+ case "mistake_limit_reached" :
695+ playSound ( "progress_loop" )
696+ setTextAreaDisabled ( false )
697+ setClineAsk ( "mistake_limit_reached" )
698+ setEnableButtons ( true )
699+ setPrimaryButtonText ( t ( "chat:proceedAnyways.title" ) )
700+ setSecondaryButtonText ( t ( "chat:startNewTask.title" ) )
701+ break
702+ case "followup" :
703+ if ( ! isPartial ) {
704+ playSound ( "notification" )
705+ }
706+ setTextAreaDisabled ( isPartial )
707+ setClineAsk ( "followup" )
708+ // setting enable buttons to `false` would trigger a focus grab when
709+ // the text area is enabled which is undesirable.
710+ // We have no buttons for this tool, so no problem having them "enabled"
711+ // to workaround this issue. See #1358.
712+ setEnableButtons ( true )
713+ setPrimaryButtonText ( undefined )
714+ setSecondaryButtonText ( undefined )
715+ break
716+ case "tool" :
717+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
718+ playSound ( "notification" )
719+ }
720+ setTextAreaDisabled ( isPartial )
721+ setClineAsk ( "tool" )
722+ setEnableButtons ( ! isPartial )
723+ const tool = JSON . parse ( lastMessage . text || "{}" ) as ClineSayTool
724+ switch ( tool . tool ) {
725+ case "editedExistingFile" :
726+ case "appliedDiff" :
727+ case "newFileCreated" :
728+ case "insertContent" :
729+ setPrimaryButtonText ( t ( "chat:save.title" ) )
730+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
731+ break
732+ case "finishTask" :
733+ setPrimaryButtonText ( t ( "chat:completeSubtaskAndReturn" ) )
734+ setSecondaryButtonText ( undefined )
735+ break
736+ default :
737+ setPrimaryButtonText ( t ( "chat:approve.title" ) )
738+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
739+ break
740+ }
741+ break
742+ case "browser_action_launch" :
743+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
744+ playSound ( "notification" )
745+ }
746+ setTextAreaDisabled ( isPartial )
747+ setClineAsk ( "browser_action_launch" )
748+ setEnableButtons ( ! isPartial )
749+ setPrimaryButtonText ( t ( "chat:approve.title" ) )
750+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
751+ break
752+ case "command" :
753+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
754+ playSound ( "notification" )
755+ }
756+ setTextAreaDisabled ( isPartial )
757+ setClineAsk ( "command" )
758+ setEnableButtons ( ! isPartial )
759+ setPrimaryButtonText ( t ( "chat:runCommand.title" ) )
760+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
761+ break
762+ case "command_output" :
763+ setTextAreaDisabled ( false )
764+ setClineAsk ( "command_output" )
765+ setEnableButtons ( true )
766+ setPrimaryButtonText ( t ( "chat:proceedWhileRunning.title" ) )
767+ setSecondaryButtonText ( t ( "chat:killCommand.title" ) )
768+ break
769+ case "use_mcp_server" :
770+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
771+ playSound ( "notification" )
772+ }
773+ setTextAreaDisabled ( isPartial )
774+ setClineAsk ( "use_mcp_server" )
775+ setEnableButtons ( ! isPartial )
776+ setPrimaryButtonText ( t ( "chat:approve.title" ) )
777+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
778+ break
779+ case "completion_result" :
780+ // extension waiting for feedback. but we can just present a new task button
781+ if ( ! isPartial ) {
782+ playSound ( "celebration" )
783+ }
784+ setTextAreaDisabled ( isPartial )
785+ setClineAsk ( "completion_result" )
786+ setEnableButtons ( ! isPartial )
787+ setPrimaryButtonText ( t ( "chat:startNewTask.title" ) )
788+ setSecondaryButtonText ( undefined )
789+ break
790+ case "resume_task" :
791+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
792+ playSound ( "notification" )
793+ }
794+ setTextAreaDisabled ( false )
795+ setClineAsk ( "resume_task" )
796+ setEnableButtons ( true )
797+ setPrimaryButtonText ( t ( "chat:resumeTask.title" ) )
798+ setSecondaryButtonText ( t ( "chat:terminate.title" ) )
799+ setDidClickCancel ( false ) // special case where we reset the cancel button state
800+ break
801+ case "resume_completed_task" :
802+ if ( ! isPartial ) {
803+ playSound ( "celebration" )
804+ }
805+ setTextAreaDisabled ( false )
806+ setClineAsk ( "resume_completed_task" )
807+ setEnableButtons ( true )
808+ setPrimaryButtonText ( t ( "chat:startNewTask.title" ) )
809+ setSecondaryButtonText ( undefined )
810+ setDidClickCancel ( false )
811+ break
812+ }
813+ break
814+ case "say" :
815+ // Don't want to reset since there could be a "say" after
816+ // an "ask" while ask is waiting for response.
817+ switch ( lastMessage . say ) {
818+ case "api_req_retry_delayed" :
819+ setTextAreaDisabled ( true )
820+ break
821+ case "api_req_started" :
822+ if ( secondLastMessage ?. ask === "command_output" ) {
823+ // If the last ask is a command_output, and we
824+ // receive an api_req_started, then that means
825+ // the command has finished and we don't need
826+ // input from the user anymore (in every other
827+ // case, the user has to interact with input
828+ // field or buttons to continue, which does the
829+ // following automatically).
830+ setInputValue ( "" )
831+ setTextAreaDisabled ( true )
832+ setSelectedImages ( [ ] )
833+ setClineAsk ( undefined )
834+ setEnableButtons ( false )
835+ }
836+ break
837+ case "api_req_finished" :
838+ case "error" :
839+ case "text" :
840+ case "browser_action" :
841+ case "browser_action_result" :
842+ case "command_output" :
843+ case "mcp_server_request_started" :
844+ case "mcp_server_response" :
845+ case "completion_result" :
846+ break
847+ }
848+ break
849+ }
850+ }
851+ } , [ lastMessage , secondLastMessage , isAutoApproved , t ] )
852+
853853 useEffect ( ( ) => {
854854 // This ensures the first message is not read, future user messages are
855855 // labeled as `user_feedback`.
0 commit comments