@@ -43,6 +43,8 @@ class ChatCommunicationManager(private val cs: CoroutineScope) {
4343 private val inflightRequestByTabId = ConcurrentHashMap <String , CompletableFuture <String >>()
4444 private val pendingSerializedChatRequests = ConcurrentHashMap <String , CompletableFuture <GetSerializedChatResult >>()
4545 private val pendingTabRequests = ConcurrentHashMap <String , CompletableFuture <LSPAny >>()
46+ private val partialResultLocks = ConcurrentHashMap <String , Any >()
47+ private val finalResultProcessed = ConcurrentHashMap <String , Boolean >()
4648
4749 fun setUiReady () {
4850 uiReady.complete(true )
@@ -97,6 +99,28 @@ class ChatCommunicationManager(private val cs: CoroutineScope) {
9799 fun removeTabOpenRequest (requestId : String ) =
98100 pendingTabRequests.remove(requestId)
99101
102+ fun setPartialResultLock (token : String , lock : Any ) {
103+ partialResultLocks[token] = lock
104+ }
105+
106+ fun removePartialResultLock (token : String ) {
107+ partialResultLocks.remove(token)
108+ }
109+
110+ fun setFinalResultProcessed (token : String , processed : Boolean ) {
111+ finalResultProcessed[token] = processed
112+ }
113+
114+ fun removeFinalResultProcessed (token : String ) {
115+ finalResultProcessed.remove(token)
116+ }
117+
118+ fun registerPartialResultToken (partialResultToken : String ) {
119+ val lock = Any ()
120+ partialResultLocks[partialResultToken] = lock
121+ finalResultProcessed[partialResultToken] = false
122+ }
123+
100124 fun handlePartialResultProgressNotification (project : Project , params : ProgressParams ) {
101125 val token = ProgressNotificationUtils .getToken(params)
102126 val tabId = getPartialChatMessage(token)
@@ -112,13 +136,49 @@ class ChatCommunicationManager(private val cs: CoroutineScope) {
112136 val encryptedPartialChatResult = getObject(params, String ::class .java)
113137 if (encryptedPartialChatResult != null ) {
114138 val partialChatResult = AmazonQLspService .getInstance(project).encryptionManager.decrypt(encryptedPartialChatResult)
115- val uiMessage = convertToJsonToSendToChat(
116- command = SEND_CHAT_COMMAND_PROMPT ,
117- tabId = tabId,
118- params = partialChatResult,
119- isPartialResult = true
120- )
121- AsyncChatUiListener .notifyPartialMessageUpdate(uiMessage)
139+
140+ // Special case: check for stop message before proceeding
141+ val partialResultMap = tryOrNull {
142+ Gson ().fromJson(partialChatResult, Map ::class .java)
143+ }
144+
145+ if (partialResultMap != null ) {
146+ @Suppress(" UNCHECKED_CAST" )
147+ val additionalMessages = partialResultMap[" additionalMessages" ] as ? List <Map <String , Any >>
148+ if (additionalMessages != null ) {
149+ for (message in additionalMessages) {
150+ val messageId = message[" messageId" ] as ? String
151+ if (messageId != null && messageId.startsWith(" stopped" )) {
152+ // Process stop messages immediately
153+ val uiMessage = convertToJsonToSendToChat(
154+ command = SEND_CHAT_COMMAND_PROMPT ,
155+ tabId = tabId,
156+ params = partialChatResult,
157+ isPartialResult = true
158+ )
159+ AsyncChatUiListener .notifyPartialMessageUpdate(uiMessage)
160+ finalResultProcessed[token] = true
161+ ChatAsyncResultManager .getInstance(project).setResult(token, partialResultMap)
162+ return
163+ }
164+ }
165+ }
166+ }
167+
168+ // Normal processing for non-stop messages
169+ val lock = partialResultLocks[token] ? : return
170+ synchronized(lock) {
171+ if (finalResultProcessed[token] == true || partialResultLocks[token] == null ) {
172+ return @synchronized
173+ }
174+ val uiMessage = convertToJsonToSendToChat(
175+ command = SEND_CHAT_COMMAND_PROMPT ,
176+ tabId = tabId,
177+ params = partialChatResult,
178+ isPartialResult = true
179+ )
180+ AsyncChatUiListener .notifyPartialMessageUpdate(uiMessage)
181+ }
122182 }
123183 }
124184
@@ -147,12 +207,12 @@ class ChatCommunicationManager(private val cs: CoroutineScope) {
147207 """ .trimIndent()
148208 return uiMessage
149209 }
150-
210+
151211 fun getCancellationUiMessage (tabId : String ): String {
152212 // Create a minimal error params with empty error message to hide the stop button
153213 // without showing an actual error message to the user
154214 val errorParams = Gson ().toJson(ErrorParams (tabId, null , " " , " " )).toString()
155-
215+
156216 return """
157217 {
158218 "command":"$CHAT_ERROR_PARAMS ",
0 commit comments