Skip to content

Commit db64637

Browse files
authored
fix(amazonq): Grouping read tool messages under contextList (aws#6975)
## Problem - We show read tool message for each file read which is occupying the entire chat with these messages which is not super important. ## Solution - 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 b6d4754 commit db64637

File tree

10 files changed

+269
-80
lines changed

10 files changed

+269
-80
lines changed

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

Lines changed: 32 additions & 2 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
@@ -363,7 +395,6 @@ export class Connector extends BaseConnector {
363395
break
364396
case 'run-shell-command':
365397
answer.header = {
366-
icon: 'shell' as MynahIconsType,
367398
body: 'shell',
368399
status: {
369400
icon: 'ok' as MynahIconsType,
@@ -374,7 +405,6 @@ export class Connector extends BaseConnector {
374405
break
375406
case 'reject-shell-command':
376407
answer.header = {
377-
icon: 'shell' as MynahIconsType,
378408
body: 'shell',
379409
status: {
380410
icon: 'cancel' as MynahIconsType,

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
@@ -98,6 +98,41 @@ export const createMynahUI = (
9898
welcomeCount += 1
9999
}
100100

101+
/**
102+
* Creates a file list header from context list
103+
* @param contextList List of file contexts
104+
* @param rootFolderTitle Title for the root folder
105+
* @returns Header object with file list
106+
*/
107+
const createFileListHeader = (contextList: any[], rootFolderTitle?: string) => {
108+
return {
109+
fileList: {
110+
fileTreeTitle: '',
111+
filePaths: contextList.map((file) => file.relativeFilePath),
112+
rootFolderTitle: rootFolderTitle,
113+
flatList: true,
114+
collapsed: true,
115+
hideFileCount: true,
116+
details: Object.fromEntries(
117+
contextList.map((file) => [
118+
file.relativeFilePath,
119+
{
120+
label: file.lineRanges
121+
.map((range: { first: number; second: number }) =>
122+
range.first === -1 || range.second === -1
123+
? ''
124+
: `line ${range.first} - ${range.second}`
125+
)
126+
.join(', '),
127+
description: file.relativeFilePath,
128+
clickable: true,
129+
},
130+
])
131+
),
132+
},
133+
}
134+
}
135+
101136
// Adding the first tab as CWC tab
102137
tabsStorage.addTab({
103138
id: 'tab-1',
@@ -342,8 +377,11 @@ export const createMynahUI = (
342377
sendMessageToExtension: (message) => {
343378
ideApi.postMessage(message)
344379
},
345-
onChatAnswerUpdated: (tabID: string, item: ChatItem) => {
380+
onChatAnswerUpdated: (tabID: string, item: CWCChatItem) => {
346381
if (item.messageId !== undefined) {
382+
if (item.contextList !== undefined && item.contextList.length > 0) {
383+
item.header = createFileListHeader(item.contextList, item.rootFolderTitle)
384+
}
347385
mynahUI.updateChatAnswerWithMessageId(tabID, item.messageId, {
348386
...(item.body !== undefined ? { body: item.body } : {}),
349387
...(item.buttons !== undefined ? { buttons: item.buttons } : {}),
@@ -405,32 +443,7 @@ export const createMynahUI = (
405443
}
406444

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

436449
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: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -715,9 +715,18 @@ export class ChatController {
715715
try {
716716
await ToolUtils.validate(tool)
717717

718-
const chatStream = new ChatStream(this.messenger, tabID, triggerID, toolUse, {
719-
requiresAcceptance: false,
720-
})
718+
const chatStream = new ChatStream(
719+
this.messenger,
720+
tabID,
721+
triggerID,
722+
toolUse,
723+
session,
724+
undefined,
725+
false,
726+
{
727+
requiresAcceptance: false,
728+
}
729+
)
721730
if (tool.type === ToolType.FsWrite && toolUse.toolUseId) {
722731
const backup = await tool.tool.getBackup()
723732
session.setFsWriteBackup(toolUse.toolUseId, backup)
@@ -1180,6 +1189,7 @@ export class ChatController {
11801189
private async processPromptMessageAsNewThread(message: PromptMessage) {
11811190
const session = this.sessionStorage.getSession(message.tabID)
11821191
session.clearListOfReadFiles()
1192+
session.clearListOfReadFolders()
11831193
session.setShowDiffOnFileWrite(false)
11841194
this.editorContextExtractor
11851195
.extractContextForTrigger('ChatMessage')

0 commit comments

Comments
 (0)