Skip to content

Commit 0288f4d

Browse files
authored
refactor(amazonq): Pass mynah references to ui handlers (aws#7046)
## Problem - Flare's hybrid chat injects MynahUI reference after chat connector creation ## Solution - Implement delayed resolution so that onces MynahUI is injected everything dynamically resolves --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent fce2479 commit 0288f4d

File tree

6 files changed

+82
-73
lines changed

6 files changed

+82
-73
lines changed

packages/core/src/amazonq/commons/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { DiffTreeFileInfo } from '../webview/ui/diffTree/types'
1111
import { Messenger } from './connector/baseMessenger'
1212
import { FeatureClient } from '../client/client'
1313
import { TelemetryHelper } from '../util/telemetryHelper'
14+
import { MynahUI } from '@aws/mynah-ui'
1415

1516
export enum FollowUpTypes {
1617
// UnitTestGeneration
@@ -164,3 +165,10 @@ export enum MetricDataResult {
164165
Error = 'Error',
165166
LlmFailure = 'LLMFailure',
166167
}
168+
169+
/**
170+
* Note: Passing a reference around allows us to lazily inject mynah UI into
171+
* connectors and handlers. This is done to supported "hybrid chat", which
172+
* injects mynah UI _after_ the connector has already been created
173+
*/
174+
export type MynahUIRef = { mynahUI: MynahUI | undefined }

packages/core/src/amazonq/webview/ui/followUps/handler.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,21 @@ import { Connector } from '../connector'
88
import { TabsStorage } from '../storages/tabsStorage'
99
import { WelcomeFollowupType } from '../apps/amazonqCommonsConnector'
1010
import { AuthFollowUpType } from './generator'
11-
import { FollowUpTypes } from '../../../commons/types'
11+
import { FollowUpTypes, MynahUIRef } from '../../../commons/types'
1212

1313
export interface FollowUpInteractionHandlerProps {
14-
mynahUI: MynahUI
14+
mynahUIRef: MynahUIRef
1515
connector: Connector
1616
tabsStorage: TabsStorage
1717
}
1818

1919
export class FollowUpInteractionHandler {
20-
private mynahUI: MynahUI
20+
private mynahUIRef: MynahUIRef
2121
private connector: Connector
2222
private tabsStorage: TabsStorage
2323

2424
constructor(props: FollowUpInteractionHandlerProps) {
25-
this.mynahUI = props.mynahUI
25+
this.mynahUIRef = props.mynahUIRef
2626
this.connector = props.connector
2727
this.tabsStorage = props.tabsStorage
2828
}
@@ -41,6 +41,11 @@ export class FollowUpInteractionHandler {
4141
this.connector.help(tabID)
4242
return
4343
}
44+
45+
if (!this.mynahUI) {
46+
return
47+
}
48+
4449
// we need to check if there is a prompt
4550
// which will cause an api call
4651
// then we can set the loading state to true
@@ -70,7 +75,7 @@ export class FollowUpInteractionHandler {
7075
}
7176

7277
const addChatItem = (tabID: string, messageId: string, options: any[]) => {
73-
this.mynahUI.addChatItem(tabID, {
78+
this.mynahUI?.addChatItem(tabID, {
7479
type: ChatItemType.ANSWER_PART,
7580
messageId,
7681
followUp: {
@@ -150,7 +155,7 @@ export class FollowUpInteractionHandler {
150155

151156
public onWelcomeFollowUpClicked(tabID: string, welcomeFollowUpType: WelcomeFollowupType) {
152157
if (welcomeFollowUpType === 'continue-to-chat') {
153-
this.mynahUI.addChatItem(tabID, {
158+
this.mynahUI?.addChatItem(tabID, {
154159
type: ChatItemType.ANSWER,
155160
body: 'Ok, please write your question below.',
156161
})
@@ -159,4 +164,8 @@ export class FollowUpInteractionHandler {
159164
return
160165
}
161166
}
167+
168+
private get mynahUI(): MynahUI | undefined {
169+
return this.mynahUIRef.mynahUI
170+
}
162171
}

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

Lines changed: 18 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const createMynahUI = (
5757
) => {
5858
const handler = new WebviewUIHandler({
5959
postMessage: ideApi.postMessage,
60-
mynahUI: undefined,
60+
mynahUIRef: { mynahUI: undefined },
6161
enableAgents: amazonQEnabled,
6262
featureConfigsSerialized,
6363
welcomeCount,
@@ -85,8 +85,7 @@ export class WebviewUIHandler {
8585

8686
tabsStorage: TabsStorage
8787

88-
_mynahUI?: MynahUI
89-
mynahUIProps?: MynahUIProps
88+
mynahUIProps: MynahUIProps
9089
connector?: Connector
9190
tabDataGenerator?: TabDataGenerator
9291

@@ -108,9 +107,11 @@ export class WebviewUIHandler {
108107

109108
savedContextCommands: MynahUIDataModel['contextCommands']
110109

110+
mynahUIRef: { mynahUI: MynahUI | undefined }
111+
111112
constructor({
112113
postMessage,
113-
mynahUI,
114+
mynahUIRef,
114115
enableAgents,
115116
featureConfigsSerialized,
116117
welcomeCount,
@@ -121,7 +122,7 @@ export class WebviewUIHandler {
121122
isSM,
122123
}: {
123124
postMessage: any
124-
mynahUI: MynahUI | undefined
125+
mynahUIRef: { mynahUI: MynahUI | undefined }
125126
enableAgents: boolean
126127
featureConfigsSerialized: [string, FeatureContext][]
127128
welcomeCount: number
@@ -136,6 +137,7 @@ export class WebviewUIHandler {
136137
this.disclaimerCardActive = !disclaimerAcknowledged
137138
this.isSMUS = isSMUS ?? false
138139
this.isSM = isSM ?? false
140+
this.mynahUIRef = mynahUIRef
139141

140142
this.responseMetadata = new Map<string, string[]>()
141143

@@ -197,7 +199,7 @@ export class WebviewUIHandler {
197199
this.isDocEnabled = isAmazonQEnabled
198200

199201
this.quickActionHandler = new QuickActionHandler({
200-
mynahUI: this.mynahUI!,
202+
mynahUIRef: this.mynahUIRef,
201203
connector: this.connector!,
202204
tabsStorage: this.tabsStorage,
203205
isFeatureDevEnabled: this.isFeatureDevEnabled,
@@ -639,7 +641,7 @@ export class WebviewUIHandler {
639641
},
640642
})
641643

642-
this.mynahUI = new MynahUI({
644+
this.mynahUIProps = {
643645
onReady: this.connector.uiReady,
644646
onTabAdd: (tabID: string) => {
645647
/**
@@ -648,7 +650,7 @@ export class WebviewUIHandler {
648650
*/
649651
if (welcomeCount + 1 >= welcomeCountThreshold) {
650652
this.tabsStorage.updateTabTypeFromUnknown(tabID, 'cwc')
651-
mynahUI?.updateTabDefaults({
653+
this.mynahUI?.updateTabDefaults({
652654
store: {
653655
...this.tabDataGenerator?.getTabData('cwc', true, undefined, this.isSMUS),
654656
tabHeaderDetails: void 0,
@@ -985,7 +987,9 @@ export class WebviewUIHandler {
985987
},
986988
],
987989
},
988-
})
990+
}
991+
992+
this.mynahUIRef = { mynahUI: new MynahUI(this.mynahUIProps) }
989993

990994
/**
991995
* Update the welcome count if we've initially shown
@@ -996,12 +1000,12 @@ export class WebviewUIHandler {
9961000
}
9971001

9981002
this.followUpsInteractionHandler = new FollowUpInteractionHandler({
999-
mynahUI: this.mynahUI,
1003+
mynahUIRef: this.mynahUIRef,
10001004
connector: this.connector,
10011005
tabsStorage: this.tabsStorage,
10021006
})
10031007
this.quickActionHandler = new QuickActionHandler({
1004-
mynahUI: this.mynahUI,
1008+
mynahUIRef: this.mynahUIRef,
10051009
connector: this.connector,
10061010
tabsStorage: this.tabsStorage,
10071011
isFeatureDevEnabled: this.isFeatureDevEnabled,
@@ -1011,12 +1015,12 @@ export class WebviewUIHandler {
10111015
isDocEnabled: this.isDocEnabled,
10121016
})
10131017
this.textMessageHandler = new TextMessageHandler({
1014-
mynahUI: this.mynahUI,
1018+
mynahUIRef: this.mynahUIRef,
10151019
connector: this.connector,
10161020
tabsStorage: this.tabsStorage,
10171021
})
10181022
this.messageController = new MessageController({
1019-
mynahUI: this.mynahUI,
1023+
mynahUIRef: this.mynahUIRef,
10201024
connector: this.connector,
10211025
tabsStorage: this.tabsStorage,
10221026
isFeatureDevEnabled: this.isFeatureDevEnabled,
@@ -1078,45 +1082,7 @@ export class WebviewUIHandler {
10781082
return {}
10791083
}
10801084

1081-
set mynahUI(mynahUI: MynahUI | undefined) {
1082-
this._mynahUI = mynahUI
1083-
1084-
this.followUpsInteractionHandler = new FollowUpInteractionHandler({
1085-
mynahUI: this.mynahUI!,
1086-
connector: this.connector!,
1087-
tabsStorage: this.tabsStorage,
1088-
})
1089-
1090-
this.quickActionHandler = new QuickActionHandler({
1091-
mynahUI: this.mynahUI!,
1092-
connector: this.connector!,
1093-
tabsStorage: this.tabsStorage,
1094-
isFeatureDevEnabled: this.isFeatureDevEnabled,
1095-
isGumbyEnabled: this.isGumbyEnabled,
1096-
isScanEnabled: this.isScanEnabled,
1097-
isTestEnabled: this.isTestEnabled,
1098-
isDocEnabled: this.isDocEnabled,
1099-
})
1100-
1101-
this.textMessageHandler = new TextMessageHandler({
1102-
mynahUI: this.mynahUI!,
1103-
connector: this.connector!,
1104-
tabsStorage: this.tabsStorage,
1105-
})
1106-
1107-
this.messageController = new MessageController({
1108-
mynahUI: this.mynahUI!,
1109-
connector: this.connector!,
1110-
tabsStorage: this.tabsStorage,
1111-
isFeatureDevEnabled: this.isFeatureDevEnabled,
1112-
isGumbyEnabled: this.isGumbyEnabled,
1113-
isScanEnabled: this.isScanEnabled,
1114-
isTestEnabled: this.isTestEnabled,
1115-
isDocEnabled: this.isDocEnabled,
1116-
})
1117-
}
1118-
11191085
get mynahUI(): MynahUI | undefined {
1120-
return this._mynahUI
1086+
return this.mynahUIRef.mynahUI
11211087
}
11221088
}

packages/core/src/amazonq/webview/ui/messages/controller.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import { Connector } from '../connector'
88
import { TabType, TabsStorage } from '../storages/tabsStorage'
99
import { TabDataGenerator } from '../tabs/generator'
1010
import { uiComponentsTexts } from '../texts/constants'
11+
import { MynahUIRef } from '../../../commons/types'
1112

1213
export interface MessageControllerProps {
13-
mynahUI: MynahUI
14+
mynahUIRef: MynahUIRef
1415
connector: Connector
1516
tabsStorage: TabsStorage
1617
isFeatureDevEnabled: boolean
@@ -22,13 +23,13 @@ export interface MessageControllerProps {
2223
}
2324

2425
export class MessageController {
25-
private mynahUI: MynahUI
26+
private mynahUIRef: MynahUIRef
2627
private connector: Connector
2728
private tabsStorage: TabsStorage
2829
private tabDataGenerator: TabDataGenerator
2930

3031
constructor(props: MessageControllerProps) {
31-
this.mynahUI = props.mynahUI
32+
this.mynahUIRef = props.mynahUIRef
3233
this.connector = props.connector
3334
this.tabsStorage = props.tabsStorage
3435
this.tabDataGenerator = new TabDataGenerator({
@@ -43,6 +44,10 @@ export class MessageController {
4344

4445
public sendSelectedCodeToTab(message: ChatItem, command: string = ''): string | undefined {
4546
const selectedTab = { ...this.tabsStorage.getSelectedTab() }
47+
if (!this.mynahUI) {
48+
return
49+
}
50+
4651
if (
4752
selectedTab?.id === undefined ||
4853
selectedTab?.type === undefined ||
@@ -76,6 +81,9 @@ export class MessageController {
7681

7782
public sendMessageToTab(message: ChatItem, tabType: TabType, command: string = ''): string | undefined {
7883
const selectedTab = this.tabsStorage.getSelectedTab()
84+
if (!this.mynahUI) {
85+
return
86+
}
7987

8088
if (
8189
selectedTab !== undefined &&
@@ -141,4 +149,8 @@ export class MessageController {
141149
return newTabID
142150
}
143151
}
152+
153+
private get mynahUI(): MynahUI | undefined {
154+
return this.mynahUIRef.mynahUI
155+
}
144156
}

packages/core/src/amazonq/webview/ui/messages/handler.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,21 @@
66
import { ChatItemType, ChatPrompt, MynahUI } from '@aws/mynah-ui'
77
import { Connector } from '../connector'
88
import { TabsStorage } from '../storages/tabsStorage'
9+
import { MynahUIRef } from '../../../commons/types'
910

1011
export interface TextMessageHandlerProps {
11-
mynahUI: MynahUI
12+
mynahUIRef: MynahUIRef
1213
connector: Connector
1314
tabsStorage: TabsStorage
1415
}
1516

1617
export class TextMessageHandler {
17-
private mynahUI: MynahUI
18+
private mynahUIRef: MynahUIRef
1819
private connector: Connector
1920
private tabsStorage: TabsStorage
2021

2122
constructor(props: TextMessageHandlerProps) {
22-
this.mynahUI = props.mynahUI
23+
this.mynahUIRef = props.mynahUIRef
2324
this.connector = props.connector
2425
this.tabsStorage = props.tabsStorage
2526
}
@@ -29,6 +30,10 @@ export class TextMessageHandler {
2930
this.tabsStorage.updateTabTypeFromUnknown(tabID, 'cwc')
3031
this.tabsStorage.resetTabTimer(tabID)
3132
this.connector.onUpdateTabType(tabID)
33+
if (!this.mynahUI) {
34+
return
35+
}
36+
3237
this.mynahUI.addChatItem(tabID, {
3338
type: ChatItemType.PROMPT,
3439
body: chatPrompt.escapedPrompt,
@@ -50,4 +55,8 @@ export class TextMessageHandler {
5055
})
5156
.then(() => {})
5257
}
58+
59+
private get mynahUI(): MynahUI | undefined {
60+
return this.mynahUIRef.mynahUI
61+
}
5362
}

0 commit comments

Comments
 (0)