Skip to content

Commit 80906aa

Browse files
authored
Merge branch 'feature/agentic-chat' into feature/agentic-chat
2 parents 595201d + db64637 commit 80906aa

File tree

14 files changed

+382
-205
lines changed

14 files changed

+382
-205
lines changed

package-lock.json

Lines changed: 10 additions & 5 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
@@ -54,7 +54,7 @@
5454
"@vscode/test-electron": "^2.3.8",
5555
"@vscode/test-web": "^0.0.65",
5656
"@vscode/vsce": "^2.19.0",
57-
"eslint": "^8.56.0",
57+
"eslint": "^8.57.0",
5858
"eslint-config-prettier": "^9.1.0",
5959
"eslint-plugin-aws-toolkits": "file:plugins/eslint-plugin-aws-toolkits",
6060
"eslint-plugin-header": "^3.1.1",

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

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export class Connector extends BaseConnector {
125125
padding: messageData.padding ?? undefined,
126126
fullWidth: messageData.fullWidth ?? undefined,
127127
codeBlockActions: messageData.codeBlockActions ?? undefined,
128+
rootFolderTitle: messageData.rootFolderTitle ?? undefined,
128129
}
129130

130131
if (messageData.relatedSuggestions !== undefined) {
@@ -178,6 +179,33 @@ export class Connector extends BaseConnector {
178179
}
179180
}
180181

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+
181209
private storeChatItem(tabId: string, messageId: string, item: ChatItem): void {
182210
if (!this.chatItems.has(tabId)) {
183211
this.chatItems.set(tabId, new Map())
@@ -237,6 +265,11 @@ export class Connector extends BaseConnector {
237265
return
238266
}
239267

268+
if (messageData.type === 'toolMessage') {
269+
await this.processToolMessage(messageData)
270+
return
271+
}
272+
240273
if (messageData.type === 'editorContextCommandMessage') {
241274
await this.processEditorContextCommandMessage(messageData)
242275
return
@@ -257,13 +290,14 @@ export class Connector extends BaseConnector {
257290
}
258291

259292
if (messageData.type === 'asyncEventProgressMessage') {
293+
const isPromptInputDisabled = true
260294
this.onAsyncEventProgress(
261295
messageData.tabID,
262296
messageData.inProgress,
263297
messageData.message ?? undefined,
264298
messageData.messageId ?? undefined,
265299
messageData.inProgress,
266-
false
300+
isPromptInputDisabled
267301
)
268302
return
269303
}
@@ -362,7 +396,6 @@ export class Connector extends BaseConnector {
362396
break
363397
case 'run-shell-command':
364398
answer.header = {
365-
icon: 'code-block' as MynahIconsType,
366399
body: 'shell',
367400
status: {
368401
icon: 'ok' as MynahIconsType,
@@ -373,7 +406,6 @@ export class Connector extends BaseConnector {
373406
break
374407
case 'reject-shell-command':
375408
answer.header = {
376-
icon: 'code-block' as MynahIconsType,
377409
body: 'shell',
378410
status: {
379411
icon: 'cancel' as MynahIconsType,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export interface CWCChatItem extends ChatItem {
6666
codeBlockLanguage?: string
6767
contextList?: Context[]
6868
title?: string
69+
rootFolderTitle?: string
6970
}
7071

7172
export interface Context {
@@ -77,7 +78,7 @@ export interface ConnectorProps {
7778
sendMessageToExtension: (message: ExtensionMessage) => void
7879
onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void
7980
onRunTestMessageReceived?: (tabID: string, showRunTestMessage: boolean) => void
80-
onChatAnswerUpdated?: (tabID: string, message: ChatItem) => void
81+
onChatAnswerUpdated?: (tabID: string, message: CWCChatItem) => void
8182
onChatAnswerReceived?: (tabID: string, message: ChatItem, messageData: any) => void
8283
onWelcomeFollowUpClicked: (tabID: string, welcomeFollowUpType: WelcomeFollowupType) => void
8384
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.title,
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/amazonq/webview/ui/tabs/generator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ export class TabDataGenerator {
7878
{
7979
type: 'toggle',
8080
id: 'prompt-type',
81-
value: 'ask',
81+
value: 'pair-programming-on',
82+
tooltip: 'Pair programmar on',
8283
options: [
8384
{
8485
value: 'pair-programming-on',

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']
@@ -43,6 +45,8 @@ export class ChatSession {
4345
* True if messages from local history have been sent to session.
4446
*/
4547
localHistoryHydrated: boolean = false
48+
private _messageIdToUpdate: string | undefined
49+
private _messageIdToUpdateListDirectory: string | undefined
4650

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

5574
public get agenticLoopInProgress(): boolean {
5675
return this._agenticLoopInProgress
@@ -124,21 +143,30 @@ export class ChatSession {
124143
public setSessionID(id?: string) {
125144
this.sessionId = id
126145
}
127-
public get readFiles(): string[] {
146+
public get readFiles(): DocumentReference[] {
128147
return this._readFiles
129148
}
149+
public get readFolders(): DocumentReference[] {
150+
return this._readFolders
151+
}
130152
public get showDiffOnFileWrite(): boolean {
131153
return this._showDiffOnFileWrite
132154
}
133155
public setShowDiffOnFileWrite(value: boolean) {
134156
this._showDiffOnFileWrite = value
135157
}
136-
public addToReadFiles(filePath: string) {
158+
public addToReadFiles(filePath: DocumentReference) {
137159
this._readFiles.push(filePath)
138160
}
139161
public clearListOfReadFiles() {
140162
this._readFiles = []
141163
}
164+
public setReadFolders(folder: DocumentReference) {
165+
this._readFolders.push(folder)
166+
}
167+
public clearListOfReadFolders() {
168+
this._readFolders = []
169+
}
142170
async chatIam(chatRequest: SendMessageRequest): Promise<SendMessageCommandOutput> {
143171
const client = await createQDeveloperStreamingClient()
144172

0 commit comments

Comments
 (0)