Skip to content

Commit e7ccaea

Browse files
authored
Merge branch 'feature/agentic-chat' into pair-programming-mode
2 parents d160d6e + 093d5bc commit e7ccaea

File tree

16 files changed

+441
-81
lines changed

16 files changed

+441
-81
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@ body.vscode-high-contrast:not(.vscode-high-contrast-light) {
1515
--mynah-color-highlight: rgba(0, 137, 255, 0.2);
1616
--mynah-color-highlight-text: rgba(0, 137, 255, 1);
1717
}
18+
19+
body .mynah-card-body h1 {
20+
--mynah-line-height: 1.5rem;
21+
}

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

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
ChatItemButton,
99
ChatItemFormItem,
1010
ChatItemType,
11+
MynahIconsType,
1112
MynahUIDataModel,
1213
QuickActionCommand,
1314
} from '@aws/mynah-ui'
@@ -33,6 +34,7 @@ export class Connector extends BaseConnector {
3334
private readonly onContextCommandDataReceived
3435
private readonly onShowCustomForm
3536
private readonly onChatAnswerUpdated
37+
private chatItems: Map<string, Map<string, ChatItem>> = new Map() // tabId -> messageId -> ChatItem
3638

3739
override getTabType(): TabType {
3840
return 'cwc'
@@ -109,6 +111,10 @@ export class Connector extends BaseConnector {
109111
title: messageData.title,
110112
buttons: messageData.buttons ?? undefined,
111113
fileList: messageData.fileList ?? undefined,
114+
header: messageData.header ?? undefined,
115+
padding: messageData.padding ?? undefined,
116+
fullWidth: messageData.fullWidth ?? undefined,
117+
codeBlockActions: messageData.codeBlockActions ?? undefined,
112118
}
113119

114120
if (messageData.relatedSuggestions !== undefined) {
@@ -117,6 +123,10 @@ export class Connector extends BaseConnector {
117123
content: messageData.relatedSuggestions,
118124
}
119125
}
126+
127+
if (answer.messageId) {
128+
this.storeChatItem(messageData.tabID, answer.messageId, answer)
129+
}
120130
this.onChatAnswerReceived(messageData.tabID, answer, messageData)
121131

122132
// Exit the function if we received an answer from AI
@@ -147,13 +157,57 @@ export class Connector extends BaseConnector {
147157
: undefined,
148158
buttons: messageData.buttons ?? undefined,
149159
canBeVoted: messageData.canBeVoted ?? false,
160+
header: messageData.header ?? undefined,
161+
padding: messageData.padding ?? undefined,
162+
fullWidth: messageData.fullWidth ?? undefined,
163+
codeBlockActions: messageData.codeBlockActions ?? undefined,
150164
}
151165
this.onChatAnswerReceived(messageData.tabID, answer, messageData)
152166

153167
return
154168
}
155169
}
156170

