Skip to content

Commit e2f0a2d

Browse files
committed
feat(amazonq): conversation persistence, view and search chat history, chat export
1 parent 1647786 commit e2f0a2d

File tree

23 files changed

+1255
-22
lines changed

23 files changed

+1255
-22
lines changed

package-lock.json

Lines changed: 17 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Amazon Q chat: View and search chat history"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Amazon Q chat: Automatically persist chats between IDE sessions"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Amazon Q chat: Click share icon to export chat to Markdown or HTML"
4+
}

packages/core/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@
454454
"@types/js-yaml": "^4.0.5",
455455
"@types/jsdom": "^21.1.6",
456456
"@types/lodash": "^4.14.180",
457+
"@types/lokijs": "^1.5.14",
457458
"@types/markdown-it": "^13.0.2",
458459
"@types/mime-types": "^2.1.4",
459460
"@types/mocha": "^10.0.6",
@@ -522,7 +523,7 @@
522523
"@aws-sdk/s3-request-presigner": "<3.731.0",
523524
"@aws-sdk/smithy-client": "<3.731.0",
524525
"@aws-sdk/util-arn-parser": "<3.731.0",
525-
"@aws/mynah-ui": "^4.26.1",
526+
"@aws/mynah-ui": "^4.27.0-beta.3",
526527
"@gerhobbelt/gitignore-parser": "^0.2.0-9",
527528
"@iarna/toml": "^2.2.5",
528529
"@smithy/fetch-http-handler": "^5.0.1",
@@ -554,6 +555,7 @@
554555
"js-yaml": "^4.1.0",
555556
"jsonc-parser": "^3.2.0",
556557
"lodash": "^4.17.21",
558+
"lokijs": "^1.5.12",
557559
"markdown-it": "^13.0.2",
558560
"mime-types": "^2.1.32",
559561
"node-fetch": "^2.7.0",

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

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,21 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { ChatItem, ChatItemAction, ChatItemType, FeedbackPayload, QuickActionCommand } from '@aws/mynah-ui'
6+
import {
7+
ChatItem,
8+
ChatItemAction,
9+
ChatItemType,
10+
DetailedList,
11+
FeedbackPayload,
12+
QuickActionCommand,
13+
} from '@aws/mynah-ui'
714
import { ExtensionMessage } from '../commands'
815
import { CodeReference } from './amazonqCommonsConnector'
916
import { TabOpenType, TabsStorage, TabType } from '../storages/tabsStorage'
1017
import { FollowUpGenerator } from '../followUps/generator'
1118
import { CWCChatItem } from '../connector'
19+
import { DetailedListSheetProps } from '@aws/mynah-ui/dist/components/detailed-list/detailed-list-sheet'
20+
import { DetailedListConnector, DetailedListType } from '../detailedList/detailedListConnector'
1221

