@@ -95,6 +95,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
9595        subscribeToConversationContextRequest ( ) 
9696        subscribeToWatchedFilesHandler ( ) 
9797        subscribeToClientToolInvokeEvent ( ) 
98+         subscribeToClientToolConfirmationEvent ( ) 
9899    } 
99100
100101    private  func  subscribeToNotifications( )  { 
@@ -136,6 +137,27 @@ public final class ChatService: ChatServiceType, ObservableObject {
136137        } ) . store ( in:  & cancellables) 
137138    } 
138139
140+     private  func  subscribeToClientToolConfirmationEvent( )  { 
141+         ClientToolHandlerImpl . shared. onClientToolConfirmationEvent. sink ( receiveValue:  {  [ weak self]  ( request,  completion)  in 
142+             guard  let  params =  request. params,  params. conversationId ==  self ? . conversationId else  {  return  } 
143+             let  editAgentRounds :  [ AgentRound ]  =  [ 
144+                 AgentRound ( roundId:  params. roundId, 
145+                            reply:  " " , 
146+                            toolCalls:  [ 
147+                             AgentToolCall ( id:  params. toolCallId,  name:  params. name,  status:  . waitForConfirmation,  invokeParams:  params) 
148+                            ] 
149+                           ) 
150+             ] 
151+             self ? . appendToolCallHistory ( turnId:  params. turnId,  editAgentRounds:  editAgentRounds) 
152+             self ? . pendingToolCallRequests [ params. toolCallId]  =  ToolCallRequest ( 
153+                 requestId:  request. id, 
154+                 turnId:  params. turnId, 
155+                 roundId:  params. roundId, 
156+                 toolCallId:  params. toolCallId, 
157+                 completion:  completion) 
158+         } ) . store ( in:  & cancellables) 
159+     } 
160+ 
139161    private  func  subscribeToClientToolInvokeEvent( )  { 
140162        ClientToolHandlerImpl . shared. onClientToolInvokeEvent. sink ( receiveValue:  {  [ weak self]  ( request,  completion)  in 
141163            guard  let  params =  request. params,  params. conversationId ==  self ? . conversationId else  {  return  } 
@@ -154,15 +176,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
154176                return 
155177            } 
156178
157-             let  completed  =  copilotTool. invokeTool ( request,  completion:  completion,  chatHistoryUpdater:  self ? . appendToolCallHistory,  contextProvider:  self ) 
158-             if  !completed { 
159-                 self ? . pendingToolCallRequests [ params. toolCallId]  =  ToolCallRequest ( 
160-                     requestId:  request. id, 
161-                     turnId:  params. turnId, 
162-                     roundId:  params. roundId, 
163-                     toolCallId:  params. toolCallId, 
164-                     completion:  completion) 
165-             } 
179+             copilotTool. invokeTool ( request,  completion:  completion,  chatHistoryUpdater:  self ? . appendToolCallHistory,  contextProvider:  self ) 
166180        } ) . store ( in:  & cancellables) 
167181    } 
168182
@@ -225,11 +239,9 @@ public final class ChatService: ChatServiceType, ObservableObject {
225239        } 
226240
227241        // Send the tool call result back to the server
228-         if  let  toolCallRequest =  self . pendingToolCallRequests [ toolCallId] ,  status ==  . completed ,   let  result  =  payload  { 
242+         if  let  toolCallRequest =  self . pendingToolCallRequests [ toolCallId] ,  status ==  . accepted  { 
229243            self . pendingToolCallRequests. removeValue ( forKey:  toolCallId) 
230-             let  toolResult  =  LanguageModelToolResult ( content:  [ 
231-                 . init( value:  result) 
232-             ] ) 
244+             let  toolResult  =  LanguageModelToolConfirmationResult ( result:  . Accept) 
233245            let  jsonResult  =  try ? JSONEncoder ( ) . encode ( toolResult) 
234246            let  jsonValue  =  ( try ? JSONDecoder ( ) . decode ( JSONValue . self,  from:  jsonResult ??  Data ( ) ) )  ??  JSONValue . null
235247            toolCallRequest. completion ( 
@@ -505,12 +517,27 @@ public final class ChatService: ChatServiceType, ObservableObject {
505517    private  func  handleProgressBegin( token:  String ,  progress:  ConversationProgressBegin )  { 
506518        guard  let  workDoneToken =  activeRequestId,  workDoneToken ==  token else  {  return  } 
507519        conversationId =  progress. conversationId
520+         let  turnId  =  progress. turnId
508521
509522        Task  { 
510523            if  var  lastUserMessage =  await  memory. history. last ( where:  {  $0. role ==  . user } )  { 
511524                lastUserMessage. clsTurnID =  progress. turnId
512525                saveChatMessageToStorage ( lastUserMessage) 
513526            } 
527+             
528+             /// Display an initial assistant message immediately after the user sends a message.
529+             /// This improves perceived responsiveness, especially in Agent Mode where the first
530+             /// ProgressReport may take long time.
531+             let  message  =  ChatMessage ( 
532+                 id:  turnId, 
533+                 chatTabID:  self . chatTabInfo. id, 
534+                 clsTurnID:  turnId, 
535+                 role:  . assistant, 
536+                 content:  " " 
537+             ) 
538+ 
539+             // will persist in resetOngoingRequest()
540+             await  memory. appendMessage ( message) 
514541        } 
515542    } 
516543
@@ -642,17 +669,18 @@ public final class ChatService: ChatServiceType, ObservableObject {
642669        // cancel all pending tool call requests
643670        for  (_,  request)  in  pendingToolCallRequests { 
644671            pendingToolCallRequests. removeValue ( forKey:  request. toolCallId) 
645-             request. completion ( AnyJSONRPCResponse ( id:  request. requestId, 
646-                                                     result:  JSONValue . array ( [ 
647-                                                         JSONValue . null, 
648-                                                         JSONValue . hash ( 
649-                                                             [ 
650-                                                                 " code " :  . number( - 32800 ) ,  // client cancelled
651-                                                                 " message " :  . string( " The client cancelled the tool call request  \( request. toolCallId) " ) 
652-                                                             ] ) 
653-                                                     ] ) 
654-                                                  ) 
655-                                ) 
672+             let  toolResult  =  LanguageModelToolConfirmationResult ( result:  . Dismiss) 
673+             let  jsonResult  =  try ? JSONEncoder ( ) . encode ( toolResult) 
674+             let  jsonValue  =  ( try ? JSONDecoder ( ) . decode ( JSONValue . self,  from:  jsonResult ??  Data ( ) ) )  ??  JSONValue . null
675+             request. completion ( 
676+                 AnyJSONRPCResponse ( 
677+                     id:  request. requestId, 
678+                     result:  JSONValue . array ( [ 
679+                         jsonValue, 
680+                         JSONValue . null
681+                     ] ) 
682+                 ) 
683+             ) 
656684        } 
657685
658686        Task  { 
@@ -901,7 +929,7 @@ extension [ChatMessage] {
901929                if  index +  1  <  count { 
902930                    let  nextMessage  =  self [ index +  1 ] 
903931                    if  nextMessage. role ==  . assistant { 
904-                         turn. response =  nextMessage. content
932+                         turn. response =  nextMessage. content  +  extractContentFromEditAgentRounds ( nextMessage . editAgentRounds ) 
905933                        index +=  1 
906934                    } 
907935                } 
@@ -912,5 +940,14 @@ extension [ChatMessage] {
912940
913941        return  turns
914942    } 
943+     
944+     private  func  extractContentFromEditAgentRounds( _ editAgentRounds:  [ AgentRound ] )  ->  String  { 
945+         var  content  =  " " 
946+         for  round  in  editAgentRounds { 
947+             if  !round. reply. isEmpty { 
948+                 content +=  round. reply
949+             } 
950+         } 
951+         return  content
952+     } 
915953} 
916- 
0 commit comments