@@ -18,7 +18,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
1818import kotlinx.coroutines.flow.launchIn
1919import kotlinx.coroutines.flow.merge
2020import kotlinx.coroutines.flow.onEach
21- import kotlinx.coroutines.future.await
2221import kotlinx.coroutines.launch
2322import org.cef.browser.CefBrowser
2423import org.eclipse.lsp4j.Position
@@ -33,6 +32,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
3332import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager
3433import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerCapabilitiesProvider
3534import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager
35+ import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager.Companion.convertToJsonToSendToChat
3636import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.getTextDocumentIdentifier
3737import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickNotification
3838import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickParams
@@ -62,6 +62,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatN
6262import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatParams
6363import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatPrompt
6464import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatReadyNotification
65+ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatUiMessageParams
6566import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ConversationClickRequest
6667import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyCodeToClipboardNotification
6768import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyCodeToClipboardParams
@@ -92,9 +93,11 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.Promp
9293import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.QuickChatActionRequest
9394import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT
9495import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_ERROR_MESSAGE
96+ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.STOP_CHAT_RESPONSE
9597import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendChatPromptRequest
9698import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SourceLinkClickNotification
9799import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SourceLinkClickParams
100+ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.StopResponseMessage
98101import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabBarActionParams
99102import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabBarActionRequest
100103import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabEventParams
@@ -104,6 +107,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.util.tabType
104107import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.AmazonQTheme
105108import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.ThemeBrowserAdapter
106109import software.aws.toolkits.jetbrains.settings.MeetQSettings
110+ import software.aws.toolkits.resources.AwsCoreBundle
107111import software.aws.toolkits.telemetry.MetricResult
108112import software.aws.toolkits.telemetry.Telemetry
109113import java.util.concurrent.CompletableFuture
@@ -247,6 +251,10 @@ class BrowserConnector(
247251 encryptionManager = this .encryptionManager
248252 encryptionManager?.encrypt(chatParams)?.let { EncryptedChatParams (it, partialResultToken) }?.let { server.sendChatPrompt(it) }
249253 } ? : (CompletableFuture .failedFuture(IllegalStateException (" LSP Server not running" )))
254+
255+ // We assume there is only one outgoing request per tab because the input is
256+ // blocked when there is an outgoing request
257+ chatCommunicationManager.setInflightRequestForTab(tabId, result)
250258 showResult(result, partialResultToken, tabId, encryptionManager, browser)
251259 }
252260 CHAT_QUICK_ACTION -> {
@@ -264,6 +272,10 @@ class BrowserConnector(
264272 }
265273 } ? : (CompletableFuture .failedFuture(IllegalStateException (" LSP Server not running" )))
266274
275+ // We assume there is only one outgoing request per tab because the input is
276+ // blocked when there is an outgoing request
277+ chatCommunicationManager.setInflightRequestForTab(tabId, result)
278+
267279 showResult(result, partialResultToken, tabId, encryptionManager, browser)
268280 }
269281 CHAT_LIST_CONVERSATIONS -> {
@@ -334,6 +346,7 @@ class BrowserConnector(
334346 CHAT_TAB_REMOVE -> {
335347 handleChatNotification<TabEventRequest , TabEventParams >(node) { server, params ->
336348 chatCommunicationManager.removePartialChatMessage(params.tabId)
349+ cancelInflightRequests(params.tabId)
337350 server.tabRemove(params)
338351 }
339352 }
@@ -448,6 +461,30 @@ class BrowserConnector(
448461 server.createPrompt(params)
449462 }
450463 }
464+ STOP_CHAT_RESPONSE -> {
465+ val stopResponseRequest = serializer.deserializeChatMessages<StopResponseMessage >(node)
466+ if (! chatCommunicationManager.hasInflightRequest(stopResponseRequest.params.tabId)) {
467+ return
468+ }
469+ cancelInflightRequests(stopResponseRequest.params.tabId)
470+ chatCommunicationManager.removePartialChatMessage(stopResponseRequest.params.tabId)
471+
472+ val paramsJson = Gson ().toJson(
473+ // https://github.com/aws/language-servers/blob/1c0d88806087125b6fc561f610cc15e98127c6bf/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts#L403
474+ ChatUiMessageParams (
475+ title = AwsCoreBundle .message(" amazonqChat.stopChatResponse" ),
476+ body = " "
477+ )
478+ )
479+
480+ val uiMessage = convertToJsonToSendToChat(
481+ command = SEND_CHAT_COMMAND_PROMPT ,
482+ tabId = stopResponseRequest.params.tabId,
483+ params = paramsJson.toString(),
484+ isPartialResult = false
485+ )
486+ browser.postChat(uiMessage)
487+ }
451488 }
452489 }
453490
@@ -471,6 +508,7 @@ class BrowserConnector(
471508 isPartialResult = false
472509 )
473510 browser.postChat(messageToChat)
511+ chatCommunicationManager.removeInflightRequestForTab(tabId)
474512 } catch (e: Exception ) {
475513 LOG .error { " Failed to send chat message $e " }
476514 chatCommunicationManager.removePartialChatMessage(partialResultToken)
@@ -483,6 +521,14 @@ class BrowserConnector(
483521 )
484522 )
485523 }
524+
525+ }
526+ }
527+
528+ private fun cancelInflightRequests (tabId : String ) {
529+ chatCommunicationManager.getInflightRequestForTab(tabId)?.let { request ->
530+ request.cancel(true )
531+ chatCommunicationManager.removeInflightRequestForTab(tabId)
486532 }
487533 }
488534
0 commit comments