Skip to content

Commit 89375c4

Browse files
authored
refactor(amazonq): add BaseConnector Abstract class for common logic (#5931)
Create an abstract class that can be used by all connectors. --- License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 34b695a commit 89375c4

File tree

5 files changed

+368
-511
lines changed

5 files changed

+368
-511
lines changed
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { ChatItem, ChatItemAction, ChatItemType, FeedbackPayload } from '@aws/mynah-ui'
7+
import { ExtensionMessage } from '../commands'
8+
import { CodeReference } from './amazonqCommonsConnector'
9+
import { TabOpenType, TabsStorage, TabType } from '../storages/tabsStorage'
10+
import { FollowUpGenerator } from '../followUps/generator'
11+
import { CWCChatItem } from '../connector'
12+
13+
interface ChatPayload {
14+
chatMessage: string
15+
chatCommand?: string
16+
}
17+
18+
export interface BaseConnectorProps {
19+
sendMessageToExtension: (message: ExtensionMessage) => void
20+
onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void
21+
onChatAnswerReceived?: (tabID: string, message: CWCChatItem | ChatItem, messageData: any) => void
22+
onError: (tabID: string, message: string, title: string) => void
23+
onWarning: (tabID: string, message: string, title: string) => void
24+
onOpenSettingsMessage: (tabID: string) => void
25+
tabsStorage: TabsStorage
26+
}
27+
28+
export abstract class BaseConnector {
29+
protected readonly sendMessageToExtension
30+
protected readonly onError
31+
protected readonly onWarning
32+
protected readonly onChatAnswerReceived
33+
protected readonly onOpenSettingsMessage
34+
protected readonly followUpGenerator: FollowUpGenerator
35+
protected readonly tabsStorage
36+
37+
abstract getTabType(): TabType
38+
39+
constructor(props: BaseConnectorProps) {
40+
this.sendMessageToExtension = props.sendMessageToExtension
41+
this.onChatAnswerReceived = props.onChatAnswerReceived
42+
this.onWarning = props.onWarning
43+
this.onError = props.onError
44+
this.onOpenSettingsMessage = props.onOpenSettingsMessage
45+
this.tabsStorage = props.tabsStorage
46+
this.followUpGenerator = new FollowUpGenerator()
47+
}
48+
49+
onResponseBodyLinkClick = (tabID: string, messageId: string, link: string): void => {
50+
this.sendMessageToExtension({
51+
command: 'response-body-link-click',
52+
tabID,
53+
messageId,
54+
link,
55+
tabType: this.getTabType(),
56+
})
57+
}
58+
onInfoLinkClick = (tabID: string, link: string): void => {
59+
this.sendMessageToExtension({
60+
command: 'footer-info-link-click',
61+
tabID,
62+
link,
63+
tabType: this.getTabType(),
64+
})
65+
}
66+
67+
followUpClicked = (tabID: string, messageId: string, followUp: ChatItemAction): void => {
68+
/**
69+
* We've pressed on a followup button and should start watching that round trip telemetry
70+
*/
71+
this.sendMessageToExtension({
72+
command: 'start-chat-message-telemetry',
73+
trigger: 'followUpClicked',
74+
tabID,
75+
traceId: messageId,
76+
tabType: this.getTabType(),
77+
startTime: Date.now(),
78+
})
79+
this.sendMessageToExtension({
80+
command: 'follow-up-was-clicked',
81+
followUp,
82+
tabID,
83+
messageId,
84+
tabType: this.getTabType(),
85+
})
86+
}
87+
88+
onTabAdd = (tabID: string, tabOpenInteractionType?: TabOpenType): void => {
89+
this.sendMessageToExtension({
90+
tabID: tabID,
91+
command: 'new-tab-was-created',
92+
tabType: this.getTabType(),
93+
tabOpenInteractionType,
94+
})
95+
}
96+
97+
onCodeInsertToCursorPosition = (
98+
tabID: string,
99+
messageId: string,
100+
code?: string,
101+
type?: 'selection' | 'block',
102+
codeReference?: CodeReference[],
103+
eventId?: string,
104+
codeBlockIndex?: number,
105+
totalCodeBlocks?: number,
106+
userIntent?: string,
107+
codeBlockLanguage?: string
108+
): void => {
109+
this.sendMessageToExtension({
110+
tabID: tabID,
111+
messageId,
112+
code,
113+
command: 'insert_code_at_cursor_position',
114+
tabType: this.getTabType(),
115+
insertionTargetType: type,
116+
codeReference,
117+
eventId,
118+
codeBlockIndex,
119+
totalCodeBlocks,
120+
userIntent,
121+
codeBlockLanguage,
122+
})
123+
}
124+
125+
onCopyCodeToClipboard = (
126+
tabID: string,
127+
messageId: string,
128+
code?: string,
129+
type?: 'selection' | 'block',
130+
codeReference?: CodeReference[],
131+
eventId?: string,
132+
codeBlockIndex?: number,
133+
totalCodeBlocks?: number,
134+
userIntent?: string,
135+
codeBlockLanguage?: string
136+
): void => {
137+
this.sendMessageToExtension({
138+
tabID: tabID,
139+
messageId,
140+
code,
141+
command: 'code_was_copied_to_clipboard',
142+
tabType: this.getTabType(),
143+
insertionTargetType: type,
144+
codeReference,
145+
eventId,
146+
codeBlockIndex,
147+
totalCodeBlocks,
148+
userIntent,
149+
codeBlockLanguage,
150+
})
151+
}
152+
153+
onTabRemove = (tabID: string): void => {
154+
this.sendMessageToExtension({
155+
tabID: tabID,
156+
command: 'tab-was-removed',
157+
tabType: this.getTabType(),
158+
})
159+
}
160+
161+
onTabChange = (tabID: string, prevTabID?: string) => {
162+
this.sendMessageToExtension({
163+
tabID: tabID,
164+
command: 'tab-was-changed',
165+
tabType: this.getTabType(),
166+
prevTabID,
167+
})
168+
}
169+
170+
onStopChatResponse = (tabID: string): void => {
171+
this.sendMessageToExtension({
172+
tabID: tabID,
173+
command: 'stop-response',
174+
tabType: this.getTabType(),
175+
})
176+
}
177+
178+
onChatItemVoted = (tabID: string, messageId: string, vote: 'upvote' | 'downvote'): void => {
179+
this.sendMessageToExtension({
180+
tabID: tabID,
181+
command: 'chat-item-voted',
182+
messageId,
183+
vote,
184+
tabType: this.getTabType(),
185+
})
186+
}
187+
onSendFeedback = (tabID: string, feedbackPayload: FeedbackPayload): void | undefined => {
188+
this.sendMessageToExtension({
189+
command: 'chat-item-feedback',
190+
...feedbackPayload,
191+
tabType: this.getTabType(),
192+
tabID: tabID,
193+
})
194+
}
195+
196+
requestGenerativeAIAnswer = (tabID: string, messageId: string, payload: ChatPayload): Promise<any> => {
197+
/**
198+
* When a user presses "enter" send an event that indicates
199+
* we should start tracking the round trip time for this message
200+
**/
201+
this.sendMessageToExtension({
202+
command: 'start-chat-message-telemetry',
203+
trigger: 'onChatPrompt',
204+
tabID,
205+
traceId: messageId,
206+
tabType: this.getTabType(),
207+
startTime: Date.now(),
208+
})
209+
return new Promise((resolve, reject) => {
210+
this.sendMessageToExtension({
211+
tabID: tabID,
212+
command: 'chat-prompt',
213+
chatMessage: payload.chatMessage,
214+
chatCommand: payload.chatCommand,
215+
tabType: this.getTabType(),
216+
})
217+
})
218+
}
219+
220+
clearChat = (tabID: string): void => {
221+
this.sendMessageToExtension({
222+
tabID: tabID,
223+
command: 'clear',
224+
chatMessage: '',
225+
tabType: this.getTabType(),
226+
})
227+
}
228+
229+
help = (tabID: string): void => {
230+
this.sendMessageToExtension({
231+
tabID: tabID,
232+
command: 'help',
233+
chatMessage: '',
234+
tabType: this.getTabType(),
235+
})
236+
}
237+
238+
onTabOpen = (tabID: string): void => {
239+
this.sendMessageToExtension({
240+
tabID,
241+
command: 'new-tab-was-created',
242+
tabType: this.getTabType(),
243+
})
244+
}
245+
246+
protected sendTriggerMessageProcessed = async (requestID: any): Promise<void> => {
247+
this.sendMessageToExtension({
248+
command: 'trigger-message-processed',
249+
requestID: requestID,
250+
tabType: this.getTabType(),
251+
})
252+
}
253+
254+
protected processAuthNeededException = async (messageData: any): Promise<void> => {
255+
if (this.onChatAnswerReceived === undefined) {
256+
return
257+
}
258+
259+
this.onChatAnswerReceived(
260+
messageData.tabID,
261+
{
262+
type: ChatItemType.ANSWER,
263+
messageId: messageData.triggerID,
264+
body: messageData.message,
265+
followUp: this.followUpGenerator.generateAuthFollowUps(this.getTabType(), messageData.authType),
266+
canBeVoted: false,
267+
},
268+
messageData
269+
)
270+
271+
return
272+
}
273+
274+
protected processOpenSettingsMessage = async (messageData: any): Promise<void> => {
275+
this.onOpenSettingsMessage(messageData.tabID)
276+
}
277+
278+
protected baseHandleMessageReceive = async (messageData: any): Promise<void> => {
279+
if (messageData.type === 'errorMessage') {
280+
this.onError(messageData.tabID, messageData.message, messageData.title)
281+
return
282+
}
283+
if (messageData.type === 'showInvalidTokenNotification') {
284+
this.onWarning(messageData.tabID, messageData.message, messageData.title)
285+
return
286+
}
287+
288+
if (messageData.type === 'authNeededException') {
289+
await this.processAuthNeededException(messageData)
290+
return
291+
}
292+
293+
if (messageData.type === 'openSettingsMessage') {
294+
await this.processOpenSettingsMessage(messageData)
295+
return
296+
}
297+
}
298+
}

0 commit comments

Comments
 (0)