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