From 456e9fd0fa841b6630beed473c78191bac06f83b Mon Sep 17 00:00:00 2001 From: nkomonen-amazon Date: Fri, 7 Feb 2025 10:52:28 -0500 Subject: [PATCH 1/2] fix(amazonq): right click options dont send context if chat not loaded 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. Signed-off-by: nkomonen-amazon --- packages/core/src/amazonq/apps/initContext.ts | 8 ++-- .../src/amazonq/messages/messagePublisher.ts | 45 +++++++++++++++++++ .../webview/messages/messageDispatcher.ts | 3 +- packages/core/src/shared/logger/logger.ts | 2 +- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/packages/core/src/amazonq/apps/initContext.ts b/packages/core/src/amazonq/apps/initContext.ts index e33fafca7c3..f8b06e4b46a 100644 --- a/packages/core/src/amazonq/apps/initContext.ts +++ b/packages/core/src/amazonq/apps/initContext.ts @@ -4,20 +4,20 @@ */ import { EventEmitter } from 'vscode' -import { MessagePublisher } from '../messages/messagePublisher' +import { MessagePublisher, UiMessagePublisher } from '../messages/messagePublisher' import { MessageListener } from '../messages/messageListener' import { TabType } from '../webview/ui/storages/tabsStorage' export interface AmazonQAppInitContext { registerWebViewToAppMessagePublisher(eventEmitter: MessagePublisher, tabType: TabType): void - getAppsToWebViewMessagePublisher(): MessagePublisher + getAppsToWebViewMessagePublisher(): UiMessagePublisher onDidChangeAmazonQVisibility: EventEmitter } export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext { private readonly appsToWebViewEventEmitter = new EventEmitter() private readonly appsToWebViewMessageListener = new MessageListener(this.appsToWebViewEventEmitter) - private readonly appsToWebViewMessagePublisher = new MessagePublisher(this.appsToWebViewEventEmitter) + private readonly appsToWebViewMessagePublisher = new UiMessagePublisher(this.appsToWebViewEventEmitter) private readonly webViewToAppsMessagePublishers: Map> = new Map() public readonly onDidChangeAmazonQVisibility = new EventEmitter() @@ -41,7 +41,7 @@ export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext { return this.appsToWebViewMessageListener } - getAppsToWebViewMessagePublisher(): MessagePublisher { + getAppsToWebViewMessagePublisher(): UiMessagePublisher { return this.appsToWebViewMessagePublisher } } diff --git a/packages/core/src/amazonq/messages/messagePublisher.ts b/packages/core/src/amazonq/messages/messagePublisher.ts index d2987a99536..7fa6976b9a9 100644 --- a/packages/core/src/amazonq/messages/messagePublisher.ts +++ b/packages/core/src/amazonq/messages/messagePublisher.ts @@ -12,3 +12,48 @@ export class MessagePublisher { this.eventEmitter.fire(event) } } + +/** + * Same as {@link MessagePublisher}, but will wait until the UI indicates it + * is ready to recieve messages, before the message is published. + * + * This solves a problem when running a right click menu option like + * "Send To Prompt" BUT chat is not opened yet, it would result in the prompt failing to + * be recieved by chat. + */ +export class UiMessagePublisher extends MessagePublisher { + private isUiReady: boolean = false + private buffer: T[] = [] + + constructor(eventEmitter: EventEmitter) { + super(eventEmitter) + } + + public override publish(event: T): void { + // immediately send if Chat UI is ready + if (this.isUiReady) { + super.publish(event) + return + } + + this.buffer.push(event) + } + + /** + * Indicate the Q Chat UI is ready to recieve messages. + */ + public setUiReady() { + this.isUiReady = true + this.flush() + } + + /** + * Publishes all blocked messages + */ + private flush() { + for (const msg of this.buffer) { + super.publish(msg) + } + this.buffer = [] + } +} diff --git a/packages/core/src/amazonq/webview/messages/messageDispatcher.ts b/packages/core/src/amazonq/webview/messages/messageDispatcher.ts index 8acd04e8953..fdd1584b767 100644 --- a/packages/core/src/amazonq/webview/messages/messageDispatcher.ts +++ b/packages/core/src/amazonq/webview/messages/messageDispatcher.ts @@ -13,6 +13,7 @@ import { telemetry } from '../../../shared/telemetry' import { AmazonQChatMessageDuration } from '../../messages/chatMessageDuration' import { globals, openUrl } from '../../../shared' import { isClickTelemetry, isOpenAgentTelemetry } from '../ui/telemetry/actions' +import { DefaultAmazonQAppInitContext } from '../../apps/initContext' export function dispatchWebViewMessagesToApps( webview: Webview, @@ -21,12 +22,12 @@ export function dispatchWebViewMessagesToApps( webview.onDidReceiveMessage((msg) => { switch (msg.command) { case 'ui-is-ready': { + DefaultAmazonQAppInitContext.instance.getAppsToWebViewMessagePublisher().setUiReady() /** * ui-is-ready isn't associated to any tab so just record the telemetry event and continue. * This would be equivalent of the duration between "user clicked open q" and "ui has become available" * NOTE: Amazon Q UI is only loaded ONCE. The state is saved between each hide/show of the webview. */ - telemetry.webview_load.emit({ webviewName: 'amazonq', duration: performance.measure(amazonqMark.uiReady, amazonqMark.open).duration, diff --git a/packages/core/src/shared/logger/logger.ts b/packages/core/src/shared/logger/logger.ts index d5bf5f13380..19be5ac2887 100644 --- a/packages/core/src/shared/logger/logger.ts +++ b/packages/core/src/shared/logger/logger.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode' -export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'unknown' +export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'unknown' | 'chat' class ErrorLog { constructor( From ac524d2ad33e02bc0bb0bae17023d3aa15d20e6e Mon Sep 17 00:00:00 2001 From: nkomonen-amazon Date: Fri, 7 Feb 2025 12:57:07 -0500 Subject: [PATCH 2/2] changelog item Signed-off-by: nkomonen-amazon --- .../Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json diff --git a/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json b/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json new file mode 100644 index 00000000000..01d6ec7c8b0 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "`Send to prompt` and other context menu options not sent if chat was closed" +}