Skip to content

Commit 69de65c

Browse files
fix(chat): Change the UI on output console and add spinner for writing process from agentic (aws#6936)
## Problem 1. On previous output console, the UI shows bash, now it need to be shell 2. For writing the file, there is no spinner so it has perceived latency illusion. ![image](https://github.com/user-attachments/assets/64ec9dbb-5717-4d7a-8a59-398e75c78af2) 3. For build failed case, the build log won't show up in code block and not formatted ## Solution 1. Updated the console UI text to "shell". 2. Identified the issue where the toolUseEvent wasn't stopping during file writing, preventing the spinner from appearing in the chat. Resolved by adding an if statement to handle the toolUseInput case appropriately. 3. Formatted the output for stderr. <img width="442" alt="Screenshot 2025-04-03 at 5 31 13 PM" src="https://github.com/user-attachments/assets/04bacb39-4945-484a-bc51-c3bda159b14e" /> --- - 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.
1 parent 93a0806 commit 69de65c

File tree

7 files changed

+100
-62
lines changed

7 files changed

+100
-62
lines changed

package-lock.json

Lines changed: 41 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"husky": "^9.0.7",
6565
"prettier": "^3.3.3",
6666
"prettier-plugin-sh": "^0.14.0",
67-
"pretty-quick": "^4.0.0",
67+
"pretty-quick": "^4.1.1",
6868
"ts-node": "^10.9.1",
6969
"typescript": "^5.0.4",
7070
"webpack": "^5.95.0",

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@
524524
"@aws-sdk/s3-request-presigner": "<3.731.0",
525525
"@aws-sdk/smithy-client": "<3.731.0",
526526
"@aws-sdk/util-arn-parser": "<3.731.0",
527-
"@aws/mynah-ui": "^4.27.0",
527+
"@aws/mynah-ui": "^4.28.0",
528528
"@gerhobbelt/gitignore-parser": "^0.2.0-9",
529529
"@iarna/toml": "^2.2.5",
530530
"@smithy/fetch-http-handler": "^5.0.1",

packages/core/src/amazonqTest/chat/controller/messenger/messenger.ts

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,16 @@ import { ChatItemType } from '../../../../amazonq/commons/model'
2727
import { ChatItemAction, ChatItemButton, ProgressField } from '@aws/mynah-ui'
2828
import * as CodeWhispererConstants from '../../../../codewhisperer/models/constants'
2929
import { TriggerPayload } from '../../../../codewhispererChat/controllers/chat/model'
30-
import {
31-
CodeWhispererStreamingServiceException,
32-
GenerateAssistantResponseCommandOutput,
33-
} from '@amzn/codewhisperer-streaming'
30+
import { GenerateAssistantResponseCommandOutput } from '@amzn/codewhisperer-streaming'
3431
import { Session } from '../../session/session'
3532
import { CodeReference } from '../../../../amazonq/webview/ui/apps/amazonqCommonsConnector'
36-
import { getHttpStatusCode, getRequestId, getTelemetryReasonDesc, ToolkitError } from '../../../../shared/errors'
33+
import { getTelemetryReasonDesc, ToolkitError } from '../../../../shared/errors'
3734
import { sleep, waitUntil } from '../../../../shared/utilities/timeoutUtils'
3835
import { keys } from '../../../../shared/utilities/tsUtils'
3936
import { cancellingProgressField, testGenCompletedField } from '../../../models/constants'
4037
import { testGenState } from '../../../../codewhisperer/models/model'
4138
import { TelemetryHelper } from '../../../../codewhisperer/util/telemetryHelper'
39+
import { extractErrorInfo } from '../../../../shared/utilities/messageUtil'
4240

4341
export type UnrecoverableErrorType = 'no-project-found' | 'no-open-file-found' | 'invalid-file-type'
4442

@@ -249,26 +247,19 @@ export class Messenger {
249247
{ timeout: 60000, truthy: true }
250248
)
251249
.catch((error: any) => {
252-
let errorMessage = 'Error reading chat stream.'
253-
let statusCode = undefined
254-
let requestID = undefined
255-
if (error instanceof CodeWhispererStreamingServiceException) {
256-
errorMessage = error.message
257-
statusCode = getHttpStatusCode(error) ?? 0
258-
requestID = getRequestId(error)
259-
}
250+
const errorInfo = extractErrorInfo(error)
260251
let message = 'This error is reported to the team automatically. Please try sending your message again.'
261-
if (errorMessage !== undefined) {
262-
message += `\n\nDetails: ${errorMessage}`
252+
if (errorInfo.errorMessage !== undefined) {
253+
message += `\n\nDetails: ${errorInfo.errorMessage}`
263254
}
264255

265-
if (statusCode !== undefined) {
266-
message += `\n\nStatus Code: ${statusCode}`
256+
if (errorInfo.statusCode !== undefined) {
257+
message += `\n\nStatus Code: ${errorInfo.statusCode}`
267258
}
268259

269-
if (requestID !== undefined) {
270-
messageId = requestID
271-
message += `\n\nRequest ID: ${requestID}`
260+
if (errorInfo.requestId !== undefined) {
261+
messageId = errorInfo.requestId
262+
message += `\n\nRequest ID: ${errorInfo.requestId}`
272263
}
273264
this.sendMessage(message.trim(), tabID, 'answer')
274265
})

packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import { EditorContextCommandType } from '../../../commands/registerCommands'
2020
import { ChatResponseStream as qdevChatResponseStream } from '@amzn/amazon-q-developer-streaming-client'
2121
import {
2222
ChatResponseStream as cwChatResponseStream,
23-
CodeWhispererStreamingServiceException,
2423
SupplementaryWebLink,
2524
ToolUse,
2625
} from '@amzn/codewhisperer-streaming'
@@ -29,7 +28,7 @@ import { ChatSession } from '../../../clients/chat/v0/chat'
2928
import { ChatException } from './model'
3029
import { CWCTelemetryHelper } from '../telemetryHelper'
3130
import { ChatPromptCommandType, DocumentReference, TriggerPayload } from '../model'
32-
import { getHttpStatusCode, getRequestId, ToolkitError } from '../../../../shared/errors'
31+
import { ToolkitError } from '../../../../shared/errors'
3332
import { keys } from '../../../../shared/utilities/tsUtils'
3433
import { getLogger } from '../../../../shared/logger/logger'
3534
import { FeatureAuthState } from '../../../../codewhisperer/util/authUtil'
@@ -46,6 +45,7 @@ import { ToolType, ToolUtils } from '../../../tools/toolUtils'
4645
import { ChatStream } from '../../../tools/chatStream'
4746
import path from 'path'
4847
import { CommandValidation } from '../../../tools/executeBash'
48+
import { extractErrorInfo } from '../../../../shared/utilities/messageUtil'
4949
import { noWriteTools, tools } from '../../../constants'
5050
import { Change } from 'diff'
5151
import { FsWriteParams } from '../../../tools/fsWrite'
@@ -279,6 +279,9 @@ export class Messenger {
279279
} else {
280280
// TODO: Handle the error
281281
}
282+
} else if (cwChatEvent.toolUseEvent?.stop === undefined && toolUseInput !== '') {
283+
// This is for the case when writing tool is executed. The toolUseEvent is non stop but in toolUseInput is not empty. In this case we need show user the current spinner UI.
284+
this.sendInitalStream(tabID, triggerID, undefined)
282285
}
283286

284287
if (
@@ -340,26 +343,21 @@ export class Messenger {
340343
{ timeout: 600000, truthy: true }
341344
)
342345
.catch((error: any) => {
343-
let errorMessage = 'Error reading chat stream.'
344-
let statusCode = undefined
345-
let requestID = undefined
346-
347-
if (error instanceof CodeWhispererStreamingServiceException) {
348-
errorMessage = error.message
349-
statusCode = getHttpStatusCode(error) ?? 0
350-
requestID = getRequestId(error)
351-
}
352-
346+
const errorInfo = extractErrorInfo(error)
353347
this.showChatExceptionMessage(
354-
{ errorMessage, statusCode: statusCode?.toString(), sessionID: undefined },
348+
{
349+
errorMessage: errorInfo.errorMessage,
350+
statusCode: errorInfo.statusCode?.toString(),
351+
sessionID: undefined,
352+
},
355353
tabID,
356-
requestID
354+
errorInfo.requestId
357355
)
358-
getLogger().error(`error: ${errorMessage} tabID: ${tabID} requestID: ${requestID}`)
356+
getLogger().error(`error: ${errorInfo.errorMessage} tabID: ${tabID} requestID: ${errorInfo.requestId}`)
359357

360358
followUps = []
361359
relatedSuggestions = []
362-
this.telemetryHelper.recordMessageResponseError(triggerPayload, tabID, statusCode ?? 0)
360+
this.telemetryHelper.recordMessageResponseError(triggerPayload, tabID, errorInfo.statusCode ?? 0)
363361
})
364362
.finally(async () => {
365363
if (

packages/core/src/codewhispererChat/tools/executeBash.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ export class ExecuteBash {
328328

329329
public queueDescription(updates: Writable): void {
330330
updates.write(`I will run the following shell command:\n`)
331-
updates.write('```bash\n' + this.command + '\n```')
331+
updates.write('```shell\n' + this.command + '\n```')
332332
updates.end()
333333
}
334334
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { CodeWhispererStreamingServiceException } from '@amzn/codewhisperer-streaming'
7+
import { getHttpStatusCode, getRequestId } from '../errors'
8+
9+
export interface MessageErrorInfo {
10+
errorMessage: string
11+
statusCode?: number
12+
requestId?: string
13+
}
14+
15+
export function extractErrorInfo(error: any): MessageErrorInfo {
16+
let errorMessage = 'Error reading chat stream.'
17+
let statusCode = undefined
18+
let requestId = undefined
19+
20+
if (error instanceof CodeWhispererStreamingServiceException) {
21+
errorMessage = error.message
22+
statusCode = getHttpStatusCode(error) ?? 0
23+
requestId = getRequestId(error)
24+
}
25+
26+
return {
27+
errorMessage,
28+
statusCode,
29+
requestId,
30+
}
31+
}

0 commit comments

Comments
 (0)