33
44package software.aws.toolkits.jetbrains.services.amazonqDoc.controller
55
6- import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
76import com.intellij.diff.DiffContentFactory
87import com.intellij.diff.DiffManager
98import com.intellij.diff.contents.EmptyContent
109import com.intellij.diff.requests.SimpleDiffRequest
1110import com.intellij.diff.util.DiffUserDataKeys
1211import com.intellij.ide.BrowserUtil
1312import com.intellij.openapi.application.runInEdt
14- import com.intellij.openapi.command.WriteCommandAction
15- import com.intellij.openapi.editor.Caret
16- import com.intellij.openapi.editor.Editor
17- import com.intellij.openapi.fileEditor.FileEditorManager
1813import com.intellij.openapi.vfs.VfsUtil
1914import com.intellij.openapi.wm.ToolWindowManager
2015import kotlinx.coroutines.withContext
2116import software.amazon.awssdk.services.codewhispererruntime.model.DocGenerationFolderLevel
2217import software.amazon.awssdk.services.codewhispererruntime.model.DocGenerationInteractionType
2318import software.amazon.awssdk.services.codewhispererruntime.model.DocGenerationUserDecision
24- import software.amazon.awssdk.services.toolkittelemetry.model.Sentiment
2519import software.aws.toolkits.core.utils.debug
2620import software.aws.toolkits.core.utils.error
2721import software.aws.toolkits.core.utils.getLogger
@@ -37,7 +31,6 @@ import software.aws.toolkits.jetbrains.services.amazonqDoc.DEFAULT_RETRY_LIMIT
3731import software.aws.toolkits.jetbrains.services.amazonqDoc.DocException
3832import software.aws.toolkits.jetbrains.services.amazonqDoc.FEATURE_NAME
3933import software.aws.toolkits.jetbrains.services.amazonqDoc.InboundAppMessagesHandler
40- import software.aws.toolkits.jetbrains.services.amazonqDoc.ModifySourceFolderErrorReason
4134import software.aws.toolkits.jetbrains.services.amazonqDoc.ZipFileError
4235import software.aws.toolkits.jetbrains.services.amazonqDoc.cancellingProgressField
4336import software.aws.toolkits.jetbrains.services.amazonqDoc.createUserFacingErrorMessage
@@ -74,13 +67,7 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Delete
7467import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.NewFileZipInfo
7568import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.SessionStatePhase
7669import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.CancellationTokenSource
77- import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.FeedbackComment
78- import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
79- import software.aws.toolkits.jetbrains.services.telemetry.TelemetryService
80- import software.aws.toolkits.jetbrains.utils.notifyError
8170import software.aws.toolkits.resources.message
82- import software.aws.toolkits.telemetry.AmazonqTelemetry
83- import software.aws.toolkits.telemetry.Result
8471import java.util.UUID
8572
8673enum class DocGenerationStep {
@@ -239,6 +226,9 @@ class DocController(
239226 if (session.sessionState.token?.token != = null ) {
240227 session.sessionState.token?.cancel()
241228 }
229+
230+ docGenerationTask.reset()
231+ newTask(message.tabId)
242232 }
243233
244234 private suspend fun updateDocumentation (tabId : String ) {
@@ -343,84 +333,13 @@ class DocController(
343333 }
344334 }
345335
346- override suspend fun processChatItemVotedMessage (message : IncomingDocMessage .ChatItemVotedMessage ) {
347- logger.debug { " $FEATURE_NAME : Processing ChatItemVotedMessage: $message " }
348-
349- val session = chatSessionStorage.getSession(message.tabId, context.project)
350- when (message.vote) {
351- " upvote" -> {
352- AmazonqTelemetry .codeGenerationThumbsUp(
353- amazonqConversationId = session.conversationId,
354- credentialStartUrl = getStartUrl(project = context.project)
355- )
356- }
357-
358- " downvote" -> {
359- AmazonqTelemetry .codeGenerationThumbsDown(
360- amazonqConversationId = session.conversationId,
361- credentialStartUrl = getStartUrl(project = context.project)
362- )
363- }
364- }
365- }
366-
367- override suspend fun processChatItemFeedbackMessage (message : IncomingDocMessage .ChatItemFeedbackMessage ) {
368- logger.debug { " $FEATURE_NAME : Processing ChatItemFeedbackMessage: ${message.comment} " }
369-
370- val session = getSessionInfo(message.tabId)
371-
372- val comment = FeedbackComment (
373- conversationId = session.conversationId,
374- userComment = message.comment.orEmpty(),
375- reason = message.selectedOption,
376- messageId = message.messageId,
377- type = " doc-chat-answer-feedback"
378- )
379-
380- try {
381- TelemetryService .getInstance().sendFeedback(
382- sentiment = Sentiment .NEGATIVE ,
383- comment = objectMapper.writeValueAsString(comment),
384- )
385- logger.info { " $FEATURE_NAME answer feedback sent: \" Negative\" " }
386- } catch (e: Throwable ) {
387- e.notifyError(message(" feedback.submit_failed" , e))
388- logger.warn(e) { " Failed to submit feedback" }
389- return
390- }
391- }
392-
393336 override suspend fun processLinkClick (message : IncomingDocMessage .ClickedLink ) {
394337 BrowserUtil .browse(message.link)
395338 }
396339
397- override suspend fun processInsertCodeAtCursorPosition (message : IncomingDocMessage .InsertCodeAtCursorPosition ) {
398- logger.debug { " $FEATURE_NAME : Processing InsertCodeAtCursorPosition: $message " }
399-
400- withContext(EDT ) {
401- val editor: Editor = FileEditorManager .getInstance(context.project).selectedTextEditor ? : return @withContext
402-
403- val caret: Caret = editor.caretModel.primaryCaret
404- val offset: Int = caret.offset
405-
406- WriteCommandAction .runWriteCommandAction(context.project) {
407- if (caret.hasSelection()) {
408- editor.document.deleteString(caret.selectionStart, caret.selectionEnd)
409- }
410- editor.document.insertString(offset, message.code)
411- }
412- }
413- }
414-
415340 override suspend fun processOpenDiff (message : IncomingDocMessage .OpenDiff ) {
416341 val session = getSessionInfo(message.tabId)
417342
418- AmazonqTelemetry .isReviewedChanges(
419- amazonqConversationId = session.conversationId,
420- enabled = true ,
421- credentialStartUrl = getStartUrl(project = context.project)
422- )
423-
424343 val project = context.project
425344 val sessionState = session.sessionState
426345
@@ -528,13 +447,6 @@ class DocController(
528447 }
529448 }
530449
531- AmazonqTelemetry .isAcceptedCodeChanges(
532- amazonqNumberOfFilesAccepted = (filePaths.filterNot { it.rejected }.size + deletedFiles.filterNot { it.rejected }.size) * 1.0 ,
533- amazonqConversationId = session.conversationId,
534- enabled = true ,
535- credentialStartUrl = getStartUrl(project = context.project)
536- )
537-
538450 session.insertChanges(
539451 filePaths = filePaths.filterNot { it.rejected },
540452 deletedFiles = deletedFiles.filterNot { it.rejected }
@@ -572,14 +484,7 @@ class DocController(
572484 }
573485
574486 private suspend fun newTask (tabId : String ) {
575- val session = getSessionInfo(tabId)
576- val sessionLatency = System .currentTimeMillis() - session.sessionStartTime
577487 docGenerationTask = DocGenerationTask ()
578- AmazonqTelemetry .endChat(
579- amazonqConversationId = session.conversationId,
580- amazonqEndOfTheConversationLatency = sessionLatency.toDouble(),
581- credentialStartUrl = getStartUrl(project = context.project)
582- )
583488 chatSessionStorage.deleteSession(tabId)
584489
585490 messenger.sendAnswer(
@@ -588,6 +493,8 @@ class DocController(
588493 message = message(" amazonqFeatureDev.chat_message.ask_for_new_task" )
589494 )
590495
496+ messenger.sendUpdatePromptProgress(tabId, null )
497+
591498 messenger.sendUpdatePlaceholder(
592499 tabId = tabId,
593500 newPlaceholder = message(" amazonqFeatureDev.placeholder.after_code_generation" )
@@ -627,25 +534,9 @@ class DocController(
627534
628535 messenger.sendChatInputEnabledMessage(tabId = tabId, enabled = false )
629536 docGenerationTask.reset()
630-
631- val session = getSessionInfo(tabId)
632- val sessionLatency = System .currentTimeMillis() - session.sessionStartTime
633- AmazonqTelemetry .endChat(
634- amazonqConversationId = session.conversationId,
635- amazonqEndOfTheConversationLatency = sessionLatency.toDouble(),
636- credentialStartUrl = getStartUrl(project = context.project)
637- )
638537 }
639538
640539 private suspend fun provideFeedbackAndRegenerateCode (tabId : String ) {
641- val session = getSessionInfo(tabId)
642-
643- AmazonqTelemetry .isProvideFeedbackForCodeGen(
644- amazonqConversationId = session.conversationId,
645- enabled = true ,
646- credentialStartUrl = getStartUrl(project = context.project)
647- )
648-
649540 // Unblock the message button
650541 messenger.sendAsyncEventProgress(tabId = tabId, inProgress = false )
651542
@@ -824,9 +715,11 @@ class DocController(
824715 else -> emptyList()
825716 }
826717
827- processOpenDiff(
828- message = IncomingDocMessage .OpenDiff (tabId = tabId, filePath = filePaths[0 ].zipFilePath, deleted = false )
829- )
718+ if (filePaths.isNotEmpty()) {
719+ processOpenDiff(
720+ message = IncomingDocMessage .OpenDiff (tabId = tabId, filePath = filePaths[0 ].zipFilePath, deleted = false )
721+ )
722+ }
830723 } catch (err: Exception ) {
831724 processErrorChatMessage(err, session, tabId)
832725
@@ -1007,16 +900,11 @@ class DocController(
1007900 val currentSourceFolder = session.context.selectedSourceFolder
1008901 val projectRoot = session.context.projectRoot
1009902
1010- var result: Result = Result .Failed
1011- var reason: ModifySourceFolderErrorReason ? = null
1012-
1013903 withContext(EDT ) {
1014904 val selectedFolder = selectFolder(context.project, currentSourceFolder)
1015905 // No folder was selected
1016906 if (selectedFolder == null ) {
1017907 logger.info { " Cancelled dialog and not selected any folder" }
1018-
1019- reason = ModifySourceFolderErrorReason .ClosedBeforeSelection
1020908 return @withContext
1021909 }
1022910
@@ -1029,8 +917,6 @@ class DocController(
1029917 messageType = DocMessageType .Answer ,
1030918 message = message(" amazonqFeatureDev.follow_up.incorrect_source_folder" ),
1031919 )
1032-
1033- reason = ModifySourceFolderErrorReason .NotInWorkspaceFolder
1034920 return @withContext
1035921 }
1036922 if (selectedFolder.path == projectRoot.path) {
@@ -1042,21 +928,13 @@ class DocController(
1042928 logger.info { " Selected correct folder inside workspace: ${selectedFolder.path} " }
1043929
1044930 session.context.selectedSourceFolder = selectedFolder
1045- result = Result .Succeeded
1046931
1047932 promptForDocTarget(tabId)
1048933
1049934 messenger.sendChatInputEnabledMessage(tabId, enabled = false )
1050935
1051936 messenger.sendUpdatePlaceholder(tabId = tabId, newPlaceholder = message(" amazonqDoc.prompt.placeholder" ))
1052937 }
1053-
1054- AmazonqTelemetry .modifySourceFolder(
1055- amazonqConversationId = session.conversationId,
1056- credentialStartUrl = getStartUrl(project = context.project),
1057- result = result,
1058- reason = reason?.toString()
1059- )
1060938 }
1061939
1062940 private fun sendDocGenerationTelemetry (tabId : String ) {
@@ -1086,7 +964,5 @@ class DocController(
1086964
1087965 companion object {
1088966 private val logger = getLogger<DocController >()
1089-
1090- private val objectMapper = jacksonObjectMapper()
1091967 }
1092968}
0 commit comments