diff --git a/packages/core/src/codewhispererChat/controllers/chat/chatRequest/converter.ts b/packages/core/src/codewhispererChat/controllers/chat/chatRequest/converter.ts index 896d597f796..adc95f2ef69 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/chatRequest/converter.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/chatRequest/converter.ts @@ -3,18 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - ConversationState, - CursorState, - DocumentSymbol, - SymbolType, - TextDocument, - ChatMessage, -} from '@amzn/codewhisperer-streaming' +import { ConversationState, CursorState, DocumentSymbol, SymbolType, TextDocument } from '@amzn/codewhisperer-streaming' import { AdditionalContentEntryAddition, ChatTriggerType, RelevantTextDocumentAddition, TriggerPayload } from '../model' import { undefinedIfEmpty } from '../../../../shared/utilities/textUtilities' -import { ChatItemType } from '../../../../amazonq/commons/model' import { getLogger } from '../../../../shared/logger/logger' +import { messageToChatMessage } from '../../../../shared/db/chatDb/util' const fqnNameSizeDownLimit = 1 const fqnNameSizeUpLimit = 256 @@ -158,19 +151,7 @@ export function triggerPayloadToChatRequest(triggerPayload: TriggerPayload): { c const history = triggerPayload.history && triggerPayload.history.length > 0 && - (triggerPayload.history.map((chat) => - chat.type === ('answer' as ChatItemType) - ? { - assistantResponseMessage: { - content: chat.body, - }, - } - : { - userInputMessage: { - content: chat.body, - }, - } - ) as ChatMessage[]) + triggerPayload.history.map((chat) => messageToChatMessage(chat)) return { conversationState: { diff --git a/packages/core/src/codewhispererChat/controllers/chat/model.ts b/packages/core/src/codewhispererChat/controllers/chat/model.ts index 5c41ba95111..2613a8bd8df 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/model.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/model.ts @@ -10,7 +10,8 @@ import { Selection } from 'vscode' import { TabOpenType } from '../../../amazonq/webview/ui/storages/tabsStorage' import { CodeReference } from '../../view/connector/connector' import { Customization } from '../../../codewhisperer/client/codewhispereruserclient' -import { ChatItem, QuickActionCommand } from '@aws/mynah-ui' +import { QuickActionCommand } from '@aws/mynah-ui' +import { Message } from '../../../shared/db/chatDb/util' export interface TriggerTabIDReceived { tabID: string @@ -206,7 +207,7 @@ export interface TriggerPayload { traceId?: string contextLengths: ContextLengths workspaceRulesCount?: number - history?: ChatItem[] + history?: Message[] } export type ContextLengths = { diff --git a/packages/core/src/codewhispererChat/controllers/chat/tabBarController.ts b/packages/core/src/codewhispererChat/controllers/chat/tabBarController.ts index ce0970040a2..13088e096f8 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/tabBarController.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/tabBarController.ts @@ -13,7 +13,7 @@ import * as vscode from 'vscode' import { Messenger } from './messenger/messenger' import { Database } from '../../../shared/db/chatDb/chatDb' import { TabBarButtonClick, SaveChatMessage } from './model' -import { Conversation, Tab } from '../../../shared/db/chatDb/util' +import { Conversation, messageToChatItem, Tab } from '../../../shared/db/chatDb/util' import { DetailedListItemGroup, MynahIconsType } from '@aws/mynah-ui' export class TabBarController { @@ -87,7 +87,9 @@ export class TabBarController { this.messenger.sendRestoreTabMessage( selectedTab.historyId, selectedTab.tabType, - selectedTab.conversations.flatMap((conv: Conversation) => conv.messages), + selectedTab.conversations.flatMap((conv: Conversation) => + conv.messages.map((message) => messageToChatItem(message)) + ), exportTab ) } diff --git a/packages/core/src/shared/db/chatDb/chatDb.ts b/packages/core/src/shared/db/chatDb/chatDb.ts index 43c594dc376..df936601799 100644 --- a/packages/core/src/shared/db/chatDb/chatDb.ts +++ b/packages/core/src/shared/db/chatDb/chatDb.ts @@ -5,12 +5,13 @@ import Loki from 'lokijs' import * as vscode from 'vscode' import { TabType } from '../../../amazonq/webview/ui/storages/tabsStorage' -import { ChatItem, ChatItemType, DetailedListItemGroup } from '@aws/mynah-ui' +import { ChatItemType, DetailedListItemGroup } from '@aws/mynah-ui' import { ClientType, Conversation, FileSystemAdapter, groupTabsByDate, + Message, Tab, TabCollection, updateOrCreateConversation, @@ -171,7 +172,7 @@ export class Database { const tabs = tabCollection.find() const filteredTabs = tabs.filter((tab: Tab) => { return tab.conversations.some((conversation: Conversation) => { - return conversation.messages.some((message: ChatItem) => { + return conversation.messages.some((message: Message) => { return message.body?.toLowerCase().includes(searchTermLower) }) }) @@ -225,7 +226,7 @@ export class Database { } } - addMessage(tabId: string, tabType: TabType, conversationId: string, chatItem: ChatItem) { + addMessage(tabId: string, tabType: TabType, conversationId: string, message: Message) { if (this.initialized) { const tabCollection = this.db.getCollection(TabCollection) @@ -238,9 +239,9 @@ export class Database { const tabData = historyId ? tabCollection.findOne({ historyId }) : undefined const tabTitle = - (chatItem.type === ('prompt' as ChatItemType) ? chatItem.body : tabData?.title) || 'Amazon Q Chat' + (message.type === ('prompt' as ChatItemType) ? message.body : tabData?.title) || 'Amazon Q Chat' if (tabData) { - tabData.conversations = updateOrCreateConversation(tabData.conversations, conversationId, chatItem) + tabData.conversations = updateOrCreateConversation(tabData.conversations, conversationId, message) tabData.updatedAt = new Date() tabData.title = tabTitle tabCollection.update(tabData) @@ -251,7 +252,7 @@ export class Database { isOpen: true, tabType: tabType, title: tabTitle, - conversations: [{ conversationId, clientType: ClientType.VSCode, messages: [chatItem] }], + conversations: [{ conversationId, clientType: ClientType.VSCode, messages: [message] }], }) } } diff --git a/packages/core/src/shared/db/chatDb/util.ts b/packages/core/src/shared/db/chatDb/util.ts index 5c260be60b5..09ba4090b9c 100644 --- a/packages/core/src/shared/db/chatDb/util.ts +++ b/packages/core/src/shared/db/chatDb/util.ts @@ -6,7 +6,17 @@ import fs from '../../fs/fs' import path from 'path' import { TabType } from '../../../amazonq/webview/ui/storages/tabsStorage' -import { ChatItem, ChatItemButton, DetailedListItem, DetailedListItemGroup, MynahIconsType } from '@aws/mynah-ui' +import { + ChatItem, + ChatItemButton, + ChatItemType, + DetailedListItem, + DetailedListItemGroup, + MynahIconsType, + ReferenceTrackerInformation, + SourceLink, +} from '@aws/mynah-ui' +import { ChatMessage, Origin, ToolUse, UserInputMessageContext, UserIntent } from '@amzn/codewhisperer-streaming' export const TabCollection = 'tabs' @@ -24,7 +34,7 @@ export type Tab = { export type Conversation = { conversationId: string clientType: ClientType - messages: ChatItem[] + messages: Message[] } export enum ClientType { @@ -33,6 +43,56 @@ export enum ClientType { CLI = 'CLI', } +export type Message = { + body: string + type: ChatItemType + codeReference?: ReferenceTrackerInformation[] + relatedContent?: { + title?: string + content: SourceLink[] + } + messageId?: string + userIntent?: UserIntent + origin?: Origin + userInputMessageContext?: UserInputMessageContext + toolUses?: ToolUse[] +} + +/** + * Converts Message to CodeWhisperer Streaming ChatMessage + */ +export function messageToChatMessage(msg: Message): ChatMessage { + return msg.type === ('answer' as ChatItemType) + ? { + assistantResponseMessage: { + messageId: msg.messageId, + content: msg.body, + references: msg.codeReference || [], + toolUses: msg.toolUses || [], + }, + } + : { + userInputMessage: { + content: msg.body, + userIntent: msg.userIntent, + origin: msg.origin || 'IDE', + userInputMessageContext: msg.userInputMessageContext || {}, + }, + } +} + +/** + * Converts Message to MynahUI Chat Item + */ +export function messageToChatItem(msg: Message): ChatItem { + return { + body: msg.body, + type: msg.type as ChatItemType, + codeReference: msg.codeReference, + relatedContent: msg.relatedContent && msg.relatedContent?.content.length > 0 ? msg.relatedContent : undefined, + } +} + /** * * This adapter implements the LokiPersistenceAdapter interface for file system operations using web-compatible shared fs utils. @@ -107,7 +167,7 @@ export class FileSystemAdapter implements LokiPersistenceAdapter { export function updateOrCreateConversation( conversations: Conversation[], conversationId: string, - newMessage: ChatItem + newMessage: Message ): Conversation[] { const existingConversation = conversations.find((conv) => conv.conversationId === conversationId)