Skip to content

Commit f446fd2

Browse files
authored
Merge branch 'feature/agentic-chat' into agentic-chat
2 parents b4fdf03 + 28168cb commit f446fd2

File tree

18 files changed

+238
-62
lines changed

18 files changed

+238
-62
lines changed

packages/core/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@
459459
"AWS.amazonq.executeBash.reject": "Reject",
460460
"AWS.amazonq.chat.directive.pairProgrammingModeOn": "You are using **pair programming mode**: Q can now list files, preview code diffs and allow you to run shell commands.",
461461
"AWS.amazonq.chat.directive.pairProgrammingModeOff": "You turned off **pair programming mode**. Q will not include code diffs or run commands in the chat.",
462+
"AWS.amazonq.chat.directive.permission.readAndList": "I need permission to read files and list directories outside the workspace.",
462463
"AWS.amazonq.chat.directive.runCommandToProceed": "Run the command to proceed.",
463464
"AWS.toolkit.lambda.walkthrough.quickpickTitle": "Application Builder Walkthrough",
464465
"AWS.toolkit.lambda.walkthrough.title": "Get started building your application",

packages/core/resources/css/amazonq-webview.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,6 @@ div.mynah-card.padding-large {
130130
}
131131

132132
.mynah-chat-wrapper {
133-
padding: 0.75rem 1.25rem !important; /* 12px top/bottom, 20px left/right */
133+
padding: 0.75rem 1.25rem;
134134
box-sizing: border-box;
135135
}

