\n" +
+ "{{selectedCode}}
\n" +
+ "For each identified issue, provide a report in the following format:\n" +
+ "\n" +
+ "### performance review report\n" +
+ "1. **the specific problem summary**\n" +
+ " - Code: [Provide the problematic code snippet or a range of lines in the code where the issue was found.]\n" +
+ " - Problem: [Describe the specific problem]\n" +
+ " - Suggestion: [Provide a suggestion for fixing the issue]"
+ ),
GENERATE_COMMENTS("devpilot.action.generate.comments", "Generate comments in the following code",
- "{{selectedCode}}\nGiving the code above, please generate code comments, return code with comments."),
+ "Write inline comments for the key parts of the specified function.\n" +
+ "The comments should explain what each part of the function does in a clear and concise manner.\n" +
+ "Avoid commenting on every single line of code, as this can make the code harder to read and maintain. Instead, focus on the parts of the function that are complex, important, or not immediately obvious.\n" +
+ "Remember, the goal of inline comments is to help other developers understand the code, not to explain every single detail.\n\n" +
+ "The comment is being written for the following code: \n" +
+ "{{selectedCode}}
"),
+
+ GENERATE_METHOD_COMMENTS("devpilot.action.generate.method.comments", "",
+ "Write a function comment for the specified function in the appropriate style for the programming language being used.\n" +
+ "The comment should start with a brief summary of what the function does. This should be followed by a detailed description, if necessary.\n" +
+ "Then, document each parameter, explaining the purpose of each one.\n" +
+ "If the function returns a value, describe what the function returns.\n" +
+ "If the function throws exceptions, document each exception and under what conditions it is thrown.\n" +
+ "Make sure the comment is clear, concise, and free of spelling and grammar errors.\n" +
+ "The comment should help other developers understand what the function does, how it works, and how to use it.\n" +
+ "Please note that the function definition is not included in this task, only the function comment is required.\n\n" +
+ "The comment is being written for the following code: \n" +
+ "{{selectedCode}}
"),
GENERATE_TESTS("devpilot.action.generate.tests", "Generate Tests in the following code",
"{{selectedCode}}\nGiving the {{language:unknown}} code above, " +
@@ -19,22 +58,57 @@ public enum EditorActionEnum {
"please state it and give suggestions instead."),
FIX_THIS("devpilot.action.fix", "Fix This in the following code",
- "{{selectedCode}}\nGiving the code above, please help to fix it:\n\n" +
- "- Fix any typos or grammar issues.\n" +
- "- Use better names as replacement to magic numbers or arbitrary acronyms.\n" +
- "- Simplify the code so that it's more strait forward and easy to understand.\n" +
- "- Optimize it for performance reasons.\n" +
- "- Refactor it using best practice in software engineering.\n" + "\nMust only provide the code to be fixed and explain why it should be fixed.\n"),
+ "Perform a code fix on the specified code. Only identify and make changes in the aspects where actual issues are found. Do not list out aspects that do not have issues. \n" +
+ "The fix may focus on, but is not limited to, the following aspects:\n" +
+ "1. Bug Fixes: Identify and correct any errors or bugs in the code. Ensure the fix doesn't introduce new bugs.\n" +
+ "2. Performance Improvements: Look for opportunities to optimize the code for better performance. This could involve changing algorithms, reducing memory usage, or other optimizations.\n" +
+ "3. Code Clarity: Make the code easier to read and understand. This could involve renaming variables for clarity, breaking up complex functions into smaller ones.\n" +
+ "4. Code Structure: Improve the organization of the code. This could involve refactoring the code to improve its structure, or rearranging code for better readability.\n" +
+ "5. Coding Standards: Ensure the code follows the agreed-upon coding standards. This includes naming conventions, comment style, indentation, and other formatting rules.\n" +
+ "6. Error Handling: Improve error handling in the code. The code should fail gracefully and not expose any sensitive information when an error occurs.\n" +
+ "Remember, the goal of a code fix is to improve the quality of the code and make it work correctly, efficiently, and in line with the requirements. Always test the code after making changes to ensure it still works as expected.\n" +
+ "\n" +
+ "The following code is being fixed: \n" +
+ "{{selectedCode}}
\n" +
+ "For each identified issue, provide an explanation of the problem and describe how it will be fixed. Then, present the fixed code."),
REVIEW_CODE("devpilot.action.review", "Review code in the following code",
- "{{selectedCode}}\nGiving the code above, please review the code line by line:\n\n" +
- "- Think carefully, you should be extremely careful.\n" +
- "- Find out if any bugs exists.\n" +
- "- Reveal any bad smell in the code.\n" +
- "- Give optimization or best practice suggestion.\n"),
+ "Perform a code review on the specified code. Only identify and report on the aspects where actual issues are found. Do not list out aspects that do not have issues.\n" +
+ "The review may focus on, but is not limited to, the following aspects:\n" +
+ "1. Code Clarity: Is the code easy to read and understand?\n" +
+ "2. Code Structure: Is the code well-structured and organized?\n" +
+ "3. Coding Standards: Does the code follow the agreed-upon coding standards?\n" +
+ "4. Error Handling: Does the code handle errors gracefully?\n" +
+ "5. Logic Errors: Are there any obvious mistakes in the code?\n" +
+ "6. Security: Are there any potential security vulnerabilities in the code?\n" +
+ "Remember, the goal of a code review is to improve the quality of the code and catch bugs before the code is executed. Always provide constructive feedback and explain why a change might be necessary.\n" +
+ "\n" +
+ "The following code is being reviewed: \n" +
+ "{{selectedCode}}
\n" +
+ "For each identified issue, provide a report in the following format:\n" +
+ "\n" +
+ "### code review report" +
+ "1. **the specific problem summary**\n" +
+ " - Code: [Provide the problematic code snippet or a range of lines in the code where the issue was found.]\n" +
+ " - Problem: [Describe the specific problem]\n" +
+ " - Suggestion: [Provide a suggestion for fixing the issue]"),
EXPLAIN_THIS("devpilot.action.explain", "Explain this in the following code",
- "{{selectedCode}}\nGiving the code above, please explain it in detail, line by line.\n");
+ "Write a detailed explanation for the specified code.\n" +
+ "Begin with a brief summary outlining its purpose and functionality.\n" +
+ "Then, dissect the code line by line or block by block.After each segment of code, provide a detailed explanation of its role and operation.\n" +
+ "Aim for clarity and conciseness in your explanation.Ensure that the explanation is comprehensive, covering all aspects of the code's operation, and free of spelling and grammar errors.\n" +
+ "The explanation should be interwoven with the code, providing a clear understanding of each part as it appears in the code sequence.\n" +
+ "Avoid including a separate copy of the complete original code, as the code is already explained in segments.\n\n" +
+ "The explanation is being written for the following code: \n" +
+ "{{selectedCode}}
"),
+
+ CODE_COMPLETIONS("devpilot.action.completions", "code completions",
+ "You are a code completion service, please try to auto complete the code below at {{offsetCode}}, " +
+ "only output the code, don't try to have conversation with user.```{{selectedCode}}```"
+// +
+// "\nThe completion code returned is controlled within {{maxCompletionLength}} bytes within"
+ );
private final String label;
diff --git a/src/main/java/com/zhongan/devpilot/enums/LoginTypeEnum.java b/src/main/java/com/zhongan/devpilot/enums/LoginTypeEnum.java
new file mode 100644
index 00000000..9932d0c3
--- /dev/null
+++ b/src/main/java/com/zhongan/devpilot/enums/LoginTypeEnum.java
@@ -0,0 +1,34 @@
+package com.zhongan.devpilot.enums;
+
+public enum LoginTypeEnum {
+ ZA("ZA", "众安保险SSO"),
+ ZA_TI("ZA_TI", "众安国际SSO"),
+ WX("WX", "微信公众号");
+
+ // login type
+ private final String type;
+
+ private final String displayName;
+
+ LoginTypeEnum(String type, String displayName) {
+ this.type = type;
+ this.displayName = displayName;
+ }
+
+ public static LoginTypeEnum getLoginTypeEnum(String type) {
+ for (LoginTypeEnum loginTypeEnum : LoginTypeEnum.values()) {
+ if (loginTypeEnum.getType().equals(type)) {
+ return loginTypeEnum;
+ }
+ }
+ return LoginTypeEnum.ZA;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+}
diff --git a/src/main/java/com/zhongan/devpilot/enums/ModelServiceEnum.java b/src/main/java/com/zhongan/devpilot/enums/ModelServiceEnum.java
index 6a617015..cb1ffdd1 100644
--- a/src/main/java/com/zhongan/devpilot/enums/ModelServiceEnum.java
+++ b/src/main/java/com/zhongan/devpilot/enums/ModelServiceEnum.java
@@ -4,7 +4,7 @@ public enum ModelServiceEnum {
OPENAI("OpenAI", "OpenAI Service"),
LLAMA("LLaMA", "Code LLaMA (Locally)"),
AIGATEWAY("AIGateway", "AI Gateway"),
- OLLAMA("Ollama", "Ollama Service");
+ TRIAL("Trial", "Trial Service (Free)");
// model name
private final String name;
diff --git a/src/main/java/com/zhongan/devpilot/enums/OpenAIModelNameEnum.java b/src/main/java/com/zhongan/devpilot/enums/OpenAIModelNameEnum.java
new file mode 100644
index 00000000..3f303dd7
--- /dev/null
+++ b/src/main/java/com/zhongan/devpilot/enums/OpenAIModelNameEnum.java
@@ -0,0 +1,51 @@
+package com.zhongan.devpilot.enums;
+
+public enum OpenAIModelNameEnum {
+ GPT3_5_TURBO("gpt-3.5-turbo", "gpt-3.5-turbo"),
+ GPT3_5_TURBO_16K("gpt-3.5-turbo-16k", "gpt-3.5-turbo(16k)"),
+ GPT4("gpt-4", "gpt-4"),
+ GPT4_32K("gpt-4-32k", "gpt-4(32k)"),
+ CUSTOM("custom", "Custom Model");
+
+ private String name;
+
+ private String displayName;
+
+ OpenAIModelNameEnum(String name, String displayName) {
+ this.name = name;
+ this.displayName = displayName;
+ }
+
+ public static OpenAIModelNameEnum fromName(String name) {
+ if (name == null) {
+ return GPT3_5_TURBO;
+ }
+ for (OpenAIModelNameEnum type : OpenAIModelNameEnum.values()) {
+ if (type.getName().equals(name)) {
+ return type;
+ }
+ }
+ return GPT3_5_TURBO;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ @Override
+ public String toString() {
+ return displayName;
+ }
+}
diff --git a/src/main/java/com/zhongan/devpilot/enums/ZaSsoEnum.java b/src/main/java/com/zhongan/devpilot/enums/ZaSsoEnum.java
new file mode 100644
index 00000000..90f3ab58
--- /dev/null
+++ b/src/main/java/com/zhongan/devpilot/enums/ZaSsoEnum.java
@@ -0,0 +1,42 @@
+package com.zhongan.devpilot.enums;
+
+public enum ZaSsoEnum {
+ ZA("ZA", "众安保险SSO"),
+ ZA_TI("ZA_TI", "众安国际SSO");
+
+ // sso name
+ private final String name;
+
+ // sso display name
+ private final String displayName;
+
+ ZaSsoEnum(String name, String displayName) {
+ this.name = name;
+ this.displayName = displayName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public static ZaSsoEnum fromName(String name) {
+ if (name == null) {
+ return ZA;
+ }
+ for (ZaSsoEnum type : ZaSsoEnum.values()) {
+ if (type.getName().equals(name)) {
+ return type;
+ }
+ }
+ return ZA;
+ }
+
+ @Override
+ public String toString() {
+ return displayName;
+ }
+}
diff --git a/src/main/java/com/zhongan/devpilot/exception/DevPilotErrorReporter.java b/src/main/java/com/zhongan/devpilot/exception/DevPilotErrorReporter.java
new file mode 100644
index 00000000..467530bf
--- /dev/null
+++ b/src/main/java/com/zhongan/devpilot/exception/DevPilotErrorReporter.java
@@ -0,0 +1,69 @@
+package com.zhongan.devpilot.exception;
+
+import com.intellij.diagnostic.ITNReporter;
+import com.intellij.diagnostic.PluginException;
+import com.intellij.ide.plugins.PluginUtil;
+import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
+import com.intellij.openapi.diagnostic.SubmittedReportInfo;
+import com.intellij.openapi.extensions.PluginId;
+import com.intellij.util.Consumer;
+import com.zhongan.devpilot.util.DevPilotMessageBundle;
+
+import java.awt.Component;
+import java.util.Objects;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * see {@link com.intellij.diagnostic.DefaultIdeaErrorLogger}
+ */
+public class DevPilotErrorReporter extends ITNReporter {
+
+ private static final String DEPRECATED_DEFAULT_PREFIX = "The default implementation of method";
+
+ private static final String DEPRECATED_DEFAULT_SUFFIX = "is deprecated, you need to override it in";
+
+ private static final String DEPRECATED_USAGE = "is deprecated and going to be removed soon.";
+
+ private final PluginId devpilotPluginId = PluginId.getId("com.zhongan.devPilot");
+
+
+ /**
+ * Ignore deprecated method error, in internal model, still receiver warning
+ * @param event
+ * @return
+ */
+ @Override
+ public boolean showErrorInRelease(IdeaLoggingEvent event) {
+ boolean isDevpilotDeprecatedUseNotice = false;
+ Throwable t = event.getThrowable();
+ PluginId pluginId = PluginUtil.getInstance().findPluginId(t);
+ if (Objects.equals(pluginId, devpilotPluginId)) {
+ if (t instanceof PluginException) {
+ PluginException pluginException = (PluginException) t;
+ String message = pluginException.getMessage();
+ if (StringUtils.isNoneBlank(message)) {
+ if (message.contains(DEPRECATED_USAGE) || (message.contains(DEPRECATED_DEFAULT_PREFIX) && message.contains(DEPRECATED_DEFAULT_SUFFIX))) {
+ isDevpilotDeprecatedUseNotice = true;
+ }
+ }
+ }
+ }
+ return !isDevpilotDeprecatedUseNotice;
+ }
+
+ @NotNull
+ @Override
+ public String getReportActionText() {
+ return DevPilotMessageBundle.get("devpilot.error.report");
+ }
+
+ @Override
+ public boolean submit(IdeaLoggingEvent @NotNull [] events, @Nullable String additionalInfo, @NotNull Component parentComponent, @NotNull Consumer super SubmittedReportInfo> consumer) {
+ // do nothing
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/zhongan/devpilot/gui/toolwindows/chat/DevPilotChatToolWindow.java b/src/main/java/com/zhongan/devpilot/gui/toolwindows/chat/DevPilotChatToolWindow.java
index e1b59b9e..7b835b76 100644
--- a/src/main/java/com/zhongan/devpilot/gui/toolwindows/chat/DevPilotChatToolWindow.java
+++ b/src/main/java/com/zhongan/devpilot/gui/toolwindows/chat/DevPilotChatToolWindow.java
@@ -5,23 +5,27 @@
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.SystemInfo;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.ui.jcef.JBCefBrowser;
import com.intellij.ui.jcef.JBCefBrowserBase;
import com.intellij.ui.jcef.JBCefJSQuery;
+import com.zhongan.devpilot.enums.ChatActionTypeEnum;
import com.zhongan.devpilot.enums.EditorActionEnum;
import com.zhongan.devpilot.enums.SessionTypeEnum;
import com.zhongan.devpilot.settings.state.DevPilotLlmSettingsState;
import com.zhongan.devpilot.util.ConfigChangeUtils;
import com.zhongan.devpilot.util.EditorUtils;
+import com.zhongan.devpilot.util.JetbrainsVersionUtils;
import com.zhongan.devpilot.util.JsonUtils;
+import com.zhongan.devpilot.util.LoginUtils;
import com.zhongan.devpilot.util.NewFileUtils;
+import com.zhongan.devpilot.util.TelemetryUtils;
import com.zhongan.devpilot.webview.DevPilotCustomHandlerFactory;
import com.zhongan.devpilot.webview.model.CodeActionModel;
import com.zhongan.devpilot.webview.model.CodeReferenceModel;
-import com.zhongan.devpilot.webview.model.CopyModel;
import com.zhongan.devpilot.webview.model.JsCallModel;
import com.zhongan.devpilot.webview.model.MessageModel;
@@ -56,8 +60,20 @@ public synchronized JBCefBrowser jbCefBrowser() {
private void load() {
JBCefBrowser browser;
try {
- browser = JBCefBrowser.createBuilder().setOffScreenRendering(false).build();
- } catch (Exception e) {
+ boolean isOffScreenRendering = true;
+ if (SystemInfo.isMac) {
+ isOffScreenRendering = false;
+ } else if (!SystemInfo.isLinux && !SystemInfo.isUnix) {
+ if (SystemInfo.isWindows) {
+ isOffScreenRendering = true;
+ }
+ } else {
+ isOffScreenRendering = JetbrainsVersionUtils.isVersionLaterThan233();
+ }
+
+ browser = JBCefBrowser.createBuilder().setOffScreenRendering(isOffScreenRendering).createBrowser();
+
+ } catch (Throwable e) {
browser = new JBCefBrowser();
}
@@ -112,6 +128,9 @@ private void registerJsCallJavaHandler(JBCefBrowser browser) {
}
insertAtCaret(codeActionModel.getContent());
+
+ TelemetryUtils.chatAccept(codeActionModel, ChatActionTypeEnum.INSERT);
+
return new JBCefJSQuery.Response("success");
}
case "ReplaceSelectedCode": {
@@ -123,6 +142,9 @@ private void registerJsCallJavaHandler(JBCefBrowser browser) {
}
replaceSelectionCode(codeActionModel.getContent());
+
+ TelemetryUtils.chatAccept(codeActionModel, ChatActionTypeEnum.REPLACE);
+
return new JBCefJSQuery.Response("success");
}
case "CreateNewFile": {
@@ -141,7 +163,9 @@ private void registerJsCallJavaHandler(JBCefBrowser browser) {
ApplicationManager.getApplication().invokeLater(
() -> NewFileUtils.createNewFile(project, codeActionModel.getContent(),
- userMessage.getCodeRef()));
+ userMessage.getCodeRef(), codeActionModel.getLang()));
+
+ TelemetryUtils.chatAccept(codeActionModel, ChatActionTypeEnum.NEW_FILE);
return new JBCefJSQuery.Response("success");
}
@@ -186,14 +210,51 @@ private void registerJsCallJavaHandler(JBCefBrowser browser) {
}
case "CopyCode": {
var payload = jsCallModel.getPayload();
- var copyModel = JsonUtils.fromJson(JsonUtils.toJson(payload), CopyModel.class);
+ var codeActionModel = JsonUtils.fromJson(JsonUtils.toJson(payload), CodeActionModel.class);
- if (copyModel == null || copyModel.getContent() == null) {
+ if (codeActionModel == null || codeActionModel.getContent() == null) {
return new JBCefJSQuery.Response("error");
}
var clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- clipboard.setContents(new StringSelection(copyModel.getContent()), null);
+ clipboard.setContents(new StringSelection(codeActionModel.getContent()), null);
+
+ TelemetryUtils.chatAccept(codeActionModel, ChatActionTypeEnum.COPY);
+
+ return new JBCefJSQuery.Response("success");
+ }
+ case "OpenFile": {
+ var payload = jsCallModel.getPayload();
+ var codeActionModel = JsonUtils.fromJson(JsonUtils.toJson(payload), CodeActionModel.class);
+
+ if (codeActionModel == null || codeActionModel.getContent() == null) {
+ return new JBCefJSQuery.Response("error");
+ }
+
+ String relativePath = codeActionModel.getContent();
+ String repo = codeActionModel.getRepo();
+ ApplicationManager.getApplication().invokeLater(
+ () -> EditorUtils.openFileByRelativePath(repo, project, relativePath));
+
+ return new JBCefJSQuery.Response("success");
+ }
+ case "Login": {
+ LoginUtils.gotoLogin();
+ return new JBCefJSQuery.Response("success");
+ }
+ case "DislikeMessage":
+ case "LikeMessage": {
+ var payload = jsCallModel.getPayload();
+ var messageModel = JsonUtils.fromJson(JsonUtils.toJson(payload), MessageModel.class);
+ if (messageModel == null || messageModel.getId() == null) {
+ return new JBCefJSQuery.Response("error");
+ }
+
+ var id = messageModel.getId();
+ var action = !command.equals("DislikeMessage");
+
+ TelemetryUtils.messageFeedback(id, action);
+ return new JBCefJSQuery.Response("success");
}
default:
return new JBCefJSQuery.Response("success");
@@ -214,9 +275,11 @@ public void onLoadStart(CefBrowser browser, CefFrame frame, CefRequest.Transitio
0
);
- var format = "window.intellijConfig = {theme: '%s', locale: '%s', username: '%s'};";
+ var format = "window.intellijConfig = {theme: '%s', locale: '%s', username: '%s', loggedIn: %s, env: '%s', version: '%s', platform: '%s'};";
var configModel = ConfigChangeUtils.configInit();
- var code = String.format(format, configModel.getTheme(), configModel.getLocale(), configModel.getUsername());
+ var code = String.format(format, configModel.getTheme(),
+ configModel.getLocale(), configModel.getUsername(), configModel.isLoggedIn(),
+ configModel.getEnv(), configModel.getVersion(), configModel.getPlatform());
browser.executeJavaScript(code, null, 0);
}
diff --git a/src/main/java/com/zhongan/devpilot/gui/toolwindows/chat/DevPilotChatToolWindowService.java b/src/main/java/com/zhongan/devpilot/gui/toolwindows/chat/DevPilotChatToolWindowService.java
index ccce7690..95b22792 100644
--- a/src/main/java/com/zhongan/devpilot/gui/toolwindows/chat/DevPilotChatToolWindowService.java
+++ b/src/main/java/com/zhongan/devpilot/gui/toolwindows/chat/DevPilotChatToolWindowService.java
@@ -6,7 +6,9 @@
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.Balloon;
import com.zhongan.devpilot.actions.editor.popupmenu.BasicEditorAction;
+import com.zhongan.devpilot.constant.DefaultConst;
import com.zhongan.devpilot.constant.PromptConst;
import com.zhongan.devpilot.enums.EditorActionEnum;
import com.zhongan.devpilot.enums.SessionTypeEnum;
@@ -14,15 +16,20 @@
import com.zhongan.devpilot.integrations.llms.LlmProviderFactory;
import com.zhongan.devpilot.integrations.llms.entity.DevPilotChatCompletionRequest;
import com.zhongan.devpilot.integrations.llms.entity.DevPilotMessage;
+import com.zhongan.devpilot.util.BalloonAlertUtils;
import com.zhongan.devpilot.util.DevPilotMessageBundle;
import com.zhongan.devpilot.util.JsonUtils;
import com.zhongan.devpilot.util.MessageUtil;
+import com.zhongan.devpilot.util.TokenUtils;
+import com.zhongan.devpilot.webview.model.EmbeddedModel;
import com.zhongan.devpilot.webview.model.JavaCallModel;
import com.zhongan.devpilot.webview.model.LocaleModel;
+import com.zhongan.devpilot.webview.model.LoginModel;
import com.zhongan.devpilot.webview.model.MessageModel;
import com.zhongan.devpilot.webview.model.ThemeModel;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@@ -58,15 +65,20 @@ public String sendMessage(Integer sessionType, String message, Consumer