From f0f0f01ca50616723dd6ba346219aa5cda4bf4f0 Mon Sep 17 00:00:00 2001 From: Randall-Jiang Date: Tue, 15 Apr 2025 11:20:41 -0700 Subject: [PATCH 1/4] When user reject executing command, loop will be terminated, reject won't send to LLM --- .../controllers/chat/controller.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/core/src/codewhispererChat/controllers/chat/controller.ts b/packages/core/src/codewhispererChat/controllers/chat/controller.ts index e0cd1c699e8..7182d818cdf 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/controller.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/controller.ts @@ -928,13 +928,24 @@ export class ChatController { case 'reject-shell-command': case 'reject-tool-use': await this.rejectShellCommand(message) - await this.processToolUseMessage(message) + if (message.tabID) { + await this.sendCommandRejectMessage(message.tabID) + } + if (message.triggerId) { + ConversationTracker.getInstance().markTriggerCompleted(message.triggerId) + } break default: getLogger().warn(`Unhandled action: ${message.action.id}`) } } + private async sendCommandRejectMessage(tabID: string) { + const session = this.sessionStorage.getSession(tabID) + session.setAgenticLoopInProgress(false) + this.messenger.sendDirectiveMessage(tabID, '', 'Command Rejected') + } + private async restoreBackup(message: CustomFormActionMessage) { const tabID = message.tabID const toolUseId = message.action.formItemValues?.toolUseId From 5f64d905e7378649c835c4e54d502d54cf9b02ae Mon Sep 17 00:00:00 2001 From: Randall-Jiang Date: Tue, 15 Apr 2025 10:59:30 -0700 Subject: [PATCH 2/4] fix(chat): Add Undo clickable button and string change (#7051) ## Problem The Ux design does not meet the requirement ## Solution Make the undo a clickable button and change the string when user reject the generated code ![image](https://github.com/user-attachments/assets/53bf59e8-ffc6-45ba-9944-236e4e3bae69) --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- .../webview/ui/apps/cwChatConnector.ts | 2 +- .../controllers/chat/messenger/messenger.ts | 19 ++----------------- 2 files changed, 3 insertions(+), 18 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..7ce9b2cc00d 100644 --- a/packages/core/src/amazonq/webview/ui/apps/cwChatConnector.ts +++ b/packages/core/src/amazonq/webview/ui/apps/cwChatConnector.ts @@ -394,7 +394,7 @@ export class Connector extends BaseConnector { if (answer.header) { answer.header.status = { icon: 'cancel' as MynahIconsType, - text: 'Rejected', + text: 'Change discarded', status: 'error', } answer.header.buttons = [] diff --git a/packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts b/packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts index 91e1bc512f7..3a4c5799def 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts @@ -53,8 +53,6 @@ import { MynahIconsType, DetailedList, MynahUIDataModel, - MynahIcons, - Status, } from '@aws/mynah-ui' import { Database } from '../../../../shared/db/chatDb/chatDb' import { TabType } from '../../../../amazonq/webview/ui/storages/tabsStorage' @@ -810,25 +808,12 @@ export class Messenger { { id: 'reject-code-diff', status: 'clear', - icon: 'cancel' as MynahIconsType, + icon: 'revert' as MynahIconsType, + text: 'Undo', }, ] - const status: { - icon?: MynahIcons | MynahIconsType - status?: { - status?: Status - icon?: MynahIcons | MynahIconsType - text?: string - } - } = { - status: { - text: 'Accepted', - status: 'success', - }, - } header = { buttons, - ...status, fileList, } } else if (toolUse?.name === ToolType.ListDirectory || toolUse?.name === ToolType.FsRead) { From d637201f0604457908c6fa9a2942b03b1ae1f79f Mon Sep 17 00:00:00 2001 From: chungjac Date: Tue, 15 Apr 2025 11:01:12 -0700 Subject: [PATCH 3/4] telemetry(chat): request id and error message in error metric (#7045) ## Problem - do not have `requestID` and `errorMessage` in amazonq_messageResponseError ## Solution - emit amazonq_messageResponseError event with `requestID` and `errorMessage` --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- .../controllers/chat/controller.ts | 21 ++++++++++++++++++- .../controllers/chat/messenger/messenger.ts | 8 ++++++- .../controllers/chat/telemetryHelper.ts | 14 ++++++++++--- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/core/src/codewhispererChat/controllers/chat/controller.ts b/packages/core/src/codewhispererChat/controllers/chat/controller.ts index 7182d818cdf..701bd8a9367 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/controller.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/controller.ts @@ -1662,7 +1662,26 @@ export class ChatController { await this.messenger.sendAIResponse(response, session, tabID, triggerID, triggerPayload) } catch (e: any) { - this.telemetryHelper.recordMessageResponseError(triggerPayload, tabID, getHttpStatusCode(e) ?? 0) + let errorMessage: string + let requestID: string | undefined + + if (e instanceof CodeWhispererStreamingServiceException) { + errorMessage = e.message + requestID = e.$metadata.requestId + } else { + errorMessage = 'Error is not CodeWhispererStreamingServiceException. ' + if (e instanceof Error || e?.message) { + errorMessage += `Error message is: ${e.message}` + } + } + + this.telemetryHelper.recordMessageResponseError( + triggerPayload, + tabID, + getHttpStatusCode(e) ?? 0, + requestID, + errorMessage + ) // clears session, record telemetry before this call this.processException(e, tabID) } diff --git a/packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts b/packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts index 3a4c5799def..2296377922e 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts @@ -540,7 +540,13 @@ export class Messenger { followUps = [] relatedSuggestions = [] - this.telemetryHelper.recordMessageResponseError(triggerPayload, tabID, errorInfo.statusCode ?? 0) + this.telemetryHelper.recordMessageResponseError( + triggerPayload, + tabID, + errorInfo.statusCode ?? 0, + errorInfo.requestId, + errorInfo.errorMessage + ) }) .finally(async () => { if (session.sessionIdentifier && !this.isTriggerCancelled(triggerID)) { diff --git a/packages/core/src/codewhispererChat/controllers/chat/telemetryHelper.ts b/packages/core/src/codewhispererChat/controllers/chat/telemetryHelper.ts index 52bb1674f4d..14f07c536e4 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/telemetryHelper.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/telemetryHelper.ts @@ -38,7 +38,7 @@ import { TriggerEvent, TriggerEventsStorage } from '../../storages/triggerEvents import globals from '../../../shared/extensionGlobals' import { getLogger } from '../../../shared/logger/logger' import { codeWhispererClient } from '../../../codewhisperer/client/codewhisperer' -import { isAwsError } from '../../../shared/errors' +import { getTelemetryReasonDesc, isAwsError } from '../../../shared/errors' import { ChatMessageInteractionType } from '../../../codewhisperer/client/codewhispereruserclient' import { supportedLanguagesList } from '../chat/chatRequest/converter' import { AuthUtil } from '../../../codewhisperer/util/authUtil' @@ -603,7 +603,13 @@ export class CWCTelemetryHelper { this.messageStorage.delete(tabID) } - public recordMessageResponseError(triggerPayload: TriggerPayload, tabID: string, responseCode: number) { + public recordMessageResponseError( + triggerPayload: TriggerPayload, + tabID: string, + responseCode: number, + requestID?: string, + errorReason?: string + ) { const triggerEvent = this.triggerEventsStorage.getLastTriggerEventByTabID(tabID) telemetry.amazonq_messageResponseError.emit({ @@ -617,8 +623,10 @@ export class CWCTelemetryHelper { cwsprChatActiveEditorImportCount: triggerPayload.codeQuery?.fullyQualifiedNames?.used?.length, cwsprChatResponseCode: responseCode, cwsprChatRequestLength: triggerPayload.message?.length ?? 0, - cwsprChatConversationType: 'Chat', + cwsprChatConversationType: triggerPayload.origin ? 'AgenticChat' : 'Chat', credentialStartUrl: AuthUtil.instance.startUrl, + requestId: requestID, + reasonDesc: getTelemetryReasonDesc(errorReason), }) } From 8ac0127b7b75569b639d48d56688c069f31202b9 Mon Sep 17 00:00:00 2001 From: Randall-Jiang Date: Tue, 15 Apr 2025 12:43:56 -0700 Subject: [PATCH 4/4] enble use input after user reject execute command --- .../core/src/codewhispererChat/controllers/chat/controller.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core/src/codewhispererChat/controllers/chat/controller.ts b/packages/core/src/codewhispererChat/controllers/chat/controller.ts index 701bd8a9367..d1d4e3bc4ce 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/controller.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/controller.ts @@ -894,6 +894,8 @@ export class ChatController { currentToolUse.name === ToolType.ListDirectory) ) { session.toolUseWithError.error = new Error('Tool use was rejected by the user.') + session.setToolUseWithError(undefined) + this.messenger.sendAsyncEventProgress(message.tabID!, false, undefined) } else { getLogger().error( `toolUse name: ${currentToolUse!.name} of toolUseWithError in the stored session doesn't match when click shell command reject button.`