Skip to content

Commit 2028754

Browse files
committed
fix(amazonq): Grouping read tool messages under contextList (#6975)
- We show read tool message for each file read which is occupying the entire chat with these messages which is not super important. - Group all the read tool messaged under ContextList. ![image](https://github.com/user-attachments/assets/194e4ca1-7645-4419-8b9b-b5ac9a58279f) --- - 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 e9e8a94 commit 2028754

File tree

10 files changed

+226
-67
lines changed

10 files changed

+226
-67
lines changed

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,33 @@ export class Connector extends BaseConnector {
179179
}
180180
}
181181

182+
private processToolMessage = async (messageData: any): Promise<void> => {
183+
if (this.onChatAnswerUpdated === undefined) {
184+
return
185+
}
186+
const answer: CWCChatItem = {
187+
type: messageData.messageType,
188+
messageId: messageData.messageID ?? messageData.triggerID,
189+
body: messageData.message,
190+
followUp: messageData.followUps,
191+
canBeVoted: messageData.canBeVoted ?? false,
192+
codeReference: messageData.codeReference,
193+
userIntent: messageData.contextList,
194+
codeBlockLanguage: messageData.codeBlockLanguage,
195+
contextList: messageData.contextList,
196+
title: messageData.title,
197+
buttons: messageData.buttons,
198+
fileList: messageData.fileList,
199+
header: messageData.header ?? undefined,
200+
padding: messageData.padding ?? undefined,
201+
fullWidth: messageData.fullWidth ?? undefined,
202+
codeBlockActions: messageData.codeBlockActions ?? undefined,
203+
rootFolderTitle: messageData.rootFolderTitle,
204+
}
205+
this.onChatAnswerUpdated(messageData.tabID, answer)
206+
return
207+
}
208+
182209
private storeChatItem(tabId: string, messageId: string, item: ChatItem): void {
183210
if (!this.chatItems.has(tabId)) {
184211
this.chatItems.set(tabId, new Map())
@@ -238,6 +265,11 @@ export class Connector extends BaseConnector {
238265
return
239266
}
240267

268+
if (messageData.type === 'toolMessage') {
269+
await this.processToolMessage(messageData)
270+
return
271+
}
272+
241273
if (messageData.type === 'editorContextCommandMessage') {
242274
await this.processEditorContextCommandMessage(messageData)
243275
return

packages/core/src/amazonq/webview/ui/connector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export interface ConnectorProps {
7878
sendMessageToExtension: (message: ExtensionMessage) => void
7979
onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void
8080
onRunTestMessageReceived?: (tabID: string, showRunTestMessage: boolean) => void
81-
onChatAnswerUpdated?: (tabID: string, message: ChatItem) => void
81+
onChatAnswerUpdated?: (tabID: string, message: CWCChatItem) => void
8282
onChatAnswerReceived?: (tabID: string, message: ChatItem, messageData: any) => void
8383
onWelcomeFollowUpClicked: (tabID: string, welcomeFollowUpType: WelcomeFollowupType) => void
8484
onAsyncEventProgress: (tabID: string, inProgress: boolean, message: string | undefined) => void

packages/core/src/amazonq/webview/ui/main.ts

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,41 @@ export const createMynahUI = (
100100
welcomeCount += 1
101101
}
102102

103+
/**
104+
* Creates a file list header from context list
105+
* @param contextList List of file contexts
106+
* @param rootFolderTitle Title for the root folder
107+
* @returns Header object with file list
108+
*/
109+
const createFileListHeader = (contextList: any[], rootFolderTitle?: string) => {
110+
return {
111+
fileList: {
112+
fileTreeTitle: '',
113+
filePaths: contextList.map((file) => file.relativeFilePath),
114+
rootFolderTitle: rootFolderTitle,
115+
flatList: true,
116+
collapsed: true,
117+
hideFileCount: true,
118+
details: Object.fromEntries(
119+
contextList.map((file) => [
120+
file.relativeFilePath,
121+
{
122+
label: file.lineRanges
123+
.map((range: { first: number; second: number }) =>
124+
range.first === -1 || range.second === -1
125+
? ''
126+
: `line ${range.first} - ${range.second}`
127+
)
128+
.join(', '),
129+
description: file.relativeFilePath,
130+
clickable: true,
131+
},
132+
])
133+
),
134+
},
135+
}
136+
}
137+
103138
// Adding the first tab as CWC tab
104139
tabsStorage.addTab({
105140
id: 'tab-1',
@@ -346,8 +381,11 @@ export const createMynahUI = (
346381
sendMessageToExtension: (message) => {
347382
ideApi.postMessage(message)
348383
},
349-
onChatAnswerUpdated: (tabID: string, item: ChatItem) => {
384+
onChatAnswerUpdated: (tabID: string, item: CWCChatItem) => {
350385
if (item.messageId !== undefined) {
386+
if (item.contextList !== undefined && item.contextList.length > 0) {
387+
item.header = createFileListHeader(item.contextList, item.rootFolderTitle)
388+
}
351389
mynahUI.updateChatAnswerWithMessageId(tabID, item.messageId, {
352390
...(item.body !== undefined ? { body: item.body } : {}),
353391
...(item.buttons !== undefined ? { buttons: item.buttons } : {}),
@@ -409,32 +447,7 @@ export const createMynahUI = (
409447
}
410448

411449
if (item.contextList !== undefined && item.contextList.length > 0) {
412-
item.header = {
413-
fileList: {
414-
fileTreeTitle: '',
415-
filePaths: item.contextList.map((file) => file.relativeFilePath),
416-
rootFolderTitle: item.rootFolderTitle,
417-
flatList: true,
418-
collapsed: true,
419-
hideFileCount: true,
420-
details: Object.fromEntries(
421-
item.contextList.map((file) => [
422-
file.relativeFilePath,
423-
{
424-
label: file.lineRanges
425-
.map((range) =>
426-
range.first === -1 || range.second === -1
427-
? ''
428-
: `line ${range.first} - ${range.second}`
429-
)
430-
.join(', '),
431-
description: file.relativeFilePath,
432-
clickable: true,
433-
},
434-
])
435-
),
436-
},
437-
}
450+
item.header = createFileListHeader(item.contextList, item.rootFolderTitle)
438451
}
439452

440453
if (

packages/core/src/codewhispererChat/clients/chat/v0/chat.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { ToolkitError } from '../../../../shared/errors'
1414
import { createCodeWhispererChatStreamingClient } from '../../../../shared/clients/codewhispererChatClient'
1515
import { createQDeveloperStreamingClient } from '../../../../shared/clients/qDeveloperChatClient'
1616
import { UserWrittenCodeTracker } from '../../../../codewhisperer/tracker/userWrittenCodeTracker'
17-
import { PromptMessage } from '../../../controllers/chat/model'
17+
import { DocumentReference, PromptMessage } from '../../../controllers/chat/model'
1818
import { FsWriteBackup } from '../../../../codewhispererChat/tools/fsWrite'
1919

2020
export type ToolUseWithError = {
@@ -30,8 +30,10 @@ export class ChatSession {
3030
* _readFiles = list of files read from the project to gather context before generating response.
3131
* _showDiffOnFileWrite = Controls whether to show diff view (true) or file context view (false) to the user
3232
* _context = Additional context to be passed to the LLM for generating the response
33+
* _messageIdToUpdate = messageId of a chat message to be updated, used for reducing consecutive tool messages
3334
*/
34-
private _readFiles: string[] = []
35+
private _readFiles: DocumentReference[] = []
36+
private _readFolders: DocumentReference[] = []
3537
private _toolUseWithError: ToolUseWithError | undefined
3638
private _showDiffOnFileWrite: boolean = false
3739
private _context: PromptMessage['context']
@@ -41,6 +43,8 @@ export class ChatSession {
4143
* True if messages from local history have been sent to session.
4244
*/
4345
localHistoryHydrated: boolean = false
46+
private _messageIdToUpdate: string | undefined
47+
private _messageIdToUpdateListDirectory: string | undefined
4448

4549
contexts: Map<string, { first: number; second: number }[]> = new Map()
4650
// TODO: doesn't handle the edge case when two files share the same relativePath string but from different root
@@ -49,6 +53,21 @@ export class ChatSession {
4953
public get sessionIdentifier(): string | undefined {
5054
return this.sessionId
5155
}
56+
public get messageIdToUpdate(): string | undefined {
57+
return this._messageIdToUpdate
58+
}
59+
60+
public setMessageIdToUpdate(messageId: string | undefined) {
61+
this._messageIdToUpdate = messageId
62+
}
63+
64+
public get messageIdToUpdateListDirectory(): string | undefined {
65+
return this._messageIdToUpdateListDirectory
66+
}
67+
68+
public setMessageIdToUpdateListDirectory(messageId: string | undefined) {
69+
this._messageIdToUpdateListDirectory = messageId
70+
}
5271

5372
public get pairProgrammingModeOn(): boolean {
5473
return this._pairProgrammingModeOn
@@ -95,21 +114,30 @@ export class ChatSession {
95114
public setSessionID(id?: string) {
96115
this.sessionId = id
97116
}
98-
public get readFiles(): string[] {
117+
public get readFiles(): DocumentReference[] {
99118
return this._readFiles
100119
}
120+
public get readFolders(): DocumentReference[] {
121+
return this._readFolders
122+
}
101123
public get showDiffOnFileWrite(): boolean {
102124
return this._showDiffOnFileWrite
103125
}
104126
public setShowDiffOnFileWrite(value: boolean) {
105127
this._showDiffOnFileWrite = value
106128
}
107-
public addToReadFiles(filePath: string) {
129+
public addToReadFiles(filePath: DocumentReference) {
108130
this._readFiles.push(filePath)
109131
}
110132
public clearListOfReadFiles() {
111133
this._readFiles = []
112134
}
135+
public setReadFolders(folder: DocumentReference) {
136+
this._readFolders.push(folder)
137+
}
138+
public clearListOfReadFolders() {
139+
this._readFolders = []
140+
}
113141
async chatIam(chatRequest: SendMessageRequest): Promise<SendMessageCommandOutput> {
114142
const client = await createQDeveloperStreamingClient()
115143

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,7 @@ export class ChatController {
12151215
private async processPromptMessageAsNewThread(message: PromptMessage) {
12161216
const session = this.sessionStorage.getSession(message.tabID)
12171217
session.clearListOfReadFiles()
1218+
session.clearListOfReadFolders()
12181219
session.setShowDiffOnFileWrite(false)
12191220
this.editorContextExtractor
12201221
.extractContextForTrigger('ChatMessage')

0 commit comments

Comments
 (0)