1322
interface ChatPayload {
1423
chatMessage: string
@@ -23,6 +32,14 @@ export interface BaseConnectorProps {
2332
onError: (tabID: string, message: string, title: string) => void
2433
onWarning: (tabID: string, message: string, title: string) => void
2534
onOpenSettingsMessage: (tabID: string) => void
35+
onNewTab: (tabType: TabType, chats?: ChatItem[]) => string | undefined
36+
onOpenDetailedList: (data: DetailedListSheetProps) => {
37+
update: (data: DetailedList) => void
38+
close: () => void
39+
changeTarget: (direction: 'up' | 'down', snapOnLastAndFirst?: boolean) => void
40+
}
41+
onSelectTab: (tabID: string, eventID: string) => void
42+
onExportChat: (tabId: string, format: 'html' | 'markdown') => string
2643
tabsStorage: TabsStorage
2744
}
2845

@@ -32,8 +49,13 @@ export abstract class BaseConnector {
3249
protected readonly onWarning
3350
protected readonly onChatAnswerReceived
3451
protected readonly onOpenSettingsMessage
52+
protected readonly onNewTab
53+
protected readonly onOpenDetailedList
54+
protected readonly onExportChat
55+
protected readonly onSelectTab
3556
protected readonly followUpGenerator: FollowUpGenerator
3657
protected readonly tabsStorage
58+
protected historyConnector
3759

3860
abstract getTabType(): TabType
3961

@@ -43,8 +65,17 @@ export abstract class BaseConnector {
4365
this.onWarning = props.onWarning
4466
this.onError = props.onError
4567
this.onOpenSettingsMessage = props.onOpenSettingsMessage
68+
this.onNewTab = props.onNewTab
4669
this.tabsStorage = props.tabsStorage
70+
this.onOpenDetailedList = props.onOpenDetailedList
71+
this.onExportChat = props.onExportChat
72+
this.onSelectTab = props.onSelectTab
4773
this.followUpGenerator = new FollowUpGenerator()
74+
this.historyConnector = new DetailedListConnector(
75+
DetailedListType.history,
76+
this.sendMessageToExtension,
77+
this.onOpenDetailedList
78+
)
4879
}
4980

5081
onResponseBodyLinkClick = (tabID: string, messageId: string, link: string): void => {
@@ -296,5 +327,53 @@ export abstract class BaseConnector {
296327
await this.processOpenSettingsMessage(messageData)
297328
return
298329
}
330+
331+
if (messageData.type === 'restoreTabMessage') {
332+
const newTabId = this.onNewTab(messageData.tabType, messageData.chats)
333+
this.sendMessageToExtension({
334+
command: 'tab-restored',
335+
historyId: messageData.historyId,
336+
newTabId,
337+
tabType: this.getTabType(),
338+
exportTab: messageData.exportTab,
339+
})
340+
return
341+
}
342+
343+
if (messageData.type === 'updateDetailedListMessage') {
344+
if (messageData.listType === DetailedListType.history) {
345+
this.historyConnector.updateList(messageData.detailedList)
346+
}
347+
return
348+
}
349+
350+
if (messageData.type === 'closeDetailedListMessage') {
351+
if (messageData.listType === DetailedListType.history) {
352+
this.historyConnector.closeList()
353+
}
354+
return
355+
}
356+
357+
if (messageData.type === 'openDetailedListMessage') {
358+
if (messageData.listType === DetailedListType.history) {
359+
this.historyConnector.openList(messageData)
360+
}
361+
return
362+
}
363+
364+
if (messageData.type === 'exportChatMessage') {
365+
const serializedChat = this.onExportChat(messageData.tabID, messageData.format)
366+
this.sendMessageToExtension({
367+
command: 'save-chat',
368+
uri: messageData.uri,
369+
serializedChat,
370+
tabType: 'cwc',
371+
})
372+
return
373+
}
374+
375+
if (messageData.type === 'selectTabMessage') {
376+
this.onSelectTab(messageData.tabID, messageData.eventID)
377+
}
299378
}
300379
}

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export interface ConnectorProps extends BaseConnectorProps {
2323
onUpdatePromptProgress: (tabID: string, progressField: ProgressField) => void
2424
onChatInputEnabled: (tabID: string, enabled: boolean) => void
2525
onUpdateAuthentication: (featureDevEnabled: boolean, authenticatingTabIDs: string[]) => void
26-
onNewTab: (tabType: TabType) => void
2726
}
2827

2928
export class Connector extends BaseConnector {
@@ -32,7 +31,6 @@ export class Connector extends BaseConnector {
3231
private readonly updatePlaceholder
3332
private readonly chatInputEnabled
3433
private readonly onUpdateAuthentication
35-
private readonly onNewTab
3634
private readonly updatePromptProgress
3735

3836
override getTabType(): TabType {
@@ -46,7 +44,6 @@ export class Connector extends BaseConnector {
4644
this.updatePlaceholder = props.onUpdatePlaceholder
4745
this.chatInputEnabled = props.onChatInputEnabled
4846
this.onUpdateAuthentication = props.onUpdateAuthentication
49-
this.onNewTab = props.onNewTab
5047
this.updatePromptProgress = props.onUpdatePromptProgress
5148
}
5249

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export interface ConnectorProps extends BaseConnectorProps {
3030
onUpdatePlaceholder: (tabID: string, newPlaceholder: string) => void
3131
onChatInputEnabled: (tabID: string, enabled: boolean) => void
3232
onUpdateAuthentication: (featureDevEnabled: boolean, authenticatingTabIDs: string[]) => void
33-
onNewTab: (tabType: TabType) => void
3433
}
3534

3635
export class Connector extends BaseConnector {
@@ -40,7 +39,6 @@ export class Connector extends BaseConnector {
4039
private readonly updatePlaceholder
4140
private readonly chatInputEnabled
4241
private readonly onUpdateAuthentication
43-
private readonly onNewTab
4442

4543
override getTabType(): TabType {
4644
return 'featuredev'
@@ -53,7 +51,6 @@ export class Connector extends BaseConnector {
5351
this.updatePlaceholder = props.onUpdatePlaceholder
5452
this.chatInputEnabled = props.onChatInputEnabled
5553
this.onUpdateAuthentication = props.onUpdateAuthentication
56-
this.onNewTab = props.onNewTab
5754
this.onChatAnswerUpdated = props.onChatAnswerUpdated
5855
}
5956

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,12 @@ type MessageCommand =
4444
| 'update-welcome-count'
4545
| 'quick-command-group-action-click'
4646
| 'context-selected'
47+
| 'tab-restored'
48+
| 'tab-bar-button-clicked'
49+
| 'export-chat'
50+
| 'save-chat'
51+
| 'detailed-list-filter-change'
52+
| 'detailed-list-item-select'
53+
| 'detailed-list-action-click'
4754

4855
export type ExtensionMessage = Record<string, any> & { command: MessageCommand }

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
QuickActionCommand,
1717
ChatItemFormItem,
1818
ChatItemButton,
19+
DetailedList,
1920
} from '@aws/mynah-ui'
2021
import { Connector as CWChatConnector } from './apps/cwChatConnector'
2122
import { Connector as FeatureDevChatConnector } from './apps/featureDevChatConnector'
@@ -30,6 +31,7 @@ import { WelcomeFollowupType } from './apps/amazonqCommonsConnector'
3031
import { AuthFollowUpType } from './followUps/generator'
3132
import { DiffTreeFileInfo } from './diffTree/types'
3233
import { UserIntent } from '@amzn/codewhisperer-streaming'
34+
import { DetailedListSheetProps } from '@aws/mynah-ui/dist/components/detailed-list/detailed-list-sheet'
3335

3436
export interface CodeReference {
3537
licenseName?: string
@@ -94,7 +96,7 @@ export interface ConnectorProps {
9496
onUpdatePromptProgress: (tabID: string, progressField: ProgressField) => void
9597
onChatInputEnabled: (tabID: string, enabled: boolean) => void
9698
onUpdateAuthentication: (featureDevEnabled: boolean, authenticatingTabIDs: string[]) => void
97-
onNewTab: (tabType: TabType) => void
99+
onNewTab: (tabType: TabType, chats?: ChatItem[]) => string | undefined
98100
onFileActionClick: (tabID: string, messageId: string, filePath: string, actionName: string) => void
99101
handleCommand: (chatPrompt: ChatPrompt, tabId: string) => void
100102
sendStaticMessages: (tabID: string, messages: ChatItem[]) => void
@@ -106,6 +108,13 @@ export interface ConnectorProps {
106108
title?: string,
107109
description?: string
108110
) => void
111+
onOpenDetailedList: (data: DetailedListSheetProps) => {
112+
update: (data: DetailedList) => void
113+
close: () => void
114+
changeTarget: (direction: 'up' | 'down', snapOnLastAndFirst?: boolean) => void
115+
}
116+
onSelectTab: (tabID: string, eventID: string) => void
117+
onExportChat: (tabID: string, format: 'markdown' | 'html') => string
109118
tabsStorage: TabsStorage
110119
}
111120

@@ -291,6 +300,7 @@ export class Connector {
291300
this.tabsStorage.updateTabLastCommand(messageData.tabID, '')
292301
}
293302

303+
// Run when user opens new tab in UI
294304
onTabAdd = (tabID: string): void => {
295305
this.tabsStorage.addTab({
296306
id: tabID,
@@ -684,6 +694,16 @@ export class Connector {
684694
return false
685695
}
686696

697+
onTabBarButtonClick = async (tabId: string, buttonId: string, eventId?: string) => {
698+
this.sendMessageToExtension({
699+
command: 'tab-bar-button-clicked',
700+
buttonId,
701+
type: '',
702+
tabID: tabId,
703+
tabType: 'cwc',
704+
})
705+
}
706+
687707
onCustomFormAction = (
688708
tabId: string,
689709
messageId: string | undefined,

0 commit comments

Comments
 (0)