From 80468480b7cc72bb19fef0a8deb16851494a7217 Mon Sep 17 00:00:00 2001 From: Ashish Reddy Podduturi Date: Tue, 15 Apr 2025 11:59:45 -0700 Subject: [PATCH 1/3] Fix for stop button for disappearing for subsequent conversations --- package-lock.json | 8 ++++---- packages/core/package.json | 2 +- packages/core/src/amazonq/webview/ui/followUps/handler.ts | 1 - packages/core/src/amazonq/webview/ui/main.ts | 1 - .../core/src/amazonq/webview/ui/messages/controller.ts | 3 +-- packages/core/src/amazonq/webview/ui/messages/handler.ts | 1 - .../core/src/amazonq/webview/ui/quickActions/handler.ts | 3 --- packages/core/src/shared/db/chatDb/chatDb.ts | 4 +++- 8 files changed, 9 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index ee2c9263304..c8ca368c17f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11940,9 +11940,9 @@ } }, "node_modules/@aws/mynah-ui": { - "version": "4.31.0-beta.2", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.31.0-beta.2.tgz", - "integrity": "sha512-2nRjWUlVYyTAvrZqOizs23PCL6dVDcdjQcf0ONrtHfZWl40kOhp6Z8bR3kOBB2TDf/FayV3NlSiewfatj4zLMw==", + "version": "4.31.0-beta.3", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.31.0-beta.3.tgz", + "integrity": "sha512-TkjZ/t2352fsNsPfGxyPlwoq1Y+PuEl51dc405GTzx1dIeUPFsNPha6qvDAdxhPDZyyeOviqJXXGtQBWTHcEBg==", "hasInstallScript": true, "license": "Apache License 2.0", "dependencies": { @@ -26777,7 +26777,7 @@ "@aws-sdk/s3-request-presigner": "<3.731.0", "@aws-sdk/smithy-client": "<3.731.0", "@aws-sdk/util-arn-parser": "<3.731.0", - "@aws/mynah-ui": "^4.31.0-beta.2", + "@aws/mynah-ui": "^4.31.0-beta.3", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "@iarna/toml": "^2.2.5", "@smithy/fetch-http-handler": "^5.0.1", diff --git a/packages/core/package.json b/packages/core/package.json index 0c426b0ec93..f4ca3f6d5a5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -525,7 +525,7 @@ "@aws-sdk/s3-request-presigner": "<3.731.0", "@aws-sdk/smithy-client": "<3.731.0", "@aws-sdk/util-arn-parser": "<3.731.0", - "@aws/mynah-ui": "^4.31.0-beta.2", + "@aws/mynah-ui": "^4.31.0-beta.3", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "@iarna/toml": "^2.2.5", "@smithy/fetch-http-handler": "^5.0.1", diff --git a/packages/core/src/amazonq/webview/ui/followUps/handler.ts b/packages/core/src/amazonq/webview/ui/followUps/handler.ts index 4cb7c8530dc..d93644f9279 100644 --- a/packages/core/src/amazonq/webview/ui/followUps/handler.ts +++ b/packages/core/src/amazonq/webview/ui/followUps/handler.ts @@ -47,7 +47,6 @@ export class FollowUpInteractionHandler { if (followUp.prompt !== undefined) { this.mynahUI.updateStore(tabID, { loadingChat: true, - cancelButtonWhenLoading: false, promptInputDisabledState: true, }) this.mynahUI.addChatItem(tabID, { diff --git a/packages/core/src/amazonq/webview/ui/main.ts b/packages/core/src/amazonq/webview/ui/main.ts index 8ff69fa51cd..6fb2ce273d8 100644 --- a/packages/core/src/amazonq/webview/ui/main.ts +++ b/packages/core/src/amazonq/webview/ui/main.ts @@ -471,7 +471,6 @@ export const createMynahUI = ( ) { mynahUI.updateStore(tabID, { loadingChat: true, - cancelButtonWhenLoading: false, promptInputDisabledState: true, }) diff --git a/packages/core/src/amazonq/webview/ui/messages/controller.ts b/packages/core/src/amazonq/webview/ui/messages/controller.ts index df9e5454ce1..cfcb196022c 100644 --- a/packages/core/src/amazonq/webview/ui/messages/controller.ts +++ b/packages/core/src/amazonq/webview/ui/messages/controller.ts @@ -88,7 +88,6 @@ export class MessageController { this.mynahUI.updateStore(selectedTab.id, { loadingChat: true, - cancelButtonWhenLoading: false, promptInputDisabledState: true, }) this.mynahUI.addChatItem(selectedTab.id, message) @@ -120,7 +119,7 @@ export class MessageController { this.mynahUI.updateStore(newTabID, { loadingChat: true, - cancelButtonWhenLoading: false, + // cancelButtonWhenLoading: false, promptInputDisabledState: true, }) diff --git a/packages/core/src/amazonq/webview/ui/messages/handler.ts b/packages/core/src/amazonq/webview/ui/messages/handler.ts index 92a96d1c2da..5c9137e7868 100644 --- a/packages/core/src/amazonq/webview/ui/messages/handler.ts +++ b/packages/core/src/amazonq/webview/ui/messages/handler.ts @@ -36,7 +36,6 @@ export class TextMessageHandler { this.mynahUI.updateStore(tabID, { loadingChat: true, - cancelButtonWhenLoading: false, promptInputDisabledState: true, }) diff --git a/packages/core/src/amazonq/webview/ui/quickActions/handler.ts b/packages/core/src/amazonq/webview/ui/quickActions/handler.ts index 221fb4e53b6..ecae150b96e 100644 --- a/packages/core/src/amazonq/webview/ui/quickActions/handler.ts +++ b/packages/core/src/amazonq/webview/ui/quickActions/handler.ts @@ -272,7 +272,6 @@ export class QuickActionHandler { this.mynahUI.updateStore(affectedTabId, { loadingChat: true, - cancelButtonWhenLoading: false, promptInputDisabledState: true, }) @@ -310,7 +309,6 @@ export class QuickActionHandler { if (currentTabType !== 'unknown' && currentTabType !== 'welcome') { affectedTabId = this.mynahUI.updateStore('', { loadingChat: true, - cancelButtonWhenLoading: false, }) } @@ -335,7 +333,6 @@ export class QuickActionHandler { // disable chat prompt this.mynahUI.updateStore(affectedTabId, { loadingChat: true, - cancelButtonWhenLoading: false, }) this.connector.transform(affectedTabId) diff --git a/packages/core/src/shared/db/chatDb/chatDb.ts b/packages/core/src/shared/db/chatDb/chatDb.ts index 2b949b23869..07bb8c325e2 100644 --- a/packages/core/src/shared/db/chatDb/chatDb.ts +++ b/packages/core/src/shared/db/chatDb/chatDb.ts @@ -483,7 +483,9 @@ export class Database { } // Make sure the last stored message is from the assistant (type === 'answer'), else drop - if (messages.length > 0 && messages[messages.length - 1].type === ('prompt' as ChatItemType)) { + if (messages.length > 0 && messages[messages.length - 1].userInputMessageContext) { + // eslint-disable-next-line aws-toolkits/no-console-log + console.log('found the last message to be userInputMessage') messages.pop() this.logger.debug('Dropped trailing user message') } From f6f30e40e2e61c4508a7a21f3ae582989c9669a7 Mon Sep 17 00:00:00 2001 From: Ashish Reddy Podduturi Date: Tue, 15 Apr 2025 12:03:50 -0700 Subject: [PATCH 2/3] revert for chatDb --- packages/core/src/shared/db/chatDb/chatDb.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/core/src/shared/db/chatDb/chatDb.ts b/packages/core/src/shared/db/chatDb/chatDb.ts index 07bb8c325e2..2b949b23869 100644 --- a/packages/core/src/shared/db/chatDb/chatDb.ts +++ b/packages/core/src/shared/db/chatDb/chatDb.ts @@ -483,9 +483,7 @@ export class Database { } // Make sure the last stored message is from the assistant (type === 'answer'), else drop - if (messages.length > 0 && messages[messages.length - 1].userInputMessageContext) { - // eslint-disable-next-line aws-toolkits/no-console-log - console.log('found the last message to be userInputMessage') + if (messages.length > 0 && messages[messages.length - 1].type === ('prompt' as ChatItemType)) { messages.pop() this.logger.debug('Dropped trailing user message') } From 40e3f3d558ef0fe820c55b8c719a92668b0babdb Mon Sep 17 00:00:00 2001 From: Ashish Reddy Podduturi Date: Tue, 15 Apr 2025 14:40:10 -0700 Subject: [PATCH 3/3] fix for opening prompt while agentic loop and lint fix for duplicate --- .../webview/ui/apps/cwChatConnector.ts | 2 +- .../amazonq/webview/ui/messages/controller.ts | 1 - .../webview/ui/quickActions/handler.ts | 220 ++++++++---------- 3 files changed, 99 insertions(+), 124 deletions(-) diff --git a/packages/core/src/amazonq/webview/ui/apps/cwChatConnector.ts b/packages/core/src/amazonq/webview/ui/apps/cwChatConnector.ts index 4f23045109f..8c4ef3170e6 100644 --- a/packages/core/src/amazonq/webview/ui/apps/cwChatConnector.ts +++ b/packages/core/src/amazonq/webview/ui/apps/cwChatConnector.ts @@ -290,7 +290,7 @@ export class Connector extends BaseConnector { } if (messageData.type === 'asyncEventProgressMessage') { - const isPromptInputDisabled = true + const isPromptInputDisabled = false this.onAsyncEventProgress( messageData.tabID, messageData.inProgress, diff --git a/packages/core/src/amazonq/webview/ui/messages/controller.ts b/packages/core/src/amazonq/webview/ui/messages/controller.ts index cfcb196022c..a6d4973d293 100644 --- a/packages/core/src/amazonq/webview/ui/messages/controller.ts +++ b/packages/core/src/amazonq/webview/ui/messages/controller.ts @@ -119,7 +119,6 @@ export class MessageController { this.mynahUI.updateStore(newTabID, { loadingChat: true, - // cancelButtonWhenLoading: false, promptInputDisabledState: true, }) diff --git a/packages/core/src/amazonq/webview/ui/quickActions/handler.ts b/packages/core/src/amazonq/webview/ui/quickActions/handler.ts index ecae150b96e..5fefe5df2bf 100644 --- a/packages/core/src/amazonq/webview/ui/quickActions/handler.ts +++ b/packages/core/src/amazonq/webview/ui/quickActions/handler.ts @@ -103,27 +103,46 @@ export class QuickActionHandler { } } - private handleScanCommand(tabID: string, eventId: string | undefined) { - if (!this.isScanEnabled) { + /** + * Common helper method to handle specialized tab commands (scan, test, transform) + * @param options Configuration options for the specialized tab + */ + private handleSpecializedTabCommand(options: { + tabID: string // Current tab ID + eventId?: string // Event ID for tracking + isEnabled: boolean // Feature flag + tabType: TabType // Type of tab to create/switch to + existingTabType: TabType // Type to look for in existing tabs + taskName?: string // Optional task name + promptText?: string // Optional prompt text + onExistingTab: (tabId: string) => void // Callback for existing tab + onNewTab: (tabId: string) => void // Callback for new tab + }): void { + if (!options.isEnabled) { return } - let scanTabId: string | undefined = undefined + // Check if a tab of this type already exists + let existingTabId: string | undefined = undefined for (const tab of this.tabsStorage.getTabs()) { - if (tab.type === 'review') { - scanTabId = tab.id + if (tab.type === options.existingTabType) { + existingTabId = tab.id + break } } - if (scanTabId !== undefined) { - this.mynahUI.selectTab(scanTabId, eventId || '') - this.connector.onTabChange(scanTabId) - this.connector.scans(scanTabId) + // If tab exists, select it and run the callback + if (existingTabId !== undefined) { + this.mynahUI.selectTab(existingTabId, options.eventId || '') + this.connector.onTabChange(existingTabId) + options.onExistingTab(existingTabId) return } - let affectedTabId: string | undefined = tabID - // if there is no scan tab, open a new one + // Otherwise, create a new tab + let affectedTabId: string | undefined = options.tabID + + // If current tab is not unknown or welcome, create a new tab const currentTabType = this.tabsStorage.getTab(affectedTabId)?.type if (currentTabType !== 'unknown' && currentTabType !== 'welcome') { affectedTabId = this.mynahUI.updateStore('', { @@ -131,79 +150,75 @@ export class QuickActionHandler { }) } + // Handle case where we can't create a new tab if (affectedTabId === undefined) { this.mynahUI.notify({ content: uiComponentsTexts.noMoreTabsTooltip, type: NotificationType.WARNING, }) return - } else { - this.tabsStorage.updateTabTypeFromUnknown(affectedTabId, 'review') - this.connector.onKnownTabOpen(affectedTabId) - this.connector.onUpdateTabType(affectedTabId) - - // reset chat history - this.mynahUI.updateStore(affectedTabId, { - chatItems: [], - }) - - this.mynahUI.updateStore(affectedTabId, this.tabDataGenerator.getTabData('review', true, undefined)) // creating a new tab and printing some title - - // disable chat prompt - this.mynahUI.updateStore(affectedTabId, { - loadingChat: true, - }) - this.connector.scans(affectedTabId) } - } - private handleTestCommand(chatPrompt: ChatPrompt, tabID: string, eventId: string | undefined) { - if (!this.isTestEnabled) { - return - } - const testTabId = this.tabsStorage.getTabs().find((tab) => tab.type === 'testgen')?.id - const realPromptText = chatPrompt.escapedPrompt?.trim() ?? '' + // Set up the new tab + this.tabsStorage.updateTabTypeFromUnknown(affectedTabId, options.tabType) + this.connector.onKnownTabOpen(affectedTabId) + this.connector.onUpdateTabType(affectedTabId) - if (testTabId !== undefined) { - this.mynahUI.selectTab(testTabId, eventId || '') - this.connector.onTabChange(testTabId) - this.connector.startTestGen(testTabId, realPromptText) - return - } + // Reset chat history + this.mynahUI.updateStore(affectedTabId, { + chatItems: [], + }) - let affectedTabId: string | undefined = tabID - // if there is no test tab, open a new one - const currentTabType = this.tabsStorage.getTab(affectedTabId)?.type - if (currentTabType !== 'unknown' && currentTabType !== 'welcome') { - affectedTabId = this.mynahUI.updateStore('', { - loadingChat: true, - }) - } + // Set tab data + const isEmpty = options.promptText === undefined || options.promptText === '' + this.mynahUI.updateStore( + affectedTabId, + this.tabDataGenerator.getTabData(options.tabType, isEmpty, options.taskName) + ) - if (affectedTabId === undefined) { - this.mynahUI.notify({ - content: uiComponentsTexts.noMoreTabsTooltip, - type: NotificationType.WARNING, - }) - return - } else { - this.tabsStorage.updateTabTypeFromUnknown(affectedTabId, 'testgen') - this.connector.onKnownTabOpen(affectedTabId) - this.connector.onUpdateTabType(affectedTabId) + // Disable chat prompt while loading + this.mynahUI.updateStore(affectedTabId, { + loadingChat: true, + }) - // reset chat history - this.mynahUI.updateStore(affectedTabId, { - chatItems: [], - }) + // Run the callback for the new tab + options.onNewTab(affectedTabId) + } - // creating a new tab and printing some title - this.mynahUI.updateStore( - affectedTabId, - this.tabDataGenerator.getTabData('testgen', realPromptText === '', 'Q - Test') - ) + private handleScanCommand(tabID: string, eventId: string | undefined) { + this.handleSpecializedTabCommand({ + tabID, + eventId, + isEnabled: this.isScanEnabled, + tabType: 'review', + existingTabType: 'review', + onExistingTab: (tabId) => { + this.connector.scans(tabId) + }, + onNewTab: (tabId) => { + this.connector.scans(tabId) + }, + }) + } - this.connector.startTestGen(affectedTabId, realPromptText) - } + private handleTestCommand(chatPrompt: ChatPrompt, tabID: string, eventId: string | undefined) { + const realPromptText = chatPrompt.escapedPrompt?.trim() ?? '' + + this.handleSpecializedTabCommand({ + tabID, + eventId, + isEnabled: this.isTestEnabled, + tabType: 'testgen', + existingTabType: 'testgen', + taskName: 'Q - Test', + promptText: realPromptText, + onExistingTab: (tabId) => { + this.connector.startTestGen(tabId, realPromptText) + }, + onNewTab: (tabId) => { + this.connector.startTestGen(tabId, realPromptText) + }, + }) } private handleCommand(props: HandleCommandProps) { @@ -285,58 +300,19 @@ export class QuickActionHandler { } private handleGumbyCommand(tabID: string, eventId: string | undefined) { - if (!this.isGumbyEnabled) { - return - } - - let gumbyTabId: string | undefined = undefined - - for (const tab of this.tabsStorage.getTabs()) { - if (tab.type === 'gumby') { - gumbyTabId = tab.id - } - } - - if (gumbyTabId !== undefined) { - this.mynahUI.selectTab(gumbyTabId, eventId || '') - this.connector.onTabChange(gumbyTabId) - return - } - - let affectedTabId: string | undefined = tabID - // if there is no gumby tab, open a new one - const currentTabType = this.tabsStorage.getTab(affectedTabId)?.type - if (currentTabType !== 'unknown' && currentTabType !== 'welcome') { - affectedTabId = this.mynahUI.updateStore('', { - loadingChat: true, - }) - } - - if (affectedTabId === undefined) { - this.mynahUI.notify({ - content: uiComponentsTexts.noMoreTabsTooltip, - type: NotificationType.WARNING, - }) - return - } else { - this.tabsStorage.updateTabTypeFromUnknown(affectedTabId, 'gumby') - this.connector.onKnownTabOpen(affectedTabId) - this.connector.onUpdateTabType(affectedTabId) - - // reset chat history - this.mynahUI.updateStore(affectedTabId, { - chatItems: [], - }) - - this.mynahUI.updateStore(affectedTabId, this.tabDataGenerator.getTabData('gumby', true, undefined)) - - // disable chat prompt - this.mynahUI.updateStore(affectedTabId, { - loadingChat: true, - }) - - this.connector.transform(affectedTabId) - } + this.handleSpecializedTabCommand({ + tabID, + eventId, + isEnabled: this.isGumbyEnabled, + tabType: 'gumby', + existingTabType: 'gumby', + onExistingTab: () => { + // Nothing special to do for existing transform tab + }, + onNewTab: (tabId) => { + this.connector.transform(tabId) + }, + }) } private handleClearCommand(tabID: string) {