diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt index ebe5858d97e..87f977adfa1 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt @@ -22,6 +22,7 @@ import kotlinx.coroutines.launch import org.cef.browser.CefBrowser import org.eclipse.lsp4j.Position import org.eclipse.lsp4j.Range +import software.aws.toolkits.core.utils.error import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.warn import software.aws.toolkits.jetbrains.services.amazonq.apps.AppConnection @@ -31,7 +32,6 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerCapabilitiesProvider import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager -import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager.Companion.convertToJsonToSendToChat import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.getTextDocumentIdentifier import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickNotification import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickParams @@ -416,8 +416,18 @@ class BrowserConnector( server, params -> val result = server.tabBarActions(params) result.whenComplete { params1, error -> - val res = ChatCommunicationManager.convertNotificationToJsonForChat(CHAT_TAB_BAR_ACTIONS, params1) - browser.postChat(res) + try { + if (error != null) { + throw error + } + val res = ChatCommunicationManager.convertNotificationToJsonForChat(CHAT_TAB_BAR_ACTIONS, params1) + browser.postChat(res) + } catch (e: Exception) { + LOG.error { "Failed to perform chat tab bar action $e" } + params.tabId?.let { + browser.postChat(chatCommunicationManager.getErrorUiMessage(it, e, null)) + } + } } } } @@ -443,7 +453,7 @@ class BrowserConnector( ) ) - val uiMessage = convertToJsonToSendToChat( + val uiMessage = ChatCommunicationManager.convertToJsonToSendToChat( command = SEND_CHAT_COMMAND_PROMPT, tabId = stopResponseRequest.params.tabId, params = paramsJson.toString(), @@ -462,15 +472,23 @@ class BrowserConnector( browser: Browser, ) { result.whenComplete { value, error -> - chatCommunicationManager.removePartialChatMessage(partialResultToken) - val messageToChat = ChatCommunicationManager.convertToJsonToSendToChat( - SEND_CHAT_COMMAND_PROMPT, - tabId, - encryptionManager?.decrypt(value).orEmpty(), - isPartialResult = false - ) - browser.postChat(messageToChat) - chatCommunicationManager.removeInflightRequestForTab(tabId) + try { + if (error != null) { + throw error + } + chatCommunicationManager.removePartialChatMessage(partialResultToken) + val messageToChat = ChatCommunicationManager.convertToJsonToSendToChat( + SEND_CHAT_COMMAND_PROMPT, + tabId, + encryptionManager?.decrypt(value).orEmpty(), + isPartialResult = false + ) + browser.postChat(messageToChat) + chatCommunicationManager.removeInflightRequestForTab(tabId) + } catch (e: Exception) { + LOG.error { "Failed to send chat message $e" } + browser.postChat(chatCommunicationManager.getErrorUiMessage(tabId, e, partialResultToken)) + } } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/flareChat/ChatCommunicationManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/flareChat/ChatCommunicationManager.kt index 90a321b24c5..67116573e1f 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/flareChat/ChatCommunicationManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/flareChat/ChatCommunicationManager.kt @@ -10,6 +10,8 @@ import com.intellij.openapi.project.Project import org.eclipse.lsp4j.ProgressParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ProgressNotificationUtils.getObject +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_ERROR_PARAMS +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ErrorParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResult import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenTabResult import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT @@ -70,6 +72,25 @@ class ChatCommunicationManager { } } + fun getErrorUiMessage(tabId: String, exception: Exception, token: String?): String { + token?.let { + removePartialChatMessage(it) + } + val errorTitle = "An error occurred while processing your request." + val errorMessage = "Details: ${exception.message}" + val errorParams = Gson().toJson(ErrorParams(tabId, null, errorMessage, errorTitle)).toString() + val isPartialResult = false + val uiMessage = """ + { + "command":"$CHAT_ERROR_PARAMS", + "tabId": "$tabId", + "params": $errorParams, + "isPartialResult": $isPartialResult + } + """.trimIndent() + return uiMessage + } + companion object { fun getInstance(project: Project) = project.service() diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/ErrorParams.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/ErrorParams.kt new file mode 100644 index 00000000000..225fa3a20c1 --- /dev/null +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/ErrorParams.kt @@ -0,0 +1,11 @@ +// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat + +data class ErrorParams( + val tabId: String, + val triggerType: String?, + val message: String, + val title: String, +) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt index 8c8b830a07e..6b7d5a1f3e5 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt @@ -32,4 +32,5 @@ const val CHAT_CREATE_PROMPT = "aws/chat/createPrompt" const val SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD = "aws/showSaveFileDialog" const val GET_SERIALIZED_CHAT_REQUEST_METHOD = "aws/chat/getSerializedChat" const val OPEN_FILE_DIFF = "aws/openFileDiff" +const val CHAT_ERROR_PARAMS = "errorMessage" const val STOP_CHAT_RESPONSE = "stopChatResponse"