Skip to content

Commit

Permalink
Foundation of Chat communication with LSP (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
angjordn authored Sep 17, 2024
1 parent 5556d3a commit bc75939
Show file tree
Hide file tree
Showing 19 changed files with 253 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat;

import software.aws.toolkits.eclipse.amazonq.chat.models.GenericTabParams;
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 chatMessageProivder;

public ChatCommunicationManager() {
this.jsonHandler = new JsonHandler();
this.chatMessageProivder = new ChatMessageProvider();
}

public void sendMessageToChatServerAsync(final Command command, final Object params) {

String jsonParams = jsonHandler.serialize(params);

switch (command) {
case CHAT_TAB_ADD:
GenericTabParams tabParams = jsonHandler.deserialize(jsonParams, GenericTabParams.class);
chatMessageProivder.sendTabAdd(tabParams);
break;
default:
PluginLogger.error("Unhandled chat command: " + command.toString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat;

import java.util.concurrent.ExecutionException;

import software.aws.toolkits.eclipse.amazonq.chat.models.GenericTabParams;
import software.aws.toolkits.eclipse.amazonq.lsp.AmazonQLspServer;
import software.aws.toolkits.eclipse.amazonq.providers.LspProvider;
import software.aws.toolkits.eclipse.amazonq.util.PluginLogger;
import software.aws.toolkits.eclipse.amazonq.views.model.Command;

public final class ChatMessageProvider {

private 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.");
}
}

public void sendTabAdd(final GenericTabParams tabParams) {
try {
PluginLogger.info("Sending " + Command.CHAT_TAB_ADD + " message to Amazon Q LSP server");
amazonQLspServer.tabAdd(tabParams).get();
} catch (InterruptedException | ExecutionException e) {
PluginLogger.error("Error occurred while sending message to Amazon Q LSP server for command " + Command.CHAT_TAB_ADD);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record ChatItemAction(
@JsonProperty("pillText") String pillText,
@JsonProperty("prompt") String prompt,
@JsonProperty("disabled") Boolean disabled,
@JsonProperty("description") String description,
@JsonProperty("type") String type
) { };

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record ChatPrompt(
@JsonProperty("prompt") String prompt,
@JsonProperty("escapedPrompt") String escapedPrompt,
@JsonProperty("command") String command
) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record ChatRequestParams(
@JsonProperty("tabId") String tabId,
@JsonProperty("prompt") ChatPrompt prompt
) { }

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record ChatResult(
@JsonProperty("body") String body,
@JsonProperty("messageId") String messageId,
@JsonProperty("canBeVoted") Boolean canBeVoted,
@JsonProperty("relatedContent") RelatedContent relatedContent,
@JsonProperty("followUp") FollowUp followUp,
@JsonProperty("codeReference") ReferenceTrackerInformation[] codeReference
) { };
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record FollowUp(
@JsonProperty("text") String text,
@JsonProperty("options") ChatItemAction[] options
) { }

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record GenericTabParams(
@JsonProperty("tabId") String tabId
) { }

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record RecommendationContentSpan(
@JsonProperty("start") Integer start,
@JsonProperty("end") Integer end
) { };
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record ReferenceTrackerInformation(
@JsonProperty("licenseName") String licenseName,
@JsonProperty("repository") String repository,
@JsonProperty("url") String url,
@JsonProperty("recommendationContentSpan") RecommendationContentSpan recommendationContentSpan,
@JsonProperty("information") String information
) { };
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record RelatedContent(
@JsonProperty("title") String title,
@JsonProperty("content") SourceLink[] content
) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.chat.models;

import com.fasterxml.jackson.annotation.JsonProperty;

public record SourceLink(
@JsonProperty("title") String title,
@JsonProperty("url") String url,
@JsonProperty("body") String body
) { };
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.eclipse.amazonq.lsp;

import java.util.concurrent.CompletableFuture;

import org.eclipse.lsp4j.jsonrpc.messages.ResponseMessage;
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
import org.eclipse.lsp4j.jsonrpc.services.JsonNotification;
import org.eclipse.lsp4j.services.LanguageServer;

import software.aws.toolkits.eclipse.amazonq.chat.models.ChatResult;
import software.aws.toolkits.eclipse.amazonq.chat.models.GenericTabParams;
import software.aws.toolkits.eclipse.amazonq.lsp.model.InlineCompletionParams;
import software.aws.toolkits.eclipse.amazonq.lsp.model.InlineCompletionResponse;
import software.aws.toolkits.eclipse.amazonq.lsp.model.UpdateCredentialsPayload;
Expand All @@ -18,6 +20,9 @@ public interface AmazonQLspServer extends LanguageServer {
@JsonRequest("aws/textDocument/inlineCompletionWithReferences")
CompletableFuture<InlineCompletionResponse> inlineCompletionWithReferences(InlineCompletionParams params);

@JsonNotification("aws/chat/tabAdd")
CompletableFuture<ChatResult> tabAdd(GenericTabParams params);

@JsonRequest("aws/credentials/token/update")
CompletableFuture<ResponseMessage> updateTokenCredentials(UpdateCredentialsPayload payload);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

package software.aws.toolkits.eclipse.amazonq.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public final class JsonHandler {
private final ObjectMapper objectMapper;

public JsonHandler() {
this.objectMapper = ObjectMapperFactory.getInstance();
}

public String serialize(final Object obj) {
String serializedObj = null;
try {
serializedObj = objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
PluginLogger.error("Error occurred while serializing object: " + obj.toString(), e);
return null;
}
return serializedObj;
}

public <T> T deserialize(final String jsonString, final Class<T> cls) {
try {
T params = objectMapper.readValue(jsonString, cls);
return params;
} catch (JsonProcessingException e) {
PluginLogger.error("Error occurred while deserializing jsonString: " + jsonString, e);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.eclipse.amazonq.views;


import org.eclipse.swt.browser.Browser;

import software.aws.toolkits.eclipse.amazonq.chat.ChatCommunicationManager;
import software.aws.toolkits.eclipse.amazonq.util.PluginLogger;
import software.aws.toolkits.eclipse.amazonq.views.model.Command;
import software.aws.toolkits.eclipse.amazonq.views.model.ParsedCommand;

public class AmazonQChatViewActionHandler implements ViewActionHandler {
private ChatCommunicationManager chatCommunicationManager;

public AmazonQChatViewActionHandler() {
chatCommunicationManager = new ChatCommunicationManager();
}

@Override
public final void handleCommand(final ParsedCommand parsedCommand, final Browser browser) {
switch (parsedCommand.getCommand()) {
Command command = parsedCommand.getCommand();
Object params = parsedCommand.getParams();

PluginLogger.info(command + " being processed by ActionHandler");

switch (command) {
case CHAT_READY:
PluginLogger.info("Chat_ready command received");
break;
case CHAT_TAB_ADD:
PluginLogger.info("Chat_tab_add command received with params " + parsedCommand.getParams().toString());
chatCommunicationManager.sendMessageToChatServerAsync(command, params);
break;
case TELEMETRY_EVENT:
PluginLogger.info("Telemetry command received with params " + parsedCommand.getParams().toString());
break;
default:
PluginLogger.info("Unhandled command: " + parsedCommand.getCommand());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ public final Optional<ParsedCommand> parseCommand(final Object[] arguments) {
String jsonString = (String) arguments[0];
try {
CommandRequest commandRequest = objectMapper.readValue(jsonString, CommandRequest.class);
return commandRequest.getParsedCommand();
ParsedCommand parsedCommand = commandRequest.getParsedCommand();

if (parsedCommand.getCommand() == null) {
return Optional.empty();
}

return Optional.ofNullable(parsedCommand);
} catch (JsonProcessingException e) {
PluginLogger.error("Error parsing webview command JSON: " + e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.eclipse.amazonq.views.model;

Expand Down Expand Up @@ -33,4 +32,8 @@ public static Optional<Command> fromString(final String value) {
PluginLogger.info("Unregistered command parsed: " + value);
return Optional.empty();
}

public String toString() {
return commandString;
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.eclipse.amazonq.views.model;
import java.util.Optional;

import com.fasterxml.jackson.annotation.JsonProperty;

public record CommandRequest(
@JsonProperty("command") String commandString,
@JsonProperty("params") Object params) {
public Optional<ParsedCommand> getParsedCommand() {
Optional<Command> command = Command.fromString(commandString);

if (!command.isPresent()) {
return Optional.empty();
}

ParsedCommand parsedCommand = new ParsedCommand(command.get(), Optional.ofNullable(params));
return Optional.ofNullable(parsedCommand);
public ParsedCommand getParsedCommand() {
Command command = Command.fromString(commandString).orElse(null);
ParsedCommand parsedCommand = new ParsedCommand(command, params);
return parsedCommand;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

package software.aws.toolkits.eclipse.amazonq.views.model;

import java.util.Optional;

public class ParsedCommand {

private final Command command;
private final Object params;

public ParsedCommand(final Command command, final Optional<Object> params) {
public ParsedCommand(final Command command, final Object params) {
this.command = command;
this.params = params;
}
Expand Down

0 comments on commit bc75939

Please sign in to comment.