Skip to content

Commit 54f77f6

Browse files
telemetry(/dev): add feedback telemetry (#4867)
1 parent c610a57 commit 54f77f6

File tree

6 files changed

+85
-9
lines changed

6 files changed

+85
-9
lines changed

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/FeatureDevApp.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class FeatureDevApp : AmazonQApp {
3737
"auth-follow-up-was-clicked" to IncomingFeatureDevMessage.AuthFollowUpWasClicked::class,
3838
"follow-up-was-clicked" to IncomingFeatureDevMessage.FollowupClicked::class,
3939
"chat-item-voted" to IncomingFeatureDevMessage.ChatItemVotedMessage::class,
40+
"chat-item-feedback" to IncomingFeatureDevMessage.ChatItemFeedbackMessage::class,
4041
"response-body-link-click" to IncomingFeatureDevMessage.ClickedLink::class,
4142
"insert_code_at_cursor_position" to IncomingFeatureDevMessage.InsertCodeAtCursorPosition::class,
4243
"open-diff" to IncomingFeatureDevMessage.OpenDiff::class,
@@ -76,6 +77,7 @@ class FeatureDevApp : AmazonQApp {
7677
is IncomingFeatureDevMessage.AuthFollowUpWasClicked -> inboundAppMessagesHandler.processAuthFollowUpClick(message)
7778
is IncomingFeatureDevMessage.FollowupClicked -> inboundAppMessagesHandler.processFollowupClickedMessage(message)
7879
is IncomingFeatureDevMessage.ChatItemVotedMessage -> inboundAppMessagesHandler.processChatItemVotedMessage(message)
80+
is IncomingFeatureDevMessage.ChatItemFeedbackMessage -> inboundAppMessagesHandler.processChatItemFeedbackMessage(message)
7981
is IncomingFeatureDevMessage.ClickedLink -> inboundAppMessagesHandler.processLinkClick(message)
8082
is IncomingFeatureDevMessage.InsertCodeAtCursorPosition -> inboundAppMessagesHandler.processInsertCodeAtCursorPosition(message)
8183
is IncomingFeatureDevMessage.OpenDiff -> inboundAppMessagesHandler.processOpenDiff(message)

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/InboundAppMessagesHandler.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface InboundAppMessagesHandler {
1212
suspend fun processAuthFollowUpClick(message: IncomingFeatureDevMessage.AuthFollowUpWasClicked)
1313
suspend fun processFollowupClickedMessage(message: IncomingFeatureDevMessage.FollowupClicked)
1414
suspend fun processChatItemVotedMessage(message: IncomingFeatureDevMessage.ChatItemVotedMessage)
15+
suspend fun processChatItemFeedbackMessage(message: IncomingFeatureDevMessage.ChatItemFeedbackMessage)
1516
suspend fun processLinkClick(message: IncomingFeatureDevMessage.ClickedLink)
1617
suspend fun processInsertCodeAtCursorPosition(message: IncomingFeatureDevMessage.InsertCodeAtCursorPosition)
1718
suspend fun processOpenDiff(message: IncomingFeatureDevMessage.OpenDiff)

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/controller/FeatureDevController.kt

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.controller
55

6+
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
67
import com.intellij.diff.DiffContentFactory
78
import com.intellij.diff.DiffManager
89
import com.intellij.diff.contents.EmptyContent
@@ -17,6 +18,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager
1718
import com.intellij.openapi.vfs.VfsUtil
1819
import com.intellij.openapi.wm.ToolWindowManager
1920
import kotlinx.coroutines.withContext
21+
import software.amazon.awssdk.services.toolkittelemetry.model.Sentiment
2022
import software.aws.toolkits.core.utils.debug
2123
import software.aws.toolkits.core.utils.error
2224
import software.aws.toolkits.core.utils.getLogger
@@ -62,8 +64,11 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Sessio
6264
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.SessionStatePhase
6365
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.storage.ChatSessionStorage
6466
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.selectFolder
67+
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.FeedbackComment
6568
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
69+
import software.aws.toolkits.jetbrains.services.telemetry.TelemetryService
6670
import software.aws.toolkits.jetbrains.ui.feedback.FeatureDevFeedbackDialog
71+
import software.aws.toolkits.jetbrains.utils.notifyError
6772
import software.aws.toolkits.resources.message
6873
import software.aws.toolkits.telemetry.AmazonqTelemetry
6974
import software.aws.toolkits.telemetry.Result
@@ -132,6 +137,32 @@ class FeatureDevController(
132137
}
133138
}
134139

140+
override suspend fun processChatItemFeedbackMessage(message: IncomingFeatureDevMessage.ChatItemFeedbackMessage) {
141+
logger.debug { "$FEATURE_NAME: Processing ChatItemFeedbackMessage: ${message.comment}" }
142+
143+
val session = getSessionInfo(message.tabId)
144+
145+
val comment = FeedbackComment(
146+
conversationId = session.conversationId,
147+
userComment = message.comment.orEmpty(),
148+
reason = message.selectedOption,
149+
messageId = message.messageId,
150+
type = "featuredev-chat-answer-feedback"
151+
)
152+
153+
try {
154+
TelemetryService.getInstance().sendFeedback(
155+
sentiment = Sentiment.NEGATIVE,
156+
comment = objectMapper.writeValueAsString(comment),
157+
)
158+
logger.info { "$FEATURE_NAME answer feedback sent: \"Negative\"" }
159+
} catch (e: Throwable) {
160+
e.notifyError(message("feedback.submit_failed", e))
161+
logger.warn(e) { "Failed to submit feedback" }
162+
return
163+
}
164+
}
165+
135166
override suspend fun processLinkClick(message: IncomingFeatureDevMessage.ClickedLink) {
136167
BrowserUtil.browse(message.link)
137168
}
@@ -284,7 +315,8 @@ class FeatureDevController(
284315
messenger.sendAnswer(
285316
tabId = tabId,
286317
message = message("amazonqFeatureDev.code_generation.updated_code"),
287-
messageType = FeatureDevMessageType.Answer
318+
messageType = FeatureDevMessageType.Answer,
319+
canBeVoted = true
288320
)
289321

290322
messenger.sendSystemPrompt(
@@ -331,9 +363,18 @@ class FeatureDevController(
331363
}
332364

333365
private suspend fun closeSession(tabId: String) {
334-
messenger.sendAnswer(tabId = tabId, messageType = FeatureDevMessageType.Answer, message = message("amazonqFeatureDev.chat_message.closed_session"))
366+
messenger.sendAnswer(
367+
tabId = tabId,
368+
messageType = FeatureDevMessageType.Answer,
369+
message = message("amazonqFeatureDev.chat_message.closed_session"),
370+
canBeVoted = true
371+
)
372+
373+
messenger.sendUpdatePlaceholder(
374+
tabId = tabId,
375+
newPlaceholder = message("amazonqFeatureDev.placeholder.closed_session")
376+
)
335377

336-
messenger.sendUpdatePlaceholder(tabId = tabId, newPlaceholder = message("amazonqFeatureDev.placeholder.closed_session"))
337378
messenger.sendChatInputEnabledMessage(tabId = tabId, enabled = false)
338379

339380
val session = getSessionInfo(tabId)
@@ -360,7 +401,8 @@ class FeatureDevController(
360401
messenger.sendAnswer(
361402
tabId = tabId,
362403
message = message("amazonqFeatureDev.code_generation.provide_code_feedback"),
363-
messageType = FeatureDevMessageType.Answer
404+
messageType = FeatureDevMessageType.Answer,
405+
canBeVoted = true
364406
)
365407
messenger.sendUpdatePlaceholder(tabId, message("amazonqFeatureDev.placeholder.provide_code_feedback"))
366408
}
@@ -575,6 +617,7 @@ class FeatureDevController(
575617
tabId = tabId,
576618
messageType = FeatureDevMessageType.Answer,
577619
message = message("amazonqFeatureDev.follow_up.modified_source_folder", selectedFolder.path),
620+
canBeVoted = true,
578621
)
579622

580623
messenger.sendAnswer(
@@ -615,5 +658,7 @@ class FeatureDevController(
615658

616659
companion object {
617660
private val logger = getLogger<FeatureDevController>()
661+
662+
private val objectMapper = jacksonObjectMapper()
618663
}
619664
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/messages/FeatureDevMessage.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ sealed interface IncomingFeatureDevMessage : FeatureDevBaseMessage {
5252
val vote: String,
5353
) : IncomingFeatureDevMessage
5454

55+
data class ChatItemFeedbackMessage(
56+
@JsonProperty("tabID") val tabId: String,
57+
val selectedOption: String,
58+
val comment: String?,
59+
val messageId: String,
60+
) : IncomingFeatureDevMessage
61+
5562
data class ClickedLink(
5663
@JsonProperty("tabID") val tabId: String,
5764
val command: String,

plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/controller/FeatureDevControllerTest.kt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,12 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
157157
mockitoVerify(chatSessionStorage, times(1)).deleteSession(testTabId)
158158

159159
coVerifyOrder {
160-
messenger.sendAnswer(testTabId, message("amazonqFeatureDev.chat_message.closed_session"), FeatureDevMessageType.Answer)
160+
messenger.sendAnswer(
161+
tabId = testTabId,
162+
message = message("amazonqFeatureDev.chat_message.closed_session"),
163+
messageType = FeatureDevMessageType.Answer,
164+
canBeVoted = true
165+
)
161166
messenger.sendUpdatePlaceholder(testTabId, message("amazonqFeatureDev.placeholder.closed_session"))
162167
messenger.sendChatInputEnabledMessage(testTabId, false)
163168
messenger.sendAnswer(testTabId, message("amazonqFeatureDev.chat_message.ask_for_new_task"), FeatureDevMessageType.Answer)
@@ -187,7 +192,12 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
187192
coVerifyOrder {
188193
AmazonqTelemetry.isProvideFeedbackForCodeGen(amazonqConversationId = testConversationId, enabled = true, createTime = any())
189194
messenger.sendAsyncEventProgress(testTabId, inProgress = false)
190-
messenger.sendAnswer(testTabId, message("amazonqFeatureDev.code_generation.provide_code_feedback"), FeatureDevMessageType.Answer)
195+
messenger.sendAnswer(
196+
tabId = testTabId,
197+
message = message("amazonqFeatureDev.code_generation.provide_code_feedback"),
198+
messageType = FeatureDevMessageType.Answer,
199+
canBeVoted = true
200+
)
191201
messenger.sendUpdatePlaceholder(testTabId, message("amazonqFeatureDev.placeholder.provide_code_feedback"))
192202
}
193203
}
@@ -226,7 +236,12 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
226236
enabled = true,
227237
createTime = any()
228238
)
229-
messenger.sendAnswer(testTabId, message("amazonqFeatureDev.code_generation.updated_code"), FeatureDevMessageType.Answer)
239+
messenger.sendAnswer(
240+
tabId = testTabId,
241+
message = message("amazonqFeatureDev.code_generation.updated_code"),
242+
messageType = FeatureDevMessageType.Answer,
243+
canBeVoted = true
244+
)
230245
messenger.sendSystemPrompt(
231246
testTabId,
232247
listOf(
@@ -441,7 +456,8 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
441456
messenger.sendAnswer(
442457
tabId = testTabId,
443458
messageType = FeatureDevMessageType.Answer,
444-
message = message("amazonqFeatureDev.follow_up.modified_source_folder", folder.path)
459+
message = message("amazonqFeatureDev.follow_up.modified_source_folder", folder.path),
460+
canBeVoted = true,
445461
)
446462
}
447463
}

plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/featureDevChatConnector.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,12 @@ export class Connector {
280280
}
281281

282282
sendFeedback = (tabId: string, feedbackPayload: FeedbackPayload): void | undefined => {
283-
// TODO implement telemetry
283+
this.sendMessageToExtension({
284+
command: 'chat-item-feedback',
285+
...feedbackPayload,
286+
tabType: 'featuredev',
287+
tabID: tabId,
288+
})
284289
}
285290

286291
onChatItemVoted = (tabId: string, messageId: string, vote: string): void | undefined => {

0 commit comments

Comments
 (0)