171+
private processToolMessage = async (messageData: any): Promise<void> => {
172+
if (this.onChatAnswerUpdated === undefined) {
173+
return
174+
}
175+
const answer: CWCChatItem = {
176+
type: messageData.messageType,
177+
messageId: messageData.messageID ?? messageData.triggerID,
178+
body: messageData.message,
179+
followUp: messageData.followUps,
180+
canBeVoted: messageData.canBeVoted ?? false,
181+
codeReference: messageData.codeReference,
182+
userIntent: messageData.contextList,
183+
codeBlockLanguage: messageData.codeBlockLanguage,
184+
contextList: messageData.contextList,
185+
title: messageData.title,
186+
buttons: messageData.buttons,
187+
fileList: messageData.fileList,
188+
header: messageData.header ?? undefined,
189+
padding: messageData.padding ?? undefined,
190+
fullWidth: messageData.fullWidth ?? undefined,
191+
codeBlockActions: messageData.codeBlockActions ?? undefined,
192+
}
193+
if (answer.messageId) {
194+
this.storeChatItem(messageData.tabID, answer.messageId, answer)
195+
}
196+
this.onChatAnswerUpdated(messageData.tabID, answer)
197+
return
198+
}
199+
200+
private storeChatItem(tabId: string, messageId: string, item: ChatItem): void {
201+
if (!this.chatItems.has(tabId)) {
202+
this.chatItems.set(tabId, new Map())
203+
}
204+
this.chatItems.get(tabId)?.set(messageId, { ...item })
205+
}
206+
207+
private getCurrentChatItem(tabId: string, messageId: string): ChatItem | undefined {
208+
return this.chatItems.get(tabId)?.get(messageId)
209+
}
210+
157211
processContextCommandData(messageData: any) {
158212
if (messageData.data) {
159213
this.onContextCommandDataReceived(messageData.data)
@@ -199,6 +253,11 @@ export class Connector extends BaseConnector {
199253
return
200254
}
201255

256+
if (messageData.type === 'toolMessage') {
257+
await this.processToolMessage(messageData)
258+
return
259+
}
260+
202261
if (messageData.type === 'editorContextCommandMessage') {
203262
await this.processEditorContextCommandMessage(messageData)
204263
return
@@ -270,35 +329,39 @@ export class Connector extends BaseConnector {
270329
) {
271330
return
272331
}
332+
333+
// Can not assign body as "undefined" or "null" because both of these values will be overriden at main.ts in onChatAnswerUpdated
334+
// TODO: Refactor in next PR if necessary.
335+
const currentChatItem = this.getCurrentChatItem(tabId, messageId)
273336
const answer: ChatItem = {
274337
type: ChatItemType.ANSWER,
275338
messageId: messageId,
276339
buttons: [],
340+
body: undefined,
341+
header: currentChatItem?.header ? { ...currentChatItem.header } : {},
277342
}
278343
switch (action.id) {
279344
case 'accept-code-diff':
280-
answer.buttons = [
281-
{
282-
keepCardAfterClick: true,
283-
text: 'Accepted code',
284-
id: 'accepted-code-diff',
345+
if (answer.header) {
346+
answer.header.status = {
347+
icon: 'ok' as MynahIconsType,
348+
text: 'Accepted',
285349
status: 'success',
286-
position: 'outside',
287-
disabled: true,
288-
},
289-
]
350+
}
351+
answer.header.buttons = []
352+
answer.body = ' '
353+
}
290354
break
291355
case 'reject-code-diff':
292-
answer.buttons = [
293-
{
294-
keepCardAfterClick: true,
295-
text: 'Rejected code',
296-
id: 'rejected-code-diff',
356+
if (answer.header) {
357+
answer.header.status = {
358+
icon: 'cancel' as MynahIconsType,
359+
text: 'Rejected',
297360
status: 'error',
298-
position: 'outside',
299-
disabled: true,
300-
},
301-
]
361+
}
362+
answer.header.buttons = []
363+
answer.body = ' '
364+
}
302365
break
303366
case 'confirm-tool-use':
304367
answer.buttons = [
@@ -315,6 +378,12 @@ export class Connector extends BaseConnector {
315378
default:
316379
break
317380
}
381+
382+
if (currentChatItem && answer.messageId) {
383+
const updatedItem = { ...currentChatItem, ...answer }
384+
this.storeChatItem(tabId, answer.messageId, updatedItem)
385+
}
386+
318387
this.onChatAnswerUpdated(tabId, answer)
319388
}
320389

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,12 @@ export const createMynahUI = (
332332
...(item.followUp !== undefined ? { followUp: item.followUp } : {}),
333333
...(item.footer !== undefined ? { footer: item.footer } : {}),
334334
...(item.canBeVoted !== undefined ? { canBeVoted: item.canBeVoted } : {}),
335+
...(item.fileList !== undefined ? { fileList: item.fileList } : {}),
336+
...(item.header !== undefined ? { header: item.header } : {}),
337+
...(item.buttons !== undefined ? { buttons: item.buttons } : {}),
338+
...(item.fullWidth !== undefined ? { fullWidth: item.fullWidth } : {}),
339+
...(item.padding !== undefined ? { padding: item.padding } : {}),
340+
...(item.codeBlockActions !== undefined ? { codeBlockActions: item.codeBlockActions } : {}),
335341
})
336342
} else {
337343
mynahUI.updateLastChatAnswer(tabID, {
@@ -340,6 +346,11 @@ export const createMynahUI = (
340346
...(item.followUp !== undefined ? { followUp: item.followUp } : {}),
341347
...(item.footer !== undefined ? { footer: item.footer } : {}),
342348
...(item.canBeVoted !== undefined ? { canBeVoted: item.canBeVoted } : {}),
349+
...(item.header !== undefined ? { header: item.header } : {}),
350+
...(item.buttons !== undefined ? { buttons: item.buttons } : {}),
351+
...(item.fullWidth !== undefined ? { fullWidth: item.fullWidth } : {}),
352+
...(item.padding !== undefined ? { padding: item.padding } : {}),
353+
...(item.codeBlockActions !== undefined ? { codeBlockActions: item.codeBlockActions } : {}),
343354
})
344355
}
345356
},
@@ -353,8 +364,11 @@ export const createMynahUI = (
353364
...(item.relatedContent !== undefined ? { relatedContent: item.relatedContent } : {}),
354365
...(item.followUp !== undefined ? { followUp: item.followUp } : {}),
355366
...(item.fileList !== undefined ? { fileList: item.fileList } : {}),
356-
...(item.header !== undefined ? { header: item.header } : { header: undefined }),
357-
...(item.buttons !== undefined ? { buttons: item.buttons } : { buttons: undefined }),
367+
...(item.header !== undefined ? { header: item.header } : {}),
368+
...(item.buttons !== undefined ? { buttons: item.buttons } : {}),
369+
...(item.fullWidth !== undefined ? { fullWidth: item.fullWidth } : {}),
370+
...(item.padding !== undefined ? { padding: item.padding } : {}),
371+
...(item.codeBlockActions !== undefined ? { codeBlockActions: item.codeBlockActions } : {}),
358372
})
359373
if (
360374
item.messageId !== undefined &&

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ export class ChatSession {
2222
* _readFiles = list of files read from the project to gather context before generating response.
2323
* _showDiffOnFileWrite = Controls whether to show diff view (true) or file context view (false) to the user
2424
* _context = Additional context to be passed to the LLM for generating the response
25+
* _messageIdToUpdate = messageId of a chat message to be updated, used for reducing consecutive tool messages
2526
*/
2627
private _readFiles: string[] = []
2728
private _toolUse: ToolUse | undefined
2829
private _showDiffOnFileWrite: boolean = false
2930
private _context: PromptMessage['context']
3031
private _pairProgrammingModeOn: boolean = true
32+
private _messageIdToUpdate: string | undefined
3133

3234
contexts: Map<string, { first: number; second: number }[]> = new Map()
3335
// TODO: doesn't handle the edge case when two files share the same relativePath string but from different root
@@ -61,6 +63,14 @@ export class ChatSession {
6163
this._context = context
6264
}
6365

66+
public get messageIdToUpdate(): string | undefined {
67+
return this._messageIdToUpdate
68+
}
69+
70+
public setMessageIdToUpdate(messageId: string | undefined) {
71+
this._messageIdToUpdate = messageId
72+
}
73+
6474
public tokenSource!: vscode.CancellationTokenSource
6575

6676
constructor() {

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ import {
9090
} from '../../constants'
9191
import { ChatSession } from '../../clients/chat/v0/chat'
9292
import { amazonQTabSuffix } from '../../../shared/constants'
93-
import { OutputKind } from '../../tools/toolShared'
93+
import { maxToolOutputCharacterLength, OutputKind } from '../../tools/toolShared'
9494
import { ToolUtils, Tool, ToolType } from '../../tools/toolUtils'
9595
import { ChatStream } from '../../tools/chatStream'
9696
import { ChatHistoryStorage } from '../../storages/chatHistoryStorage'
@@ -670,10 +670,22 @@ export class ChatController {
670670
try {
671671
await ToolUtils.validate(tool)
672672

673-
const chatStream = new ChatStream(this.messenger, tabID, triggerID, toolUse, {
674-
requiresAcceptance: false,
675-
})
673+
const chatStream = new ChatStream(
674+
this.messenger,
675+
tabID,
676+
triggerID,
677+
// Pass in a different toolUseId so that the output does not overwrite
678+
// any previous messages
679+
{ ...toolUse, toolUseId: `${toolUse.toolUseId}-output` },
680+
{ requiresAcceptance: false },
681+
undefined
682+
)
676683
const output = await ToolUtils.invoke(tool, chatStream)
684+
if (output.output.content.length > maxToolOutputCharacterLength) {
685+
throw Error(
686+
`Tool output exceeds maximum character limit of ${maxToolOutputCharacterLength}`
687+
)
688+
}
677689

678690
toolResults.push({
679691
content: [

0 commit comments

Comments
 (0)