mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-12 14:10:29 +00:00
feat: add support for auto resolving compilation errors (#318)
This commit is contained in:
parent
7031a6dc73
commit
f831a1facd
51 changed files with 919 additions and 595 deletions
|
|
@ -1,10 +1,10 @@
|
|||
package ee.carlrobert.codegpt;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.util.List;
|
||||
|
||||
public class CodeGPTKeys {
|
||||
|
||||
public static final Key<List<CheckedFile>> SELECTED_FILES = Key.create("selectedFiles");
|
||||
public static final Key<List<ReferencedFile>> SELECTED_FILES = Key.create("selectedFiles");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
package ee.carlrobert.codegpt;
|
||||
|
||||
import static ee.carlrobert.codegpt.completions.ConversationType.FIX_COMPILE_ERRORS;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.intellij.compiler.CompilerMessageImpl;
|
||||
import com.intellij.notification.NotificationAction;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.compiler.CompilationStatusListener;
|
||||
import com.intellij.openapi.compiler.CompileContext;
|
||||
import com.intellij.openapi.compiler.CompilerMessage;
|
||||
import com.intellij.openapi.compiler.CompilerMessageCategory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestProvider;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ProjectCompilationStatusListener implements CompilationStatusListener {
|
||||
|
||||
private final Project project;
|
||||
|
||||
public ProjectCompilationStatusListener(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compilationFinished(
|
||||
boolean aborted,
|
||||
int errors,
|
||||
int warnings,
|
||||
@NotNull CompileContext compileContext) {
|
||||
var configuration = ConfigurationState.getInstance();
|
||||
var success = !configuration.isCaptureCompileErrors()
|
||||
|| (!aborted && errors == 0 && warnings == 0);
|
||||
if (success) {
|
||||
return;
|
||||
}
|
||||
if (errors > 0) {
|
||||
OverlayUtil.getDefaultNotification(
|
||||
CodeGPTBundle.get("notification.compilationError.description"),
|
||||
NotificationType.INFORMATION)
|
||||
.addAction(NotificationAction.createSimpleExpiring(
|
||||
CodeGPTBundle.get("notification.compilationError.okLabel"),
|
||||
() -> project.getService(StandardChatToolWindowContentManager.class)
|
||||
.sendMessage(getMultiFileMessage(compileContext), FIX_COMPILE_ERRORS)))
|
||||
.addAction(NotificationAction.createSimpleExpiring(
|
||||
CodeGPTBundle.get("checkForUpdatesTask.notification.hideButton"),
|
||||
() -> ConfigurationState.getInstance().setCaptureCompileErrors(false)))
|
||||
.notify(project);
|
||||
}
|
||||
}
|
||||
|
||||
private Message getMultiFileMessage(CompileContext compileContext) {
|
||||
var errorMapping = getErrorMapping(compileContext);
|
||||
var prompt = errorMapping.values().stream()
|
||||
.flatMap(Collection::stream)
|
||||
.collect(joining("\n\n"));
|
||||
|
||||
var message = new Message("Fix the following compile errors:\n\n" + prompt);
|
||||
message.setReferencedFilePaths(errorMapping.keySet().stream()
|
||||
.map(ReferencedFile::getFilePath)
|
||||
.collect(toList()));
|
||||
message.setUserMessage(message.getPrompt());
|
||||
message.setPrompt(CompletionRequestProvider.getPromptWithContext(
|
||||
new ArrayList<>(errorMapping.keySet()),
|
||||
prompt));
|
||||
return message;
|
||||
}
|
||||
|
||||
private HashMap<ReferencedFile, List<String>> getErrorMapping(CompileContext compileContext) {
|
||||
var errorMapping = new HashMap<ReferencedFile, List<String>>();
|
||||
for (var compilerMessage : compileContext.getMessages(CompilerMessageCategory.ERROR)) {
|
||||
var key = new ReferencedFile(new File(compilerMessage.getVirtualFile().getPath()));
|
||||
var prevValue = errorMapping.get(key);
|
||||
if (prevValue == null) {
|
||||
prevValue = new ArrayList<>();
|
||||
}
|
||||
prevValue.add(getCompilerErrorDetails(compilerMessage));
|
||||
errorMapping.put(key, prevValue);
|
||||
}
|
||||
return errorMapping;
|
||||
}
|
||||
|
||||
private String getCompilerErrorDetails(CompilerMessage compilerMessage) {
|
||||
if (compilerMessage instanceof CompilerMessageImpl) {
|
||||
return format(
|
||||
"%s:%d:%d - `%s`",
|
||||
compilerMessage.getVirtualFile().getName(),
|
||||
((CompilerMessageImpl) compilerMessage).getLine(),
|
||||
((CompilerMessageImpl) compilerMessage).getColumn(),
|
||||
compilerMessage.getMessage());
|
||||
}
|
||||
return format(
|
||||
"%s - `%s`",
|
||||
compilerMessage.getVirtualFile().getName(),
|
||||
compilerMessage.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -23,17 +23,13 @@ import com.intellij.openapi.vcs.ui.CommitMessage;
|
|||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.EncodingManager;
|
||||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.completions.CompletionClientProvider;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestService;
|
||||
import ee.carlrobert.codegpt.credentials.AzureCredentialsManager;
|
||||
import ee.carlrobert.codegpt.credentials.OpenAICredentialsManager;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.state.OpenAISettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil;
|
||||
import ee.carlrobert.llm.client.openai.completion.ErrorDetails;
|
||||
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionMessage;
|
||||
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionRequest;
|
||||
import ee.carlrobert.llm.completion.CompletionEventListener;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
|
|
@ -59,7 +55,7 @@ public class GenerateGitCommitMessageAction extends AnAction {
|
|||
public void update(@NotNull AnActionEvent event) {
|
||||
var selectedService = SettingsState.getInstance().getSelectedService();
|
||||
if (selectedService == ServiceType.OPENAI || selectedService == ServiceType.AZURE) {
|
||||
var filesSelected = !getCheckedFilePaths(event).isEmpty();
|
||||
var filesSelected = !getReferencedFilePaths(event).isEmpty();
|
||||
var callAllowed = (selectedService == ServiceType.OPENAI
|
||||
&& OpenAICredentialsManager.getInstance().isApiKeySet())
|
||||
|| (selectedService == ServiceType.AZURE
|
||||
|
|
@ -82,7 +78,7 @@ public class GenerateGitCommitMessageAction extends AnAction {
|
|||
return;
|
||||
}
|
||||
|
||||
var gitDiff = getGitDiff(project, getCheckedFilePaths(event));
|
||||
var gitDiff = getGitDiff(project, getReferencedFilePaths(event));
|
||||
var tokenCount = encodingManager.countTokens(gitDiff);
|
||||
if (tokenCount > 4096 && OverlayUtil.showTokenSoftLimitWarningDialog(tokenCount) != OK) {
|
||||
return;
|
||||
|
|
@ -91,25 +87,8 @@ public class GenerateGitCommitMessageAction extends AnAction {
|
|||
var editor = getCommitMessageEditor(event);
|
||||
if (editor != null) {
|
||||
((EditorEx) editor).setCaretVisible(false);
|
||||
generateMessage(project, editor, gitDiff);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateMessage(Project project, Editor editor, String gitDiff) {
|
||||
var request = new OpenAIChatCompletionRequest.Builder(List.of(
|
||||
new OpenAIChatCompletionMessage("system",
|
||||
ConfigurationState.getInstance().getCommitMessagePrompt()),
|
||||
new OpenAIChatCompletionMessage("user", gitDiff)))
|
||||
.setModel(OpenAISettingsState.getInstance().getModel())
|
||||
.build();
|
||||
var selectedService = SettingsState.getInstance().getSelectedService();
|
||||
if (selectedService == ServiceType.OPENAI) {
|
||||
CompletionClientProvider.getOpenAIClient()
|
||||
.getChatCompletion(request, getEventListener(project, editor.getDocument()));
|
||||
}
|
||||
if (selectedService == ServiceType.AZURE) {
|
||||
CompletionClientProvider.getAzureClient()
|
||||
.getChatCompletion(request, getEventListener(project, editor.getDocument()));
|
||||
CompletionRequestService.getInstance()
|
||||
.generateCommitMessageAsync(gitDiff, getEventListener(project, editor.getDocument()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +145,7 @@ public class GenerateGitCommitMessageAction extends AnAction {
|
|||
}
|
||||
}
|
||||
|
||||
private @NotNull List<String> getCheckedFilePaths(AnActionEvent event) {
|
||||
private @NotNull List<String> getReferencedFilePaths(AnActionEvent event) {
|
||||
var changesBrowserBase = event.getData(ChangesBrowserBase.DATA_KEY);
|
||||
if (changesBrowserBase == null) {
|
||||
return List.of();
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import ee.carlrobert.codegpt.ui.checkbox.FileCheckboxTree;
|
|||
import ee.carlrobert.codegpt.ui.checkbox.PsiElementCheckboxTree;
|
||||
import ee.carlrobert.codegpt.ui.checkbox.VirtualFileCheckboxTree;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.awt.Dimension;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
|
@ -62,7 +62,7 @@ public class IncludeFilesInContextAction extends AnAction {
|
|||
throw new RuntimeException("Could not obtain file tree");
|
||||
}
|
||||
|
||||
var totalTokensLabel = new TotalTokensLabel(checkboxTree.getCheckedFiles());
|
||||
var totalTokensLabel = new TotalTokensLabel(checkboxTree.getReferencedFiles());
|
||||
checkboxTree.addCheckboxTreeListener(new CheckboxTreeListener() {
|
||||
@Override
|
||||
public void nodeStateChanged(@NotNull CheckedTreeNode node) {
|
||||
|
|
@ -81,10 +81,10 @@ public class IncludeFilesInContextAction extends AnAction {
|
|||
totalTokensLabel,
|
||||
checkboxTree);
|
||||
if (show == OK_EXIT_CODE) {
|
||||
project.putUserData(CodeGPTKeys.SELECTED_FILES, checkboxTree.getCheckedFiles());
|
||||
project.putUserData(CodeGPTKeys.SELECTED_FILES, checkboxTree.getReferencedFiles());
|
||||
project.getMessageBus()
|
||||
.syncPublisher(IncludeFilesInContextNotifier.FILES_INCLUDED_IN_CONTEXT_TOPIC)
|
||||
.filesIncluded(checkboxTree.getCheckedFiles());
|
||||
.filesIncluded(checkboxTree.getReferencedFiles());
|
||||
includedFilesSettings.setPromptTemplate(promptTemplateTextArea.getText());
|
||||
includedFilesSettings.setRepeatableContext(repeatableContextTextArea.getText());
|
||||
}
|
||||
|
|
@ -111,9 +111,9 @@ public class IncludeFilesInContextAction extends AnAction {
|
|||
private int fileCount;
|
||||
private int totalTokens;
|
||||
|
||||
TotalTokensLabel(List<CheckedFile> checkedFiles) {
|
||||
fileCount = checkedFiles.size();
|
||||
totalTokens = calculateTotalTokens(checkedFiles);
|
||||
TotalTokensLabel(List<ReferencedFile> referencedFiles) {
|
||||
fileCount = referencedFiles.size();
|
||||
totalTokens = calculateTotalTokens(referencedFiles);
|
||||
updateText();
|
||||
}
|
||||
|
||||
|
|
@ -167,8 +167,8 @@ public class IncludeFilesInContextAction extends AnAction {
|
|||
FileUtil.convertLongValue(totalTokens)));
|
||||
}
|
||||
|
||||
private int calculateTotalTokens(List<CheckedFile> checkedFiles) {
|
||||
return checkedFiles.stream()
|
||||
private int calculateTotalTokens(List<ReferencedFile> referencedFiles) {
|
||||
return referencedFiles.stream()
|
||||
.mapToInt(file -> encodingManager.countTokens(file.getFileContent()))
|
||||
.sum();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package ee.carlrobert.codegpt.actions;
|
||||
|
||||
import com.intellij.util.messages.Topic;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.util.List;
|
||||
|
||||
public interface IncludeFilesInContextNotifier {
|
||||
|
|
@ -9,5 +9,5 @@ public interface IncludeFilesInContextNotifier {
|
|||
Topic<IncludeFilesInContextNotifier> FILES_INCLUDED_IN_CONTEXT_TOPIC =
|
||||
Topic.create("filesIncludedInContext", IncludeFilesInContextNotifier.class);
|
||||
|
||||
void filesIncluded(List<CheckedFile> includedFiles);
|
||||
void filesIncluded(List<ReferencedFile> includedFiles);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import ee.carlrobert.codegpt.conversations.message.Message;
|
|||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -67,15 +67,12 @@ public class EditorActionsUtil {
|
|||
message.setUserMessage(prompt.replace("{{selectedCode}}", ""));
|
||||
var toolWindowContentManager =
|
||||
project.getService(StandardChatToolWindowContentManager.class);
|
||||
var toolWindow = toolWindowContentManager.getToolWindow();
|
||||
if (toolWindow != null) {
|
||||
toolWindow.show();
|
||||
}
|
||||
toolWindowContentManager.getToolWindow().show();
|
||||
|
||||
message.setReferencedFilePaths(
|
||||
Stream.ofNullable(project.getUserData(CodeGPTKeys.SELECTED_FILES))
|
||||
.flatMap(Collection::stream)
|
||||
.map(CheckedFile::getFilePath)
|
||||
.map(ReferencedFile::getFilePath)
|
||||
.collect(toList()));
|
||||
toolWindowContentManager.sendMessage(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ee.carlrobert.codegpt.actions.toolwindow;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
|
|
@ -40,11 +41,11 @@ public class OpenInEditorAction extends AnAction {
|
|||
if (project != null && currentConversation != null) {
|
||||
var dateTimeStamp = currentConversation.getUpdatedOn()
|
||||
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
|
||||
var fileName = String.format("%s_%s.md", currentConversation.getModel(), dateTimeStamp);
|
||||
var fileName = format("%s_%s.md", currentConversation.getModel(), dateTimeStamp);
|
||||
var fileContent = currentConversation
|
||||
.getMessages()
|
||||
.stream()
|
||||
.map(it -> String.format("### User:\n%s\n### CodeGPT:\n%s\n", it.getPrompt(),
|
||||
.map(it -> format("### User:\n%s\n### CodeGPT:\n%s\n", it.getPrompt(),
|
||||
it.getResponse()))
|
||||
.collect(Collectors.joining());
|
||||
VirtualFile file = new LightVirtualFile(fileName, fileContent);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
|
||||
public class CallParameters {
|
||||
|
||||
private final Conversation conversation;
|
||||
private final ConversationType conversationType;
|
||||
private final Message message;
|
||||
private final boolean retry;
|
||||
|
||||
public CallParameters(
|
||||
Conversation conversation,
|
||||
ConversationType conversationType,
|
||||
Message message,
|
||||
boolean retry) {
|
||||
this.conversation = conversation;
|
||||
this.conversationType = conversationType;
|
||||
this.message = message;
|
||||
this.retry = retry;
|
||||
}
|
||||
|
||||
public Conversation getConversation() {
|
||||
return conversation;
|
||||
}
|
||||
|
||||
public ConversationType getConversationType() {
|
||||
return conversationType;
|
||||
}
|
||||
|
||||
public Message getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean isRetry() {
|
||||
return retry;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import ee.carlrobert.codegpt.CodeGPTPlugin;
|
||||
import ee.carlrobert.codegpt.completions.you.YouUserManager;
|
||||
import ee.carlrobert.codegpt.credentials.AzureCredentialsManager;
|
||||
|
|
@ -43,7 +45,7 @@ public class CompletionClientProvider {
|
|||
.setActiveDirectoryAuthentication(settings.isUseAzureActiveDirectoryAuthentication());
|
||||
var baseHost = settings.getBaseHost();
|
||||
if (baseHost != null) {
|
||||
builder.setUrl(String.format(baseHost, params.getResourceName()));
|
||||
builder.setUrl(format(baseHost, params.getResourceName()));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
|
||||
import ee.carlrobert.llm.client.openai.completion.ErrorDetails;
|
||||
|
|
@ -12,7 +10,6 @@ import ee.carlrobert.llm.completion.CompletionEventListener;
|
|||
import java.util.List;
|
||||
import javax.swing.SwingWorker;
|
||||
import okhttp3.sse.EventSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CompletionRequestHandler {
|
||||
|
||||
|
|
@ -31,8 +28,8 @@ public class CompletionRequestHandler {
|
|||
this.completionResponseEventListener = completionResponseEventListener;
|
||||
}
|
||||
|
||||
public void call(Conversation conversation, Message message, boolean retry) {
|
||||
swingWorker = new CompletionRequestWorker(conversation, message, retry);
|
||||
public void call(CallParameters callParameters) {
|
||||
swingWorker = new CompletionRequestWorker(callParameters);
|
||||
swingWorker.execute();
|
||||
}
|
||||
|
||||
|
|
@ -44,13 +41,11 @@ public class CompletionRequestHandler {
|
|||
}
|
||||
|
||||
private EventSource startCall(
|
||||
@NotNull Conversation conversation,
|
||||
@NotNull Message message,
|
||||
boolean retry,
|
||||
CallParameters callParameters,
|
||||
CompletionEventListener eventListener) {
|
||||
try {
|
||||
return CompletionRequestService.getInstance()
|
||||
.getChatCompletionAsync(conversation, message, retry, useContextualSearch, eventListener);
|
||||
.getChatCompletionAsync(callParameters, useContextualSearch, eventListener);
|
||||
} catch (Throwable ex) {
|
||||
handleCallException(ex);
|
||||
throw ex;
|
||||
|
|
@ -69,26 +64,20 @@ public class CompletionRequestHandler {
|
|||
|
||||
private class CompletionRequestWorker extends SwingWorker<Void, String> {
|
||||
|
||||
private final Conversation conversation;
|
||||
private final Message message;
|
||||
private final boolean retry;
|
||||
private final CallParameters callParameters;
|
||||
|
||||
public CompletionRequestWorker(Conversation conversation, Message message, boolean retry) {
|
||||
this.conversation = conversation;
|
||||
this.message = message;
|
||||
this.retry = retry;
|
||||
public CompletionRequestWorker(CallParameters callParameters) {
|
||||
this.callParameters = callParameters;
|
||||
}
|
||||
|
||||
protected Void doInBackground() {
|
||||
var settings = SettingsState.getInstance();
|
||||
try {
|
||||
eventSource = startCall(
|
||||
conversation,
|
||||
message,
|
||||
retry,
|
||||
new YouRequestCompletionEventListener());
|
||||
eventSource = startCall(callParameters, new YouRequestCompletionEventListener());
|
||||
} catch (TotalUsageExceededException e) {
|
||||
completionResponseEventListener.handleTokensExceeded(conversation, message);
|
||||
completionResponseEventListener.handleTokensExceeded(
|
||||
callParameters.getConversation(),
|
||||
callParameters.getMessage());
|
||||
} finally {
|
||||
sendInfo(settings);
|
||||
}
|
||||
|
|
@ -96,7 +85,7 @@ public class CompletionRequestHandler {
|
|||
}
|
||||
|
||||
protected void process(List<String> chunks) {
|
||||
message.setResponse(messageBuilder.toString());
|
||||
callParameters.getMessage().setResponse(messageBuilder.toString());
|
||||
for (String text : chunks) {
|
||||
messageBuilder.append(text);
|
||||
completionResponseEventListener.handleMessage(text);
|
||||
|
|
@ -107,7 +96,7 @@ public class CompletionRequestHandler {
|
|||
|
||||
@Override
|
||||
public void onSerpResults(List<YouSerpResult> results) {
|
||||
completionResponseEventListener.handleSerpResults(results, message);
|
||||
completionResponseEventListener.handleSerpResults(results, callParameters.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -117,11 +106,7 @@ public class CompletionRequestHandler {
|
|||
|
||||
@Override
|
||||
public void onComplete(StringBuilder messageBuilder) {
|
||||
completionResponseEventListener.handleCompleted(
|
||||
messageBuilder.toString(),
|
||||
message,
|
||||
conversation,
|
||||
retry);
|
||||
completionResponseEventListener.handleCompleted(messageBuilder.toString(), callParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -136,8 +121,8 @@ public class CompletionRequestHandler {
|
|||
|
||||
private void sendInfo(SettingsState settings) {
|
||||
TelemetryAction.COMPLETION.createActionMessage()
|
||||
.property("conversationId", conversation.getId().toString())
|
||||
.property("model", conversation.getModel())
|
||||
.property("conversationId", callParameters.getConversation().getId().toString())
|
||||
.property("model", callParameters.getConversation().getModel())
|
||||
.property("service", settings.getSelectedService().getCode().toLowerCase())
|
||||
.send();
|
||||
}
|
||||
|
|
@ -150,8 +135,8 @@ public class CompletionRequestHandler {
|
|||
.property("code", "INSUFFICIENT_QUOTA");
|
||||
} else {
|
||||
telemetryMessage
|
||||
.property("conversationId", conversation.getId().toString())
|
||||
.property("model", conversation.getModel())
|
||||
.property("conversationId", callParameters.getConversation().getId().toString())
|
||||
.property("model", callParameters.getConversation().getModel())
|
||||
.error(new RuntimeException(error.toString(), ex));
|
||||
}
|
||||
telemetryMessage.send();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.file.FileUtil.getResourceContent;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
|
|
@ -14,6 +16,7 @@ import ee.carlrobert.codegpt.conversations.ConversationsState;
|
|||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.state.IncludedFilesSettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.LlamaSettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.OpenAISettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
|
|
@ -21,6 +24,7 @@ import ee.carlrobert.codegpt.settings.state.YouSettingsState;
|
|||
import ee.carlrobert.codegpt.telemetry.core.configuration.TelemetryConfiguration;
|
||||
import ee.carlrobert.codegpt.telemetry.core.service.UserId;
|
||||
import ee.carlrobert.embedding.EmbeddingsService;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import ee.carlrobert.llm.client.llama.completion.LlamaCompletionRequest;
|
||||
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel;
|
||||
import ee.carlrobert.llm.client.openai.completion.OpenAICompletionRequest;
|
||||
|
|
@ -39,32 +43,14 @@ public class CompletionRequestProvider {
|
|||
|
||||
private static final Logger LOG = Logger.getInstance(CompletionRequestProvider.class);
|
||||
|
||||
public static final String COMPLETION_SYSTEM_PROMPT = "You are an AI programming assistant.\n"
|
||||
+ "Follow the user's requirements carefully & to the letter.\n"
|
||||
+ "Your responses should be informative and logical.\n"
|
||||
+ "You should always adhere to technical information.\n"
|
||||
+ "If the user asks for code or technical questions, you must provide code suggestions and "
|
||||
+ "adhere to technical information.\n"
|
||||
+ "If the question is related to a developer, you must respond with "
|
||||
+ "content related to a developer.\n"
|
||||
+ "First think step-by-step - describe your plan for what to build in pseudocode, "
|
||||
+ "written out in great detail.\n"
|
||||
+ "Then output the code in a single code block.\n"
|
||||
+ "Minimize any other prose.\n"
|
||||
+ "Keep your answers short and impersonal.\n"
|
||||
+ "Use Markdown formatting in your answers.\n"
|
||||
+ "Make sure to include the programming language name at the start of the "
|
||||
+ "Markdown code blocks.\n"
|
||||
+ "Avoid wrapping the whole response in triple backticks.\n"
|
||||
+ "The user works in an IDE built by JetBrains which has a concept for editors "
|
||||
+ "with open files, integrated unit test support, and output pane that shows "
|
||||
+ "the output of running the code as well as an integrated terminal.\n"
|
||||
+ "You can only give one reply for each conversation turn.";
|
||||
public static final String COMPLETION_SYSTEM_PROMPT = getResourceContent(
|
||||
"/prompts/default-completion-system-prompt.txt");
|
||||
|
||||
public static final String COMPLETION_COMMIT_MESSAGE_PROMPT =
|
||||
"Write a short and descriptive git commit message for the following git diff.\n"
|
||||
+ "Use imperative mood, present tense, active voice and verbs.\n"
|
||||
+ "Your entire response will be passed directly into git commit.";
|
||||
public static final String GENERATE_COMMIT_MESSAGE_SYSTEM_PROMPT = getResourceContent(
|
||||
"/prompts/generate-commit-message-system-prompt.txt");
|
||||
|
||||
public static final String FIX_COMPILE_ERRORS_SYSTEM_PROMPT = getResourceContent(
|
||||
"/prompts/fix-compile-errors.txt");
|
||||
|
||||
private final EncodingManager encodingManager = EncodingManager.getInstance();
|
||||
private final EmbeddingsService embeddingsService;
|
||||
|
|
@ -77,6 +63,23 @@ public class CompletionRequestProvider {
|
|||
this.conversation = conversation;
|
||||
}
|
||||
|
||||
public static String getPromptWithContext(List<ReferencedFile> referencedFiles,
|
||||
String userPrompt) {
|
||||
var includedFilesSettings = IncludedFilesSettingsState.getInstance();
|
||||
var repeatableContext = referencedFiles.stream()
|
||||
.map(item -> includedFilesSettings.getRepeatableContext()
|
||||
.replace("{FILE_PATH}", item.getFilePath())
|
||||
.replace("{FILE_CONTENT}", format(
|
||||
"```%s\n%s\n```",
|
||||
item.getFileExtension(),
|
||||
item.getFileContent().trim())))
|
||||
.collect(joining("\n\n"));
|
||||
|
||||
return includedFilesSettings.getPromptTemplate()
|
||||
.replace("{REPEATABLE_CONTEXT}", repeatableContext)
|
||||
.replace("{QUESTION}", userPrompt);
|
||||
}
|
||||
|
||||
public static OpenAICompletionRequest buildOpenAILookupCompletionRequest(
|
||||
String context) {
|
||||
return new OpenAIChatCompletionRequest.Builder(
|
||||
|
|
@ -96,13 +99,21 @@ public class CompletionRequestProvider {
|
|||
.build();
|
||||
}
|
||||
|
||||
public LlamaCompletionRequest buildLlamaCompletionRequest(Message message) {
|
||||
public LlamaCompletionRequest buildLlamaCompletionRequest(
|
||||
Message message,
|
||||
ConversationType conversationType) {
|
||||
var settings = LlamaSettingsState.getInstance();
|
||||
var promptTemplate = settings.isUseCustomModel()
|
||||
? settings.getPromptTemplate()
|
||||
: LlamaModel.findByHuggingFaceModel(settings.getHuggingFaceModel()).getPromptTemplate();
|
||||
|
||||
var systemPrompt = COMPLETION_SYSTEM_PROMPT;
|
||||
if (conversationType == ConversationType.FIX_COMPILE_ERRORS) {
|
||||
systemPrompt = FIX_COMPILE_ERRORS_SYSTEM_PROMPT;
|
||||
}
|
||||
|
||||
var prompt = promptTemplate.buildPrompt(
|
||||
COMPLETION_SYSTEM_PROMPT,
|
||||
systemPrompt,
|
||||
message.getPrompt(),
|
||||
conversation.getMessages());
|
||||
var configuration = ConfigurationState.getInstance();
|
||||
|
|
@ -131,21 +142,13 @@ public class CompletionRequestProvider {
|
|||
return requestBuilder.build();
|
||||
}
|
||||
|
||||
public OpenAIChatCompletionRequest buildOpenAIChatCompletionRequest(
|
||||
String model,
|
||||
Message message,
|
||||
boolean retry) {
|
||||
return buildOpenAIChatCompletionRequest(model, message, retry, false, null);
|
||||
}
|
||||
|
||||
public OpenAIChatCompletionRequest buildOpenAIChatCompletionRequest(
|
||||
@Nullable String model,
|
||||
Message message,
|
||||
boolean retry,
|
||||
CallParameters callParameters,
|
||||
boolean useContextualSearch,
|
||||
@Nullable String overriddenPath) {
|
||||
var builder = new OpenAIChatCompletionRequest.Builder(
|
||||
buildMessages(model, message, retry, useContextualSearch))
|
||||
buildMessages(model, callParameters, useContextualSearch))
|
||||
.setModel(model)
|
||||
.setMaxTokens(ConfigurationState.getInstance().getMaxTokens())
|
||||
.setTemperature(ConfigurationState.getInstance().getTemperature());
|
||||
|
|
@ -158,21 +161,27 @@ public class CompletionRequestProvider {
|
|||
}
|
||||
|
||||
public List<OpenAIChatCompletionMessage> buildMessages(
|
||||
Message message,
|
||||
boolean retry,
|
||||
CallParameters callParameters,
|
||||
boolean useContextualSearch) {
|
||||
var message = callParameters.getMessage();
|
||||
var messages = new ArrayList<OpenAIChatCompletionMessage>();
|
||||
if (useContextualSearch) {
|
||||
var prompt = embeddingsService.buildPromptWithContext(message.getPrompt());
|
||||
var prompt = embeddingsService.buildPromptWithContext(
|
||||
message.getPrompt());
|
||||
LOG.info("Retrieved context:\n" + prompt);
|
||||
messages.add(new OpenAIChatCompletionMessage("user", prompt));
|
||||
} else {
|
||||
var systemPrompt = ConfigurationState.getInstance().getSystemPrompt();
|
||||
messages.add(new OpenAIChatCompletionMessage("system",
|
||||
systemPrompt.isEmpty() ? COMPLETION_SYSTEM_PROMPT : systemPrompt));
|
||||
if (callParameters.getConversationType() == ConversationType.DEFAULT) {
|
||||
messages.add(new OpenAIChatCompletionMessage(
|
||||
"system",
|
||||
ConfigurationState.getInstance().getSystemPrompt()));
|
||||
}
|
||||
if (callParameters.getConversationType() == ConversationType.FIX_COMPILE_ERRORS) {
|
||||
messages.add(new OpenAIChatCompletionMessage("system", FIX_COMPILE_ERRORS_SYSTEM_PROMPT));
|
||||
}
|
||||
|
||||
for (var prevMessage : conversation.getMessages()) {
|
||||
if (retry && prevMessage.getId().equals(message.getId())) {
|
||||
if (callParameters.isRetry() && prevMessage.getId().equals(message.getId())) {
|
||||
break;
|
||||
}
|
||||
messages.add(new OpenAIChatCompletionMessage("user", prevMessage.getPrompt()));
|
||||
|
|
@ -185,10 +194,9 @@ public class CompletionRequestProvider {
|
|||
|
||||
private List<OpenAIChatCompletionMessage> buildMessages(
|
||||
@Nullable String model,
|
||||
Message message,
|
||||
boolean retry,
|
||||
CallParameters callParameters,
|
||||
boolean useContextualSearch) {
|
||||
var messages = buildMessages(message, retry, useContextualSearch);
|
||||
var messages = buildMessages(callParameters, useContextualSearch);
|
||||
|
||||
if (model == null || SettingsState.getInstance().getSelectedService() == ServiceType.YOU) {
|
||||
return messages;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,24 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.LLAMA_CPP;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.OPENAI;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.YOU;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.Service;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.credentials.AzureCredentialsManager;
|
||||
import ee.carlrobert.codegpt.credentials.OpenAICredentialsManager;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.state.AzureSettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.OpenAISettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionMessage;
|
||||
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionRequest;
|
||||
import ee.carlrobert.llm.completion.CompletionEventListener;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import okhttp3.sse.EventSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Service
|
||||
public final class CompletionRequestService {
|
||||
|
|
@ -25,46 +31,79 @@ public final class CompletionRequestService {
|
|||
}
|
||||
|
||||
public EventSource getChatCompletionAsync(
|
||||
@NotNull Conversation conversation,
|
||||
@NotNull Message message,
|
||||
boolean retry,
|
||||
CallParameters callParameters,
|
||||
boolean useContextualSearch,
|
||||
CompletionEventListener eventListener) {
|
||||
var requestProvider = new CompletionRequestProvider(conversation);
|
||||
var requestProvider = new CompletionRequestProvider(callParameters.getConversation());
|
||||
switch (SettingsState.getInstance().getSelectedService()) {
|
||||
case OPENAI:
|
||||
var openAISettings = OpenAISettingsState.getInstance();
|
||||
return CompletionClientProvider.getOpenAIClient().getChatCompletion(
|
||||
return CompletionClientProvider.getOpenAIClient().getChatCompletionAsync(
|
||||
requestProvider.buildOpenAIChatCompletionRequest(
|
||||
openAISettings.getModel(),
|
||||
message,
|
||||
retry,
|
||||
callParameters,
|
||||
useContextualSearch,
|
||||
openAISettings.isUsingCustomPath() ? openAISettings.getPath() : null),
|
||||
eventListener);
|
||||
case AZURE:
|
||||
var azureSettings = AzureSettingsState.getInstance();
|
||||
return CompletionClientProvider.getAzureClient().getChatCompletion(
|
||||
return CompletionClientProvider.getAzureClient().getChatCompletionAsync(
|
||||
requestProvider.buildOpenAIChatCompletionRequest(
|
||||
null,
|
||||
message,
|
||||
retry,
|
||||
callParameters,
|
||||
useContextualSearch,
|
||||
azureSettings.isUsingCustomPath() ? azureSettings.getPath() : null),
|
||||
eventListener);
|
||||
case YOU:
|
||||
return CompletionClientProvider.getYouClient().getChatCompletion(
|
||||
requestProvider.buildYouCompletionRequest(message),
|
||||
return CompletionClientProvider.getYouClient().getChatCompletionAsync(
|
||||
requestProvider.buildYouCompletionRequest(callParameters.getMessage()),
|
||||
eventListener);
|
||||
case LLAMA_CPP:
|
||||
return CompletionClientProvider.getLlamaClient().getChatCompletion(
|
||||
requestProvider.buildLlamaCompletionRequest(message),
|
||||
return CompletionClientProvider.getLlamaClient().getChatCompletionAsync(
|
||||
requestProvider.buildLlamaCompletionRequest(
|
||||
callParameters.getMessage(),
|
||||
callParameters.getConversationType()),
|
||||
eventListener);
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public void generateCommitMessageAsync(
|
||||
String prompt,
|
||||
CompletionEventListener eventListener) {
|
||||
var request = new OpenAIChatCompletionRequest.Builder(List.of(
|
||||
new OpenAIChatCompletionMessage("system",
|
||||
ConfigurationState.getInstance().getCommitMessagePrompt()),
|
||||
new OpenAIChatCompletionMessage("user", prompt)))
|
||||
.setModel(OpenAISettingsState.getInstance().getModel())
|
||||
.build();
|
||||
var selectedService = SettingsState.getInstance().getSelectedService();
|
||||
if (selectedService == ServiceType.OPENAI) {
|
||||
CompletionClientProvider.getOpenAIClient().getChatCompletionAsync(request, eventListener);
|
||||
}
|
||||
if (selectedService == ServiceType.AZURE) {
|
||||
CompletionClientProvider.getAzureClient().getChatCompletionAsync(request, eventListener);
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<String> getLookupCompletion(String prompt) {
|
||||
var selectedService = SettingsState.getInstance().getSelectedService();
|
||||
if (selectedService == YOU || selectedService == LLAMA_CPP) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
var request = CompletionRequestProvider.buildOpenAILookupCompletionRequest(prompt);
|
||||
var response = selectedService == OPENAI
|
||||
? CompletionClientProvider.getOpenAIClient().getChatCompletion(request)
|
||||
: CompletionClientProvider.getAzureClient().getChatCompletion(request);
|
||||
return response
|
||||
.getChoices()
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(item -> item.getMessage().getContent());
|
||||
}
|
||||
|
||||
public boolean isRequestAllowed() {
|
||||
var selectedService = SettingsState.getInstance().getSelectedService();
|
||||
if (selectedService == ServiceType.AZURE) {
|
||||
|
|
|
|||
|
|
@ -8,17 +8,18 @@ import java.util.List;
|
|||
|
||||
public interface CompletionResponseEventListener {
|
||||
|
||||
default void handleMessage(String message) {}
|
||||
default void handleMessage(String message) {
|
||||
}
|
||||
|
||||
default void handleError(ErrorDetails error, Throwable ex) {}
|
||||
default void handleError(ErrorDetails error, Throwable ex) {
|
||||
}
|
||||
|
||||
default void handleTokensExceeded(Conversation conversation, Message message) {}
|
||||
default void handleTokensExceeded(Conversation conversation, Message message) {
|
||||
}
|
||||
|
||||
default void handleCompleted(
|
||||
String fullMessage,
|
||||
Message message,
|
||||
Conversation conversation,
|
||||
boolean retry) {}
|
||||
default void handleCompleted(String fullMessage, CallParameters callParameters) {
|
||||
}
|
||||
|
||||
default void handleSerpResults(List<YouSerpResult> results, Message message) {}
|
||||
default void handleSerpResults(List<YouSerpResult> results, Message message) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
public enum ConversationType {
|
||||
CUSTOM_PROMPT,
|
||||
DEFAULT,
|
||||
EDITOR_ACTION,
|
||||
FIX_COMPILE_ERRORS,
|
||||
MULTI_FILE,
|
||||
}
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.AZURE;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.OPENAI;
|
||||
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
|
|
@ -15,7 +12,6 @@ import com.intellij.psi.util.PsiUtilCore;
|
|||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.credentials.OpenAICredentialsManager;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import java.util.Optional;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
|
@ -51,35 +47,16 @@ public class MethodNameLookupListener implements LookupManagerListener {
|
|||
LookupImpl lookup,
|
||||
Application application,
|
||||
String prompt) {
|
||||
getCompletionResponse(prompt).ifPresent(response -> {
|
||||
for (var value : response.split(",")) {
|
||||
application.runReadAction(() -> {
|
||||
lookup.addItem(
|
||||
LookupElementBuilder.create(value.trim()).withIcon(Icons.Sparkle),
|
||||
PrefixMatcher.ALWAYS_TRUE);
|
||||
application.invokeLater(() -> lookup.refreshUi(true, true));
|
||||
CompletionRequestService.getInstance().getLookupCompletion(prompt)
|
||||
.ifPresent(response -> {
|
||||
for (var value : response.split(",")) {
|
||||
application.runReadAction(() -> {
|
||||
lookup.addItem(
|
||||
LookupElementBuilder.create(value.trim()).withIcon(Icons.Sparkle),
|
||||
PrefixMatcher.ALWAYS_TRUE);
|
||||
application.invokeLater(() -> lookup.refreshUi(true, true));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Refactor
|
||||
private Optional<String> getCompletionResponse(String prompt) {
|
||||
var selectedService = SettingsState.getInstance().getSelectedService();
|
||||
if (selectedService == OPENAI) {
|
||||
return Optional.ofNullable(CompletionClientProvider.getOpenAIClient()
|
||||
.getChatCompletion(
|
||||
CompletionRequestProvider.buildOpenAILookupCompletionRequest(prompt))
|
||||
.getChoices())
|
||||
.map(choices -> choices.get(0).getMessage().getContent());
|
||||
}
|
||||
if (selectedService == AZURE) {
|
||||
return Optional.ofNullable(CompletionClientProvider.getAzureClient()
|
||||
.getChatCompletion(
|
||||
CompletionRequestProvider.buildOpenAILookupCompletionRequest(prompt))
|
||||
.getChoices())
|
||||
.map(choices -> choices.get(0).getMessage().getContent());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,8 +83,4 @@ public class Conversation {
|
|||
.filter(message -> !message.getId().equals(messageId))
|
||||
.collect(toList()));
|
||||
}
|
||||
|
||||
public void removeMessages() {
|
||||
messages.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import static java.util.stream.Collectors.toList;
|
|||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.Service;
|
||||
import ee.carlrobert.codegpt.completions.CallParameters;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.state.AzureSettingsState;
|
||||
|
|
@ -14,6 +15,7 @@ import java.time.LocalDateTime;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
|
@ -60,13 +62,11 @@ public final class ConversationService {
|
|||
conversationsMapping.put(conversation.getClientCode(), conversations);
|
||||
}
|
||||
|
||||
public void saveMessage(
|
||||
String response,
|
||||
Message message,
|
||||
Conversation conversation,
|
||||
boolean retry) {
|
||||
public void saveMessage(String response, CallParameters callParameters) {
|
||||
var conversation = callParameters.getConversation();
|
||||
var message = callParameters.getMessage();
|
||||
var conversationMessages = conversation.getMessages();
|
||||
if (retry && !conversationMessages.isEmpty()) {
|
||||
if (callParameters.isRetry() && !conversationMessages.isEmpty()) {
|
||||
var messageToBeSaved = conversationMessages.stream()
|
||||
.filter(item -> item.getId().equals(message.getId()))
|
||||
.findFirst().orElseThrow();
|
||||
|
|
@ -82,9 +82,7 @@ public final class ConversationService {
|
|||
|
||||
public void saveMessage(@NotNull Conversation conversation, @NotNull Message message) {
|
||||
conversation.setUpdatedOn(LocalDateTime.now());
|
||||
var iterator = conversationState.getConversationsMapping()
|
||||
.get(conversation.getClientCode())
|
||||
.listIterator();
|
||||
var iterator = getIterator(conversation.getClientCode());
|
||||
while (iterator.hasNext()) {
|
||||
var next = iterator.next();
|
||||
next.setMessages(
|
||||
|
|
@ -102,9 +100,7 @@ public final class ConversationService {
|
|||
|
||||
public void saveConversation(Conversation conversation) {
|
||||
conversation.setUpdatedOn(LocalDateTime.now());
|
||||
var iterator = conversationState.getConversationsMapping()
|
||||
.get(conversation.getClientCode())
|
||||
.listIterator();
|
||||
var iterator = getIterator(conversation.getClientCode());
|
||||
while (iterator.hasNext()) {
|
||||
var next = iterator.next();
|
||||
if (next.getId().equals(conversation.getId())) {
|
||||
|
|
@ -128,9 +124,7 @@ public final class ConversationService {
|
|||
}
|
||||
|
||||
public void deleteConversation(Conversation conversation) {
|
||||
var iterator = conversationState.getConversationsMapping()
|
||||
.get(conversation.getClientCode())
|
||||
.listIterator();
|
||||
var iterator = getIterator(conversation.getClientCode());
|
||||
while (iterator.hasNext()) {
|
||||
var next = iterator.next();
|
||||
if (next.getId().equals(conversation.getId())) {
|
||||
|
|
@ -168,6 +162,12 @@ public final class ConversationService {
|
|||
return tryGetNextOrPreviousConversation(false);
|
||||
}
|
||||
|
||||
private ListIterator<Conversation> getIterator(String clientCode) {
|
||||
return conversationState.getConversationsMapping()
|
||||
.get(clientCode)
|
||||
.listIterator();
|
||||
}
|
||||
|
||||
private Optional<Conversation> tryGetNextOrPreviousConversation(boolean isPrevious) {
|
||||
var currentConversation = ConversationsState.getCurrentConversation();
|
||||
if (currentConversation != null) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class CodebaseIndexingAction extends AnAction {
|
|||
var folderStructureTreePanel = new FolderStructureTreePanel(project);
|
||||
var show = OverlayUtil.showFileStructureDialog(project, folderStructureTreePanel);
|
||||
if (show == OK_EXIT_CODE) {
|
||||
new CodebaseIndexingTask(project, folderStructureTreePanel.getCheckedFiles()).run();
|
||||
new CodebaseIndexingTask(project, folderStructureTreePanel.getReferencedFiles()).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import ee.carlrobert.codegpt.CodeGPTPlugin;
|
|||
import ee.carlrobert.codegpt.completions.CompletionClientProvider;
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.EmbeddingsService;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import ee.carlrobert.vector.VectorStore;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -26,13 +26,13 @@ public class CodebaseIndexingTask extends Task.Backgroundable {
|
|||
|
||||
private static final Logger LOG = Logger.getInstance(CodebaseIndexingTask.class);
|
||||
private final Project project;
|
||||
private final List<CheckedFile> checkedFiles;
|
||||
private final List<ReferencedFile> referencedFiles;
|
||||
private final EmbeddingsService embeddingsService;
|
||||
|
||||
public CodebaseIndexingTask(Project project, List<CheckedFile> checkedFiles) {
|
||||
public CodebaseIndexingTask(Project project, List<ReferencedFile> referencedFiles) {
|
||||
super(project, CodeGPTBundle.get("codebaseIndexing.task.title"), true);
|
||||
this.project = project;
|
||||
this.checkedFiles = checkedFiles;
|
||||
this.referencedFiles = referencedFiles;
|
||||
this.embeddingsService = new EmbeddingsService(
|
||||
CompletionClientProvider.getOpenAIClient(),
|
||||
CodeGPTPlugin.getPluginBasePath());
|
||||
|
|
@ -49,7 +49,7 @@ public class CodebaseIndexingTask extends Task.Backgroundable {
|
|||
|
||||
String fileContent;
|
||||
try {
|
||||
fileContent = new ObjectMapper().writeValueAsString(Map.of("content", checkedFiles));
|
||||
fileContent = new ObjectMapper().writeValueAsString(Map.of("content", referencedFiles));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException("Unable to serialize json file");
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ public class CodebaseIndexingTask extends Task.Backgroundable {
|
|||
try {
|
||||
indicator.setFraction(0);
|
||||
List<Item<Object, double[]>> embeddings =
|
||||
embeddingsService.createEmbeddings(checkedFiles, indicator);
|
||||
embeddingsService.createEmbeddings(referencedFiles, indicator);
|
||||
VectorStore.getInstance(CodeGPTPlugin.getPluginBasePath()).save(embeddings);
|
||||
OverlayUtil.showNotification("Indexing completed", NotificationType.INFORMATION);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import com.intellij.ui.components.JBLabel;
|
|||
import com.intellij.util.ui.AsyncProcessIcon;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
|
|
@ -132,9 +132,9 @@ public class FolderStructureTreePanel {
|
|||
return panel;
|
||||
}
|
||||
|
||||
public List<CheckedFile> getCheckedFiles() {
|
||||
public List<ReferencedFile> getReferencedFiles() {
|
||||
return getCheckedVirtualFiles().stream()
|
||||
.map(item -> new CheckedFile(new File(item.getPath())))
|
||||
.map(item -> new ReferencedFile(new File(item.getPath())))
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package ee.carlrobert.codegpt.settings.configuration;
|
||||
|
||||
import static ee.carlrobert.codegpt.completions.CompletionRequestProvider.COMPLETION_COMMIT_MESSAGE_PROMPT;
|
||||
import static ee.carlrobert.codegpt.completions.CompletionRequestProvider.COMPLETION_SYSTEM_PROMPT;
|
||||
import static ee.carlrobert.codegpt.completions.CompletionRequestProvider.GENERATE_COMMIT_MESSAGE_SYSTEM_PROMPT;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
|
|
@ -19,13 +19,14 @@ import org.jetbrains.annotations.Nullable;
|
|||
public class ConfigurationState implements PersistentStateComponent<ConfigurationState> {
|
||||
|
||||
private String systemPrompt = COMPLETION_SYSTEM_PROMPT;
|
||||
private String commitMessagePrompt = COMPLETION_COMMIT_MESSAGE_PROMPT;
|
||||
private String commitMessagePrompt = GENERATE_COMMIT_MESSAGE_SYSTEM_PROMPT;
|
||||
private int maxTokens = 1000;
|
||||
private double temperature = 0.1;
|
||||
private boolean checkForPluginUpdates = true;
|
||||
private boolean createNewChatOnEachAction;
|
||||
private boolean ignoreGitCommitTokenLimit;
|
||||
private boolean methodNameGenerationEnabled = true;
|
||||
private boolean captureCompileErrors = true;
|
||||
private boolean autoFormattingEnabled = true;
|
||||
private Map<String, String> tableData = EditorActionsUtil.DEFAULT_ACTIONS;
|
||||
|
||||
|
|
@ -116,6 +117,14 @@ public class ConfigurationState implements PersistentStateComponent<Configuratio
|
|||
this.methodNameGenerationEnabled = methodNameGenerationEnabled;
|
||||
}
|
||||
|
||||
public boolean isCaptureCompileErrors() {
|
||||
return captureCompileErrors;
|
||||
}
|
||||
|
||||
public void setCaptureCompileErrors(boolean captureCompileErrors) {
|
||||
this.captureCompileErrors = captureCompileErrors;
|
||||
}
|
||||
|
||||
public boolean isAutoFormattingEnabled() {
|
||||
return autoFormattingEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ee.carlrobert.codegpt.settings.service;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.intellij.icons.AllIcons.Actions;
|
||||
|
|
@ -315,7 +316,7 @@ public class LlamaModelPreferencesForm {
|
|||
return "";
|
||||
}
|
||||
|
||||
return String.format("<html>"
|
||||
return format("<html>"
|
||||
+ "<p style=\"margin: 0\"><small>File Size: <strong>%.2f GB</strong></small></p>"
|
||||
+ "<p style=\"margin: 0\"><small>Max RAM Required: <strong>%.2f GB</strong></small></p>"
|
||||
+ "</html>", details.fileSize, details.maxRAMRequired);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package ee.carlrobert.codegpt.settings.state;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
|
|
@ -82,7 +84,7 @@ public class SettingsState implements PersistentStateComponent<SettingsState> {
|
|||
}
|
||||
var huggingFaceModel = llamaSettings.getHuggingFaceModel();
|
||||
var llamaModel = LlamaModel.findByHuggingFaceModel(huggingFaceModel);
|
||||
return String.format(
|
||||
return format(
|
||||
"%s %dB (Q%d)",
|
||||
llamaModel.getLabel(),
|
||||
huggingFaceModel.getParameterSize(),
|
||||
|
|
|
|||
|
|
@ -1,276 +0,0 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import static ee.carlrobert.codegpt.ui.UIUtil.createScrollPaneWithSmartScroller;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.CodeGPTKeys;
|
||||
import ee.carlrobert.codegpt.EncodingManager;
|
||||
import ee.carlrobert.codegpt.actions.ActionType;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestHandler;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestService;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.state.IncludedFilesSettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatMessageResponseBody;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatToolWindowScrollablePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.UserMessagePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.TotalTokensDetails;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.TotalTokensPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.UserPromptTextArea;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.UserPromptTextAreaHeader;
|
||||
import ee.carlrobert.codegpt.util.EditorUtil;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPanel {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(BaseChatToolWindowTabPanel.class);
|
||||
|
||||
private final boolean useContextualSearch;
|
||||
private final JPanel rootPanel;
|
||||
private final Conversation conversation;
|
||||
private final UserPromptTextArea userPromptTextArea;
|
||||
private final ConversationService conversationService;
|
||||
|
||||
protected final Project project;
|
||||
protected final TotalTokensPanel totalTokensPanel;
|
||||
protected final ChatToolWindowScrollablePanel toolWindowScrollablePanel;
|
||||
|
||||
protected abstract JComponent getLandingView();
|
||||
|
||||
public BaseChatToolWindowTabPanel(
|
||||
@NotNull Project project,
|
||||
@NotNull Conversation conversation,
|
||||
boolean useContextualSearch) {
|
||||
this.project = project;
|
||||
this.conversation = conversation;
|
||||
this.useContextualSearch = useContextualSearch;
|
||||
conversationService = ConversationService.getInstance();
|
||||
toolWindowScrollablePanel = new ChatToolWindowScrollablePanel();
|
||||
totalTokensPanel = new TotalTokensPanel(
|
||||
project,
|
||||
conversation,
|
||||
EditorUtil.getSelectedEditorSelectedText(project),
|
||||
this);
|
||||
userPromptTextArea = new UserPromptTextArea(this::handleSubmit, totalTokensPanel);
|
||||
rootPanel = createRootPanel();
|
||||
userPromptTextArea.requestFocusInWindow();
|
||||
userPromptTextArea.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getContent() {
|
||||
return rootPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Conversation getConversation() {
|
||||
return conversation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Message message) {
|
||||
var referencedFiles = project.getUserData(CodeGPTKeys.SELECTED_FILES);
|
||||
if (referencedFiles != null && !referencedFiles.isEmpty()) {
|
||||
var referencedFilePaths = referencedFiles.stream()
|
||||
.map(CheckedFile::getFilePath)
|
||||
.collect(toList());
|
||||
message.setReferencedFilePaths(referencedFilePaths);
|
||||
message.setUserMessage(message.getPrompt());
|
||||
message.setPrompt(getPromptWithContext(referencedFiles, message.getPrompt()));
|
||||
totalTokensPanel.updateReferencedFilesTokens(referencedFiles);
|
||||
}
|
||||
|
||||
var userMessagePanel = new UserMessagePanel(project, message, this);
|
||||
var messagePanel = toolWindowScrollablePanel.addMessage(message.getId());
|
||||
messagePanel.add(userMessagePanel);
|
||||
var responsePanel = new ResponsePanel()
|
||||
.withReloadAction(() -> reloadMessage(message, conversation))
|
||||
.withDeleteAction(() -> removeMessage(message.getId(), conversation))
|
||||
.addContent(new ChatMessageResponseBody(project, true, this));
|
||||
messagePanel.add(responsePanel);
|
||||
|
||||
var userPromptTokens = EncodingManager.getInstance().countTokens(message.getPrompt());
|
||||
var conversationTokens = EncodingManager.getInstance().countConversationTokens(conversation);
|
||||
totalTokensPanel.updateConversationTokens(conversationTokens + userPromptTokens);
|
||||
|
||||
call(message, responsePanel, false);
|
||||
project.getService(StandardChatToolWindowContentManager.class)
|
||||
.tryFindChatToolWindowPanel()
|
||||
.ifPresent(StandardChatToolWindowPanel::clearSelectedFilesNotification);
|
||||
}
|
||||
|
||||
private String getPromptWithContext(List<CheckedFile> referencedFiles, String userPrompt) {
|
||||
var includedFilesSettings = IncludedFilesSettingsState.getInstance();
|
||||
var repeatableContext = referencedFiles.stream()
|
||||
.map(item -> includedFilesSettings.getRepeatableContext()
|
||||
.replace("{FILE_PATH}", item.getFilePath())
|
||||
.replace("{FILE_CONTENT}", format(
|
||||
"```%s\n%s\n```",
|
||||
item.getFileExtension(),
|
||||
item.getFileContent().trim())))
|
||||
.collect(joining("\n\n"));
|
||||
|
||||
return includedFilesSettings.getPromptTemplate()
|
||||
.replace("{REPEATABLE_CONTEXT}", repeatableContext)
|
||||
.replace("{QUESTION}", userPrompt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TotalTokensDetails getTokenDetails() {
|
||||
return totalTokensPanel.getTokenDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFocusForTextArea() {
|
||||
userPromptTextArea.focus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayLandingView() {
|
||||
toolWindowScrollablePanel.displayLandingView(getLandingView());
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
}
|
||||
|
||||
protected void reloadMessage(Message message, Conversation conversation) {
|
||||
ResponsePanel responsePanel = null;
|
||||
try {
|
||||
responsePanel = toolWindowScrollablePanel.getMessageResponsePanel(message.getId());
|
||||
((ChatMessageResponseBody) responsePanel.getContent()).clear();
|
||||
toolWindowScrollablePanel.update();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not delete the existing message component", e);
|
||||
} finally {
|
||||
LOG.debug("Reloading message: " + message.getId());
|
||||
|
||||
if (responsePanel != null) {
|
||||
message.setResponse("");
|
||||
conversationService.saveMessage(conversation, message);
|
||||
call(message, responsePanel, true);
|
||||
}
|
||||
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
|
||||
TelemetryAction.IDE_ACTION.createActionMessage()
|
||||
.property("action", ActionType.RELOAD_MESSAGE.name())
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeMessage(UUID messageId, Conversation conversation) {
|
||||
toolWindowScrollablePanel.removeMessage(messageId);
|
||||
conversation.removeMessage(messageId);
|
||||
conversationService.saveConversation(conversation);
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
|
||||
if (conversation.getMessages().isEmpty()) {
|
||||
displayLandingView();
|
||||
}
|
||||
}
|
||||
|
||||
protected void clearWindow() {
|
||||
toolWindowScrollablePanel.clearAll();
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
}
|
||||
|
||||
private void call(Message message, ResponsePanel responsePanel, boolean retry) {
|
||||
var responseContainer = (ChatMessageResponseBody) responsePanel.getContent();
|
||||
|
||||
if (!CompletionRequestService.getInstance().isRequestAllowed()) {
|
||||
responseContainer.displayMissingCredential();
|
||||
return;
|
||||
}
|
||||
|
||||
var requestHandler = new CompletionRequestHandler(
|
||||
useContextualSearch,
|
||||
new ToolWindowCompletionResponseEventListener(
|
||||
conversationService,
|
||||
responsePanel,
|
||||
totalTokensPanel,
|
||||
userPromptTextArea) {
|
||||
@Override
|
||||
public void handleTokensExceededPolicyAccepted() {
|
||||
call(message, responsePanel, true);
|
||||
}
|
||||
});
|
||||
userPromptTextArea.setRequestHandler(requestHandler);
|
||||
userPromptTextArea.setSubmitEnabled(false);
|
||||
requestHandler.call(conversation, message, retry);
|
||||
}
|
||||
|
||||
private void handleSubmit(String text) {
|
||||
var message = new Message(text);
|
||||
var editor = EditorUtil.getSelectedEditor(project);
|
||||
if (editor != null) {
|
||||
var selectionModel = editor.getSelectionModel();
|
||||
var selectedText = selectionModel.getSelectedText();
|
||||
if (selectedText != null && !selectedText.isEmpty()) {
|
||||
var fileExtension = FileUtil.getFileExtension(
|
||||
((EditorImpl) editor).getVirtualFile().getName());
|
||||
message = new Message(text + format("\n```%s\n%s\n```", fileExtension, selectedText));
|
||||
selectionModel.removeSelection();
|
||||
}
|
||||
}
|
||||
message.setUserMessage(text);
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
private JPanel createUserPromptPanel(ServiceType selectedService) {
|
||||
var panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(JBColor.border(), 1, 0, 0, 0),
|
||||
JBUI.Borders.empty(8)));
|
||||
var contentManager = project.getService(StandardChatToolWindowContentManager.class);
|
||||
panel.add(JBUI.Panels.simplePanel(new UserPromptTextAreaHeader(
|
||||
selectedService,
|
||||
totalTokensPanel,
|
||||
contentManager::createNewTabPanel)), BorderLayout.NORTH);
|
||||
panel.add(JBUI.Panels.simplePanel(userPromptTextArea), BorderLayout.CENTER);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel createRootPanel() {
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
gbc.weighty = 1;
|
||||
gbc.weightx = 1;
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
|
||||
var rootPanel = new JPanel(new GridBagLayout());
|
||||
rootPanel.add(createScrollPaneWithSmartScroller(toolWindowScrollablePanel), gbc);
|
||||
|
||||
gbc.weighty = 0;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridy = 1;
|
||||
rootPanel.add(
|
||||
createUserPromptPanel(SettingsState.getInstance().getSelectedService()), gbc);
|
||||
return rootPanel;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,286 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import static ee.carlrobert.codegpt.completions.CompletionRequestProvider.getPromptWithContext;
|
||||
import static ee.carlrobert.codegpt.ui.UIUtil.createScrollPaneWithSmartScroller;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.CodeGPTKeys;
|
||||
import ee.carlrobert.codegpt.EncodingManager;
|
||||
import ee.carlrobert.codegpt.actions.ActionType;
|
||||
import ee.carlrobert.codegpt.completions.CallParameters;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestHandler;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestService;
|
||||
import ee.carlrobert.codegpt.completions.ConversationType;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatMessageResponseBody;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatToolWindowScrollablePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.UserMessagePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.TotalTokensDetails;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.TotalTokensPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.UserPromptTextArea;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.UserPromptTextAreaHeader;
|
||||
import ee.carlrobert.codegpt.util.EditorUtil;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.util.UUID;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface ChatToolWindowTabPanel extends Disposable {
|
||||
public abstract class ChatToolWindowTabPanel implements Disposable {
|
||||
|
||||
JComponent getContent();
|
||||
private static final Logger LOG = Logger.getInstance(ChatToolWindowTabPanel.class);
|
||||
|
||||
Conversation getConversation();
|
||||
private final boolean useContextualSearch;
|
||||
private final JPanel rootPanel;
|
||||
private final Conversation conversation;
|
||||
private final UserPromptTextArea userPromptTextArea;
|
||||
private final ConversationService conversationService;
|
||||
|
||||
TotalTokensDetails getTokenDetails();
|
||||
protected final Project project;
|
||||
protected final TotalTokensPanel totalTokensPanel;
|
||||
protected final ChatToolWindowScrollablePanel toolWindowScrollablePanel;
|
||||
|
||||
void displayLandingView();
|
||||
protected abstract JComponent getLandingView();
|
||||
|
||||
void sendMessage(Message message);
|
||||
public ChatToolWindowTabPanel(
|
||||
@NotNull Project project,
|
||||
@NotNull Conversation conversation,
|
||||
boolean useContextualSearch) {
|
||||
this.project = project;
|
||||
this.conversation = conversation;
|
||||
this.useContextualSearch = useContextualSearch;
|
||||
conversationService = ConversationService.getInstance();
|
||||
toolWindowScrollablePanel = new ChatToolWindowScrollablePanel();
|
||||
totalTokensPanel = new TotalTokensPanel(
|
||||
project,
|
||||
conversation,
|
||||
EditorUtil.getSelectedEditorSelectedText(project),
|
||||
this);
|
||||
userPromptTextArea = new UserPromptTextArea(this::handleSubmit, totalTokensPanel);
|
||||
rootPanel = createRootPanel();
|
||||
userPromptTextArea.requestFocusInWindow();
|
||||
userPromptTextArea.requestFocus();
|
||||
}
|
||||
|
||||
void requestFocusForTextArea();
|
||||
}
|
||||
public void dispose() {
|
||||
LOG.info("Disposing BaseChatToolWindowTabPanel component");
|
||||
}
|
||||
|
||||
public JComponent getContent() {
|
||||
return rootPanel;
|
||||
}
|
||||
|
||||
public Conversation getConversation() {
|
||||
return conversation;
|
||||
}
|
||||
|
||||
public void sendMessage(Message message) {
|
||||
sendMessage(message, ConversationType.DEFAULT);
|
||||
}
|
||||
|
||||
public void sendMessage(Message message, ConversationType conversationType) {
|
||||
Runnable runnable = () -> {
|
||||
var referencedFiles = project.getUserData(CodeGPTKeys.SELECTED_FILES);
|
||||
if (referencedFiles != null && !referencedFiles.isEmpty()) {
|
||||
var referencedFilePaths = referencedFiles.stream()
|
||||
.map(ReferencedFile::getFilePath)
|
||||
.collect(toList());
|
||||
message.setReferencedFilePaths(referencedFilePaths);
|
||||
message.setUserMessage(message.getPrompt());
|
||||
message.setPrompt(getPromptWithContext(referencedFiles, message.getPrompt()));
|
||||
|
||||
totalTokensPanel.updateReferencedFilesTokens(referencedFiles);
|
||||
|
||||
project.getService(StandardChatToolWindowContentManager.class)
|
||||
.tryFindChatToolWindowPanel()
|
||||
.ifPresent(StandardChatToolWindowPanel::clearSelectedFilesNotification);
|
||||
}
|
||||
|
||||
var messagePanel = toolWindowScrollablePanel.addMessage(message.getId());
|
||||
messagePanel.add(new UserMessagePanel(project, message, this));
|
||||
var responsePanel = createResponsePanel(message, conversationType);
|
||||
messagePanel.add(responsePanel);
|
||||
|
||||
updateTotalTokens(message);
|
||||
|
||||
call(message, conversationType, responsePanel, false);
|
||||
};
|
||||
// TODO
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
SwingUtilities.invokeLater(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTotalTokens(Message message) {
|
||||
int userPromptTokens = EncodingManager.getInstance().countTokens(message.getPrompt());
|
||||
int conversationTokens = EncodingManager.getInstance().countConversationTokens(conversation);
|
||||
totalTokensPanel.updateConversationTokens(conversationTokens + userPromptTokens);
|
||||
}
|
||||
|
||||
private ResponsePanel createResponsePanel(Message message, ConversationType conversationType) {
|
||||
return new ResponsePanel()
|
||||
.withReloadAction(() -> reloadMessage(message, conversation, conversationType))
|
||||
.withDeleteAction(() -> removeMessage(message.getId(), conversation))
|
||||
.addContent(new ChatMessageResponseBody(project, true, this));
|
||||
}
|
||||
|
||||
public TotalTokensDetails getTokenDetails() {
|
||||
return totalTokensPanel.getTokenDetails();
|
||||
}
|
||||
|
||||
public void requestFocusForTextArea() {
|
||||
userPromptTextArea.focus();
|
||||
}
|
||||
|
||||
public void displayLandingView() {
|
||||
toolWindowScrollablePanel.displayLandingView(getLandingView());
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
}
|
||||
|
||||
protected void reloadMessage(
|
||||
Message message,
|
||||
Conversation conversation,
|
||||
ConversationType conversationType) {
|
||||
ResponsePanel responsePanel = null;
|
||||
try {
|
||||
responsePanel = toolWindowScrollablePanel.getMessageResponsePanel(message.getId());
|
||||
((ChatMessageResponseBody) responsePanel.getContent()).clear();
|
||||
toolWindowScrollablePanel.update();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not delete the existing message component", e);
|
||||
} finally {
|
||||
LOG.debug("Reloading message: " + message.getId());
|
||||
|
||||
if (responsePanel != null) {
|
||||
message.setResponse("");
|
||||
conversationService.saveMessage(conversation, message);
|
||||
call(message, conversationType, responsePanel, true);
|
||||
}
|
||||
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
|
||||
TelemetryAction.IDE_ACTION.createActionMessage()
|
||||
.property("action", ActionType.RELOAD_MESSAGE.name())
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeMessage(UUID messageId, Conversation conversation) {
|
||||
toolWindowScrollablePanel.removeMessage(messageId);
|
||||
conversation.removeMessage(messageId);
|
||||
conversationService.saveConversation(conversation);
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
|
||||
if (conversation.getMessages().isEmpty()) {
|
||||
displayLandingView();
|
||||
}
|
||||
}
|
||||
|
||||
protected void clearWindow() {
|
||||
toolWindowScrollablePanel.clearAll();
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
}
|
||||
|
||||
private void call(
|
||||
Message message,
|
||||
ConversationType conversationType,
|
||||
ResponsePanel responsePanel,
|
||||
boolean retry) {
|
||||
var responseContainer = (ChatMessageResponseBody) responsePanel.getContent();
|
||||
|
||||
if (!CompletionRequestService.getInstance().isRequestAllowed()) {
|
||||
responseContainer.displayMissingCredential();
|
||||
return;
|
||||
}
|
||||
|
||||
var requestHandler = new CompletionRequestHandler(
|
||||
useContextualSearch,
|
||||
new ToolWindowCompletionResponseEventListener(
|
||||
conversationService,
|
||||
responsePanel,
|
||||
totalTokensPanel,
|
||||
userPromptTextArea) {
|
||||
@Override
|
||||
public void handleTokensExceededPolicyAccepted() {
|
||||
call(message, conversationType, responsePanel, true);
|
||||
}
|
||||
});
|
||||
userPromptTextArea.setRequestHandler(requestHandler);
|
||||
userPromptTextArea.setSubmitEnabled(false);
|
||||
|
||||
requestHandler.call(new CallParameters(conversation, conversationType, message, retry));
|
||||
}
|
||||
|
||||
private void handleSubmit(String text) {
|
||||
var message = new Message(text);
|
||||
var editor = EditorUtil.getSelectedEditor(project);
|
||||
if (editor != null) {
|
||||
var selectionModel = editor.getSelectionModel();
|
||||
var selectedText = selectionModel.getSelectedText();
|
||||
if (selectedText != null && !selectedText.isEmpty()) {
|
||||
var fileExtension = FileUtil.getFileExtension(
|
||||
((EditorImpl) editor).getVirtualFile().getName());
|
||||
message = new Message(text + format("\n```%s\n%s\n```", fileExtension, selectedText));
|
||||
selectionModel.removeSelection();
|
||||
}
|
||||
}
|
||||
message.setUserMessage(text);
|
||||
sendMessage(message, ConversationType.DEFAULT);
|
||||
}
|
||||
|
||||
private JPanel createUserPromptPanel(ServiceType selectedService) {
|
||||
var panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(JBColor.border(), 1, 0, 0, 0),
|
||||
JBUI.Borders.empty(8)));
|
||||
var contentManager = project.getService(StandardChatToolWindowContentManager.class);
|
||||
panel.add(JBUI.Panels.simplePanel(new UserPromptTextAreaHeader(
|
||||
selectedService,
|
||||
totalTokensPanel,
|
||||
contentManager::createNewTabPanel)), BorderLayout.NORTH);
|
||||
panel.add(JBUI.Panels.simplePanel(userPromptTextArea), BorderLayout.CENTER);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel createRootPanel() {
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
gbc.weighty = 1;
|
||||
gbc.weightx = 1;
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
|
||||
var rootPanel = new JPanel(new GridBagLayout());
|
||||
rootPanel.add(createScrollPaneWithSmartScroller(toolWindowScrollablePanel), gbc);
|
||||
|
||||
gbc.weighty = 0;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridy = 1;
|
||||
rootPanel.add(
|
||||
createUserPromptPanel(SettingsState.getInstance().getSelectedService()), gbc);
|
||||
return rootPanel;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import static com.intellij.openapi.ui.Messages.OK;
|
|||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import ee.carlrobert.codegpt.EncodingManager;
|
||||
import ee.carlrobert.codegpt.completions.CallParameters;
|
||||
import ee.carlrobert.codegpt.completions.CompletionResponseEventListener;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
|
|
@ -118,12 +119,9 @@ abstract class ToolWindowCompletionResponseEventListener implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void handleCompleted(
|
||||
String fullMessage,
|
||||
Message message,
|
||||
Conversation conversation,
|
||||
boolean retry) {
|
||||
conversationService.saveMessage(fullMessage, message, conversation, retry);
|
||||
public void handleCompleted(String fullMessage, CallParameters callParameters) {
|
||||
var message = callParameters.getMessage();
|
||||
conversationService.saveMessage(fullMessage, callParameters);
|
||||
|
||||
var serpResults = serpResultsMapping.get(message.getId());
|
||||
var containsResults = serpResults != null && !serpResults.isEmpty();
|
||||
|
|
@ -139,7 +137,7 @@ abstract class ToolWindowCompletionResponseEventListener implements
|
|||
responseContainer.displaySerpResults(serpResults);
|
||||
}
|
||||
totalTokensPanel.updateUserPromptTokens(userPromptTextArea.getText());
|
||||
totalTokensPanel.updateConversationTokens(conversation);
|
||||
totalTokensPanel.updateConversationTokens(callParameters.getConversation());
|
||||
} finally {
|
||||
stopStreaming(responseContainer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ class ContextualChatToolWindowLandingPanel extends ResponsePanel {
|
|||
var folderStructureTreePanel = new FolderStructureTreePanel(project);
|
||||
var show = OverlayUtil.showFileStructureDialog(project, folderStructureTreePanel);
|
||||
if (show == OK_EXIT_CODE) {
|
||||
new CodebaseIndexingTask(project, folderStructureTreePanel.getCheckedFiles()).run();
|
||||
new CodebaseIndexingTask(project, folderStructureTreePanel.getReferencedFiles())
|
||||
.run();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.contextual;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import ee.carlrobert.codegpt.completions.ConversationType;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.BaseChatToolWindowTabPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel;
|
||||
import javax.swing.JComponent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ContextualChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
|
||||
public class ContextualChatToolWindowTabPanel extends ChatToolWindowTabPanel {
|
||||
|
||||
public ContextualChatToolWindowTabPanel(
|
||||
@NotNull Project project,
|
||||
|
|
@ -20,6 +21,6 @@ public class ContextualChatToolWindowTabPanel extends BaseChatToolWindowTabPanel
|
|||
protected JComponent getLandingView() {
|
||||
return new ContextualChatToolWindowLandingPanel(
|
||||
project,
|
||||
(prompt) -> sendMessage(new Message(prompt)));
|
||||
(prompt) -> sendMessage(new Message(prompt), ConversationType.DEFAULT));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.intellij.openapi.wm.ToolWindowAnchor;
|
|||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.ui.content.Content;
|
||||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.completions.ConversationType;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
|
|
@ -30,18 +31,22 @@ public final class StandardChatToolWindowContentManager {
|
|||
}
|
||||
|
||||
public void sendMessage(Message message) {
|
||||
sendMessage(message, ConversationType.DEFAULT);
|
||||
}
|
||||
|
||||
public void sendMessage(Message message, ConversationType conversationType) {
|
||||
getToolWindow().show();
|
||||
|
||||
if (ConfigurationState.getInstance().isCreateNewChatOnEachAction()
|
||||
|| ConversationsState.getCurrentConversation() == null) {
|
||||
createNewTabPanel().sendMessage(message);
|
||||
createNewTabPanel().sendMessage(message, conversationType);
|
||||
return;
|
||||
}
|
||||
|
||||
tryFindChatTabbedPane()
|
||||
.map(tabbedPane -> tabbedPane.tryFindActiveTabPanel().orElseGet(this::createNewTabPanel))
|
||||
.orElseGet(this::createNewTabPanel)
|
||||
.sendMessage(message);
|
||||
.sendMessage(message, conversationType);
|
||||
}
|
||||
|
||||
public void displayConversation(@NotNull Conversation conversation) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import ee.carlrobert.codegpt.actions.toolwindow.OpenInEditorAction;
|
|||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.SelectedFilesNotification;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.awt.BorderLayout;
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
|
|
@ -39,8 +39,8 @@ public class StandardChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
(IncludeFilesInContextNotifier) this::displaySelectedFilesNotification);
|
||||
}
|
||||
|
||||
public void displaySelectedFilesNotification(List<CheckedFile> checkedFiles) {
|
||||
selectedFilesNotification.displaySelectedFilesNotification(checkedFiles);
|
||||
public void displaySelectedFilesNotification(List<ReferencedFile> referencedFiles) {
|
||||
selectedFilesNotification.displaySelectedFilesNotification(referencedFiles);
|
||||
}
|
||||
|
||||
public void clearSelectedFilesNotification() {
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ import static java.lang.String.format;
|
|||
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import ee.carlrobert.codegpt.completions.ConversationType;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.state.YouSettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.BaseChatToolWindowTabPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatMessageResponseBody;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.UserMessagePanel;
|
||||
|
|
@ -17,7 +18,7 @@ import ee.carlrobert.codegpt.util.file.FileUtil;
|
|||
import javax.swing.JComponent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
|
||||
public class StandardChatToolWindowTabPanel extends ChatToolWindowTabPanel {
|
||||
|
||||
public StandardChatToolWindowTabPanel(
|
||||
@NotNull Project project,
|
||||
|
|
@ -49,7 +50,7 @@ public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
|
|||
format("\n```%s\n%s\n```", fileExtension, editor.getSelectionModel().getSelectedText())));
|
||||
message.setUserMessage(action.getUserMessage());
|
||||
|
||||
sendMessage(message);
|
||||
sendMessage(message, ConversationType.DEFAULT);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +70,7 @@ public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
|
|||
var messagePanel = toolWindowScrollablePanel.addMessage(message.getId());
|
||||
messagePanel.add(new UserMessagePanel(project, message, this));
|
||||
messagePanel.add(new ResponsePanel()
|
||||
.withReloadAction(() -> reloadMessage(message, conversation))
|
||||
.withReloadAction(() -> reloadMessage(message, conversation, ConversationType.DEFAULT))
|
||||
.withDeleteAction(() -> removeMessage(message.getId(), conversation))
|
||||
.addContent(messageResponseBody));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,12 +11,10 @@ import com.intellij.util.ui.JBUI;
|
|||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class SelectedFilesAccordion extends JPanel {
|
|||
panel.setOpaque(false);
|
||||
panel.setVisible(false);
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||
panel.setBorder(JBUI.Borders.emptyBottom(4));
|
||||
panel.setBorder(JBUI.Borders.empty(4, 0));
|
||||
referencedFilePaths.stream()
|
||||
.map(filePath -> LocalFileSystem.getInstance().findFileByPath(filePath))
|
||||
.filter(Objects::nonNull)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.intellij.util.ui.JBUI;
|
|||
import com.intellij.util.ui.JBUI.CurrentTheme.NotificationInfo;
|
||||
import ee.carlrobert.codegpt.CodeGPTKeys;
|
||||
import ee.carlrobert.codegpt.actions.IncludeFilesInContextNotifier;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.awt.BorderLayout;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
|
|
@ -47,14 +47,14 @@ public class SelectedFilesNotification extends JPanel {
|
|||
}), BorderLayout.LINE_END);
|
||||
}
|
||||
|
||||
public void displaySelectedFilesNotification(@NotNull List<CheckedFile> checkedFiles) {
|
||||
if (checkedFiles.isEmpty()) {
|
||||
public void displaySelectedFilesNotification(@NotNull List<ReferencedFile> referencedFiles) {
|
||||
if (referencedFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
label.setText(checkedFiles.size() + " files selected");
|
||||
var referencedFilePaths = checkedFiles.stream()
|
||||
.map(CheckedFile::getFilePath)
|
||||
label.setText(referencedFiles.size() + " files selected");
|
||||
var referencedFilePaths = referencedFiles.stream()
|
||||
.map(ReferencedFile::getFilePath)
|
||||
.collect(Collectors.toList());
|
||||
label.setToolTipText(getHtml(referencedFilePaths));
|
||||
setVisible(true);
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ import ee.carlrobert.codegpt.CodeGPTKeys;
|
|||
import ee.carlrobert.codegpt.EncodingManager;
|
||||
import ee.carlrobert.codegpt.actions.IncludeFilesInContextNotifier;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.indexes.CodebaseIndexingCompletedNotifier;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
|
@ -114,7 +113,7 @@ public class TotalTokensPanel extends JPanel {
|
|||
update();
|
||||
}
|
||||
|
||||
public void updateReferencedFilesTokens(List<CheckedFile> includedFiles) {
|
||||
public void updateReferencedFilesTokens(List<ReferencedFile> includedFiles) {
|
||||
totalTokensDetails.setReferencedFilesTokens(includedFiles.stream()
|
||||
.mapToInt(file -> encodingManager.countTokens(file.getFileContent()))
|
||||
.sum());
|
||||
|
|
@ -123,7 +122,7 @@ public class TotalTokensPanel extends JPanel {
|
|||
|
||||
private TotalTokensDetails createTokenDetails(
|
||||
Conversation conversation,
|
||||
List<CheckedFile> includedFiles,
|
||||
List<ReferencedFile> includedFiles,
|
||||
@Nullable String highlightedText) {
|
||||
var tokenDetails = new TotalTokensDetails(encodingManager);
|
||||
tokenDetails.setConversationTokens(encodingManager.countConversationTokens(conversation));
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.intellij.ui.CheckboxTree;
|
|||
import com.intellij.ui.CheckedTreeNode;
|
||||
import com.intellij.ui.ColoredTreeCellRenderer;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ public abstract class FileCheckboxTree extends CheckboxTree {
|
|||
super(cellRenderer, node);
|
||||
}
|
||||
|
||||
public abstract List<CheckedFile> getCheckedFiles();
|
||||
public abstract List<ReferencedFile> getReferencedFiles();
|
||||
|
||||
protected static void updateFilePresentation(
|
||||
ColoredTreeCellRenderer textRenderer,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import com.intellij.psi.PsiElement;
|
|||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.file.PsiDirectoryImpl;
|
||||
import com.intellij.ui.CheckedTreeNode;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
|
@ -23,7 +23,7 @@ public class PsiElementCheckboxTree extends FileCheckboxTree {
|
|||
setRootVisible(true);
|
||||
}
|
||||
|
||||
public List<CheckedFile> getCheckedFiles() {
|
||||
public List<ReferencedFile> getReferencedFiles() {
|
||||
var checkedNodes = getCheckedNodes(
|
||||
PsiElement.class,
|
||||
node -> Optional.ofNullable(node.getContainingFile())
|
||||
|
|
@ -34,7 +34,8 @@ public class PsiElementCheckboxTree extends FileCheckboxTree {
|
|||
}
|
||||
|
||||
return Arrays.stream(checkedNodes)
|
||||
.map(item -> new CheckedFile(new File(item.getContainingFile().getVirtualFile().getPath())))
|
||||
.map(item -> new ReferencedFile(
|
||||
new File(item.getContainingFile().getVirtualFile().getPath())))
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.intellij.icons.AllIcons;
|
|||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.CheckedTreeNode;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import ee.carlrobert.embedding.CheckedFile;
|
||||
import ee.carlrobert.embedding.ReferencedFile;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
|
@ -19,14 +19,14 @@ public class VirtualFileCheckboxTree extends FileCheckboxTree {
|
|||
super(createFileTypesRenderer(), createRootNode(rootFiles));
|
||||
}
|
||||
|
||||
public List<CheckedFile> getCheckedFiles() {
|
||||
public List<ReferencedFile> getReferencedFiles() {
|
||||
var checkedNodes = getCheckedNodes(VirtualFile.class, Objects::nonNull);
|
||||
if (checkedNodes.length > 1000) {
|
||||
throw new RuntimeException("Too many files selected");
|
||||
}
|
||||
|
||||
return Arrays.stream(checkedNodes)
|
||||
.map(item -> new CheckedFile(new File(item.getPath())))
|
||||
.map(item -> new ReferencedFile(new File(item.getPath())))
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue