From c8abd31ee556a26d088cc6966b021496b79a0275 Mon Sep 17 00:00:00 2001 From: Jonathan Breedlove Date: Wed, 25 Sep 2024 11:23:09 -0700 Subject: [PATCH] Make command handling in Q chat webview async --- .../chat/ChatCommunicationManager.java | 58 +++++++++---------- .../amazonq/chat/ChatMessageProvider.java | 28 ++++----- .../fetcher/RemoteManifestLspFetcher.java | 1 - .../views/AmazonQChatViewActionHandler.java | 55 +++++++++--------- 4 files changed, 72 insertions(+), 70 deletions(-) diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/chat/ChatCommunicationManager.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/chat/ChatCommunicationManager.java index 143e6269..2c229bce 100644 --- a/plugin/src/software/aws/toolkits/eclipse/amazonq/chat/ChatCommunicationManager.java +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/chat/ChatCommunicationManager.java @@ -2,6 +2,8 @@ package software.aws.toolkits.eclipse.amazonq.chat; +import java.util.concurrent.CompletableFuture; + import org.eclipse.swt.browser.Browser; import software.aws.toolkits.eclipse.amazonq.chat.models.ChatRequestParams; @@ -10,46 +12,43 @@ import software.aws.toolkits.eclipse.amazonq.chat.models.GenericTabParams; import software.aws.toolkits.eclipse.amazonq.exception.AmazonQPluginException; import software.aws.toolkits.eclipse.amazonq.util.JsonHandler; +import software.aws.toolkits.eclipse.amazonq.util.PluginLogger; import software.aws.toolkits.eclipse.amazonq.views.model.Command; public final class ChatCommunicationManager { private final JsonHandler jsonHandler; - private final ChatMessageProvider chatMessageProvider; + private final CompletableFuture chatMessageProvider; public ChatCommunicationManager() { this.jsonHandler = new JsonHandler(); - this.chatMessageProvider = new ChatMessageProvider(); + this.chatMessageProvider = ChatMessageProvider.createAsync(); } - /* - * Sends a message to the Amazon Q LSP server. - */ - public ChatResult sendMessageToChatServer(final Command command, final Object params) { - - switch (command) { - case CHAT_SEND_PROMPT: - ChatRequestParams chatRequestParams = jsonHandler.convertObject(params, ChatRequestParams.class); - ChatResult result = chatMessageProvider.sendChatPrompt(chatRequestParams); - return result; - case CHAT_READY: - chatMessageProvider.sendChatReady(); - return null; - case CHAT_TAB_ADD: - GenericTabParams tabParams = jsonHandler.convertObject(params, GenericTabParams.class); - chatMessageProvider.sendTabAdd(tabParams); - return null; - default: - throw new AmazonQPluginException("Unhandled command in ChatCommunicationManager: " + command.toString()); - } + public CompletableFuture sendMessageToChatServer(final Command command, final Object params) { + return chatMessageProvider.thenCompose(chatMessageProvider -> { + try { + switch (command) { + case CHAT_SEND_PROMPT: + ChatRequestParams chatRequestParams = jsonHandler.convertObject(params, ChatRequestParams.class); + return chatMessageProvider.sendChatPrompt(chatRequestParams); + case CHAT_READY: + chatMessageProvider.sendChatReady(); + return CompletableFuture.completedFuture(null); + case CHAT_TAB_ADD: + GenericTabParams tabParams = jsonHandler.convertObject(params, GenericTabParams.class); + chatMessageProvider.sendTabAdd(tabParams); + return CompletableFuture.completedFuture(null); + default: + throw new AmazonQPluginException("Unhandled command in ChatCommunicationManager: " + command.toString()); + } + } catch (Exception e) { + PluginLogger.error("Error occurred in sendMessageToChatServer", e); + return CompletableFuture.failedFuture(new AmazonQPluginException(e)); + } + }); } - /** - * Sends a message to the webview. - * - * See handlers in Flare chat-client: - * https://github.com/aws/language-servers/blob/9226fb4ed10dc54f1719b14a5b1dac1807641f79/chat-client/src/client/chat.ts#L67-L101 - */ public void sendMessageToChatUI(final Browser browser, final ChatUIInboundCommand command) { String message = this.jsonHandler.serialize(command); String script = "window.postMessage(" + message + ");"; @@ -57,4 +56,5 @@ public void sendMessageToChatUI(final Browser browser, final ChatUIInboundComman browser.evaluate(script); }); } -} + +} \ No newline at end of file diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/chat/ChatMessageProvider.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/chat/ChatMessageProvider.java index d1184b21..d8287739 100644 --- a/plugin/src/software/aws/toolkits/eclipse/amazonq/chat/ChatMessageProvider.java +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/chat/ChatMessageProvider.java @@ -2,7 +2,7 @@ package software.aws.toolkits.eclipse.amazonq.chat; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletableFuture; import software.aws.toolkits.eclipse.amazonq.chat.models.ChatRequestParams; import software.aws.toolkits.eclipse.amazonq.chat.models.ChatResult; @@ -15,25 +15,24 @@ public final class ChatMessageProvider { - private AmazonQLspServer amazonQLspServer; + private final AmazonQLspServer amazonQLspServer; - public ChatMessageProvider() { - try { - amazonQLspServer = LspProvider.getAmazonQServer().get(); - } catch (InterruptedException | ExecutionException e) { - PluginLogger.error("Error occurred while retrieving Amazon Q LSP server. Failed to instantiate ChatMessageProvider.", e); - throw new AmazonQPluginException(e); - } + public static CompletableFuture createAsync() { + return LspProvider.getAmazonQServer() + .thenApply(ChatMessageProvider::new); + } + + private ChatMessageProvider(AmazonQLspServer amazonQLspServer) { + this.amazonQLspServer = amazonQLspServer; } - public ChatResult sendChatPrompt(final ChatRequestParams chatRequestParams) { + public CompletableFuture sendChatPrompt(final ChatRequestParams chatRequestParams) { try { PluginLogger.info("Sending " + Command.CHAT_SEND_PROMPT + " message to Amazon Q LSP server"); - ChatResult chatResult = amazonQLspServer.sendChatPrompt(chatRequestParams).get(); - return chatResult; - } catch (InterruptedException | ExecutionException e) { + return amazonQLspServer.sendChatPrompt(chatRequestParams); + } catch (Exception e) { PluginLogger.error("Error occurred while sending " + Command.CHAT_SEND_PROMPT + " message to Amazon Q LSP server", e); - throw new AmazonQPluginException(e); + return CompletableFuture.failedFuture(new AmazonQPluginException(e)); } } @@ -56,4 +55,5 @@ public void sendTabAdd(final GenericTabParams tabParams) { throw new AmazonQPluginException(e); } } + } diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/lsp/manager/fetcher/RemoteManifestLspFetcher.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/lsp/manager/fetcher/RemoteManifestLspFetcher.java index 156da676..16c53ba8 100644 --- a/plugin/src/software/aws/toolkits/eclipse/amazonq/lsp/manager/fetcher/RemoteManifestLspFetcher.java +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/lsp/manager/fetcher/RemoteManifestLspFetcher.java @@ -35,7 +35,6 @@ public final class RemoteManifestLspFetcher implements LspFetcher { private static final int TIMEOUT_SECONDS = 10; private static final ObjectMapper OBJECT_MAPPER = ObjectMapperFactory.getInstance(); - private final String manifestUrl; private final VersionRange versionRange; private final boolean integrityChecking; diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/views/AmazonQChatViewActionHandler.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/views/AmazonQChatViewActionHandler.java index 3a1c6b62..56ea36e8 100644 --- a/plugin/src/software/aws/toolkits/eclipse/amazonq/views/AmazonQChatViewActionHandler.java +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/views/AmazonQChatViewActionHandler.java @@ -7,12 +7,12 @@ import software.aws.toolkits.eclipse.amazonq.chat.ChatCommunicationManager; import software.aws.toolkits.eclipse.amazonq.chat.models.ChatRequestParams; -import software.aws.toolkits.eclipse.amazonq.chat.models.ChatResult; import software.aws.toolkits.eclipse.amazonq.chat.models.ChatUIInboundCommand; import software.aws.toolkits.eclipse.amazonq.chat.models.ChatUIInboundCommandName; import software.aws.toolkits.eclipse.amazonq.exception.AmazonQPluginException; import software.aws.toolkits.eclipse.amazonq.util.JsonHandler; import software.aws.toolkits.eclipse.amazonq.util.PluginLogger; +import software.aws.toolkits.eclipse.amazonq.util.ThreadingUtils; import software.aws.toolkits.eclipse.amazonq.views.model.Command; import software.aws.toolkits.eclipse.amazonq.views.model.ParsedCommand; @@ -35,30 +35,33 @@ public final void handleCommand(final ParsedCommand parsedCommand, final Browser PluginLogger.info(command + " being processed by ActionHandler"); - switch (command) { - case CHAT_SEND_PROMPT: - ChatResult chatResult = chatCommunicationManager.sendMessageToChatServer(command, params); - - ChatRequestParams chatRequestParams = jsonHandler.convertObject(params, ChatRequestParams.class); - ChatUIInboundCommand chatUIInboundCommand = new ChatUIInboundCommand( - ChatUIInboundCommandName.ChatPrompt.toString(), - chatRequestParams.tabId(), - chatResult, - false - ); - chatCommunicationManager.sendMessageToChatUI(browser, chatUIInboundCommand); - break; - case CHAT_READY: - chatCommunicationManager.sendMessageToChatServer(command, params); - break; - case CHAT_TAB_ADD: - chatCommunicationManager.sendMessageToChatServer(command, params); - break; - case TELEMETRY_EVENT: - break; - default: - throw new AmazonQPluginException("Unhandled command in AmazonQChatViewActionHandler: " + command.toString()); - } + ThreadingUtils.executeAsyncTask(() -> { + switch (command) { + case CHAT_SEND_PROMPT: + chatCommunicationManager.sendMessageToChatServer(command, params) + .thenAccept(chatResult -> { + ChatRequestParams chatRequestParams = jsonHandler.convertObject(params, ChatRequestParams.class); + ChatUIInboundCommand chatUIInboundCommand = new ChatUIInboundCommand( + ChatUIInboundCommandName.ChatPrompt.toString(), + chatRequestParams.tabId(), + chatResult, + false + ); + chatCommunicationManager.sendMessageToChatUI(browser, chatUIInboundCommand); + }); + break; + case CHAT_READY: + chatCommunicationManager.sendMessageToChatServer(command, params); + break; + case CHAT_TAB_ADD: + chatCommunicationManager.sendMessageToChatServer(command, params); + break; + case TELEMETRY_EVENT: + break; + default: + throw new AmazonQPluginException("Unhandled command in AmazonQChatViewActionHandler: " + command.toString()); + } + }); } -} +} \ No newline at end of file