@@ -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