@@ -50,10 +50,6 @@ struct ToolCallRequest {
5050
5151public final class ChatService : ChatServiceType , ObservableObject {
5252
53- public enum RequestType : String , Equatable {
54- case conversation , codeReview
55- }
56-
5753 public var memory : ContextAwareAutoManagedChatMemory
5854 @ Published public internal( set) var chatHistory : [ ChatMessage ] = [ ]
5955 @ Published public internal( set) var isReceivingMessage = false
@@ -183,11 +179,24 @@ public final class ChatService: ChatServiceType, ObservableObject {
183179 func appendToolCallHistory ( turnId : String , editAgentRounds : [ AgentRound ] , fileEdits : [ FileEdit ] = [ ] ) {
184180 let chatTabId = self . chatTabInfo . id
185181 Task {
182+ let turnStatus : ChatMessage . TurnStatus ? = {
183+ guard let round = editAgentRounds . first , let toolCall = round . toolCalls ? . first else {
184+ return nil
185+ }
186+
187+ switch toolCall . status {
188+ case . waitForConfirmation : return . waitForConfirmation
189+ case . accepted , . running , . completed , . error : return . inProgress
190+ case . cancelled : return . cancelled
191+ }
192+ } ( )
193+
186194 let message = ChatMessage (
187195 assistantMessageWithId : turnId ,
188196 chatTabID : chatTabId ,
189197 editAgentRounds : editAgentRounds ,
190- fileEdits : fileEdits
198+ fileEdits : fileEdits ,
199+ turnStatus : turnStatus
191200 )
192201
193202 await self . memory . appendMessage ( message )
@@ -221,7 +230,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
221230
222231 public func updateToolCallStatus ( toolCallId : String , status : AgentToolCall . ToolCallStatus , payload : Any ? = nil ) {
223232 if status == . cancelled {
224- resetOngoingRequest ( )
233+ resetOngoingRequest ( with : . cancelled )
225234 return
226235 }
227236
@@ -282,7 +291,8 @@ public final class ChatService: ChatServiceType, ObservableObject {
282291 content : " " ,
283292 references : [ ] ,
284293 steps : [ ] ,
285- editAgentRounds : updatedAgentRounds
294+ editAgentRounds : updatedAgentRounds ,
295+ turnStatus : . inProgress
286296 )
287297
288298 await self . memory . appendMessage ( message )
@@ -481,9 +491,10 @@ public final class ChatService: ChatServiceType, ObservableObject {
481491 print ( " Failed to cancel ongoing request with WDT: \( activeRequestId ) " )
482492 }
483493 }
484- resetOngoingRequest ( )
494+ resetOngoingRequest ( with : . cancelled )
485495 }
486496
497+ // Not used
487498 public func clearHistory ( ) async {
488499 let messageIds = await memory . history . map { $0 . id }
489500
@@ -669,7 +680,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
669680 /// Display an initial assistant message immediately after the user sends a message.
670681 /// This improves perceived responsiveness, especially in Agent Mode where the first
671682 /// ProgressReport may take long time.
672- let message = ChatMessage ( assistantMessageWithId : turnId , chatTabID : chatTabInfo . id )
683+ let message = ChatMessage ( assistantMessageWithId : turnId , chatTabID : chatTabInfo . id , turnStatus : . inProgress )
673684
674685 // will persist in resetOngoingRequest()
675686 await memory . appendMessage ( message )
@@ -720,7 +731,8 @@ public final class ChatService: ChatServiceType, ObservableObject {
720731 content : messageContent ,
721732 references : messageReferences ,
722733 steps : messageSteps ,
723- editAgentRounds : messageAgentRounds
734+ editAgentRounds : messageAgentRounds ,
735+ turnStatus : . inProgress
724736 )
725737
726738 // will persist in resetOngoingRequest()
@@ -762,7 +774,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
762774 guard let fallbackModel = CopilotModelManager . getFallbackLLM (
763775 scope : lastUserRequest . agentMode ? . agentPanel : . chatPanel
764776 ) else {
765- resetOngoingRequest ( )
777+ resetOngoingRequest ( with : . error )
766778 return
767779 }
768780 do {
@@ -774,7 +786,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
774786 )
775787 } catch {
776788 Logger . gitHubCopilot . error ( error )
777- resetOngoingRequest ( )
789+ resetOngoingRequest ( with : . error )
778790 }
779791 return
780792 }
@@ -787,7 +799,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
787799 errorMessages : [ " Oops, the model is not supported. Please enable it first in [GitHub Copilot settings](https://github.com/settings/copilot). " ]
788800 )
789801 await memory . appendMessage ( errorMessage )
790- resetOngoingRequest ( )
802+ resetOngoingRequest ( with : . error )
791803 return
792804 }
793805 } else {
@@ -799,7 +811,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
799811 )
800812 // will persist in resetOngoingRequest()
801813 await memory . appendMessage ( errorMessage )
802- resetOngoingRequest ( )
814+ resetOngoingRequest ( with : . error )
803815 return
804816 }
805817 }
@@ -810,15 +822,16 @@ public final class ChatService: ChatServiceType, ObservableObject {
810822 assistantMessageWithId : progress . turnId ,
811823 chatTabID : chatTabInfo . id ,
812824 followUp : followUp ,
813- suggestedTitle : progress . suggestedTitle
825+ suggestedTitle : progress . suggestedTitle ,
826+ turnStatus : . success
814827 )
815828 // will persist in resetOngoingRequest()
816829 await memory . appendMessage ( message )
817- resetOngoingRequest ( )
830+ resetOngoingRequest ( with : . success )
818831 }
819832 }
820833
821- private func resetOngoingRequest ( ) {
834+ private func resetOngoingRequest ( with turnStatus : ChatMessage . TurnStatus = . success ) {
822835 activeRequestId = nil
823836 isReceivingMessage = false
824837 requestType = nil
@@ -874,6 +887,8 @@ public final class ChatService: ChatServiceType, ObservableObject {
874887 {
875888 history [ lastIndex ] . codeReviewRound ! . status = . cancelled
876889 }
890+
891+ history [ lastIndex ] . turnStatus = turnStatus
877892 } )
878893
879894 // The message of progress report could change rapidly
@@ -913,7 +928,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
913928 try await conversationProvider ? . createConversation ( requestWithTurns , workspaceURL : getWorkspaceURL ( ) )
914929 }
915930 } catch {
916- resetOngoingRequest ( )
931+ resetOngoingRequest ( with : . error )
917932 throw error
918933 }
919934 }
@@ -1114,25 +1129,26 @@ extension ChatService {
11141129 }
11151130 isReceivingMessage = true
11161131 requestType = . codeReview
1132+ let turnId = UUID ( ) . uuidString
11171133
11181134 do {
11191135 await CodeReviewService . shared . resetComments ( )
11201136
1121- let turnId = UUID ( ) . uuidString
1122-
11231137 await addCodeReviewUserMessage ( id : UUID ( ) . uuidString , turnId : turnId , group : group )
11241138
11251139 let initialBotMessage = ChatMessage (
11261140 assistantMessageWithId : turnId ,
1127- chatTabID : chatTabInfo . id
1141+ chatTabID : chatTabInfo . id ,
1142+ turnStatus : . inProgress ,
1143+ requestType : . codeReview
11281144 )
11291145 await memory . appendMessage ( initialBotMessage )
11301146
11311147 guard let projectRootURL = getProjectRootURL ( )
11321148 else {
11331149 let round = CodeReviewRound . fromError ( turnId : turnId , error : " Invalid git repository. " )
11341150 await appendCodeReviewRound ( round )
1135- resetOngoingRequest ( )
1151+ resetOngoingRequest ( with : . error )
11361152 return
11371153 }
11381154
@@ -1156,9 +1172,9 @@ extension ChatService {
11561172 status : . waitForConfirmation ,
11571173 request : . from ( prChanges )
11581174 )
1159- await appendCodeReviewRound ( round )
1175+ await appendCodeReviewRound ( round , turnStatus : . waitForConfirmation )
11601176 } catch {
1161- resetOngoingRequest ( )
1177+ resetOngoingRequest ( with : . error )
11621178 throw error
11631179 }
11641180 }
@@ -1173,9 +1189,15 @@ extension ChatService {
11731189 }
11741190 }
11751191
1176- private func appendCodeReviewRound ( _ round : CodeReviewRound ) async {
1192+ private func appendCodeReviewRound (
1193+ _ round : CodeReviewRound ,
1194+ turnStatus : ChatMessage . TurnStatus ? = nil
1195+ ) async {
11771196 let message = ChatMessage (
1178- assistantMessageWithId : round . turnId , chatTabID : chatTabInfo . id , codeReviewRound : round
1197+ assistantMessageWithId : round . turnId ,
1198+ chatTabID : chatTabInfo . id ,
1199+ codeReviewRound : round ,
1200+ turnStatus : turnStatus
11791201 )
11801202
11811203 await memory . appendMessage ( message )
@@ -1211,7 +1233,7 @@ extension ChatService {
12111233 round . status = . accepted
12121234 request . updateSelectedChanges ( by : selectedFileUris )
12131235 round . request = request
1214- await appendCodeReviewRound ( round )
1236+ await appendCodeReviewRound ( round , turnStatus : . inProgress )
12151237
12161238 round . status = . running
12171239 await appendCodeReviewRound ( round )
@@ -1224,7 +1246,7 @@ extension ChatService {
12241246 if let errorMessage = errorMessage {
12251247 round = round . withError ( errorMessage )
12261248 await appendCodeReviewRound ( round )
1227- resetOngoingRequest ( )
1249+ resetOngoingRequest ( with : . error )
12281250 return
12291251 }
12301252
@@ -1248,14 +1270,19 @@ extension ChatService {
12481270 round . status = . cancelled
12491271 await appendCodeReviewRound ( round )
12501272
1251- resetOngoingRequest ( )
1273+ resetOngoingRequest ( with : . cancelled )
12521274 }
12531275
12541276 private func addCodeReviewUserMessage ( id : String , turnId : String , group : GitDiffGroup ) async {
12551277 let content = group == . index
12561278 ? " Code review for staged changes. "
12571279 : " Code review for unstaged changes. "
1258- let chatMessage = ChatMessage ( userMessageWithId : id , chatTabId : chatTabInfo . id , content : content )
1280+ let chatMessage = ChatMessage (
1281+ userMessageWithId : id ,
1282+ chatTabId : chatTabInfo . id ,
1283+ content : content ,
1284+ requestType : . codeReview
1285+ )
12591286 await memory . appendMessage ( chatMessage )
12601287 saveChatMessageToStorage ( chatMessage )
12611288 }
0 commit comments