@@ -48,37 +48,6 @@ struct ToolCallRequest {
4848    let  completion :  ( AnyJSONRPCResponse )  ->  Void 
4949} 
5050
51- public  struct  FileEdit :  Equatable  { 
52-     
53-     public  enum  Status :  String  { 
54-         case  none =  " none " 
55-         case  kept =  " kept " 
56-         case  undone =  " undone " 
57-     } 
58-     
59-     public  let  fileURL :  URL 
60-     public  let  originalContent :  String 
61-     public  var  modifiedContent :  String 
62-     public  var  status :  Status 
63-     
64-     /// Different toolName, the different undo logic. Like `insert_edit_into_file` and `create_file`
65-     public  var  toolName :  ToolName 
66-     
67-     public  init ( 
68-         fileURL:  URL , 
69-         originalContent:  String , 
70-         modifiedContent:  String , 
71-         status:  Status  =  . none, 
72-         toolName:  ToolName 
73-     )  { 
74-         self . fileURL =  fileURL
75-         self . originalContent =  originalContent
76-         self . modifiedContent =  modifiedContent
77-         self . status =  status
78-         self . toolName =  toolName
79-     } 
80- } 
81- 
8251public  final  class  ChatService :  ChatServiceType ,  ObservableObject  { 
8352
8453    public  enum  RequestType :  String ,  Equatable  { 
@@ -207,35 +176,23 @@ public final class ChatService: ChatServiceType, ObservableObject {
207176                return 
208177            } 
209178
210-             copilotTool. invokeTool ( request,  completion:  completion,  chatHistoryUpdater :   self ? . appendToolCallHistory ,   contextProvider:  self ) 
179+             copilotTool. invokeTool ( request,  completion:  completion,  contextProvider:  self ) 
211180        } ) . store ( in:  & cancellables) 
212181    } 
213182
214-     private   func  appendToolCallHistory( turnId:  String ,  editAgentRounds:  [ AgentRound ] )  { 
183+     func  appendToolCallHistory( turnId:  String ,  editAgentRounds:  [ AgentRound ] ,  fileEdits :   [ FileEdit ]   =   [ ] )  { 
215184        let  chatTabId  =  self . chatTabInfo. id
216185        Task  { 
217186            let  message  =  ChatMessage ( 
218187                assistantMessageWithId:  turnId, 
219188                chatTabID:  chatTabId, 
220-                 editAgentRounds:  editAgentRounds
189+                 editAgentRounds:  editAgentRounds, 
190+                 fileEdits:  fileEdits
221191            ) 
222192
223193            await  self . memory. appendMessage ( message) 
224194        } 
225195    } 
226-     
227-     public  func  updateFileEdits( by fileEdit:  FileEdit )  { 
228-         if  let  existingFileEdit =  self . fileEditMap [ fileEdit. fileURL]  { 
229-             self . fileEditMap [ fileEdit. fileURL]  =  . init( 
230-                 fileURL:  fileEdit. fileURL, 
231-                 originalContent:  existingFileEdit. originalContent, 
232-                 modifiedContent:  fileEdit. modifiedContent, 
233-                 toolName:  existingFileEdit. toolName
234-             ) 
235-         }  else  { 
236-             self . fileEditMap [ fileEdit. fileURL]  =  fileEdit
237-         } 
238-     } 
239196
240197    public  func  notifyChangeTextDocument( fileURL:  URL ,  content:  String ,  version:  Int )  async  throws  { 
241198        try await  conversationProvider? . notifyChangeTextDocument ( fileURL:  fileURL,  content:  content,  version:  version,  workspaceURL:  getWorkspaceURL ( ) ) 
@@ -542,10 +499,17 @@ public final class ChatService: ChatServiceType, ObservableObject {
542499        deleteAllChatMessagesFromStorage ( messageIds) 
543500        resetOngoingRequest ( ) 
544501    } 
545- 
546-     public  func  deleteMessage( id:  String )  async  { 
547-         await  memory. removeMessage ( id) 
548-         deleteChatMessageFromStorage ( id) 
502+     
503+     public  func  deleteMessages( ids:  [ String ] )  async  { 
504+         let  turnIdsFromMessages  =  await  memory. history
505+             . filter  {  ids. contains ( $0. id)  } 
506+             . compactMap  {  $0. clsTurnID } 
507+             . map  {  String ( $0)  } 
508+         let  turnIds  =  Array ( Set ( turnIdsFromMessages) ) 
509+         
510+         await  memory. removeMessages ( ids) 
511+         await  deleteTurns ( turnIds) 
512+         deleteAllChatMessagesFromStorage ( ids) 
549513    } 
550514
551515    public  func  resendMessage( id:  String ,  model:  String ? =  nil ,  modelProviderName:  String ? =  nil )  async  throws  { 
@@ -772,12 +736,22 @@ public final class ChatService: ChatServiceType, ObservableObject {
772736            // CLS Error Code 402: reached monthly chat messages limit
773737            if  CLSError . code ==  402  { 
774738                Task  { 
739+                     let  selectedModel  =  lastUserRequest? . model
740+                     let  selectedModelProviderName  =  lastUserRequest? . modelProviderName
741+                     
742+                     var  errorMessageText :  String 
743+                     if  let  selectedModel =  selectedModel,  let  selectedModelProviderName =  selectedModelProviderName { 
744+                         errorMessageText =  " You've reached your quota limit for your BYOK model  \( selectedModel) . Please check with  \( selectedModelProviderName)  for more information. " 
745+                     }  else  { 
746+                         errorMessageText =  CLSError . message
747+                     } 
748+ 
775749                    await  Status . shared
776-                         . updateCLSStatus ( . warning,  busy:  false ,  message:  CLSError . message ) 
750+                         . updateCLSStatus ( . warning,  busy:  false ,  message:  errorMessageText ) 
777751                    let  errorMessage  =  ChatMessage ( 
778752                        errorMessageWithId:  progress. turnId, 
779753                        chatTabID:  chatTabInfo. id, 
780-                         panelMessages:  [ . init( type:  . error,  title:  String ( CLSError . code ??  0 ) ,  message:  CLSError . message ,  location:  . Panel) ] 
754+                         panelMessages:  [ . init( type:  . error,  title:  String ( CLSError . code ??  0 ) ,  message:  errorMessageText ,  location:  . Panel) ] 
781755                    ) 
782756                    // will persist in resetongoingRequest()
783757                    await  memory. appendMessage ( errorMessage) 
@@ -944,37 +918,21 @@ public final class ChatService: ChatServiceType, ObservableObject {
944918        } 
945919    } 
946920
947-     // MARK: - File Edit
948-     public  func  undoFileEdit( for fileURL:  URL )  throws  { 
949-         guard  let  fileEdit =  self . fileEditMap [ fileURL] , 
950-               fileEdit. status ==  . none
951-         else  {  return  } 
952-         
953-         switch  fileEdit. toolName { 
954-         case  . insertEditIntoFile: 
955-             InsertEditIntoFileTool . applyEdit ( for:  fileURL,  content:  fileEdit. originalContent,  contextProvider:  self ) 
956-         case  . createFile: 
957-             try CreateFileTool . undo ( for:  fileURL) 
958-         default : 
921+     private  func  deleteTurns( _ turnIds:  [ String ] )  async  { 
922+         guard  !turnIds. isEmpty,  let  conversationId =  conversationId else  { 
959923            return 
960924        } 
961925
962-         self . fileEditMap [ fileURL] !. status =  . undone
963-     } 
964-     
965-     public  func  keepFileEdit( for fileURL:  URL )  { 
966-         guard  let  fileEdit =  self . fileEditMap [ fileURL] ,  fileEdit. status ==  . none
967-         else  {  return  } 
968-         self . fileEditMap [ fileURL] !. status =  . kept
969-     } 
970-     
971-     public  func  resetFileEdits( )  { 
972-         self . fileEditMap =  [ : ] 
973-     } 
974-     
975-     public  func  discardFileEdit( for fileURL:  URL )  throws  { 
976-         try self . undoFileEdit ( for:  fileURL) 
977-         self . fileEditMap. removeValue ( forKey:  fileURL) 
926+         let  workspaceURL  =  getWorkspaceURL ( ) 
927+         
928+         for  turnId  in  turnIds { 
929+             do  { 
930+                 try await  conversationProvider? 
931+                     . deleteTurn ( with:  conversationId,  turnId:  turnId,  workspaceURL:  workspaceURL) 
932+             }  catch  { 
933+                 Logger . client. error ( " Failed to delete turn:  \( error) " ) 
934+             } 
935+         } 
978936    } 
979937} 
980938
0 commit comments