@@ -250,179 +250,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
250250 vscode . postMessage ( { type : "playTts" , text } )
251251 }
252252
253- useDeepCompareEffect ( ( ) => {
254- // if last message is an ask, show user ask UI
255- // 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.
256- // basically as long as a task is active, the conversation history will be persisted
257- if ( lastMessage ) {
258- switch ( lastMessage . type ) {
259- case "ask" :
260- // Reset user response flag when a new ask arrives to allow auto-approval
261- userRespondedRef . current = false
262- const isPartial = lastMessage . partial === true
263- switch ( lastMessage . ask ) {
264- case "api_req_failed" :
265- playSound ( "progress_loop" )
266- setSendingDisabled ( true )
267- setClineAsk ( "api_req_failed" )
268- setEnableButtons ( true )
269- setPrimaryButtonText ( t ( "chat:retry.title" ) )
270- setSecondaryButtonText ( t ( "chat:startNewTask.title" ) )
271- break
272- case "mistake_limit_reached" :
273- playSound ( "progress_loop" )
274- setSendingDisabled ( false )
275- setClineAsk ( "mistake_limit_reached" )
276- setEnableButtons ( true )
277- setPrimaryButtonText ( t ( "chat:proceedAnyways.title" ) )
278- setSecondaryButtonText ( t ( "chat:startNewTask.title" ) )
279- break
280- case "followup" :
281- if ( ! isPartial ) {
282- playSound ( "notification" )
283- }
284- setSendingDisabled ( isPartial )
285- setClineAsk ( "followup" )
286- // setting enable buttons to `false` would trigger a focus grab when
287- // the text area is enabled which is undesirable.
288- // We have no buttons for this tool, so no problem having them "enabled"
289- // to workaround this issue. See #1358.
290- setEnableButtons ( true )
291- setPrimaryButtonText ( undefined )
292- setSecondaryButtonText ( undefined )
293- break
294- case "tool" :
295- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
296- playSound ( "notification" )
297- }
298- setSendingDisabled ( isPartial )
299- setClineAsk ( "tool" )
300- setEnableButtons ( ! isPartial )
301- const tool = JSON . parse ( lastMessage . text || "{}" ) as ClineSayTool
302- switch ( tool . tool ) {
303- case "editedExistingFile" :
304- case "appliedDiff" :
305- case "newFileCreated" :
306- case "insertContent" :
307- setPrimaryButtonText ( t ( "chat:save.title" ) )
308- setSecondaryButtonText ( t ( "chat:reject.title" ) )
309- break
310- case "finishTask" :
311- setPrimaryButtonText ( t ( "chat:completeSubtaskAndReturn" ) )
312- setSecondaryButtonText ( undefined )
313- break
314- case "readFile" :
315- if ( tool . batchFiles && Array . isArray ( tool . batchFiles ) ) {
316- setPrimaryButtonText ( t ( "chat:read-batch.approve.title" ) )
317- setSecondaryButtonText ( t ( "chat:read-batch.deny.title" ) )
318- } else {
319- setPrimaryButtonText ( t ( "chat:approve.title" ) )
320- setSecondaryButtonText ( t ( "chat:reject.title" ) )
321- }
322- break
323- default :
324- setPrimaryButtonText ( t ( "chat:approve.title" ) )
325- setSecondaryButtonText ( t ( "chat:reject.title" ) )
326- break
327- }
328- break
329- case "browser_action_launch" :
330- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
331- playSound ( "notification" )
332- }
333- setSendingDisabled ( isPartial )
334- setClineAsk ( "browser_action_launch" )
335- setEnableButtons ( ! isPartial )
336- setPrimaryButtonText ( t ( "chat:approve.title" ) )
337- setSecondaryButtonText ( t ( "chat:reject.title" ) )
338- break
339- case "command" :
340- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
341- playSound ( "notification" )
342- }
343- setSendingDisabled ( isPartial )
344- setClineAsk ( "command" )
345- setEnableButtons ( ! isPartial )
346- setPrimaryButtonText ( t ( "chat:runCommand.title" ) )
347- setSecondaryButtonText ( t ( "chat:reject.title" ) )
348- break
349- case "command_output" :
350- setSendingDisabled ( false )
351- setClineAsk ( "command_output" )
352- setEnableButtons ( true )
353- setPrimaryButtonText ( t ( "chat:proceedWhileRunning.title" ) )
354- setSecondaryButtonText ( t ( "chat:killCommand.title" ) )
355- break
356- case "use_mcp_server" :
357- if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
358- playSound ( "notification" )
359- }
360- setSendingDisabled ( isPartial )
361- setClineAsk ( "use_mcp_server" )
362- setEnableButtons ( ! isPartial )
363- setPrimaryButtonText ( t ( "chat:approve.title" ) )
364- setSecondaryButtonText ( t ( "chat:reject.title" ) )
365- break
366- case "completion_result" :
367- // extension waiting for feedback. but we can just present a new task button
368- if ( ! isPartial ) {
369- playSound ( "celebration" )
370- }
371- setSendingDisabled ( isPartial )
372- setClineAsk ( "completion_result" )
373- setEnableButtons ( ! isPartial )
374- setPrimaryButtonText ( t ( "chat:startNewTask.title" ) )
375- setSecondaryButtonText ( undefined )
376- break
377- case "resume_task" :
378- setSendingDisabled ( false )
379- setClineAsk ( "resume_task" )
380- setEnableButtons ( true )
381- setPrimaryButtonText ( t ( "chat:resumeTask.title" ) )
382- setSecondaryButtonText ( t ( "chat:terminate.title" ) )
383- setDidClickCancel ( false ) // special case where we reset the cancel button state
384- break
385- case "resume_completed_task" :
386- setSendingDisabled ( false )
387- setClineAsk ( "resume_completed_task" )
388- setEnableButtons ( true )
389- setPrimaryButtonText ( t ( "chat:startNewTask.title" ) )
390- setSecondaryButtonText ( undefined )
391- setDidClickCancel ( false )
392- break
393- }
394- break
395- case "say" :
396- // Don't want to reset since there could be a "say" after
397- // an "ask" while ask is waiting for response.
398- switch ( lastMessage . say ) {
399- case "api_req_retry_delayed" :
400- setSendingDisabled ( true )
401- break
402- case "api_req_started" :
403- if ( secondLastMessage ?. ask === "command_output" ) {
404- setSendingDisabled ( true )
405- setSelectedImages ( [ ] )
406- setClineAsk ( undefined )
407- setEnableButtons ( false )
408- }
409- break
410- case "api_req_finished" :
411- case "error" :
412- case "text" :
413- case "browser_action" :
414- case "browser_action_result" :
415- case "command_output" :
416- case "mcp_server_request_started" :
417- case "mcp_server_response" :
418- case "completion_result" :
419- break
420- }
421- break
422- }
423- }
424- } , [ lastMessage , secondLastMessage ] )
425-
426253 useEffect ( ( ) => {
427254 if ( messages . length === 0 ) {
428255 setSendingDisabled ( false )
@@ -1181,6 +1008,179 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
11811008 ] ,
11821009 )
11831010
1011+ useDeepCompareEffect ( ( ) => {
1012+ // if last message is an ask, show user ask UI
1013+ // 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.
1014+ // basically as long as a task is active, the conversation history will be persisted
1015+ if ( lastMessage ) {
1016+ switch ( lastMessage . type ) {
1017+ case "ask" :
1018+ // Reset user response flag when a new ask arrives to allow auto-approval
1019+ userRespondedRef . current = false
1020+ const isPartial = lastMessage . partial === true
1021+ switch ( lastMessage . ask ) {
1022+ case "api_req_failed" :
1023+ playSound ( "progress_loop" )
1024+ setSendingDisabled ( true )
1025+ setClineAsk ( "api_req_failed" )
1026+ setEnableButtons ( true )
1027+ setPrimaryButtonText ( t ( "chat:retry.title" ) )
1028+ setSecondaryButtonText ( t ( "chat:startNewTask.title" ) )
1029+ break
1030+ case "mistake_limit_reached" :
1031+ playSound ( "progress_loop" )
1032+ setSendingDisabled ( false )
1033+ setClineAsk ( "mistake_limit_reached" )
1034+ setEnableButtons ( true )
1035+ setPrimaryButtonText ( t ( "chat:proceedAnyways.title" ) )
1036+ setSecondaryButtonText ( t ( "chat:startNewTask.title" ) )
1037+ break
1038+ case "followup" :
1039+ if ( ! isPartial ) {
1040+ playSound ( "notification" )
1041+ }
1042+ setSendingDisabled ( isPartial )
1043+ setClineAsk ( "followup" )
1044+ // setting enable buttons to `false` would trigger a focus grab when
1045+ // the text area is enabled which is undesirable.
1046+ // We have no buttons for this tool, so no problem having them "enabled"
1047+ // to workaround this issue. See #1358.
1048+ setEnableButtons ( true )
1049+ setPrimaryButtonText ( undefined )
1050+ setSecondaryButtonText ( undefined )
1051+ break
1052+ case "tool" :
1053+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
1054+ playSound ( "notification" )
1055+ }
1056+ setSendingDisabled ( isPartial )
1057+ setClineAsk ( "tool" )
1058+ setEnableButtons ( ! isPartial )
1059+ const tool = JSON . parse ( lastMessage . text || "{}" ) as ClineSayTool
1060+ switch ( tool . tool ) {
1061+ case "editedExistingFile" :
1062+ case "appliedDiff" :
1063+ case "newFileCreated" :
1064+ case "insertContent" :
1065+ setPrimaryButtonText ( t ( "chat:save.title" ) )
1066+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
1067+ break
1068+ case "finishTask" :
1069+ setPrimaryButtonText ( t ( "chat:completeSubtaskAndReturn" ) )
1070+ setSecondaryButtonText ( undefined )
1071+ break
1072+ case "readFile" :
1073+ if ( tool . batchFiles && Array . isArray ( tool . batchFiles ) ) {
1074+ setPrimaryButtonText ( t ( "chat:read-batch.approve.title" ) )
1075+ setSecondaryButtonText ( t ( "chat:read-batch.deny.title" ) )
1076+ } else {
1077+ setPrimaryButtonText ( t ( "chat:approve.title" ) )
1078+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
1079+ }
1080+ break
1081+ default :
1082+ setPrimaryButtonText ( t ( "chat:approve.title" ) )
1083+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
1084+ break
1085+ }
1086+ break
1087+ case "browser_action_launch" :
1088+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
1089+ playSound ( "notification" )
1090+ }
1091+ setSendingDisabled ( isPartial )
1092+ setClineAsk ( "browser_action_launch" )
1093+ setEnableButtons ( ! isPartial )
1094+ setPrimaryButtonText ( t ( "chat:approve.title" ) )
1095+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
1096+ break
1097+ case "command" :
1098+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
1099+ playSound ( "notification" )
1100+ }
1101+ setSendingDisabled ( isPartial )
1102+ setClineAsk ( "command" )
1103+ setEnableButtons ( ! isPartial )
1104+ setPrimaryButtonText ( t ( "chat:runCommand.title" ) )
1105+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
1106+ break
1107+ case "command_output" :
1108+ setSendingDisabled ( false )
1109+ setClineAsk ( "command_output" )
1110+ setEnableButtons ( true )
1111+ setPrimaryButtonText ( t ( "chat:proceedWhileRunning.title" ) )
1112+ setSecondaryButtonText ( t ( "chat:killCommand.title" ) )
1113+ break
1114+ case "use_mcp_server" :
1115+ if ( ! isAutoApproved ( lastMessage ) && ! isPartial ) {
1116+ playSound ( "notification" )
1117+ }
1118+ setSendingDisabled ( isPartial )
1119+ setClineAsk ( "use_mcp_server" )
1120+ setEnableButtons ( ! isPartial )
1121+ setPrimaryButtonText ( t ( "chat:approve.title" ) )
1122+ setSecondaryButtonText ( t ( "chat:reject.title" ) )
1123+ break
1124+ case "completion_result" :
1125+ // extension waiting for feedback. but we can just present a new task button
1126+ if ( ! isPartial ) {
1127+ playSound ( "celebration" )
1128+ }
1129+ setSendingDisabled ( isPartial )
1130+ setClineAsk ( "completion_result" )
1131+ setEnableButtons ( ! isPartial )
1132+ setPrimaryButtonText ( t ( "chat:startNewTask.title" ) )
1133+ setSecondaryButtonText ( undefined )
1134+ break
1135+ case "resume_task" :
1136+ setSendingDisabled ( false )
1137+ setClineAsk ( "resume_task" )
1138+ setEnableButtons ( true )
1139+ setPrimaryButtonText ( t ( "chat:resumeTask.title" ) )
1140+ setSecondaryButtonText ( t ( "chat:terminate.title" ) )
1141+ setDidClickCancel ( false ) // special case where we reset the cancel button state
1142+ break
1143+ case "resume_completed_task" :
1144+ setSendingDisabled ( false )
1145+ setClineAsk ( "resume_completed_task" )
1146+ setEnableButtons ( true )
1147+ setPrimaryButtonText ( t ( "chat:startNewTask.title" ) )
1148+ setSecondaryButtonText ( undefined )
1149+ setDidClickCancel ( false )
1150+ break
1151+ }
1152+ break
1153+ case "say" :
1154+ // Don't want to reset since there could be a "say" after
1155+ // an "ask" while ask is waiting for response.
1156+ switch ( lastMessage . say ) {
1157+ case "api_req_retry_delayed" :
1158+ setSendingDisabled ( true )
1159+ break
1160+ case "api_req_started" :
1161+ if ( secondLastMessage ?. ask === "command_output" ) {
1162+ setSendingDisabled ( true )
1163+ setSelectedImages ( [ ] )
1164+ setClineAsk ( undefined )
1165+ setEnableButtons ( false )
1166+ }
1167+ break
1168+ case "api_req_finished" :
1169+ case "error" :
1170+ case "text" :
1171+ case "browser_action" :
1172+ case "browser_action_result" :
1173+ case "command_output" :
1174+ case "mcp_server_request_started" :
1175+ case "mcp_server_response" :
1176+ case "completion_result" :
1177+ break
1178+ }
1179+ break
1180+ }
1181+ }
1182+ } , [ lastMessage , secondLastMessage ] )
1183+
11841184 useEffect ( ( ) => {
11851185 // This ensures the first message is not read, future user messages are
11861186 // labeled as `user_feedback`.
0 commit comments