From fa8c411555bf8b2d20ce3e82a88265f16ddd974d Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:09:12 -0700 Subject: [PATCH 01/12] Adding Acceptance metrics for UTG --- .../chat/messenger/ChatPromptHandler.kt | 26 ++++-- .../services/cwc/messages/CwcMessage.kt | 1 + .../src/mynah-ui/ui/apps/cwChatConnector.ts | 21 +++-- .../mynah-ui/src/mynah-ui/ui/connector.ts | 16 +++- .../amazonq/mynah-ui/src/mynah-ui/ui/main.ts | 81 ++++++++++++------- 5 files changed, 102 insertions(+), 43 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt index 3d921ffec1d..6c0924ea796 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt @@ -58,7 +58,14 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) { .onStart { // The first thing we always send back is an AnswerStream message to indicate the beginning of a streaming answer val response = - ChatMessage(tabId = tabId, triggerId = triggerId, messageId = requestId, messageType = ChatMessageType.AnswerStream, message = "") + ChatMessage( + tabId = tabId, + triggerId = triggerId, + messageId = requestId, + messageType = ChatMessageType.AnswerStream, + message = "", + userIntent = data.userIntent, + ) telemetryHelper.setResponseStreamStartTime(tabId) emit(response) @@ -81,13 +88,20 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) { messageType = ChatMessageType.AnswerPart, message = responseText.toString(), relatedSuggestions = relatedSuggestions, + userIntent = data.userIntent, ) emit(suggestionMessage) } // Send the Answer message to indicate the end of the response stream - val response = - ChatMessage(tabId = tabId, triggerId = triggerId, messageId = requestId, messageType = ChatMessageType.Answer, followUps = followUps) + val response = ChatMessage( + tabId = tabId, + triggerId = triggerId, + messageId = requestId, + messageType = ChatMessageType.Answer, + followUps = followUps, + userIntent = data.userIntent, + ) telemetryHelper.setResponseStreamTotalTime(tabId) telemetryHelper.setResponseHasProjectContext( @@ -119,11 +133,12 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) { } } .collect { responseEvent -> - processChatEvent(tabId, triggerId, responseEvent, shouldAddIndexInProgressMessage)?.let { emit(it) } + processChatEvent(tabId, triggerId, data, + responseEvent, shouldAddIndexInProgressMessage)?.let { emit(it) } } } - private fun processChatEvent(tabId: String, triggerId: String, event: ChatResponseEvent, shouldAddIndexInProgressMessage: Boolean): ChatMessage? { + private fun processChatEvent(tabId: String, triggerId: String, data: ChatRequestData, event: ChatResponseEvent, shouldAddIndexInProgressMessage: Boolean): ChatMessage? { requestId = event.requestId statusCode = event.statusCode @@ -190,6 +205,7 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) { messageType = ChatMessageType.AnswerPart, message = message, codeReference = codeReferences, + userIntent = data.userIntent, ) } else { null diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/messages/CwcMessage.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/messages/CwcMessage.kt index 599b050d272..06193bdc4ac 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/messages/CwcMessage.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/messages/CwcMessage.kt @@ -213,6 +213,7 @@ data class ChatMessage( val followUpsHeader: String? = null, val relatedSuggestions: List? = null, val codeReference: List? = null, + val userIntent: UserIntent? = null, ) : UiMessage( tabId = tabId, type = "chatMessage", diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/cwChatConnector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/cwChatConnector.ts index d89201d35e4..9752c44e99d 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/cwChatConnector.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/cwChatConnector.ts @@ -3,11 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { ChatItem, ChatItemAction, ChatItemType, FeedbackPayload } from '@aws/mynah-ui-chat' +import { ChatItemAction, ChatItemType, FeedbackPayload } from '@aws/mynah-ui-chat' import { ExtensionMessage } from '../commands' import { CodeReference } from './amazonqCommonsConnector' import { TabOpenType, TabsStorage } from '../storages/tabsStorage' import { FollowUpGenerator } from '../followUps/generator' +import { CWCChatItem } from "../connector"; interface ChatPayload { chatMessage: string @@ -17,8 +18,8 @@ interface ChatPayload { export interface ConnectorProps { sendMessageToExtension: (message: ExtensionMessage) => void onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void - onChatAnswerReceived?: (tabID: string, message: ChatItem) => void - onCWCContextCommandMessage: (message: ChatItem, command?: string) => string | undefined + onChatAnswerReceived?: (tabID: string, message: CWCChatItem) => void + onCWCContextCommandMessage: (message: CWCChatItem, command?: string) => string | undefined onError: (tabID: string, message: string, title: string) => void onWarning: (tabID: string, message: string, title: string) => void onOpenSettingsMessage: (tabID: string) => void @@ -98,7 +99,8 @@ export class Connector { codeReference?: CodeReference[], eventId?: string, codeBlockIndex?: number, - totalCodeBlocks?: number + totalCodeBlocks?: number, + userIntent?: string, ): void => { this.sendMessageToExtension({ tabID: tabID, @@ -111,6 +113,7 @@ export class Connector { eventId, codeBlockIndex, totalCodeBlocks, + userIntent }) } @@ -122,7 +125,8 @@ export class Connector { codeReference?: CodeReference[], eventId?: string, codeBlockIndex?: number, - totalCodeBlocks?: number + totalCodeBlocks?: number, + userIntent?: string, ): void => { this.sendMessageToExtension({ tabID: tabID, @@ -135,6 +139,7 @@ export class Connector { eventId, codeBlockIndex, totalCodeBlocks, + userIntent }) } @@ -258,13 +263,14 @@ export class Connector { } : undefined - const answer: ChatItem = { + const answer: CWCChatItem = { type: messageData.messageType, messageId: messageData.messageId ?? messageData.triggerID, body: messageData.message, followUp: followUps, canBeVoted: true, codeReference: messageData.codeReference, + userIntent: messageData.userIntent, } // If it is not there we will not set it @@ -291,12 +297,13 @@ export class Connector { return } if (messageData.messageType === ChatItemType.ANSWER) { - const answer: ChatItem = { + const answer: CWCChatItem = { type: messageData.messageType, body: undefined, relatedContent: undefined, messageId: messageData.messageId, codeReference: messageData.codeReference, + userIntent: messageData.userIntent, followUp: messageData.followUps !== undefined && messageData.followUps.length > 0 ? { diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/connector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/connector.ts index 77ac82f7e70..efe6e6fb6a2 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/connector.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/connector.ts @@ -30,6 +30,10 @@ export interface ChatPayload { chatCommand?: string } +export interface CWCChatItem extends ChatItem { + userIntent?: string +} + export interface ConnectorProps { sendMessageToExtension: (message: ExtensionMessage) => void onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void @@ -230,7 +234,8 @@ export class Connector { codeReference?: CodeReference[], eventId?: string, codeBlockIndex?: number, - totalCodeBlocks?: number + totalCodeBlocks?: number, + userIntent?: string ): void => { switch (this.tabsStorage.getTab(tabID)?.type) { case 'cwc': @@ -242,7 +247,8 @@ export class Connector { codeReference, eventId, codeBlockIndex, - totalCodeBlocks + totalCodeBlocks, + userIntent ) break case 'featuredev': @@ -259,7 +265,8 @@ export class Connector { codeReference?: CodeReference[], eventId?: string, codeBlockIndex?: number, - totalCodeBlocks?: number + totalCodeBlocks?: number, + userIntent?: string ): void => { switch (this.tabsStorage.getTab(tabID)?.type) { case 'cwc': @@ -271,7 +278,8 @@ export class Connector { codeReference, eventId, codeBlockIndex, - totalCodeBlocks + totalCodeBlocks, + userIntent ) break case 'featuredev': diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts index cd5f572ba7e..72f87ef5a76 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts @@ -2,8 +2,8 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -import { Connector } from './connector' -import { ChatItem, ChatItemType, MynahIcons, MynahUI, MynahUIDataModel, NotificationType } from '@aws/mynah-ui-chat' +import { Connector, CWCChatItem } from './connector' +import {ChatItem, ChatItemType, MynahIcons, MynahUI, MynahUIDataModel, NotificationType, ReferenceTrackerInformation} from '@aws/mynah-ui-chat' import './styles/dark.scss' import { TabsStorage, TabType } from './storages/tabsStorage' import { WelcomeFollowupType } from './apps/amazonqCommonsConnector' @@ -17,12 +17,15 @@ import { MessageController } from './messages/controller' import { getActions, getDetails } from './diffTree/actions' import { DiffTreeFileInfo } from './diffTree/types' import './styles.css' +import {CodeSelectionType} from "@aws/mynah-ui-chat/dist/static"; export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeTransformInitEnabled: boolean) => { // eslint-disable-next-line prefer-const let mynahUI: MynahUI // eslint-disable-next-line prefer-const let connector: Connector + const messageUserIntentMap = new Map() + const tabsStorage = new TabsStorage({ onTabTimeout: tabID => { mynahUI.addChatItem(tabID, { @@ -239,7 +242,7 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT sendMessageToExtension: message => { ideApi.postMessage(message) }, - onChatAnswerReceived: (tabID: string, item: ChatItem) => { + onChatAnswerReceived: (tabID: string, item: CWCChatItem) => { if (item.type === ChatItemType.ANSWER_PART || item.type === ChatItemType.CODE_RESULT) { mynahUI.updateLastChatAnswer(tabID, { ...(item.messageId !== undefined ? { messageId: item.messageId } : {}), @@ -251,6 +254,9 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT ? { type: ChatItemType.CODE_RESULT, fileList: item.fileList } : {}), }) + if (item.messageId !== undefined && item.userIntent !== undefined) { + messageUserIntentMap.set(item.messageId, item.userIntent) + } return } @@ -437,31 +443,52 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT content: 'Thanks for your feedback.', }) }, - onCodeInsertToCursorPosition: connector.onCodeInsertToCursorPosition, - onCopyCodeToClipboard: ( - tabId, - messageId, - code, - type, - referenceTrackerInfo, - eventId, - codeBlockIndex, - totalCodeBlocks + onCodeBlockActionClicked: ( + tabId: string, + messageId: string, + actionId: string, + data?: string, + code?: string, + type?: CodeSelectionType, + referenceTrackerInformation?: ReferenceTrackerInformation[], + eventId?: string, + codeBlockIndex?: number, + totalCodeBlocks?: number ) => { - connector.onCopyCodeToClipboard( - tabId, - messageId, - code, - type, - referenceTrackerInfo, - eventId, - codeBlockIndex, - totalCodeBlocks - ) - mynahUI.notify({ - type: NotificationType.SUCCESS, - content: 'Selected code is copied to clipboard', - }) + switch (actionId) { + case 'insert-to-cursor': + connector.onCodeInsertToCursorPosition( + tabId, + messageId, + code, + type, + referenceTrackerInformation, + eventId, + codeBlockIndex, + totalCodeBlocks, + messageUserIntentMap.get(messageId) ?? undefined + ) + break + case 'copy': + connector.onCopyCodeToClipboard( + tabId, + messageId, + code, + type, + referenceTrackerInformation, + eventId, + codeBlockIndex, + totalCodeBlocks, + messageUserIntentMap.get(messageId) ?? undefined + ) + mynahUI.notify({ + type: NotificationType.SUCCESS, + content: 'Selected code is copied to clipboard', + }) + break + default: + break + } }, onChatItemEngagement: connector.triggerSuggestionEngagement, onSourceLinkClick: (tabId, messageId, link, mouseEvent) => { From 89ae57fd54c1faa78c4417e53e0a8538e7f649ff Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:32:10 -0700 Subject: [PATCH 02/12] Fixing lint errors --- .../chat/messenger/ChatPromptHandler.kt | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt index 6c0924ea796..ccb6434fd21 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt @@ -95,13 +95,13 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) { // Send the Answer message to indicate the end of the response stream val response = ChatMessage( - tabId = tabId, - triggerId = triggerId, - messageId = requestId, - messageType = ChatMessageType.Answer, - followUps = followUps, - userIntent = data.userIntent, - ) + tabId = tabId, + triggerId = triggerId, + messageId = requestId, + messageType = ChatMessageType.Answer, + followUps = followUps, + userIntent = data.userIntent, + ) telemetryHelper.setResponseStreamTotalTime(tabId) telemetryHelper.setResponseHasProjectContext( @@ -133,12 +133,23 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) { } } .collect { responseEvent -> - processChatEvent(tabId, triggerId, data, - responseEvent, shouldAddIndexInProgressMessage)?.let { emit(it) } + processChatEvent( + tabId, + triggerId, + data, + responseEvent, + shouldAddIndexInProgressMessage + )?.let { emit(it) } } } - private fun processChatEvent(tabId: String, triggerId: String, data: ChatRequestData, event: ChatResponseEvent, shouldAddIndexInProgressMessage: Boolean): ChatMessage? { + private fun processChatEvent( + tabId: String, + triggerId: String, + data: ChatRequestData, + event: ChatResponseEvent, + shouldAddIndexInProgressMessage: Boolean, + ): ChatMessage? { requestId = event.requestId statusCode = event.statusCode From fefcb99a4ee4941ce382e079b1f6ff2996f15a77 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:16:54 -0700 Subject: [PATCH 03/12] Adding Language to user events --- .../chat/messenger/ChatPromptHandler.kt | 24 +++++++++++++++++++ .../chat/telemetry/TelemetryHelper.kt | 6 +++-- .../services/cwc/messages/CwcMessage.kt | 3 +++ .../src/mynah-ui/ui/apps/cwChatConnector.ts | 10 ++++++-- .../mynah-ui/src/mynah-ui/ui/connector.ts | 15 ++++++++---- .../amazonq/mynah-ui/src/mynah-ui/ui/main.ts | 12 ++++++---- .../resources/telemetryOverride.json | 4 ++++ 7 files changed, 60 insertions(+), 14 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt index ccb6434fd21..5466c5d5ca5 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt @@ -33,6 +33,7 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) { private val codeReferences = mutableListOf() private var requestId: String = "" private var statusCode: Int = 0 + private var codeBlockLanguage: String = "plaintext" companion object { private val CODE_BLOCK_PATTERN = Regex("
\\s*? = null,
     val codeReference: List? = null,
     val userIntent: UserIntent? = null,
+    val codeBlockLanguage: String? = "plaintext",
 ) : UiMessage(
     tabId = tabId,
     type = "chatMessage",
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/cwChatConnector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/cwChatConnector.ts
index 9752c44e99d..ffbca2fb063 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/cwChatConnector.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/cwChatConnector.ts
@@ -101,6 +101,7 @@ export class Connector {
         codeBlockIndex?: number,
         totalCodeBlocks?: number,
         userIntent?: string,
+        codeBlockLanguage?: string,
     ): void => {
         this.sendMessageToExtension({
             tabID: tabID,
@@ -113,7 +114,8 @@ export class Connector {
             eventId,
             codeBlockIndex,
             totalCodeBlocks,
-            userIntent
+            userIntent,
+            codeBlockLanguage
         })
     }
 
@@ -127,6 +129,7 @@ export class Connector {
         codeBlockIndex?: number,
         totalCodeBlocks?: number,
         userIntent?: string,
+        codeBlockLanguage?: string,
     ): void => {
         this.sendMessageToExtension({
             tabID: tabID,
@@ -139,7 +142,8 @@ export class Connector {
             eventId,
             codeBlockIndex,
             totalCodeBlocks,
-            userIntent
+            userIntent,
+            codeBlockLanguage
         })
     }
 
@@ -271,6 +275,7 @@ export class Connector {
                 canBeVoted: true,
                 codeReference: messageData.codeReference,
                 userIntent: messageData.userIntent,
+                codeBlockLanguage: messageData.codeBlockLanguage,
             }
 
             // If it is not there we will not set it
@@ -304,6 +309,7 @@ export class Connector {
                 messageId: messageData.messageId,
                 codeReference: messageData.codeReference,
                 userIntent: messageData.userIntent,
+                codeBlockLanguage: messageData.codeBlockLanguage,
                 followUp:
                     messageData.followUps !== undefined && messageData.followUps.length > 0
                         ? {
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/connector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/connector.ts
index efe6e6fb6a2..cb5ecd1e08c 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/connector.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/connector.ts
@@ -31,7 +31,8 @@ export interface ChatPayload {
 }
 
 export interface CWCChatItem extends ChatItem {
-    userIntent?: string
+    userIntent?: string,
+    codeBlockLanguage?: string,
 }
 
 export interface ConnectorProps {
@@ -235,7 +236,8 @@ export class Connector {
         eventId?: string,
         codeBlockIndex?: number,
         totalCodeBlocks?: number,
-        userIntent?: string
+        userIntent?: string,
+        codeBlockLanguage?: string
     ): void => {
         switch (this.tabsStorage.getTab(tabID)?.type) {
             case 'cwc':
@@ -248,7 +250,8 @@ export class Connector {
                     eventId,
                     codeBlockIndex,
                     totalCodeBlocks,
-                    userIntent
+                    userIntent,
+                    codeBlockLanguage
                 )
                 break
             case 'featuredev':
@@ -266,7 +269,8 @@ export class Connector {
         eventId?: string,
         codeBlockIndex?: number,
         totalCodeBlocks?: number,
-        userIntent?: string
+        userIntent?: string,
+        codeBlockLanguage?: string
     ): void => {
         switch (this.tabsStorage.getTab(tabID)?.type) {
             case 'cwc':
@@ -279,7 +283,8 @@ export class Connector {
                     eventId,
                     codeBlockIndex,
                     totalCodeBlocks,
-                    userIntent
+                    userIntent,
+                    codeBlockLanguage
                 )
                 break
             case 'featuredev':
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts
index 72f87ef5a76..2e258c8c467 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts
@@ -24,7 +24,7 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT
     let mynahUI: MynahUI
     // eslint-disable-next-line prefer-const
     let connector: Connector
-    const messageUserIntentMap = new Map()
+    const messageUserIntentMap = new Map()
 
     const tabsStorage = new TabsStorage({
         onTabTimeout: tabID => {
@@ -254,8 +254,8 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT
                         ? { type: ChatItemType.CODE_RESULT, fileList: item.fileList }
                         : {}),
                 })
-                if (item.messageId !== undefined && item.userIntent !== undefined) {
-                    messageUserIntentMap.set(item.messageId, item.userIntent)
+                if (item.messageId !== undefined && item.userIntent !== undefined && item.codeBlockLanguage !== undefined) {
+                    messageUserIntentMap.set(item.messageId, [item.userIntent, item.codeBlockLanguage])
                 }
                 return
             }
@@ -466,7 +466,8 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT
                         eventId,
                         codeBlockIndex,
                         totalCodeBlocks,
-                        messageUserIntentMap.get(messageId) ?? undefined
+                        messageUserIntentMap.get(messageId)?.[0] ?? undefined,
+                        messageUserIntentMap.get(messageId)?.[1] ?? undefined
                     )
                     break
                 case 'copy':
@@ -479,7 +480,8 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT
                         eventId,
                         codeBlockIndex,
                         totalCodeBlocks,
-                        messageUserIntentMap.get(messageId) ?? undefined
+                        messageUserIntentMap.get(messageId)?.[0] ?? undefined,
+                        messageUserIntentMap.get(messageId)?.[1] ?? undefined
                     )
                     mynahUI.notify({
                         type: NotificationType.SUCCESS,
diff --git a/plugins/core/jetbrains-community/resources/telemetryOverride.json b/plugins/core/jetbrains-community/resources/telemetryOverride.json
index e221fbcfb84..27d3c57f4fa 100644
--- a/plugins/core/jetbrains-community/resources/telemetryOverride.json
+++ b/plugins/core/jetbrains-community/resources/telemetryOverride.json
@@ -692,6 +692,10 @@
                 {
                     "type": "cwsprChatHasProjectContext",
                     "required": false
+                },
+                {
+                    "type": "cwsprChatProgrammingLanguage",
+                    "required": false
                 }
             ]
         },

From 3aacba42320c290ece2919a96de0a1de123b21ee Mon Sep 17 00:00:00 2001
From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com>
Date: Thu, 10 Oct 2024 14:06:22 -0700
Subject: [PATCH 04/12] minor fixes

---
 .../services/cwc/controller/chat/messenger/ChatPromptHandler.kt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
index 5466c5d5ca5..52a47598ae3 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
@@ -228,7 +228,7 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) {
             } else {
                 responseText.toString()
             }
-            if (codeBlockLanguage === "plaintext") {
+            if (codeBlockLanguage == "plaintext") {
                 // To get the language of generated code in Q chat.
                 codeBlockLanguage = extractCodeBlockLanguage(message)
             }

From 7b6fbd1d8f08963a8481b0a4ba122b1db18d8752 Mon Sep 17 00:00:00 2001
From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com>
Date: Fri, 11 Oct 2024 10:38:03 -0700
Subject: [PATCH 05/12] minor edits

---
 plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts
index 2e258c8c467..7f073b4f44e 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts
@@ -24,7 +24,7 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT
     let mynahUI: MynahUI
     // eslint-disable-next-line prefer-const
     let connector: Connector
-    const messageUserIntentMap = new Map()
+    const responseMetadata = new Map()
 
     const tabsStorage = new TabsStorage({
         onTabTimeout: tabID => {
@@ -255,7 +255,7 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT
                         : {}),
                 })
                 if (item.messageId !== undefined && item.userIntent !== undefined && item.codeBlockLanguage !== undefined) {
-                    messageUserIntentMap.set(item.messageId, [item.userIntent, item.codeBlockLanguage])
+                    responseMetadata.set(item.messageId, [item.userIntent, item.codeBlockLanguage])
                 }
                 return
             }
@@ -466,8 +466,8 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT
                         eventId,
                         codeBlockIndex,
                         totalCodeBlocks,
-                        messageUserIntentMap.get(messageId)?.[0] ?? undefined,
-                        messageUserIntentMap.get(messageId)?.[1] ?? undefined
+                        responseMetadata.get(messageId)?.[0] ?? undefined,
+                        responseMetadata.get(messageId)?.[1] ?? undefined
                     )
                     break
                 case 'copy':
@@ -480,8 +480,8 @@ export const createMynahUI = (ideApi: any, featureDevInitEnabled: boolean, codeT
                         eventId,
                         codeBlockIndex,
                         totalCodeBlocks,
-                        messageUserIntentMap.get(messageId)?.[0] ?? undefined,
-                        messageUserIntentMap.get(messageId)?.[1] ?? undefined
+                        responseMetadata.get(messageId)?.[0] ?? undefined,
+                        responseMetadata.get(messageId)?.[1] ?? undefined
                     )
                     mynahUI.notify({
                         type: NotificationType.SUCCESS,

From fc6a8a1d702099a10b5fd247b43b2deb6e368fe3 Mon Sep 17 00:00:00 2001
From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com>
Date: Fri, 11 Oct 2024 12:47:14 -0700
Subject: [PATCH 06/12] minor edits in Test files

---
 .../jetbrains/services/amazonq/TelemetryHelperTest.kt       | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/TelemetryHelperTest.kt b/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/TelemetryHelperTest.kt
index 0cba45227e8..95658f75304 100644
--- a/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/TelemetryHelperTest.kt
+++ b/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/TelemetryHelperTest.kt
@@ -420,7 +420,8 @@ class TelemetryHelperTest {
                 "insertionTargetType",
                 "eventId",
                 codeBlockIndex,
-                totalCodeBlocks
+                totalCodeBlocks,
+                lang
             )
         )
 
@@ -484,7 +485,8 @@ class TelemetryHelperTest {
                 emptyList(),
                 eventId,
                 codeBlockIndex,
-                totalCodeBlocks
+                totalCodeBlocks,
+                lang
             )
         )
 

From da650e83acd0252d9d338df1244899c8535347c1 Mon Sep 17 00:00:00 2001
From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com>
Date: Tue, 15 Oct 2024 12:02:31 -0700
Subject: [PATCH 07/12] Addressing comments and adding
 cwsprChatProgrammingLanguage to commons package

---
 gradle/libs.versions.toml                             |  2 +-
 .../controller/chat/messenger/ChatPromptHandler.kt    | 11 ++++++-----
 .../resources/telemetryOverride.json                  |  4 ----
 3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b063d950fbe..16744ec0278 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -25,7 +25,7 @@ mockitoKotlin = "5.4.0"
 mockk = "1.13.10"
 nimbus-jose-jwt = "9.40"
 node-gradle = "7.0.2"
-telemetryGenerator = "1.0.262"
+telemetryGenerator = "1.0.271"
 testLogger = "4.0.0"
 testRetry = "1.5.10"
 # test-only; platform provides slf4j transitively at runtime
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
index 52a47598ae3..5f6432021a2 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
@@ -33,7 +33,8 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) {
     private val codeReferences = mutableListOf()
     private var requestId: String = ""
     private var statusCode: Int = 0
-    private var codeBlockLanguage: String = "plaintext"
+    private val defaultTestGenResponseLanguage: String = "plaintext"
+    private var codeBlockLanguage: String = defaultTestGenResponseLanguage
 
     companion object {
         private val CODE_BLOCK_PATTERN = Regex("
\\s*
Date: Tue, 15 Oct 2024 12:24:51 -0700
Subject: [PATCH 08/12] minor edits

---
 .../cwc/controller/chat/telemetry/TelemetryHelper.kt         | 4 ++--
 .../jetbrains-community/resources/telemetryOverride.json     | 5 -----
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt
index 8a09dea2bb4..e2b12dcd21f 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt
@@ -220,7 +220,7 @@ class TelemetryHelper(private val context: AmazonQAppInitContext, private val se
                     cwsprChatCodeBlockIndex = message.codeBlockIndex?.toLong(),
                     cwsprChatTotalCodeBlocks = message.totalCodeBlocks?.toLong(),
                     cwsprChatHasProjectContext = getMessageHasProjectContext(message.messageId),
-                    cwsprChatProgrammingLanguage = message.codeBlockLanguage,
+//                    cwsprChatProgrammingLanguage = message.codeBlockLanguage,
                 )
                 ChatInteractWithMessageEvent.builder().apply {
                     conversationId(getConversationId(message.tabId).orEmpty())
@@ -246,7 +246,7 @@ class TelemetryHelper(private val context: AmazonQAppInitContext, private val se
                     cwsprChatCodeBlockIndex = message.codeBlockIndex?.toLong(),
                     cwsprChatTotalCodeBlocks = message.totalCodeBlocks?.toLong(),
                     cwsprChatHasProjectContext = getMessageHasProjectContext(message.messageId),
-                    cwsprChatProgrammingLanguage = message.codeBlockLanguage,
+//                    cwsprChatProgrammingLanguage = message.codeBlockLanguage,
                 )
                 ChatInteractWithMessageEvent.builder().apply {
                     conversationId(getConversationId(message.tabId).orEmpty())
diff --git a/plugins/core/jetbrains-community/resources/telemetryOverride.json b/plugins/core/jetbrains-community/resources/telemetryOverride.json
index f9f1c5ee8e3..bf40ff89e2e 100644
--- a/plugins/core/jetbrains-community/resources/telemetryOverride.json
+++ b/plugins/core/jetbrains-community/resources/telemetryOverride.json
@@ -99,11 +99,6 @@
             "type": "int",
             "description": "Cpu usage of LSP server"
         },
-        {
-            "name": "cwsprChatProgrammingLanguage",
-            "type": "string",
-            "description": "Programming language associated with the message"
-        },
         {
             "name": "cwsprChatConversationType",
             "type": "string",

From 20237b19b859c609e426d357b32dd90816f46522 Mon Sep 17 00:00:00 2001
From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com>
Date: Tue, 15 Oct 2024 14:13:03 -0700
Subject: [PATCH 09/12] Bumping the telemetry version

---
 gradle/libs.versions.toml                     |  2 +-
 .../chat/telemetry/TelemetryHelper.kt         |  4 +-
 .../resources/telemetryOverride.json          | 51 -------------------
 3 files changed, 3 insertions(+), 54 deletions(-)

diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 16744ec0278..b9ac4f26ff7 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -25,7 +25,7 @@ mockitoKotlin = "5.4.0"
 mockk = "1.13.10"
 nimbus-jose-jwt = "9.40"
 node-gradle = "7.0.2"
-telemetryGenerator = "1.0.271"
+telemetryGenerator = "1.0.272"
 testLogger = "4.0.0"
 testRetry = "1.5.10"
 # test-only; platform provides slf4j transitively at runtime
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt
index e2b12dcd21f..8a09dea2bb4 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt
@@ -220,7 +220,7 @@ class TelemetryHelper(private val context: AmazonQAppInitContext, private val se
                     cwsprChatCodeBlockIndex = message.codeBlockIndex?.toLong(),
                     cwsprChatTotalCodeBlocks = message.totalCodeBlocks?.toLong(),
                     cwsprChatHasProjectContext = getMessageHasProjectContext(message.messageId),
-//                    cwsprChatProgrammingLanguage = message.codeBlockLanguage,
+                    cwsprChatProgrammingLanguage = message.codeBlockLanguage,
                 )
                 ChatInteractWithMessageEvent.builder().apply {
                     conversationId(getConversationId(message.tabId).orEmpty())
@@ -246,7 +246,7 @@ class TelemetryHelper(private val context: AmazonQAppInitContext, private val se
                     cwsprChatCodeBlockIndex = message.codeBlockIndex?.toLong(),
                     cwsprChatTotalCodeBlocks = message.totalCodeBlocks?.toLong(),
                     cwsprChatHasProjectContext = getMessageHasProjectContext(message.messageId),
-//                    cwsprChatProgrammingLanguage = message.codeBlockLanguage,
+                    cwsprChatProgrammingLanguage = message.codeBlockLanguage,
                 )
                 ChatInteractWithMessageEvent.builder().apply {
                     conversationId(getConversationId(message.tabId).orEmpty())
diff --git a/plugins/core/jetbrains-community/resources/telemetryOverride.json b/plugins/core/jetbrains-community/resources/telemetryOverride.json
index bf40ff89e2e..e456dad31ef 100644
--- a/plugins/core/jetbrains-community/resources/telemetryOverride.json
+++ b/plugins/core/jetbrains-community/resources/telemetryOverride.json
@@ -639,57 +639,6 @@
                 }
             ]
         },
-        {
-            "name": "amazonq_interactWithMessage",
-            "description": "When a user interacts with a message in the conversation",
-            "metadata": [
-                {
-                    "type": "cwsprChatConversationId"
-                },
-                {
-                    "type": "cwsprChatMessageId"
-                },
-                {
-                    "type": "cwsprChatUserIntent",
-                    "required": false
-                },
-                {
-                    "type": "cwsprChatInteractionType"
-                },
-                {
-                    "type": "cwsprChatInteractionTarget",
-                    "required": false
-                },
-                {
-                    "type": "cwsprChatCodeBlockIndex",
-                    "required": false
-                },
-                {
-                    "type": "cwsprChatTotalCodeBlocks",
-                    "required": false
-                },
-                {
-                    "type": "cwsprChatAcceptedCharactersLength",
-                    "required": false
-                },
-                {
-                    "type": "cwsprChatAcceptedNumberOfLines",
-                    "required": false
-                },
-                {
-                    "type": "cwsprChatHasReference",
-                    "required": false
-                },
-                {
-                    "type": "credentialStartUrl",
-                    "required": false
-                },
-                {
-                    "type": "cwsprChatHasProjectContext",
-                    "required": false
-                }
-            ]
-        },
         {
             "name": "amazonq_modifyCode",
             "description": "Percentage of code modified by the user after copying/inserting code from a message",

From 1e18908ee5cd96342af28bfbbb166fcd587b6850 Mon Sep 17 00:00:00 2001
From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com>
Date: Wed, 16 Oct 2024 08:43:25 -0700
Subject: [PATCH 10/12] Moved extractCodeBlockLanguage to TextUtils and added
 test cases

---
 .../chat/messenger/ChatPromptHandler.kt       | 19 +-------
 .../aws/toolkits/core/utils/TextUtils.kt      | 18 ++++++++
 .../toolkits/jetbrains/utils/TextUtilsTest.kt | 45 +++++++++++++++++++
 3 files changed, 64 insertions(+), 18 deletions(-)

diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
index 5f6432021a2..e1804ef0f00 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/messenger/ChatPromptHandler.kt
@@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.onStart
 import software.amazon.awssdk.awscore.exception.AwsServiceException
 import software.amazon.awssdk.services.codewhispererstreaming.model.CodeWhispererStreamingException
 import software.aws.toolkits.core.utils.convertMarkdownToHTML
+import software.aws.toolkits.core.utils.extractCodeBlockLanguage
 import software.aws.toolkits.jetbrains.services.cwc.clients.chat.exceptions.ChatApiException
 import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.ChatRequestData
 import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.ChatResponseEvent
@@ -145,24 +146,6 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) {
             }
     }
 
-    private fun extractCodeBlockLanguage(message: String): String {
-        // This fulfills both the cases of unit test generation(java, python) and general use case(Non java and Non python) languages.
-        val codeBlockStart = message.indexOf("```")
-        if (codeBlockStart == -1) {
-            return defaultTestGenResponseLanguage
-        }
-
-        val languageStart = codeBlockStart + 3
-        val languageEnd = message.indexOf('\n', languageStart)
-
-        if (languageEnd == -1) {
-            return defaultTestGenResponseLanguage
-        }
-
-        val language = message.substring(languageStart, languageEnd).trim()
-        return if (language.isNotEmpty()) language else defaultTestGenResponseLanguage
-    }
-
     private fun processChatEvent(
         tabId: String,
         triggerId: String,
diff --git a/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt b/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
index 2c277aa1d97..f38ee6b06ca 100644
--- a/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
+++ b/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
@@ -17,6 +17,24 @@ fun convertMarkdownToHTML(markdown: String): String {
     return htmlRenderer.render(document)
 }
 
+fun extractCodeBlockLanguage(message: String): String {
+    // This fulfills both the cases of unit test generation(java, python) and general use case(Non java and Non python) languages.
+    val defaultTestGenResponseLanguage: String = "plaintext"
+    val codeBlockStart = message.indexOf("```")
+    if (codeBlockStart == -1) {
+        return defaultTestGenResponseLanguage
+    }
+
+    val languageStart = codeBlockStart + 3
+    val languageEnd = message.indexOf('\n', languageStart)
+
+    if (languageEnd == -1) {
+        return defaultTestGenResponseLanguage
+    }
+
+    return message.substring(languageStart, languageEnd).trim().ifEmpty { defaultTestGenResponseLanguage }
+}
+
 class CodeBlockRenderer(private val html: HtmlWriter) : NodeRenderer {
     override fun getNodeTypes(): Set> = setOf(FencedCodeBlock::class.java)
     override fun render(node: Node?) {
diff --git a/plugins/core/jetbrains-community/tst/software/aws/toolkits/jetbrains/utils/TextUtilsTest.kt b/plugins/core/jetbrains-community/tst/software/aws/toolkits/jetbrains/utils/TextUtilsTest.kt
index be5b9ece774..e93918fbc73 100644
--- a/plugins/core/jetbrains-community/tst/software/aws/toolkits/jetbrains/utils/TextUtilsTest.kt
+++ b/plugins/core/jetbrains-community/tst/software/aws/toolkits/jetbrains/utils/TextUtilsTest.kt
@@ -11,12 +11,15 @@ import org.intellij.lang.annotations.Language
 import org.junit.Rule
 import org.junit.Test
 import software.aws.toolkits.core.utils.convertMarkdownToHTML
+import software.aws.toolkits.core.utils.extractCodeBlockLanguage
 
 class TextUtilsTest {
     @Rule
     @JvmField
     val projectRule = ProjectRule()
 
+    private val defaultTestGenResponseLanguage = "plaintext"
+
     @Test
     fun textGetsFormatted() {
         @Language("JSON")
@@ -155,4 +158,46 @@ class TextUtilsTest {
         val actual = applyPatch(inputPatch, fileContent, inputFilePath)
         assertThat(actual).isEqualTo("dummy\ndummy\ndummy\ndummy\nfirst line\nthird line\nforth line")
     }
+
+    @Test
+    fun `extractCodeBlockLanguage returns default when no code block is present`() {
+        val message = "This is a message without a code block"
+        assertThat(defaultTestGenResponseLanguage).isEqualTo(extractCodeBlockLanguage(message))
+    }
+
+    @Test
+    fun `extractCodeBlockLanguage returns language when code block with language is present`() {
+        val message = "Here's a code block:\n```kotlin\nval x = 5\n```"
+        assertThat("kotlin").isEqualTo(extractCodeBlockLanguage(message))
+    }
+
+    @Test
+    fun `extractCodeBlockLanguage returns default when code block has no language specified`() {
+        val message = "Here's a code block:\n```\nval x = 5\n```"
+        assertThat(defaultTestGenResponseLanguage).isEqualTo(extractCodeBlockLanguage(message))
+    }
+
+    @Test
+    fun `extractCodeBlockLanguage returns language when multiple code blocks are present`() {
+        val message = "First block:\n```java\nint x = 5;\n```\nSecond block:\n```python\nx = 5\n```"
+        assertThat("java").isEqualTo(extractCodeBlockLanguage(message))
+    }
+
+    @Test
+    fun `extractCodeBlockLanguage returns default when code block is not closed`() {
+        val message = "Incomplete code block:\n```kotlin\nval x = 5"
+        assertThat("kotlin").isEqualTo(extractCodeBlockLanguage(message))
+    }
+
+    @Test
+    fun `extractCodeBlockLanguage trims whitespace from language`() {
+        val message = "Code block with spaces:\n```  kotlin  \nval x = 5\n```"
+        assertThat("kotlin").isEqualTo(extractCodeBlockLanguage(message))
+    }
+
+    @Test
+    fun `extractCodeBlockLanguage handles empty message`() {
+        val message = ""
+        assertThat(defaultTestGenResponseLanguage).isEqualTo(extractCodeBlockLanguage(message))
+    }
 }

From ee23f933512d8e15a20ca213c7ce8810a7629620 Mon Sep 17 00:00:00 2001
From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com>
Date: Wed, 16 Oct 2024 10:17:18 -0700
Subject: [PATCH 11/12] Minor edits

---
 .../core/src/software/aws/toolkits/core/utils/TextUtils.kt     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt b/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
index f38ee6b06ca..65a2886db82 100644
--- a/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
+++ b/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
@@ -20,12 +20,13 @@ fun convertMarkdownToHTML(markdown: String): String {
 fun extractCodeBlockLanguage(message: String): String {
     // This fulfills both the cases of unit test generation(java, python) and general use case(Non java and Non python) languages.
     val defaultTestGenResponseLanguage: String = "plaintext"
+    val indexStart: Int = 3
     val codeBlockStart = message.indexOf("```")
     if (codeBlockStart == -1) {
         return defaultTestGenResponseLanguage
     }
 
-    val languageStart = codeBlockStart + 3
+    val languageStart = codeBlockStart + indexStart
     val languageEnd = message.indexOf('\n', languageStart)
 
     if (languageEnd == -1) {

From b3a7e35a1fdee8e5be906d218d9e2e14cbc2d30e Mon Sep 17 00:00:00 2001
From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com>
Date: Wed, 16 Oct 2024 10:36:47 -0700
Subject: [PATCH 12/12] Minor edits

---
 .../core/src/software/aws/toolkits/core/utils/TextUtils.kt    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt b/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
index 65a2886db82..a7d7132d713 100644
--- a/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
+++ b/plugins/core/core/src/software/aws/toolkits/core/utils/TextUtils.kt
@@ -19,8 +19,8 @@ fun convertMarkdownToHTML(markdown: String): String {
 
 fun extractCodeBlockLanguage(message: String): String {
     // This fulfills both the cases of unit test generation(java, python) and general use case(Non java and Non python) languages.
-    val defaultTestGenResponseLanguage: String = "plaintext"
-    val indexStart: Int = 3
+    val defaultTestGenResponseLanguage = "plaintext"
+    val indexStart = 3
     val codeBlockStart = message.indexOf("```")
     if (codeBlockStart == -1) {
         return defaultTestGenResponseLanguage