diff --git a/packages/core/src/amazonq/webview/ui/apps/featureDevChatConnector.ts b/packages/core/src/amazonq/webview/ui/apps/featureDevChatConnector.ts index 8f9e658d8b3..37657c803cf 100644 --- a/packages/core/src/amazonq/webview/ui/apps/featureDevChatConnector.ts +++ b/packages/core/src/amazonq/webview/ui/apps/featureDevChatConnector.ts @@ -287,7 +287,12 @@ export class Connector { } sendFeedback = (tabId: string, feedbackPayload: FeedbackPayload): void | undefined => { - // TODO implement telemetry + this.sendMessageToExtension({ + command: 'chat-item-feedback', + ...feedbackPayload, + tabType: 'featuredev', + tabID: tabId, + }) } onChatItemVoted = (tabId: string, messageId: string, vote: string): void | undefined => { diff --git a/packages/core/src/amazonqFeatureDev/app.ts b/packages/core/src/amazonqFeatureDev/app.ts index a17098b4770..3e5a103011a 100644 --- a/packages/core/src/amazonqFeatureDev/app.ts +++ b/packages/core/src/amazonqFeatureDev/app.ts @@ -26,6 +26,7 @@ export function init(appContext: AmazonQAppInitContext) { followUpClicked: new vscode.EventEmitter(), openDiff: new vscode.EventEmitter(), processChatItemVotedMessage: new vscode.EventEmitter(), + processChatItemFeedbackMessage: new vscode.EventEmitter(), stopResponse: new vscode.EventEmitter(), tabOpened: new vscode.EventEmitter(), tabClosed: new vscode.EventEmitter(), diff --git a/packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts b/packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts index b791294d7fb..c4aa474179b 100644 --- a/packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts +++ b/packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts @@ -44,6 +44,7 @@ import { examples, logWithConversationId, messageWithConversationId } from '../. import { getWorkspaceFoldersByPrefixes } from '../../../shared/utilities/workspaceUtils' import { openDeletedDiff, openDiff } from '../../../amazonq/commons/diff' import { i18n } from '../../../shared/i18n-helper' +import globals from '../../../shared/extensionGlobals' export interface ChatControllerEventEmitters { readonly processHumanChatMessage: EventEmitter @@ -53,6 +54,7 @@ export interface ChatControllerEventEmitters { readonly tabOpened: EventEmitter readonly tabClosed: EventEmitter readonly processChatItemVotedMessage: EventEmitter + readonly processChatItemFeedbackMessage: EventEmitter readonly authClicked: EventEmitter readonly processResponseBodyLinkClick: EventEmitter readonly insertCodeAtPositionClicked: EventEmitter @@ -111,6 +113,11 @@ export class FeatureDevController { getLogger().error('processChatItemVotedMessage failed: %s', (e as Error).message) }) }) + this.chatControllerMessageListeners.processChatItemFeedbackMessage.event((data) => { + this.processChatItemFeedbackMessage(data).catch((e) => { + getLogger().error('processChatItemFeedbackMessage failed: %s', (e as Error).message) + }) + }) this.chatControllerMessageListeners.followUpClicked.event((data) => { switch (data.followUp.type) { case FollowUpTypes.GenerateCode: @@ -202,6 +209,21 @@ export class FeatureDevController { } } + private async processChatItemFeedbackMessage(message: any) { + const session = await this.sessionStorage.getSession(message.tabId) + + await globals.telemetry.postFeedback({ + comment: `${JSON.stringify({ + type: 'featuredev-chat-answer-feedback', + conversationId: session?.conversationId ?? '', + messageId: message?.messageId, + reason: message?.selectedOption, + userComment: message?.comment, + })}`, + sentiment: 'Negative', // The chat UI reports only negative feedback currently. + }) + } + private processErrorChatMessage = (err: any, message: any, session: Session | undefined) => { const errorMessage = createUserFacingErrorMessage( `${featureName} request failed: ${err.cause?.message ?? err.message}` @@ -429,6 +451,7 @@ export class FeatureDevController { message: i18n('AWS.amazonq.featureDev.pillText.requestingChanges'), type: 'answer-stream', tabID, + canBeVoted: true, }) this.messenger.sendUpdatePlaceholder(tabID, i18n('AWS.amazonq.featureDev.pillText.generatingCode')) await session.send(message) @@ -439,6 +462,7 @@ export class FeatureDevController { message: i18n('AWS.amazonq.featureDev.pillText.unableGenerateChanges'), type: 'answer', tabID: tabID, + canBeVoted: true, }) this.messenger.sendAnswer({ type: 'system-prompt', @@ -555,6 +579,7 @@ export class FeatureDevController { type: 'answer', tabID: message.tabID, message: i18n('AWS.amazonq.featureDev.answer.updateCode'), + canBeVoted: true, }) this.messenger.sendAnswer({ @@ -605,6 +630,7 @@ export class FeatureDevController { type: 'answer', tabID: message.tabID, message: i18n('AWS.amazonq.featureDev.answer.howCodeCanBeImproved'), + canBeVoted: true, }) this.messenger.sendUpdatePlaceholder(message.tabID, i18n('AWS.amazonq.featureDev.placeholder.feedback')) @@ -696,6 +722,7 @@ export class FeatureDevController { tabID: message.tabID, type: 'answer', message: new SelectedFolderNotInWorkspaceFolderError().message, + canBeVoted: true, }) this.messenger.sendAnswer({ tabID: message.tabID, @@ -716,6 +743,7 @@ export class FeatureDevController { message: `Changed source root to: ${uri.fsPath}`, type: 'answer', tabID: message.tabID, + canBeVoted: true, }) this.messenger.sendAnswer({ message: undefined, @@ -745,6 +773,7 @@ export class FeatureDevController { type: 'answer', tabID: message.tabID, message: examples, + canBeVoted: true, }) } diff --git a/packages/core/src/amazonqFeatureDev/views/actions/uiMessageListener.ts b/packages/core/src/amazonqFeatureDev/views/actions/uiMessageListener.ts index b9fe012ab67..790dd1a6e05 100644 --- a/packages/core/src/amazonqFeatureDev/views/actions/uiMessageListener.ts +++ b/packages/core/src/amazonqFeatureDev/views/actions/uiMessageListener.ts @@ -40,6 +40,9 @@ export class UIMessageListener { case 'chat-item-voted': this.chatItemVoted(msg) break + case 'chat-item-feedback': + this.chatItemFeedback(msg) + break case 'stop-response': this.stopResponse(msg) break @@ -73,6 +76,10 @@ export class UIMessageListener { }) } + private chatItemFeedback(msg: any) { + this.featureDevControllerEventsEmitters?.processChatItemFeedbackMessage.fire(msg) + } + private processChatMessage(msg: any) { this.featureDevControllerEventsEmitters?.processHumanChatMessage.fire({ message: msg.chatMessage, diff --git a/packages/core/src/test/amazonqFeatureDev/controllers/chat/controller.test.ts b/packages/core/src/test/amazonqFeatureDev/controllers/chat/controller.test.ts index 4bc697ba796..73ef2e30345 100644 --- a/packages/core/src/test/amazonqFeatureDev/controllers/chat/controller.test.ts +++ b/packages/core/src/test/amazonqFeatureDev/controllers/chat/controller.test.ts @@ -188,6 +188,7 @@ describe('Controller', () => { tabID, type: 'answer', message: new SelectedFolderNotInWorkspaceFolderError().message, + canBeVoted: true, }), true ) diff --git a/packages/core/src/test/amazonqFeatureDev/utils.ts b/packages/core/src/test/amazonqFeatureDev/utils.ts index 77822582c0e..57e5fb72a9d 100644 --- a/packages/core/src/test/amazonqFeatureDev/utils.ts +++ b/packages/core/src/test/amazonqFeatureDev/utils.ts @@ -31,6 +31,7 @@ export function createMockChatEmitters(): ChatControllerEventEmitters { followUpClicked: new vscode.EventEmitter(), openDiff: new vscode.EventEmitter(), processChatItemVotedMessage: new vscode.EventEmitter(), + processChatItemFeedbackMessage: new vscode.EventEmitter(), stopResponse: new vscode.EventEmitter(), tabOpened: new vscode.EventEmitter(), tabClosed: new vscode.EventEmitter(),