packages/core/src/amazonq/webview/ui/apps/cwChatConnector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ export class Connector extends BaseConnector {
394394
if (answer.header) {
395395
answer.header.status = {
396396
icon: 'cancel' as MynahIconsType,
397-
text: 'Rejected',
397+
text: 'Change discarded',
398398
status: 'error',
399399
}
400400
answer.header.buttons = []

packages/core/src/amazonq/webview/ui/tabs/generator.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ export class TabDataGenerator {
5656
if (tabType === 'welcome') {
5757
return {}
5858
}
59+
const programmerModeCard: ChatItem | undefined = {
60+
type: ChatItemType.ANSWER,
61+
title: 'NEW FEATURE',
62+
header: {
63+
icon: 'code-block',
64+
iconStatus: 'primary',
65+
body: '## Pair programmer mode',
66+
},
67+
fullWidth: true,
68+
canBeDismissed: true,
69+
body: 'Pair code with Amazon Q, your virtual pair programmer that can work alongside you autonomously making real-time code changes on your behalf. \n\n Switch off pair programmer mode to get read-only responses from Q.',
70+
}
5971

6072
const regionProfileCard: ChatItem | undefined =
6173
this.regionProfile === undefined
@@ -67,6 +79,15 @@ export class TabDataGenerator {
6779
messageId: 'regionProfile',
6880
}
6981

82+
const welcomeMessage = `Hi! I'm Amazon Q.
83+
84+
You can ask me to:
85+
• Create new projects and files
86+
• Make changes to your codebase
87+
• Explain how to do things
88+
89+
Enter \`/\` to view quick actions. Use \`@\` to add saved prompts, files, folders, or your entire workspace as context.`
90+
7091
const tabData: MynahUIDataModel = {
7192
tabTitle: taskName ?? TabTypeDataMap[tabType].title,
7293
promptInputInfo:
@@ -76,10 +97,11 @@ export class TabDataGenerator {
7697
contextCommands: this.getContextCommands(tabType),
7798
chatItems: needWelcomeMessages
7899
? [
100+
...(tabType === 'cwc' || tabType === 'unknown' ? [programmerModeCard] : []),
79101
...(regionProfileCard ? [regionProfileCard] : []),
80102
{
81103
type: ChatItemType.ANSWER,
82-
body: isSMUS ? qChatIntroMessageForSMUS : TabTypeDataMap[tabType].welcome,
104+
body: isSMUS ? qChatIntroMessageForSMUS : welcomeMessage,
83105
},
84106
{
85107
type: ChatItemType.ANSWER,
@@ -88,7 +110,7 @@ export class TabDataGenerator {
88110
]
89111
: [...(regionProfileCard ? [regionProfileCard] : [])],
90112
promptInputOptions:
91-
tabType === 'cwc'
113+
tabType === 'cwc' || tabType === 'unknown'
92114
? [
93115
{
94116
type: 'switch',

packages/core/src/amazonq/webview/ui/texts/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const uiComponentsTexts = {
2525
copyToClipboard: 'Copied to clipboard',
2626
noMoreTabsTooltip: 'You can only open ten conversation tabs at a time.',
2727
codeSuggestionWithReferenceTitle: 'Some suggestions contain code with references.',
28-
spinnerText: 'Generating your answer...',
28+
spinnerText: 'Thinking...',
2929
changeAccepted: 'Change accepted',
3030
changeRejected: 'Change rejected',
3131
acceptChange: 'Accept change',

packages/core/src/codewhispererChat/constants.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,14 @@ export const defaultContextLengths: ContextLengths = {
5555
}
5656

5757
export const defaultStreamingResponseTimeoutInMs = 180_000
58+
59+
export const ignoredDirectoriesAndFiles = [
60+
// Dependency directories
61+
'node_modules',
62+
// Build outputs
63+
'dist',
64+
'build',
65+
'out',
66+
// OS specific files
67+
'.DS_Store',
68+
]

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1651,7 +1651,26 @@ export class ChatController {
16511651

16521652
await this.messenger.sendAIResponse(response, session, tabID, triggerID, triggerPayload)
16531653
} catch (e: any) {
1654-
this.telemetryHelper.recordMessageResponseError(triggerPayload, tabID, getHttpStatusCode(e) ?? 0)
1654+
let errorMessage: string
1655+
let requestID: string | undefined
1656+
1657+
if (e instanceof CodeWhispererStreamingServiceException) {
1658+
errorMessage = e.message
1659+
requestID = e.$metadata.requestId
1660+
} else {
1661+
errorMessage = 'Error is not CodeWhispererStreamingServiceException. '
1662+
if (e instanceof Error || e?.message) {
1663+
errorMessage += `Error message is: ${e.message}`
1664+
}
1665+
}
1666+
1667+
this.telemetryHelper.recordMessageResponseError(
1668+
triggerPayload,
1669+
tabID,
1670+
getHttpStatusCode(e) ?? 0,
1671+
requestID,
1672+
errorMessage
1673+
)
16551674
// clears session, record telemetry before this call
16561675
this.processException(e, tabID)
16571676
}

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

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ import {
5353
MynahIconsType,
5454
DetailedList,
5555
MynahUIDataModel,
56-
MynahIcons,
57-
Status,
5856
} from '@aws/mynah-ui'
5957
import { Database } from '../../../../shared/db/chatDb/chatDb'
6058
import { TabType } from '../../../../amazonq/webview/ui/storages/tabsStorage'
@@ -376,7 +374,11 @@ export class Messenger {
376374
changeList,
377375
explanation
378376
)
379-
await ToolUtils.queueDescription(tool, chatStream)
377+
await ToolUtils.queueDescription(
378+
tool,
379+
chatStream,
380+
chatStream.validation.requiresAcceptance
381+
)
380382
if (session.messageIdToUpdate === undefined && tool.type === ToolType.FsRead) {
381383
// Store the first messageId in a chain of tool uses
382384
session.setMessageIdToUpdate(toolUse.toolUseId)
@@ -538,7 +540,13 @@ export class Messenger {
538540

539541
followUps = []
540542
relatedSuggestions = []
541-
this.telemetryHelper.recordMessageResponseError(triggerPayload, tabID, errorInfo.statusCode ?? 0)
543+
this.telemetryHelper.recordMessageResponseError(
544+
triggerPayload,
545+
tabID,
546+
errorInfo.statusCode ?? 0,
547+
errorInfo.requestId,
548+
errorInfo.errorMessage
549+
)
542550
})
543551
.finally(async () => {
544552
if (session.sessionIdentifier && !this.isTriggerCancelled(triggerID)) {
@@ -748,13 +756,17 @@ export class Messenger {
748756
}
749757

750758
// Handle read tool and list directory messages
751-
if (toolUse?.name === ToolType.FsRead || toolUse?.name === ToolType.ListDirectory) {
759+
if (
760+
(toolUse?.name === ToolType.FsRead || toolUse?.name === ToolType.ListDirectory) &&
761+
!validation.requiresAcceptance
762+
) {
752763
return this.sendReadAndListDirToolMessage(toolUse, session, tabID, triggerID, messageIdToUpdate)
753764
}
754765

755766
// Handle file write tool, execute bash tool and bash command output log messages
756767
const buttons: ChatItemButton[] = []
757768
let header: ChatItemHeader | undefined = undefined
769+
let messageID: string = toolUse?.toolUseId ?? ''
758770
if (toolUse?.name === ToolType.ExecuteBash && message.startsWith('```shell')) {
759771
if (validation.requiresAcceptance) {
760772
const buttons: ChatItemButton[] = [
@@ -802,29 +814,20 @@ export class Messenger {
802814
{
803815
id: 'reject-code-diff',
804816
status: 'clear',
805-
icon: 'cancel' as MynahIconsType,
817+
icon: 'revert' as MynahIconsType,
818+
text: 'Undo',
806819
},
807820
]
808-
const status: {
809-
icon?: MynahIcons | MynahIconsType
810-
status?: {
811-
status?: Status
812-
icon?: MynahIcons | MynahIconsType
813-
text?: string
814-
}
815-
} = {
816-
status: {
817-
text: 'Accepted',
818-
status: 'success',
819-
},
820-
}
821821
header = {
822822
buttons,
823-
...status,
824823
fileList,
825824
}
826825
} else if (toolUse?.name === ToolType.ListDirectory || toolUse?.name === ToolType.FsRead) {
827826
if (validation.requiresAcceptance) {
827+
/** For Read and List Directory tools
828+
* requiredAcceptance = false, we use messageID = toolID and we keep on updating this messageID
829+
* requiredAcceptance = true, IDE sends messageID != toolID, some default value, as this overlaps with previous message. */
830+
messageID = 'toolUse'
828831
const buttons: ChatItemButton[] = [
829832
{
830833
id: 'confirm-tool-use',
@@ -840,7 +843,6 @@ export class Messenger {
840843
},
841844
]
842845
header = {
843-
body: 'shell',
844846
buttons,
845847
}
846848
}
@@ -859,7 +861,7 @@ export class Messenger {
859861
followUpsHeader: undefined,
860862
relatedSuggestions: undefined,
861863
triggerID,
862-
messageID: toolUse?.toolUseId ?? '',
864+
messageID,
863865
userIntent: undefined,
864866
codeBlockLanguage: undefined,
865867
contextList: undefined,

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { TriggerEvent, TriggerEventsStorage } from '../../storages/triggerEvents
3838
import globals from '../../../shared/extensionGlobals'
3939
import { getLogger } from '../../../shared/logger/logger'
4040
import { codeWhispererClient } from '../../../codewhisperer/client/codewhisperer'
41-
import { isAwsError } from '../../../shared/errors'
41+
import { getTelemetryReasonDesc, isAwsError } from '../../../shared/errors'
4242
import { ChatMessageInteractionType } from '../../../codewhisperer/client/codewhispereruserclient'
4343
import { supportedLanguagesList } from '../chat/chatRequest/converter'
4444
import { AuthUtil } from '../../../codewhisperer/util/authUtil'
@@ -603,7 +603,13 @@ export class CWCTelemetryHelper {
603603
this.messageStorage.delete(tabID)
604604
}
605605

606-
public recordMessageResponseError(triggerPayload: TriggerPayload, tabID: string, responseCode: number) {
606+
public recordMessageResponseError(
607+
triggerPayload: TriggerPayload,
608+
tabID: string,
609+
responseCode: number,
610+
requestID?: string,
611+
errorReason?: string
612+
) {
607613
const triggerEvent = this.triggerEventsStorage.getLastTriggerEventByTabID(tabID)
608614

609615
telemetry.amazonq_messageResponseError.emit({
@@ -617,8 +623,10 @@ export class CWCTelemetryHelper {
617623
cwsprChatActiveEditorImportCount: triggerPayload.codeQuery?.fullyQualifiedNames?.used?.length,
618624
cwsprChatResponseCode: responseCode,
619625
cwsprChatRequestLength: triggerPayload.message?.length ?? 0,
620-
cwsprChatConversationType: 'Chat',
626+
cwsprChatConversationType: triggerPayload.origin ? 'AgenticChat' : 'Chat',
621627
credentialStartUrl: AuthUtil.instance.startUrl,
628+
requestId: requestID,
629+
reasonDesc: getTelemetryReasonDesc(errorReason),
622630
})
623631
}
624632

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class ChatStream extends Writable {
2929
private readonly messageIdToUpdate: string | undefined,
3030
// emitEvent decides to show the streaming message or read/list directory tool message to the user.
3131
private readonly emitEvent: boolean,
32-
private readonly validation: CommandValidation,
32+
readonly validation: CommandValidation,
3333
private readonly isReadorList: boolean,
3434
private readonly changeList?: Change[],
3535
private readonly explanation?: string,
@@ -45,7 +45,13 @@ export class ChatStream extends Writable {
4545
if (this.explanation) {
4646
this.messenger.sendDirectiveMessage(tabID, triggerID, this.explanation)
4747
}
48-
if (validation.requiresAcceptance && this.toolUse?.name === 'executeBash') {
48+
if (validation.requiresAcceptance && isReadorList) {
49+
this.messenger.sendDirectiveMessage(
50+
tabID,
51+
triggerID,
52+
i18n('AWS.amazonq.chat.directive.permission.readAndList')
53+
)
54+
} else if (validation.requiresAcceptance && this.toolUse?.name === 'executeBash') {
4955
this.messenger.sendDirectiveMessage(
5056
tabID,
5157
triggerID,

0 commit comments

Comments
 (0)