Skip to content

Commit 19d0346

Browse files
fix(amazonq): right click options dont send context if chat not loaded (#6527)
## Problem: When a user starts up VSC, hasn't opened Q chat yet, then highlights text and does a right click option like "send to prompt" THEN the whole prompt fails to make it to chat. This is because there is a race condition between the message being sent to the webview, and the webview completed loading and ready to recieve messages. ## Solution: In the appToMessage publisher, verify that the chat is ready to recieve messages based on if the webview sent the chat ui ready message. Otherwise wait until we get it, and then send the message. ### Demo #### Before https://github.com/user-attachments/assets/baf86737-4a5a-4f80-86fb-9abca2c56827 #### After  https://github.com/user-attachments/assets/c3361403-5dae-49df-a878-94722eb4fc62 --- - 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. --------- Signed-off-by: nkomonen-amazon <[email protected]>
1 parent 67f053c commit 19d0346

File tree

5 files changed

+56
-6
lines changed

5 files changed

+56
-6
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "`Send to prompt` and other context menu options not sent if chat was closed"
4+
}

packages/core/src/amazonq/apps/initContext.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@
44
*/
55

66
import { EventEmitter } from 'vscode'
7-
import { MessagePublisher } from '../messages/messagePublisher'
7+
import { MessagePublisher, UiMessagePublisher } from '../messages/messagePublisher'
88
import { MessageListener } from '../messages/messageListener'
99
import { TabType } from '../webview/ui/storages/tabsStorage'
1010

1111
export interface AmazonQAppInitContext {
1212
registerWebViewToAppMessagePublisher(eventEmitter: MessagePublisher<any>, tabType: TabType): void
13-
getAppsToWebViewMessagePublisher(): MessagePublisher<any>
13+
getAppsToWebViewMessagePublisher(): UiMessagePublisher<any>
1414
onDidChangeAmazonQVisibility: EventEmitter<boolean>
1515
}
1616

1717
export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext {
1818
private readonly appsToWebViewEventEmitter = new EventEmitter<any>()
1919
private readonly appsToWebViewMessageListener = new MessageListener<any>(this.appsToWebViewEventEmitter)
20-
private readonly appsToWebViewMessagePublisher = new MessagePublisher<any>(this.appsToWebViewEventEmitter)
20+
private readonly appsToWebViewMessagePublisher = new UiMessagePublisher<any>(this.appsToWebViewEventEmitter)
2121
private readonly webViewToAppsMessagePublishers: Map<TabType, MessagePublisher<any>> = new Map()
2222
public readonly onDidChangeAmazonQVisibility = new EventEmitter<boolean>()
2323

@@ -41,7 +41,7 @@ export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext {
4141
return this.appsToWebViewMessageListener
4242
}
4343

44-
getAppsToWebViewMessagePublisher(): MessagePublisher<any> {
44+
getAppsToWebViewMessagePublisher(): UiMessagePublisher<any> {
4545
return this.appsToWebViewMessagePublisher
4646
}
4747
}

packages/core/src/amazonq/messages/messagePublisher.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,48 @@ export class MessagePublisher<T> {
1212
this.eventEmitter.fire(event)
1313
}
1414
}
15+
16+
/**
17+
* Same as {@link MessagePublisher}, but will wait until the UI indicates it
18+
* is ready to recieve messages, before the message is published.
19+
*
20+
* This solves a problem when running a right click menu option like
21+
* "Send To Prompt" BUT chat is not opened yet, it would result in the prompt failing to
22+
* be recieved by chat.
23+
*/
24+
export class UiMessagePublisher<T> extends MessagePublisher<T> {
25+
private isUiReady: boolean = false
26+
private buffer: T[] = []
27+
28+
constructor(eventEmitter: EventEmitter<T>) {
29+
super(eventEmitter)
30+
}
31+
32+
public override publish(event: T): void {
33+
// immediately send if Chat UI is ready
34+
if (this.isUiReady) {
35+
super.publish(event)
36+
return
37+
}
38+
39+
this.buffer.push(event)
40+
}
41+
42+
/**
43+
* Indicate the Q Chat UI is ready to recieve messages.
44+
*/
45+
public setUiReady() {
46+
this.isUiReady = true
47+
this.flush()
48+
}
49+
50+
/**
51+
* Publishes all blocked messages
52+
*/
53+
private flush() {
54+
for (const msg of this.buffer) {
55+
super.publish(msg)
56+
}
57+
this.buffer = []
58+
}
59+
}

packages/core/src/amazonq/webview/messages/messageDispatcher.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { telemetry } from '../../../shared/telemetry'
1313
import { AmazonQChatMessageDuration } from '../../messages/chatMessageDuration'
1414
import { globals, openUrl } from '../../../shared'
1515
import { isClickTelemetry, isOpenAgentTelemetry } from '../ui/telemetry/actions'
16+
import { DefaultAmazonQAppInitContext } from '../../apps/initContext'
1617

1718
export function dispatchWebViewMessagesToApps(
1819
webview: Webview,
@@ -21,12 +22,12 @@ export function dispatchWebViewMessagesToApps(
2122
webview.onDidReceiveMessage((msg) => {
2223
switch (msg.command) {
2324
case 'ui-is-ready': {
25+
DefaultAmazonQAppInitContext.instance.getAppsToWebViewMessagePublisher().setUiReady()
2426
/**
2527
* ui-is-ready isn't associated to any tab so just record the telemetry event and continue.
2628
* This would be equivalent of the duration between "user clicked open q" and "ui has become available"
2729
* NOTE: Amazon Q UI is only loaded ONCE. The state is saved between each hide/show of the webview.
2830
*/
29-
3031
telemetry.webview_load.emit({
3132
webviewName: 'amazonq',
3233
duration: performance.measure(amazonqMark.uiReady, amazonqMark.open).duration,

packages/core/src/shared/logger/logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as vscode from 'vscode'
77

8-
export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'unknown'
8+
export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'unknown' | 'chat'
99

1010
class ErrorLog {
1111
constructor(

0 commit comments

Comments
 (0)