diff --git a/.changes/next-release/bugfix-b204e9b7-e11e-46c7-bfb2-4704db861dd8.json b/.changes/next-release/bugfix-b204e9b7-e11e-46c7-bfb2-4704db861dd8.json new file mode 100644 index 0000000000..e262fcb3a5 --- /dev/null +++ b/.changes/next-release/bugfix-b204e9b7-e11e-46c7-bfb2-4704db861dd8.json @@ -0,0 +1,4 @@ +{ + "type" : "bugfix", + "description" : "Amazon Q /doc: fix for user prompt to change folder in chat" +} \ No newline at end of file diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt index a6ab9b4c17..a3d675b8ef 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt @@ -52,6 +52,7 @@ import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendCodeResu import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendError import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendFolderConfirmationMessage import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendMonthlyLimitError +import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendRetryChangeFolderMessage import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendSystemPrompt import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendUpdatePlaceholder import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendUpdatePromptProgress @@ -330,6 +331,83 @@ class DocController( } } + private suspend fun promptForRetryFolderSelection(tabId: String, message: String) { + try { + messenger.sendRetryChangeFolderMessage( + tabId = tabId, + message = message, + followUps = listOf( + FollowUp( + icon = FollowUpIcons.Refresh, + pillText = message("amazonqDoc.prompt.folder.change"), + prompt = message("amazonqDoc.prompt.folder.change"), + status = FollowUpStatusType.Info, + type = FollowUpTypes.MODIFY_DEFAULT_SOURCE_FOLDER + ), + FollowUp( + icon = FollowUpIcons.Cancel, + pillText = message("general.cancel"), + prompt = message("general.cancel"), + status = FollowUpStatusType.Error, + type = FollowUpTypes.CANCEL_FOLDER_SELECTION + ), + ) + ) + + messenger.sendChatInputEnabledMessage(tabId, false) + } catch (e: Exception) { + logger.error(e) { "Error sending RetryChangeFolder message: ${e.message}" } + // Consider logging the error or handling it appropriately + } + } + + override suspend fun processChatItemVotedMessage(message: IncomingDocMessage.ChatItemVotedMessage) { + logger.debug { "$FEATURE_NAME: Processing ChatItemVotedMessage: $message" } + + val session = chatSessionStorage.getSession(message.tabId, context.project) + when (message.vote) { + "upvote" -> { + AmazonqTelemetry.codeGenerationThumbsUp( + amazonqConversationId = session.conversationId, + credentialStartUrl = getStartUrl(project = context.project) + ) + } + + "downvote" -> { + AmazonqTelemetry.codeGenerationThumbsDown( + amazonqConversationId = session.conversationId, + credentialStartUrl = getStartUrl(project = context.project) + ) + } + } + } + + override suspend fun processChatItemFeedbackMessage(message: IncomingDocMessage.ChatItemFeedbackMessage) { + logger.debug { "$FEATURE_NAME: Processing ChatItemFeedbackMessage: ${message.comment}" } + + val session = getSessionInfo(message.tabId) + + val comment = FeedbackComment( + conversationId = session.conversationId, + userComment = message.comment.orEmpty(), + reason = message.selectedOption, + messageId = message.messageId, + type = "doc-chat-answer-feedback" + ) + + try { + TelemetryService.getInstance().sendFeedback( + sentiment = Sentiment.NEGATIVE, + comment = objectMapper.writeValueAsString(comment), + ) + logger.info { "$FEATURE_NAME answer feedback sent: \"Negative\"" } + } catch (e: Throwable) { + e.notifyError(message("feedback.submit_failed", e)) + logger.warn(e) { "Failed to submit feedback" } + return + } + } + override suspend fun processLinkClick(message: IncomingDocMessage.ClickedLink) { BrowserUtil.browse(message.link) } @@ -898,6 +976,11 @@ class DocController( // No folder was selected if (selectedFolder == null) { logger.info { "Cancelled dialog and not selected any folder" } + promptForRetryFolderSelection( + tabId, + message("amazonqFeatureDev.follow_up.cancel_source_folder_selection") + ) + return@withContext } @@ -905,10 +988,9 @@ class DocController( if (!selectedFolder.path.startsWith(projectRoot.path)) { logger.info { "Selected folder not in workspace: ${selectedFolder.path}" } - messenger.sendAnswer( - tabId = tabId, - messageType = DocMessageType.Answer, - message = message("amazonqFeatureDev.follow_up.incorrect_source_folder"), + promptForRetryFolderSelection( + tabId, + message("amazonqFeatureDev.follow_up.incorrect_source_folder") ) return@withContext } diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/messages/DocMessage.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/messages/DocMessage.kt index 61c8bc0109..047501bead 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/messages/DocMessage.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/messages/DocMessage.kt @@ -179,6 +179,15 @@ data class FolderConfirmationMessage( type = "folderConfirmationMessage" ) +data class RetryChangeFolderMessage( + @JsonProperty("tabID") override val tabId: String, + val message: String, + val followUps: List?, +) : UiMessage( + tabId = tabId, + type = "retryChangeFolderMessage" +) + // this should come from mynah? data class ChatItemButton( val id: String, diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/messages/DocMessagePublisherExtensions.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/messages/DocMessagePublisherExtensions.kt index 963b6d95be..0920b8564d 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/messages/DocMessagePublisherExtensions.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/messages/DocMessagePublisherExtensions.kt @@ -208,6 +208,16 @@ suspend fun MessagePublisher.sendFolderConfirmationMessage( ) } +suspend fun MessagePublisher.sendRetryChangeFolderMessage( + tabId: String, + message: String, + followUps: List, +) { + this.publish( + RetryChangeFolderMessage(tabId = tabId, message = message, followUps = followUps) + ) +} + suspend fun MessagePublisher.sendUpdatePromptProgress(tabId: String, progressField: ProgressField?) { this.publish( PromptProgressMessage(tabId, progressField) diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/docChatConnector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/docChatConnector.ts index e92421213d..a1547b5b83 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/docChatConnector.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/docChatConnector.ts @@ -170,6 +170,21 @@ export class Connector { } } + private processRetryChangeFolderMessage = async (messageData: any): Promise => { + if (this.onChatAnswerReceived !== undefined) { + const answer: ChatItem = { + type: ChatItemType.ANSWER, + body: messageData.message ?? undefined, + messageId: messageData.messageID ?? messageData.triggerID ?? '', + followUp: { + text: '', + options: messageData.followUps, + }, + } + this.onChatAnswerReceived(messageData.tabID, answer) + } + } + private processChatMessage = async (messageData: any): Promise => { if (this.onChatAnswerReceived !== undefined) { const answer: ChatItem = { @@ -263,6 +278,11 @@ export class Connector { return } + if (messageData.type === 'retryChangeFolderMessage') { + await this.processRetryChangeFolderMessage(messageData) + return + } + if (messageData.type === 'chatMessage') { await this.processChatMessage(messageData) return diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties index 33dc4c99ec..94c63dade5 100644 --- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties +++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties @@ -113,6 +113,7 @@ amazonqFeatureDev.exception.throttling=I'm sorry, I'm experiencing high demand a amazonqFeatureDev.exception.upload_code=I'm sorry, I couldn't upload your workspace artifacts to Amazon S3 to help you with this task. You might need to allow access to the S3 bucket. For more information, see the [Amazon Q documentation](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/security_iam_manage-access-with-policies.html#data-perimeters) or contact your network or organization administrator. amazonqFeatureDev.exception.upload_url_expiry=I'm sorry, I wasn't able to generate code. A connection timed out or became unavailable. Please try again or check the following:\n\n- Exclude non-essential files in your workspace's `.gitignore`.\n\n- Check that your network connection is stable. amazonqFeatureDev.follow_instructions_for_authentication=Follow instructions to re-authenticate ... +amazonqFeatureDev.follow_up.cancel_source_folder_selection=It looks like you didn't choose a folder. Choose a folder to continue. amazonqFeatureDev.follow_up.close_session=No, thanks amazonqFeatureDev.follow_up.continue=Continue amazonqFeatureDev.follow_up.incorrect_source_folder=The folder you chose isn't in your open workspace folder. You can add this folder to your workspace, or choose a folder in your open workspace.