mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-10 03:59:43 +00:00
feat: consolidate all prompts into a single settings view (#775)
* feat: consolidate all prompts into a single configurable * feat: implement prompts settings view * feat: use prompts from PromptsSettings state * feat: use startInNewWindow settings value * fix: landing view action placeholder * feat: update default chat prompts
This commit is contained in:
parent
fdc4134aec
commit
89344346c8
53 changed files with 1439 additions and 3705 deletions
|
|
@ -1,7 +1,7 @@
|
|||
package ee.carlrobert.codegpt;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaDetails;
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonaDetails;
|
||||
import ee.carlrobert.codegpt.ui.DocumentationDetails;
|
||||
import ee.carlrobert.llm.client.codegpt.CodeGPTUserDetails;
|
||||
import java.util.List;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import ee.carlrobert.codegpt.EncodingManager;
|
|||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.completions.CommitMessageCompletionParameters;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestService;
|
||||
import ee.carlrobert.codegpt.settings.configuration.CommitMessageTemplate;
|
||||
import ee.carlrobert.codegpt.settings.prompts.CommitMessageTemplate;
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil;
|
||||
import ee.carlrobert.codegpt.util.CommitWorkflowChanges;
|
||||
import ee.carlrobert.codegpt.util.GitUtil;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import static java.lang.String.format;
|
|||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
|
@ -12,6 +13,7 @@ import ee.carlrobert.codegpt.CodeGPTKeys;
|
|||
import ee.carlrobert.codegpt.ReferencedFile;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowContentManager;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import java.util.Collection;
|
||||
|
|
@ -44,31 +46,36 @@ public class EditorActionsUtil {
|
|||
ActionManager.getInstance().getAction("CodeGPT.MyEditorActionsGroup");
|
||||
if (actionGroup instanceof DefaultActionGroup group) {
|
||||
group.removeAll();
|
||||
var configuredActions = ConfigurationSettings.getState().getTableData();
|
||||
configuredActions.forEach((label, prompt) -> {
|
||||
// using label as action description to prevent com.intellij.diagnostic.PluginException
|
||||
// https://github.com/carlrobertoh/CodeGPT/issues/95
|
||||
var action = new BaseEditorAction(label, label) {
|
||||
@Override
|
||||
protected void actionPerformed(Project project, Editor editor, String selectedText) {
|
||||
var toolWindowContentManager =
|
||||
project.getService(ChatToolWindowContentManager.class);
|
||||
toolWindowContentManager.getToolWindow().show();
|
||||
ApplicationManager.getApplication().getService(PromptsSettings.class)
|
||||
.getState()
|
||||
.getChatActions()
|
||||
.getPrompts()
|
||||
.forEach((promptDetails) -> {
|
||||
// using label as action description to prevent com.intellij.diagnostic.PluginException
|
||||
// https://github.com/carlrobertoh/CodeGPT/issues/95
|
||||
var action = new BaseEditorAction(promptDetails.getName(), promptDetails.getName()) {
|
||||
@Override
|
||||
protected void actionPerformed(Project project, Editor editor, String selectedText) {
|
||||
var toolWindowContentManager =
|
||||
project.getService(ChatToolWindowContentManager.class);
|
||||
toolWindowContentManager.getToolWindow().show();
|
||||
|
||||
var fileExtension = FileUtil.getFileExtension(editor.getVirtualFile().getName());
|
||||
var message = new Message(prompt.replace(
|
||||
"{{selectedCode}}",
|
||||
format("%n```%s%n%s%n```", fileExtension, selectedText)));
|
||||
message.setReferencedFilePaths(
|
||||
Stream.ofNullable(project.getUserData(CodeGPTKeys.SELECTED_FILES))
|
||||
.flatMap(Collection::stream)
|
||||
.map(ReferencedFile::getFilePath)
|
||||
.toList());
|
||||
toolWindowContentManager.sendMessage(message);
|
||||
}
|
||||
};
|
||||
group.add(action);
|
||||
});
|
||||
var fileExtension = FileUtil.getFileExtension(editor.getVirtualFile().getName());
|
||||
var prompt =
|
||||
promptDetails.getInstructions() == null ? "" : promptDetails.getInstructions();
|
||||
var message = new Message(prompt.replace(
|
||||
"{SELECTION}",
|
||||
format("%n```%s%n%s%n```", fileExtension, selectedText)));
|
||||
message.setReferencedFilePaths(
|
||||
Stream.ofNullable(project.getUserData(CodeGPTKeys.SELECTED_FILES))
|
||||
.flatMap(Collection::stream)
|
||||
.map(ReferencedFile::getFilePath)
|
||||
.toList());
|
||||
toolWindowContentManager.sendMessage(message);
|
||||
}
|
||||
};
|
||||
group.add(action);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package ee.carlrobert.codegpt.conversations.message;
|
|||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaDetails;
|
||||
import ee.carlrobert.codegpt.ui.DocumentationDetails;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
|
@ -20,7 +19,6 @@ public class Message {
|
|||
private @Nullable String imageFilePath;
|
||||
private boolean webSearchIncluded;
|
||||
private DocumentationDetails documentationDetails;
|
||||
private PersonaDetails personaDetails;
|
||||
|
||||
public Message(String prompt, String response) {
|
||||
this(prompt);
|
||||
|
|
@ -85,14 +83,6 @@ public class Message {
|
|||
this.documentationDetails = documentationDetails;
|
||||
}
|
||||
|
||||
public PersonaDetails getPersonaDetails() {
|
||||
return personaDetails;
|
||||
}
|
||||
|
||||
public void setPersonaDetails(PersonaDetails personaDetails) {
|
||||
this.personaDetails = personaDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
|
|
|
|||
|
|
@ -1,74 +1,39 @@
|
|||
package ee.carlrobert.codegpt.settings.configuration;
|
||||
|
||||
import static ee.carlrobert.codegpt.actions.editor.EditorActionsUtil.DEFAULT_ACTIONS_ARRAY;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.icons.AllIcons.Nodes;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.keymap.impl.ui.EditKeymapsDialog;
|
||||
import com.intellij.openapi.ui.ComponentValidator;
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import com.intellij.ui.AnActionButton;
|
||||
import com.intellij.ui.TitledSeparator;
|
||||
import com.intellij.ui.ToolbarDecorator;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBTextField;
|
||||
import com.intellij.ui.components.fields.IntegerField;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.ui.FormBuilder;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UI;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.actions.editor.EditorActionsUtil;
|
||||
import ee.carlrobert.codegpt.ui.UIUtil;
|
||||
import java.awt.Dimension;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConfigurationComponent {
|
||||
|
||||
private final JPanel mainPanel;
|
||||
private final JBTable table;
|
||||
private final JBCheckBox checkForPluginUpdatesCheckBox;
|
||||
private final JBCheckBox checkForNewScreenshotsCheckBox;
|
||||
private final JBCheckBox openNewTabCheckBox;
|
||||
private final JBCheckBox methodNameGenerationCheckBox;
|
||||
private final JBCheckBox autoFormattingCheckBox;
|
||||
private final JBCheckBox autocompletionPostProcessingCheckBox;
|
||||
private final JBCheckBox autocompletionContextAwareCheckBox;
|
||||
private final JBCheckBox autocompletionGitContextCheckBox;
|
||||
private final JTextArea commitMessagePromptTextArea;
|
||||
private final IntegerField maxTokensField;
|
||||
private final JBTextField temperatureField;
|
||||
|
||||
public ConfigurationComponent(
|
||||
Disposable parentDisposable,
|
||||
ConfigurationSettingsState configuration) {
|
||||
table = new JBTable(new DefaultTableModel(
|
||||
EditorActionsUtil.toArray(configuration.getTableData()),
|
||||
new String[]{
|
||||
CodeGPTBundle.get("configurationConfigurable.table.header.actionColumnLabel"),
|
||||
CodeGPTBundle.get("configurationConfigurable.table.header.promptColumnLabel")
|
||||
}));
|
||||
table.getColumnModel().getColumn(0).setPreferredWidth(60);
|
||||
table.getColumnModel().getColumn(1).setPreferredWidth(240);
|
||||
table.getEmptyText().setText(CodeGPTBundle.get("configurationConfigurable.table.emptyText"));
|
||||
var tablePanel = createTablePanel();
|
||||
tablePanel.setBorder(BorderFactory.createTitledBorder(
|
||||
CodeGPTBundle.get("configurationConfigurable.table.title")));
|
||||
|
||||
temperatureField = new JBTextField(12);
|
||||
temperatureField.setText(String.valueOf(configuration.getTemperature()));
|
||||
|
||||
|
|
@ -95,20 +60,12 @@ public class ConfigurationComponent {
|
|||
maxTokensField.setColumns(12);
|
||||
maxTokensField.setValue(configuration.getMaxTokens());
|
||||
|
||||
commitMessagePromptTextArea = new JTextArea(configuration.getCommitMessagePrompt(), 3, 60);
|
||||
commitMessagePromptTextArea.setLineWrap(true);
|
||||
commitMessagePromptTextArea.setWrapStyleWord(true);
|
||||
commitMessagePromptTextArea.setBorder(JBUI.Borders.empty(8, 4));
|
||||
|
||||
checkForPluginUpdatesCheckBox = new JBCheckBox(
|
||||
CodeGPTBundle.get("configurationConfigurable.checkForPluginUpdates.label"),
|
||||
configuration.getCheckForPluginUpdates());
|
||||
checkForNewScreenshotsCheckBox = new JBCheckBox(
|
||||
CodeGPTBundle.get("configurationConfigurable.checkForNewScreenshots.label"),
|
||||
configuration.getCheckForNewScreenshots());
|
||||
openNewTabCheckBox = new JBCheckBox(
|
||||
CodeGPTBundle.get("configurationConfigurable.openNewTabCheckBox.label"),
|
||||
configuration.getCreateNewChatOnEachAction());
|
||||
methodNameGenerationCheckBox = new JBCheckBox(
|
||||
CodeGPTBundle.get("configurationConfigurable.enableMethodNameGeneration.label"),
|
||||
configuration.getMethodNameGenerationEnabled());
|
||||
|
|
@ -129,11 +86,8 @@ public class ConfigurationComponent {
|
|||
);
|
||||
|
||||
mainPanel = FormBuilder.createFormBuilder()
|
||||
.addComponent(tablePanel)
|
||||
.addVerticalGap(4)
|
||||
.addComponent(checkForPluginUpdatesCheckBox)
|
||||
.addComponent(checkForNewScreenshotsCheckBox)
|
||||
.addComponent(openNewTabCheckBox)
|
||||
.addComponent(methodNameGenerationCheckBox)
|
||||
.addComponent(autoFormattingCheckBox)
|
||||
.addComponent(autocompletionPostProcessingCheckBox)
|
||||
|
|
@ -143,9 +97,6 @@ public class ConfigurationComponent {
|
|||
.addComponent(new TitledSeparator(
|
||||
CodeGPTBundle.get("configurationConfigurable.section.assistant.title")))
|
||||
.addComponent(createAssistantConfigurationForm())
|
||||
.addComponent(new TitledSeparator(
|
||||
CodeGPTBundle.get("configurationConfigurable.section.commitMessage.title")))
|
||||
.addComponent(createCommitMessageConfigurationForm())
|
||||
.addComponentFillVertically(new JPanel(), 0)
|
||||
.getPanel();
|
||||
}
|
||||
|
|
@ -156,13 +107,10 @@ public class ConfigurationComponent {
|
|||
|
||||
public ConfigurationSettingsState getCurrentFormState() {
|
||||
var state = new ConfigurationSettingsState();
|
||||
state.setTableData(getTableData());
|
||||
state.setMaxTokens(maxTokensField.getValue());
|
||||
state.setTemperature(Float.parseFloat(temperatureField.getText()));
|
||||
state.setCommitMessagePrompt(commitMessagePromptTextArea.getText());
|
||||
state.setCheckForPluginUpdates(checkForPluginUpdatesCheckBox.isSelected());
|
||||
state.setCheckForNewScreenshots(checkForNewScreenshotsCheckBox.isSelected());
|
||||
state.setCreateNewChatOnEachAction(openNewTabCheckBox.isSelected());
|
||||
state.setMethodNameGenerationEnabled(methodNameGenerationCheckBox.isSelected());
|
||||
state.setAutoFormattingEnabled(autoFormattingCheckBox.isSelected());
|
||||
state.setAutocompletionPostProcessingEnabled(autocompletionPostProcessingCheckBox.isSelected());
|
||||
|
|
@ -173,13 +121,10 @@ public class ConfigurationComponent {
|
|||
|
||||
public void resetForm() {
|
||||
var configuration = ConfigurationSettings.getState();
|
||||
setTableData(configuration.getTableData());
|
||||
maxTokensField.setValue(configuration.getMaxTokens());
|
||||
temperatureField.setText(String.valueOf(configuration.getTemperature()));
|
||||
commitMessagePromptTextArea.setText(configuration.getCommitMessagePrompt());
|
||||
checkForPluginUpdatesCheckBox.setSelected(configuration.getCheckForPluginUpdates());
|
||||
checkForNewScreenshotsCheckBox.setSelected(configuration.getCheckForNewScreenshots());
|
||||
openNewTabCheckBox.setSelected(configuration.getCreateNewChatOnEachAction());
|
||||
methodNameGenerationCheckBox.setSelected(configuration.getMethodNameGenerationEnabled());
|
||||
autoFormattingCheckBox.setSelected(configuration.getAutoFormattingEnabled());
|
||||
autocompletionPostProcessingCheckBox.setSelected(
|
||||
|
|
@ -191,34 +136,6 @@ public class ConfigurationComponent {
|
|||
);
|
||||
}
|
||||
|
||||
private Map<String, String> getTableData() {
|
||||
var model = getModel();
|
||||
Map<String, String> data = new LinkedHashMap<>();
|
||||
for (int count = 0; count < model.getRowCount(); count++) {
|
||||
data.put(
|
||||
model.getValueAt(count, 0).toString(),
|
||||
model.getValueAt(count, 1).toString());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private JPanel createTablePanel() {
|
||||
return ToolbarDecorator.createDecorator(table)
|
||||
.setPreferredSize(new Dimension(table.getPreferredSize().width, 140))
|
||||
.setAddAction(anActionButton -> {
|
||||
getModel().addRow(new Object[]{"", ""});
|
||||
int lastRowIndex = getModel().getRowCount() - 1;
|
||||
table.changeSelection(lastRowIndex, 0, false, false);
|
||||
table.editCellAt(lastRowIndex, 0);
|
||||
})
|
||||
.setRemoveAction(anActionButton -> getModel().removeRow(table.getSelectedRow()))
|
||||
.disableUpAction()
|
||||
.disableDownAction()
|
||||
.addExtraAction(new RevertToDefaultsActionButton())
|
||||
.addExtraAction(new KeymapActionButton())
|
||||
.createPanel();
|
||||
}
|
||||
|
||||
// Formatted keys are not referenced in the messages bundle file
|
||||
private void addAssistantFormLabeledComponent(
|
||||
FormBuilder formBuilder,
|
||||
|
|
@ -255,22 +172,6 @@ public class ConfigurationComponent {
|
|||
return form;
|
||||
}
|
||||
|
||||
private JPanel createCommitMessageConfigurationForm() {
|
||||
return FormBuilder.createFormBuilder()
|
||||
.setFormLeftIndent(16)
|
||||
.addLabeledComponent(
|
||||
new JBLabel(CodeGPTBundle.get(
|
||||
"configurationConfigurable.section.commitMessage.systemPromptField.label"))
|
||||
.withBorder(JBUI.Borders.emptyLeft(2)),
|
||||
UI.PanelFactory.panel(commitMessagePromptTextArea)
|
||||
.resizeX(false)
|
||||
.withComment(CommitMessageTemplate.Companion.getHtmlDescription())
|
||||
.createPanel(),
|
||||
true
|
||||
)
|
||||
.getPanel();
|
||||
}
|
||||
|
||||
private ComponentValidator createTemperatureInputValidator(
|
||||
Disposable parentDisposable,
|
||||
JBTextField component) {
|
||||
|
|
@ -297,66 +198,4 @@ public class ConfigurationComponent {
|
|||
validator.enableValidation();
|
||||
return validator;
|
||||
}
|
||||
|
||||
private DefaultTableModel getModel() {
|
||||
return (DefaultTableModel) table.getModel();
|
||||
}
|
||||
|
||||
public void setTableData(Map<String, String> tableData) {
|
||||
var model = getModel();
|
||||
model.setNumRows(0);
|
||||
tableData.forEach((action, prompt) -> model.addRow(new Object[]{action, prompt}));
|
||||
}
|
||||
|
||||
class RevertToDefaultsActionButton extends AnActionButton {
|
||||
|
||||
RevertToDefaultsActionButton() {
|
||||
super(
|
||||
CodeGPTBundle.get("configurationConfigurable.table.action.revertToDefaults.text"),
|
||||
AllIcons.Actions.Rollback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
var model = getModel();
|
||||
model.setRowCount(0);
|
||||
Arrays.stream(DEFAULT_ACTIONS_ARRAY).forEach(model::addRow);
|
||||
EditorActionsUtil.refreshActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ActionUpdateThread getActionUpdateThread() {
|
||||
return ActionUpdateThread.EDT;
|
||||
}
|
||||
}
|
||||
|
||||
class KeymapActionButton extends AnActionButton {
|
||||
|
||||
KeymapActionButton() {
|
||||
super(
|
||||
CodeGPTBundle.get("configurationConfigurable.table.action.addKeymap.text"),
|
||||
Nodes.KeymapEditor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
var actionId = "codegpt.AskChatgpt";
|
||||
var selectedRow = table.getSelectedRow();
|
||||
if (selectedRow != -1) {
|
||||
var label = getModel()
|
||||
.getDataVector()
|
||||
.get(selectedRow)
|
||||
.get(0);
|
||||
if (label != null && !label.toString().isEmpty()) {
|
||||
actionId = EditorActionsUtil.convertToId(label.toString());
|
||||
}
|
||||
}
|
||||
new EditKeymapsDialog(e.getProject(), actionId, false).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ActionUpdateThread getActionUpdateThread() {
|
||||
return ActionUpdateThread.EDT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package ee.carlrobert.codegpt.toolwindow.chat;
|
|||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.Service;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ComponentContainer;
|
||||
|
|
@ -16,7 +17,7 @@ import ee.carlrobert.codegpt.conversations.Conversation;
|
|||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
|
@ -38,8 +39,11 @@ public final class ChatToolWindowContentManager {
|
|||
public void sendMessage(Message message, ConversationType conversationType) {
|
||||
getToolWindow().show();
|
||||
|
||||
if (ConfigurationSettings.getState().getCreateNewChatOnEachAction()
|
||||
|| ConversationsState.getCurrentConversation() == null) {
|
||||
var startInNewWindow = ApplicationManager.getApplication().getService(PromptsSettings.class)
|
||||
.getState()
|
||||
.getChatActions()
|
||||
.getStartInNewWindow();
|
||||
if (startInNewWindow || ConversationsState.getCurrentConversation() == null) {
|
||||
createNewTabPanel().sendMessage(message, conversationType);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import ee.carlrobert.codegpt.actions.toolwindow.OpenInEditorAction;
|
|||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettings;
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings;
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonasConfigurable;
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsConfigurable;
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.ProviderChangeNotifier;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTUserDetailsNotifier;
|
||||
|
|
@ -213,7 +213,7 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
@NotNull String place) {
|
||||
var link = new ActionLink(getSelectedPersonaName(), (e) -> {
|
||||
ShowSettingsUtil.getInstance()
|
||||
.showSettingsDialog(project, PersonasConfigurable.class);
|
||||
.showSettingsDialog(project, PromptsConfigurable.class);
|
||||
});
|
||||
link.setExternalLinkIcon();
|
||||
link.setFont(JBUI.Fonts.smallFont());
|
||||
|
|
@ -233,8 +233,9 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
}
|
||||
|
||||
private String getSelectedPersonaName() {
|
||||
return ApplicationManager.getApplication().getService(PersonaSettings.class)
|
||||
return ApplicationManager.getApplication().getService(PromptsSettings.class)
|
||||
.getState()
|
||||
.getPersonas()
|
||||
.getSelectedPersona()
|
||||
.getName();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,9 +155,12 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
.sessionId(chatSession.getId())
|
||||
.conversationType(conversationType)
|
||||
.imageDetailsFromPath(CodeGPTKeys.IMAGE_ATTACHMENT_FILE_PATH.get(project))
|
||||
.persona(CodeGPTKeys.ADDED_PERSONA.get(project))
|
||||
.referencedFiles(getReferencedFiles())
|
||||
.build();
|
||||
|
||||
CodeGPTKeys.ADDED_PERSONA.set(project, null);
|
||||
|
||||
var referencedFiles = callParameters.getReferencedFiles();
|
||||
if ((referencedFiles != null && !referencedFiles.isEmpty())
|
||||
|| callParameters.getImageDetails() != null) {
|
||||
|
|
@ -324,7 +327,7 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
|
||||
var fileExtension = FileUtil.getFileExtension(editor.getVirtualFile().getName());
|
||||
var message = new Message(action.getPrompt().replace(
|
||||
"{{selectedCode}}",
|
||||
"{SELECTION}",
|
||||
format("%n```%s%n%s%n```", fileExtension, editor.getSelectionModel().getSelectedText())));
|
||||
sendMessage(message, ConversationType.DEFAULT);
|
||||
return Unit.INSTANCE;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import ee.carlrobert.codegpt.ui.textarea.AppliedSuggestionActionInlay;
|
|||
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.CreateDocumentationActionItem;
|
||||
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.DocumentationActionItem;
|
||||
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.GitCommitActionItem;
|
||||
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.PersonaActionItem;
|
||||
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.WebSearchActionItem;
|
||||
|
||||
public class SuggestionActionProcessor implements ActionProcessor {
|
||||
|
|
@ -37,7 +36,6 @@ public class SuggestionActionProcessor implements ActionProcessor {
|
|||
message.setWebSearchIncluded(action.getSuggestion() instanceof WebSearchActionItem);
|
||||
|
||||
processDocumentationAction(message, action);
|
||||
processPersonaAction(message, action);
|
||||
processGitCommitAction(action, promptBuilder);
|
||||
}
|
||||
|
||||
|
|
@ -52,15 +50,6 @@ public class SuggestionActionProcessor implements ActionProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private void processPersonaAction(Message message, AppliedSuggestionActionInlay action) {
|
||||
var addedPersona = CodeGPTKeys.ADDED_PERSONA.get(project);
|
||||
var personaInlayExists = action.getSuggestion() instanceof PersonaActionItem;
|
||||
if (addedPersona != null && personaInlayExists) {
|
||||
message.setPersonaDetails(addedPersona);
|
||||
CodeGPTKeys.ADDED_PERSONA.set(project, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void processGitCommitAction(
|
||||
AppliedSuggestionActionInlay action,
|
||||
StringBuilder promptBuilder) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import ee.carlrobert.codegpt.actions.IncludeFilesInContextNotifier;
|
|||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettings;
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings;
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
|
|
@ -141,7 +141,7 @@ public class TotalTokensPanel extends JPanel {
|
|||
List<ReferencedFile> includedFiles,
|
||||
@Nullable String highlightedText) {
|
||||
var tokenDetails = new TotalTokensDetails(
|
||||
encodingManager.countTokens(PersonaSettings.getSystemPrompt()));
|
||||
encodingManager.countTokens(PromptsSettings.getSelectedPersonaSystemPrompt()));
|
||||
tokenDetails.setConversationTokens(encodingManager.countConversationTokens(conversation));
|
||||
if (includedFiles != null) {
|
||||
tokenDetails.setReferencedFilesTokens(includedFiles.stream()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package ee.carlrobert.codegpt.completions
|
|||
import ee.carlrobert.codegpt.ReferencedFile
|
||||
import ee.carlrobert.codegpt.conversations.Conversation
|
||||
import ee.carlrobert.codegpt.conversations.message.Message
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonaDetails
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
|
@ -17,7 +18,8 @@ class ChatCompletionParameters private constructor(
|
|||
var sessionId: UUID?,
|
||||
var retry: Boolean,
|
||||
var imageDetails: ImageDetails?,
|
||||
var referencedFiles: List<ReferencedFile>?
|
||||
var referencedFiles: List<ReferencedFile>?,
|
||||
var persona: PersonaDetails?,
|
||||
) : CompletionParameters {
|
||||
|
||||
fun toBuilder(): Builder {
|
||||
|
|
@ -27,6 +29,7 @@ class ChatCompletionParameters private constructor(
|
|||
retry(this@ChatCompletionParameters.retry)
|
||||
imageDetails(this@ChatCompletionParameters.imageDetails)
|
||||
referencedFiles(this@ChatCompletionParameters.referencedFiles)
|
||||
persona(this@ChatCompletionParameters.persona)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,6 +39,7 @@ class ChatCompletionParameters private constructor(
|
|||
private var retry: Boolean = false
|
||||
private var imageDetails: ImageDetails? = null
|
||||
private var referencedFiles: List<ReferencedFile>? = null
|
||||
private var persona: PersonaDetails? = null
|
||||
|
||||
fun sessionId(sessionId: UUID?) = apply { this.sessionId = sessionId }
|
||||
fun conversationType(conversationType: ConversationType) =
|
||||
|
|
@ -55,6 +59,8 @@ class ChatCompletionParameters private constructor(
|
|||
fun referencedFiles(referencedFiles: List<ReferencedFile>?) =
|
||||
apply { this.referencedFiles = referencedFiles }
|
||||
|
||||
fun persona(persona: PersonaDetails?) = apply { this.persona = persona }
|
||||
|
||||
fun build(): ChatCompletionParameters {
|
||||
return ChatCompletionParameters(
|
||||
conversation,
|
||||
|
|
@ -63,7 +69,8 @@ class ChatCompletionParameters private constructor(
|
|||
sessionId,
|
||||
retry,
|
||||
imageDetails,
|
||||
referencedFiles
|
||||
referencedFiles,
|
||||
persona
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package ee.carlrobert.codegpt.completions
|
||||
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.EDIT_CODE_SYSTEM_PROMPT
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.GENERATE_METHOD_NAMES_SYSTEM_PROMPT
|
||||
import com.intellij.openapi.components.service
|
||||
import ee.carlrobert.codegpt.completions.factory.*
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType
|
||||
import ee.carlrobert.llm.completion.CompletionRequest
|
||||
|
||||
|
|
@ -32,7 +33,9 @@ interface CompletionRequestFactory {
|
|||
abstract class BaseRequestFactory : CompletionRequestFactory {
|
||||
override fun createEditCodeRequest(params: EditCodeCompletionParameters): CompletionRequest {
|
||||
val prompt = "Code to modify:\n${params.selectedText}\n\nInstructions: ${params.prompt}"
|
||||
return createBasicCompletionRequest(EDIT_CODE_SYSTEM_PROMPT, prompt, 8192, true)
|
||||
return createBasicCompletionRequest(
|
||||
service<PromptsSettings>().state.coreActions.editCode.instructions
|
||||
?: CoreActionsState.DEFAULT_EDIT_CODE_PROMPT, prompt, 8192, true)
|
||||
}
|
||||
|
||||
override fun createCommitMessageRequest(params: CommitMessageCompletionParameters): CompletionRequest {
|
||||
|
|
@ -40,7 +43,12 @@ abstract class BaseRequestFactory : CompletionRequestFactory {
|
|||
}
|
||||
|
||||
override fun createLookupRequest(params: LookupCompletionParameters): CompletionRequest {
|
||||
return createBasicCompletionRequest(GENERATE_METHOD_NAMES_SYSTEM_PROMPT, params.prompt, 512)
|
||||
return createBasicCompletionRequest(
|
||||
service<PromptsSettings>().state.coreActions.generateNameLookups.instructions
|
||||
?: CoreActionsState.DEFAULT_GENERATE_NAME_LOOKUPS_PROMPT,
|
||||
params.prompt,
|
||||
512
|
||||
)
|
||||
}
|
||||
|
||||
abstract fun createBasicCompletionRequest(
|
||||
|
|
|
|||
|
|
@ -3,19 +3,9 @@ package ee.carlrobert.codegpt.completions
|
|||
import com.intellij.openapi.components.service
|
||||
import ee.carlrobert.codegpt.ReferencedFile
|
||||
import ee.carlrobert.codegpt.settings.IncludedFilesSettings
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil.getResourceContent
|
||||
import java.util.stream.Collectors
|
||||
|
||||
object CompletionRequestUtil {
|
||||
val GENERATE_COMMIT_MESSAGE_SYSTEM_PROMPT =
|
||||
getResourceContent("/prompts/generate-commit-message.txt")
|
||||
val FIX_COMPILE_ERRORS_SYSTEM_PROMPT =
|
||||
getResourceContent("/prompts/fix-compile-errors.txt")
|
||||
val GENERATE_METHOD_NAMES_SYSTEM_PROMPT =
|
||||
getResourceContent("/prompts/method-name-generator.txt")
|
||||
val EDIT_CODE_SYSTEM_PROMPT =
|
||||
getResourceContent("/prompts/edit-code.txt")
|
||||
|
||||
@JvmStatic
|
||||
fun getPromptWithContext(
|
||||
referencedFiles: List<ReferencedFile>,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import ee.carlrobert.codegpt.completions.BaseRequestFactory
|
|||
import ee.carlrobert.codegpt.completions.ChatCompletionParameters
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.settings.service.anthropic.AnthropicSettings
|
||||
import ee.carlrobert.llm.client.anthropic.completion.*
|
||||
import ee.carlrobert.llm.completion.CompletionRequest
|
||||
|
|
@ -16,7 +17,7 @@ class ClaudeRequestFactory : BaseRequestFactory() {
|
|||
model = service<AnthropicSettings>().state.model
|
||||
maxTokens = service<ConfigurationSettings>().state.maxTokens
|
||||
isStream = true
|
||||
system = PersonaSettings.getSystemPrompt()
|
||||
system = PromptsSettings.getSelectedPersonaSystemPrompt()
|
||||
|
||||
messages = params.conversation.messages
|
||||
.filter { it.response != null && it.response.isNotEmpty() }
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@ import com.intellij.openapi.components.service
|
|||
import ee.carlrobert.codegpt.EncodingManager
|
||||
import ee.carlrobert.codegpt.completions.BaseRequestFactory
|
||||
import ee.carlrobert.codegpt.completions.ChatCompletionParameters
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.FIX_COMPILE_ERRORS_SYSTEM_PROMPT
|
||||
import ee.carlrobert.codegpt.completions.ConversationType
|
||||
import ee.carlrobert.codegpt.completions.TotalUsageExceededException
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.settings.service.google.GoogleSettings
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil
|
||||
import ee.carlrobert.llm.client.google.completion.GoogleCompletionContent
|
||||
|
|
@ -100,7 +99,7 @@ class GoogleRequestFactory : BaseRequestFactory() {
|
|||
messages.add(
|
||||
GoogleCompletionContent(
|
||||
"user",
|
||||
listOf(PersonaSettings.getSystemPrompt())
|
||||
listOf(PromptsSettings.getSelectedPersonaSystemPrompt())
|
||||
)
|
||||
)
|
||||
messages.add(GoogleCompletionContent("model", listOf("Understood.")))
|
||||
|
|
@ -108,7 +107,10 @@ class GoogleRequestFactory : BaseRequestFactory() {
|
|||
|
||||
ConversationType.FIX_COMPILE_ERRORS -> {
|
||||
messages.add(
|
||||
GoogleCompletionContent("user", listOf(FIX_COMPILE_ERRORS_SYSTEM_PROMPT))
|
||||
GoogleCompletionContent(
|
||||
"user",
|
||||
listOf(service<PromptsSettings>().state.coreActions.fixCompileErrors.instructions)
|
||||
)
|
||||
)
|
||||
messages.add(GoogleCompletionContent("model", listOf("Understood.")))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ package ee.carlrobert.codegpt.completions.factory
|
|||
import com.intellij.openapi.components.service
|
||||
import ee.carlrobert.codegpt.completions.BaseRequestFactory
|
||||
import ee.carlrobert.codegpt.completions.ChatCompletionParameters
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.FIX_COMPILE_ERRORS_SYSTEM_PROMPT
|
||||
import ee.carlrobert.codegpt.completions.ConversationType
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaModel
|
||||
import ee.carlrobert.codegpt.completions.llama.PromptTemplate
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings.Companion.getSystemPrompt
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
|
||||
import ee.carlrobert.llm.client.llama.completion.LlamaCompletionRequest
|
||||
|
||||
|
|
@ -18,9 +17,9 @@ class LlamaRequestFactory : BaseRequestFactory() {
|
|||
val promptTemplate = getPromptTemplate()
|
||||
val systemPrompt =
|
||||
if (params.conversationType == ConversationType.FIX_COMPILE_ERRORS)
|
||||
FIX_COMPILE_ERRORS_SYSTEM_PROMPT
|
||||
service<PromptsSettings>().state.coreActions.fixCompileErrors.instructions
|
||||
else
|
||||
getSystemPrompt()
|
||||
PromptsSettings.getSelectedPersonaSystemPrompt()
|
||||
val prompt = promptTemplate.buildPrompt(
|
||||
systemPrompt,
|
||||
getPromptWithFilesContext(params),
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@ package ee.carlrobert.codegpt.completions.factory
|
|||
import com.intellij.openapi.components.service
|
||||
import ee.carlrobert.codegpt.EncodingManager
|
||||
import ee.carlrobert.codegpt.completions.*
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.EDIT_CODE_SYSTEM_PROMPT
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.FIX_COMPILE_ERRORS_SYSTEM_PROMPT
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.GENERATE_METHOD_NAMES_SYSTEM_PROMPT
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings.Companion.getState
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings.Companion.getSystemPrompt
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil.getImageMediaType
|
||||
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel
|
||||
|
|
@ -47,10 +45,12 @@ class OpenAIRequestFactory : CompletionRequestFactory {
|
|||
override fun createEditCodeRequest(params: EditCodeCompletionParameters): OpenAIChatCompletionRequest {
|
||||
val model = service<OpenAISettings>().state.model
|
||||
val prompt = "Code to modify:\n${params.selectedText}\n\nInstructions: ${params.prompt}"
|
||||
val systemPrompt = service<PromptsSettings>().state.coreActions.editCode.instructions
|
||||
?: CoreActionsState.DEFAULT_EDIT_CODE_PROMPT
|
||||
if (model == "o1-mini" || model == "o1-preview") {
|
||||
return buildBasicO1Request(model, prompt, EDIT_CODE_SYSTEM_PROMPT)
|
||||
return buildBasicO1Request(model, prompt, systemPrompt)
|
||||
}
|
||||
return createBasicCompletionRequest(EDIT_CODE_SYSTEM_PROMPT, prompt, model, true)
|
||||
return createBasicCompletionRequest(systemPrompt, prompt, model, true)
|
||||
}
|
||||
|
||||
override fun createCommitMessageRequest(params: CommitMessageCompletionParameters): OpenAIChatCompletionRequest {
|
||||
|
|
@ -66,9 +66,17 @@ class OpenAIRequestFactory : CompletionRequestFactory {
|
|||
val model = service<OpenAISettings>().state.model
|
||||
val (prompt) = params
|
||||
if (model == "o1-mini" || model == "o1-preview") {
|
||||
return buildBasicO1Request(model, prompt, GENERATE_METHOD_NAMES_SYSTEM_PROMPT)
|
||||
return buildBasicO1Request(
|
||||
model,
|
||||
prompt,
|
||||
service<PromptsSettings>().state.coreActions.generateNameLookups.instructions
|
||||
?: CoreActionsState.DEFAULT_GENERATE_NAME_LOOKUPS_PROMPT
|
||||
)
|
||||
}
|
||||
return createBasicCompletionRequest(GENERATE_METHOD_NAMES_SYSTEM_PROMPT, prompt, model)
|
||||
return createBasicCompletionRequest(
|
||||
service<PromptsSettings>().state.coreActions.generateNameLookups.instructions
|
||||
?: CoreActionsState.DEFAULT_GENERATE_NAME_LOOKUPS_PROMPT, prompt, model
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
@ -142,10 +150,13 @@ class OpenAIRequestFactory : CompletionRequestFactory {
|
|||
val role = if ("o1-mini" == model || "o1-preview" == model) "user" else "system"
|
||||
|
||||
if (callParameters.conversationType == ConversationType.DEFAULT) {
|
||||
val sessionPersonaDetails = callParameters.message.personaDetails
|
||||
if (callParameters.message.personaDetails == null) {
|
||||
val sessionPersonaDetails = callParameters.persona
|
||||
if (sessionPersonaDetails == null) {
|
||||
messages.add(
|
||||
OpenAIChatCompletionStandardMessage(role, getSystemPrompt())
|
||||
OpenAIChatCompletionStandardMessage(
|
||||
role,
|
||||
PromptsSettings.getSelectedPersonaSystemPrompt()
|
||||
)
|
||||
)
|
||||
} else {
|
||||
messages.add(
|
||||
|
|
@ -158,7 +169,10 @@ class OpenAIRequestFactory : CompletionRequestFactory {
|
|||
}
|
||||
if (callParameters.conversationType == ConversationType.FIX_COMPILE_ERRORS) {
|
||||
messages.add(
|
||||
OpenAIChatCompletionStandardMessage(role, FIX_COMPILE_ERRORS_SYSTEM_PROMPT)
|
||||
OpenAIChatCompletionStandardMessage(
|
||||
role,
|
||||
service<PromptsSettings>().state.coreActions.fixCompileErrors.instructions
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package ee.carlrobert.codegpt.settings.configuration
|
|||
|
||||
import com.intellij.openapi.components.*
|
||||
import ee.carlrobert.codegpt.actions.editor.EditorActionsUtil
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.GENERATE_COMMIT_MESSAGE_SYSTEM_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
|
@ -22,12 +22,11 @@ class ConfigurationSettings :
|
|||
}
|
||||
|
||||
class ConfigurationSettingsState : BaseState() {
|
||||
var commitMessagePrompt by string(GENERATE_COMMIT_MESSAGE_SYSTEM_PROMPT)
|
||||
var commitMessagePrompt by string(CoreActionsState.DEFAULT_GENERATE_COMMIT_MESSAGE_PROMPT)
|
||||
var maxTokens by property(2048)
|
||||
var temperature by property(0.1f) { max(0f, min(1f, it)) }
|
||||
var checkForPluginUpdates by property(true)
|
||||
var checkForNewScreenshots by property(false)
|
||||
var createNewChatOnEachAction by property(false)
|
||||
var ignoreGitCommitTokenLimit by property(false)
|
||||
var methodNameGenerationEnabled by property(true)
|
||||
var captureCompileErrors by property(true)
|
||||
|
|
|
|||
|
|
@ -1,44 +1,23 @@
|
|||
package ee.carlrobert.codegpt.settings.persona
|
||||
|
||||
import com.intellij.openapi.components.*
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil.getResourceContent
|
||||
|
||||
val DEFAULT_PROMPT = getResourceContent("/prompts/default-completion.txt")
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonasState
|
||||
|
||||
@Deprecated("Use PromptsSettings instead")
|
||||
@Service
|
||||
@State(
|
||||
name = "CodeGPT_PersonaSettings",
|
||||
storages = [Storage("CodeGPT_PersonaSettings.xml")]
|
||||
)
|
||||
class PersonaSettings :
|
||||
SimplePersistentStateComponent<PersonaSettingsState>(PersonaSettingsState()) {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getSystemPrompt(): String {
|
||||
return service<PersonaSettings>().state.selectedPersona.instructions ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
SimplePersistentStateComponent<PersonaSettingsState>(PersonaSettingsState())
|
||||
|
||||
class PersonaSettingsState : BaseState() {
|
||||
var selectedPersona by property(PersonaDetailsState())
|
||||
var userCreatedPersonas by list<PersonaDetailsState>()
|
||||
}
|
||||
|
||||
class PersonaDetailsState : BaseState() {
|
||||
var id by property(1L)
|
||||
var name by string("CodeGPT Default")
|
||||
var instructions by string(DEFAULT_PROMPT)
|
||||
}
|
||||
|
||||
@JvmRecord
|
||||
data class PersonaDetails(val id: Long, val name: String, val instructions: String)
|
||||
|
||||
fun PersonaDetails.toPersonaDetailsState(): PersonaDetailsState {
|
||||
val newState = PersonaDetailsState()
|
||||
newState.id = id
|
||||
newState.name = name
|
||||
newState.instructions = instructions
|
||||
return newState
|
||||
var instructions by string(PersonasState.DEFAULT_PERSONA_PROMPT)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,308 +0,0 @@
|
|||
package ee.carlrobert.codegpt.settings.persona
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.ui.DialogPanel
|
||||
import com.intellij.ui.DocumentAdapter
|
||||
import com.intellij.ui.ToolbarDecorator
|
||||
import com.intellij.ui.components.JBScrollPane
|
||||
import com.intellij.ui.components.JBTextArea
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.dsl.builder.Align
|
||||
import com.intellij.ui.dsl.builder.LabelPosition
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import com.intellij.ui.table.JBTable
|
||||
import com.intellij.util.ui.JBUI
|
||||
import ee.carlrobert.codegpt.util.ResourceUtil
|
||||
import java.awt.Dimension
|
||||
import javax.swing.UIManager
|
||||
import javax.swing.event.DocumentEvent
|
||||
import javax.swing.table.DefaultTableModel
|
||||
import javax.swing.text.JTextComponent
|
||||
|
||||
class NonEditableTableModel(columnNames: Array<String>, rowCount: Int) :
|
||||
DefaultTableModel(columnNames, rowCount) {
|
||||
override fun isCellEditable(row: Int, column: Int) = false
|
||||
}
|
||||
|
||||
class PersonasSettingsForm {
|
||||
|
||||
private val tableModel =
|
||||
NonEditableTableModel(arrayOf("Id", "Name", "Instructions", "FromResource"), 0)
|
||||
private val table = JBTable(tableModel).apply {
|
||||
setupTableColumns()
|
||||
selectionModel.addListSelectionListener { populateEditArea() }
|
||||
}
|
||||
private val nameField = JBTextField().apply {
|
||||
addTextChangeListener { newText ->
|
||||
updateTableModelIfRowSelected(1, newText)
|
||||
}
|
||||
}
|
||||
private val instructionsTextArea = JBTextArea().apply {
|
||||
lineWrap = true
|
||||
wrapStyleWord = true
|
||||
font = UIManager.getFont("TextField.font")
|
||||
border = JBUI.Borders.empty(3, 6)
|
||||
addTextChangeListener { newText ->
|
||||
updateTableModelIfRowSelected(2, newText)
|
||||
}
|
||||
}
|
||||
private val addedItems = mutableListOf<PersonaDetails>()
|
||||
private val removedItemIds = mutableListOf<Long>()
|
||||
|
||||
init {
|
||||
setupForm()
|
||||
}
|
||||
|
||||
fun createPanel(): DialogPanel {
|
||||
return panel {
|
||||
row {
|
||||
val toolbarDecorator = ToolbarDecorator.createDecorator(table)
|
||||
.setAddAction { handleAddItem() }
|
||||
.setRemoveAction { handleRemoveItem() }
|
||||
.addExtraAction(object :
|
||||
AnAction("Duplicate", "Duplicate persona", AllIcons.Actions.Copy) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
handleDuplicateItem()
|
||||
}
|
||||
})
|
||||
.setRemoveActionUpdater {
|
||||
val selectedRow = table.selectedRow
|
||||
selectedRow != -1 && !(tableModel.getValueAt(selectedRow, 3) as Boolean)
|
||||
}
|
||||
.disableUpDownActions()
|
||||
|
||||
cell(toolbarDecorator.createPanel())
|
||||
.align(Align.FILL)
|
||||
.resizableColumn()
|
||||
.applyToComponent {
|
||||
preferredSize = Dimension(650, 250)
|
||||
}
|
||||
}
|
||||
row {
|
||||
cell(nameField)
|
||||
.label("Name:", LabelPosition.TOP)
|
||||
.align(Align.FILL)
|
||||
}
|
||||
row {
|
||||
cell(JBScrollPane(instructionsTextArea).apply {
|
||||
preferredSize = Dimension(650, 225)
|
||||
})
|
||||
.label("Instructions:", LabelPosition.TOP)
|
||||
.align(Align.FILL)
|
||||
.resizableColumn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun applyChanges() {
|
||||
val persona = getSelectedPersona()
|
||||
service<PersonaSettings>().state.run {
|
||||
if (persona != null) {
|
||||
selectedPersona = persona.toPersonaDetailsState()
|
||||
}
|
||||
|
||||
userCreatedPersonas.removeIf { removedItemIds.contains(it.id) }
|
||||
userCreatedPersonas.forEach {
|
||||
if (it.id == persona?.id) {
|
||||
it.name = persona.name
|
||||
it.instructions = persona.instructions
|
||||
}
|
||||
}
|
||||
userCreatedPersonas.addAll(findMatchingRows(addedItems.map { it.id }).map { it.toPersonaDetailsState() })
|
||||
}
|
||||
clear()
|
||||
}
|
||||
|
||||
fun isModified(): Boolean {
|
||||
service<PersonaSettings>().state.let {
|
||||
val (id, name, description) = getSelectedPersona() ?: return false
|
||||
return it.selectedPersona.id != id
|
||||
|| it.selectedPersona.name != name
|
||||
|| it.selectedPersona.instructions != description
|
||||
|| removedItemIds.size > 0
|
||||
|| addedItems.size > 0
|
||||
}
|
||||
}
|
||||
|
||||
fun resetChanges() {
|
||||
clear()
|
||||
tableModel.rowCount = 0
|
||||
setupForm()
|
||||
}
|
||||
|
||||
private fun populateEditArea() {
|
||||
val selectedRow = table.selectedRow
|
||||
if (selectedRow != -1) {
|
||||
val userCreatedResource = !(tableModel.getValueAt(selectedRow, 3) as Boolean)
|
||||
|
||||
nameField.text = tableModel.getValueAt(selectedRow, 1) as String
|
||||
nameField.isEnabled = userCreatedResource
|
||||
instructionsTextArea.text = tableModel.getValueAt(selectedRow, 2) as String
|
||||
instructionsTextArea.isEnabled = userCreatedResource
|
||||
} else {
|
||||
nameField.text = ""
|
||||
instructionsTextArea.text = ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAddItem() {
|
||||
addPersonaToTable(createNewPersona("New Persona", "New Prompt"))
|
||||
}
|
||||
|
||||
private fun handleDuplicateItem() {
|
||||
val selectedRow = table.selectedRow
|
||||
val originalName = tableModel.getValueAt(selectedRow, 1) as String
|
||||
val originalPrompt = tableModel.getValueAt(selectedRow, 2) as String
|
||||
addPersonaToTable(createNewPersona("$originalName Copy", originalPrompt))
|
||||
}
|
||||
|
||||
private fun createNewPersona(name: String, prompt: String): PersonaDetails {
|
||||
return PersonaDetails(findMaxId() + 1, name, prompt)
|
||||
}
|
||||
|
||||
private fun addPersonaToTable(persona: PersonaDetails) {
|
||||
addedItems.add(persona)
|
||||
tableModel.addRow(arrayOf(persona.id, persona.name, persona.instructions, false))
|
||||
selectLastRowAndUpdateUI()
|
||||
}
|
||||
|
||||
private fun findMaxId(): Long {
|
||||
return (0 until table.rowCount).maxOf {
|
||||
tableModel.getValueAt(it, 0) as Long
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectLastRowAndUpdateUI() {
|
||||
val lastRow = table.rowCount - 1
|
||||
table.setRowSelectionInterval(lastRow, lastRow)
|
||||
populateEditArea()
|
||||
scrollToLastRow()
|
||||
nameField.requestFocus()
|
||||
}
|
||||
|
||||
private fun handleRemoveItem() {
|
||||
val selectedRow = table.selectedRow
|
||||
if (selectedRow != -1 && !(tableModel.getValueAt(selectedRow, 3) as Boolean)) {
|
||||
val id = tableModel.getValueAt(selectedRow, 0) as Long
|
||||
if (addedItems.none { it.id == id }) {
|
||||
removedItemIds.add(id)
|
||||
}
|
||||
addedItems.filter { it.id != id }
|
||||
tableModel.removeRow(selectedRow)
|
||||
populateEditArea()
|
||||
|
||||
val newSelectedRow = if (selectedRow > 0) selectedRow - 1 else 0
|
||||
if (table.rowCount > 0) {
|
||||
table.setRowSelectionInterval(newSelectedRow, newSelectedRow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupForm() {
|
||||
service<PersonaSettings>().state.run {
|
||||
userCreatedPersonas.forEachIndexed { index, persona ->
|
||||
tableModel.addPersonaRow(
|
||||
PersonaDetails(
|
||||
persona.id,
|
||||
persona.name ?: "",
|
||||
persona.instructions ?: ""
|
||||
),
|
||||
selectedPersona.id,
|
||||
index
|
||||
)
|
||||
}
|
||||
ResourceUtil.getDefaultPersonas().forEachIndexed { index, persona ->
|
||||
tableModel.addPersonaRow(persona, selectedPersona.id, index, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DefaultTableModel.addPersonaRow(
|
||||
persona: PersonaDetails,
|
||||
selectedPersonaId: Long,
|
||||
rowIndex: Int,
|
||||
fromResource: Boolean = false
|
||||
) {
|
||||
val (id, name, instructions) = persona
|
||||
addRow(arrayOf(id, name, instructions, fromResource))
|
||||
if (selectedPersonaId == id) {
|
||||
table.setRowSelectionInterval(rowIndex, rowIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun scrollToLastRow() {
|
||||
table.scrollRectToVisible(table.getCellRect(table.rowCount - 1, 0, true))
|
||||
}
|
||||
|
||||
private fun JBTable.setupTableColumns() {
|
||||
columnModel.apply {
|
||||
getColumn(0).apply {
|
||||
minWidth = 0
|
||||
maxWidth = 0
|
||||
preferredWidth = 0
|
||||
resizable = false
|
||||
}
|
||||
getColumn(1).preferredWidth = 60
|
||||
getColumn(2).preferredWidth = 240
|
||||
getColumn(3).apply {
|
||||
minWidth = 0
|
||||
maxWidth = 0
|
||||
preferredWidth = 0
|
||||
resizable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JBTable.getSelectedPersona(): PersonaDetails? {
|
||||
if (selectedRow == -1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return PersonaDetails(
|
||||
tableModel.getValueAt(selectedRow, 0) as Long,
|
||||
tableModel.getValueAt(selectedRow, 1) as String,
|
||||
tableModel.getValueAt(selectedRow, 2) as String
|
||||
)
|
||||
}
|
||||
|
||||
private fun JTextComponent.addTextChangeListener(listener: (String) -> Unit) {
|
||||
document.addDocumentListener(object : DocumentAdapter() {
|
||||
override fun textChanged(e: DocumentEvent) {
|
||||
listener(e.document.getText(0, e.document.length))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateTableModelIfRowSelected(column: Int, newValue: Any) {
|
||||
if (table.selectedRow != -1) {
|
||||
tableModel.setValueAt(newValue, table.selectedRow, column)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectedPersona(): PersonaDetails? {
|
||||
return table.getSelectedPersona()
|
||||
}
|
||||
|
||||
private fun clear() {
|
||||
addedItems.clear()
|
||||
removedItemIds.clear()
|
||||
}
|
||||
|
||||
private fun findMatchingRows(ids: List<Long>): List<PersonaDetails> {
|
||||
val matchingRows = mutableListOf<PersonaDetails>()
|
||||
|
||||
for (rowIndex in 0 until tableModel.rowCount) {
|
||||
val personaId = tableModel.getValueAt(rowIndex, 0) as Long
|
||||
if (ids.contains(personaId)) {
|
||||
val name = tableModel.getValueAt(rowIndex, 1) as String
|
||||
val instructions = tableModel.getValueAt(rowIndex, 2) as String
|
||||
matchingRows.add(PersonaDetails(personaId, name, instructions))
|
||||
}
|
||||
}
|
||||
|
||||
return matchingRows
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
package ee.carlrobert.codegpt.settings.configuration
|
||||
package ee.carlrobert.codegpt.settings.prompts
|
||||
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.Service.Level.PROJECT
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import ee.carlrobert.codegpt.settings.configuration.BranchNamePlaceholderStrategy
|
||||
import ee.carlrobert.codegpt.settings.configuration.DatePlaceholderStrategy
|
||||
import ee.carlrobert.codegpt.settings.configuration.Placeholder
|
||||
import ee.carlrobert.codegpt.settings.configuration.Placeholder.BRANCH_NAME
|
||||
import ee.carlrobert.codegpt.settings.configuration.Placeholder.DATE_ISO_8601
|
||||
import ee.carlrobert.codegpt.settings.configuration.PlaceholderStrategy
|
||||
|
||||
@Service(PROJECT)
|
||||
class CommitMessageTemplate private constructor(project: Project) {
|
||||
|
|
@ -17,12 +21,8 @@ class CommitMessageTemplate private constructor(project: Project) {
|
|||
}
|
||||
|
||||
return buildString {
|
||||
append("<html>\n")
|
||||
append("<body>\n")
|
||||
append("<p>Template for generating commit messages. Use the following placeholders to insert dynamic values:</p>\n")
|
||||
append("<ul>$placeholderDescriptions</ul>\n")
|
||||
append("</body>\n")
|
||||
append("</html>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ class CommitMessageTemplate private constructor(project: Project) {
|
|||
)
|
||||
|
||||
fun getSystemPrompt(): String =
|
||||
service<ConfigurationSettings>().state.commitMessagePrompt.let { template ->
|
||||
service<PromptsSettings>().state.coreActions.generateCommitMessage.instructions.let { template ->
|
||||
placeholderStrategyMapping.entries.fold(
|
||||
template ?: ""
|
||||
) { acc, (placeholder, strategy) ->
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
package ee.carlrobert.codegpt.settings.persona
|
||||
package ee.carlrobert.codegpt.settings.prompts
|
||||
|
||||
import com.intellij.openapi.options.Configurable
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.PromptsForm
|
||||
import javax.swing.JComponent
|
||||
|
||||
class PersonasConfigurable : Configurable {
|
||||
class PromptsConfigurable : Configurable {
|
||||
|
||||
private lateinit var component: PersonasSettingsForm
|
||||
private lateinit var component: PromptsForm
|
||||
|
||||
override fun getDisplayName(): String {
|
||||
return "CodeGPT: Personas"
|
||||
return "CodeGPT: Prompts"
|
||||
}
|
||||
|
||||
override fun createComponent(): JComponent {
|
||||
component = PersonasSettingsForm()
|
||||
component = PromptsForm()
|
||||
return component.createPanel()
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts
|
||||
|
||||
import com.intellij.openapi.components.*
|
||||
import ee.carlrobert.codegpt.actions.editor.EditorActionsUtil
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil.getResourceContent
|
||||
|
||||
|
||||
@Service
|
||||
@State(
|
||||
name = "CodeGPT_PromptsSettings",
|
||||
storages = [Storage("CodeGPT_PromptsSettings.xml")]
|
||||
)
|
||||
class PromptsSettings :
|
||||
SimplePersistentStateComponent<PromptsSettingsState>(PromptsSettingsState()) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getSelectedPersonaSystemPrompt(): String {
|
||||
return service<PromptsSettings>().state.personas.selectedPersona.instructions ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PromptsSettingsState : BaseState() {
|
||||
var coreActions by property(CoreActionsState())
|
||||
var chatActions by property(ChatActionsState())
|
||||
var personas by property(PersonasState())
|
||||
}
|
||||
|
||||
class CoreActionsState : BaseState() {
|
||||
|
||||
companion object {
|
||||
val DEFAULT_EDIT_CODE_PROMPT = getResourceContent("/prompts/core/edit-code.txt")
|
||||
val DEFAULT_GENERATE_COMMIT_MESSAGE_PROMPT =
|
||||
getResourceContent("/prompts/core/generate-commit-message.txt")
|
||||
val DEFAULT_GENERATE_NAME_LOOKUPS_PROMPT =
|
||||
getResourceContent("/prompts/core/generate-name-lookups.txt")
|
||||
val DEFAULT_FIX_COMPILE_ERRORS_PROMPT =
|
||||
getResourceContent("/prompts/core/fix-compile-errors.txt")
|
||||
}
|
||||
|
||||
var editCode by property(CoreActionPromptDetailsState().apply {
|
||||
name = "Edit Code"
|
||||
code = "EDIT_CODE"
|
||||
instructions = DEFAULT_EDIT_CODE_PROMPT
|
||||
})
|
||||
var fixCompileErrors by property(CoreActionPromptDetailsState().apply {
|
||||
name = "Fix Compile Errors"
|
||||
code = "FIX_COMPILE_ERRORS"
|
||||
instructions = DEFAULT_FIX_COMPILE_ERRORS_PROMPT
|
||||
})
|
||||
var generateCommitMessage by property(CoreActionPromptDetailsState().apply {
|
||||
name = "Generate Commit Message"
|
||||
code = "GENERATE_COMMIT_MESSAGE"
|
||||
instructions = service<ConfigurationSettings>().state.commitMessagePrompt
|
||||
})
|
||||
var generateNameLookups by property(CoreActionPromptDetailsState().apply {
|
||||
name = "Generate Name Lookups"
|
||||
code = "GENERATE_NAME_LOOKUPS"
|
||||
instructions = DEFAULT_GENERATE_NAME_LOOKUPS_PROMPT
|
||||
})
|
||||
}
|
||||
|
||||
class PersonasState : BaseState() {
|
||||
|
||||
companion object {
|
||||
val DEFAULT_PERSONA_PROMPT = getResourceContent("/prompts/persona/default-persona.txt")
|
||||
val DEFAULT_PERSONA = PersonaPromptDetailsState().apply {
|
||||
id = 1L
|
||||
name = "CodeGPT Default"
|
||||
instructions = DEFAULT_PERSONA_PROMPT
|
||||
}
|
||||
}
|
||||
|
||||
var selectedPersona by property(DEFAULT_PERSONA)
|
||||
var prompts by list<PersonaPromptDetailsState>()
|
||||
|
||||
init {
|
||||
prompts.add(DEFAULT_PERSONA)
|
||||
prompts.add(PersonaPromptDetailsState().apply {
|
||||
id = 2L
|
||||
name = "Rubber Duck"
|
||||
instructions = getResourceContent("/prompts/persona/rubber-duck.txt")
|
||||
})
|
||||
|
||||
// migrate old personas
|
||||
var nextPersonaIndex = 3L
|
||||
prompts.addAll(service<PersonaSettings>().state.userCreatedPersonas
|
||||
.map {
|
||||
val newState = PersonaPromptDetailsState().apply {
|
||||
id = nextPersonaIndex
|
||||
name = it.name
|
||||
instructions = it.instructions
|
||||
}
|
||||
nextPersonaIndex++
|
||||
newState
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class ChatActionsState : BaseState() {
|
||||
var prompts by list<ChatActionPromptDetailsState>()
|
||||
var startInNewWindow by property(false)
|
||||
|
||||
companion object {
|
||||
val DEFAULT_FIND_BUGS_PROMPT = getResourceContent("/prompts/chat/find-bugs.txt")
|
||||
val DEFAULT_WRITE_TESTS_PROMPT = getResourceContent("/prompts/chat/write-tests.txt")
|
||||
val DEFAULT_EXPLAIN_PROMPT = getResourceContent("/prompts/chat/explain.txt")
|
||||
val DEFAULT_REFACTOR_PROMPT = getResourceContent("/prompts/chat/refactor.txt")
|
||||
val DEFAULT_OPTIMIZE_PROMPT = getResourceContent("/prompts/chat/optimize.txt")
|
||||
}
|
||||
|
||||
init {
|
||||
prompts.add(ChatActionPromptDetailsState().apply {
|
||||
id = 1L
|
||||
code = "FIND_BUGS"
|
||||
name = "Find Bugs"
|
||||
instructions = DEFAULT_FIND_BUGS_PROMPT
|
||||
})
|
||||
prompts.add(ChatActionPromptDetailsState().apply {
|
||||
id = 2L
|
||||
code = "WRITE_TESTS"
|
||||
name = "Write Tests"
|
||||
instructions = DEFAULT_WRITE_TESTS_PROMPT
|
||||
})
|
||||
prompts.add(ChatActionPromptDetailsState().apply {
|
||||
id = 3L
|
||||
code = "EXPLAIN"
|
||||
name = "Explain"
|
||||
instructions = DEFAULT_EXPLAIN_PROMPT
|
||||
})
|
||||
prompts.add(ChatActionPromptDetailsState().apply {
|
||||
id = 4L
|
||||
code = "REFACTOR"
|
||||
name = "Refactor"
|
||||
instructions = DEFAULT_REFACTOR_PROMPT
|
||||
})
|
||||
prompts.add(ChatActionPromptDetailsState().apply {
|
||||
id = 5L
|
||||
code = "OPTIMIZE"
|
||||
name = "Optimize"
|
||||
instructions = DEFAULT_OPTIMIZE_PROMPT
|
||||
})
|
||||
|
||||
// migrate old chat actions
|
||||
var nextChatActionIndex = 6L
|
||||
prompts.addAll(service<ConfigurationSettings>().state.tableData
|
||||
.filterNot { entry ->
|
||||
EditorActionsUtil.DEFAULT_ACTIONS.any { it.key == entry.key && it.value == entry.value }
|
||||
}
|
||||
.map {
|
||||
val newState = ChatActionPromptDetailsState().apply {
|
||||
id = nextChatActionIndex
|
||||
name = it.key
|
||||
instructions = it.value
|
||||
}
|
||||
nextChatActionIndex++
|
||||
newState
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PromptDetailsState : BaseState() {
|
||||
var name by string()
|
||||
var instructions by string()
|
||||
}
|
||||
|
||||
class CoreActionPromptDetailsState : PromptDetailsState() {
|
||||
var code by string()
|
||||
}
|
||||
|
||||
class ChatActionPromptDetailsState : PromptDetailsState() {
|
||||
var id by property(1L)
|
||||
var code by string()
|
||||
}
|
||||
|
||||
class PersonaPromptDetailsState : PromptDetailsState() {
|
||||
var id by property(1L)
|
||||
}
|
||||
|
||||
@JvmRecord
|
||||
data class PersonaDetails(val id: Long, val name: String, val instructions: String)
|
||||
|
|
@ -0,0 +1,392 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts.form
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.application.runInEdt
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.ui.ToolbarDecorator
|
||||
import com.intellij.ui.treeStructure.SimpleTree
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonasState
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.PromptsFormUtil.getFormState
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.PromptsFormUtil.toState
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.details.*
|
||||
import java.awt.CardLayout
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
import javax.swing.tree.DefaultTreeModel
|
||||
import javax.swing.tree.TreePath
|
||||
import javax.swing.tree.TreeSelectionModel
|
||||
|
||||
enum class PromptCategory {
|
||||
CORE_ACTIONS,
|
||||
CHAT_ACTIONS,
|
||||
PERSONAS,
|
||||
}
|
||||
|
||||
class PromptDetailsTreeNode(
|
||||
val details: FormPromptDetails,
|
||||
val category: PromptCategory
|
||||
) : DefaultMutableTreeNode() {
|
||||
|
||||
override fun toString(): String {
|
||||
return details.name ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
class PromptsForm {
|
||||
private val cardLayout = CardLayout()
|
||||
private val promptDetailsContainer = JPanel(cardLayout)
|
||||
private val categoryPanels = mapOf(
|
||||
PromptCategory.CORE_ACTIONS to CoreActionsDetailsPanel(),
|
||||
PromptCategory.CHAT_ACTIONS to ChatActionsDetailsPanel(),
|
||||
PromptCategory.PERSONAS to PersonasDetailsPanel { handleDefaultPersonaChanged(it) },
|
||||
).onEach { (category, panel) ->
|
||||
promptDetailsContainer.add(panel.getPanel(), category.name)
|
||||
}
|
||||
|
||||
private val coreActionsNode = DefaultMutableTreeNode("Core Actions")
|
||||
private val chatActionsNode = DefaultMutableTreeNode("Chat Actions")
|
||||
private val personasNode = DefaultMutableTreeNode("Personas")
|
||||
private val root = DefaultMutableTreeNode("Root").apply {
|
||||
add(coreActionsNode)
|
||||
add(chatActionsNode)
|
||||
add(personasNode)
|
||||
}
|
||||
private val treeModel = DefaultTreeModel(root)
|
||||
private val tree = SimpleTree(treeModel).apply {
|
||||
isRootVisible = false
|
||||
selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION
|
||||
cellRenderer = PromptsFormTreeCellRenderer(root)
|
||||
|
||||
setupChildNodes()
|
||||
|
||||
addTreeSelectionListener { e ->
|
||||
val node = (e.newLeadSelectionPath?.lastPathComponent as? PromptDetailsTreeNode)
|
||||
if (node == null || node.parent == root) {
|
||||
return@addTreeSelectionListener
|
||||
}
|
||||
|
||||
categoryPanels[node.category]?.updateData(node.details)
|
||||
cardLayout.show(promptDetailsContainer, node.category.name)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
runInEdt {
|
||||
expandAll()
|
||||
selectFirstPersonaNode()
|
||||
}
|
||||
}
|
||||
|
||||
fun createPanel(): JComponent {
|
||||
return BorderLayoutPanel(8, 0)
|
||||
.addToLeft(createToolbarDecorator().createPanel())
|
||||
.addToCenter(promptDetailsContainer)
|
||||
}
|
||||
|
||||
fun isModified(): Boolean {
|
||||
val settings = service<PromptsSettings>().state
|
||||
return isCoreActionsModified(settings.coreActions) ||
|
||||
isChatActionsModified(settings.chatActions) ||
|
||||
isPersonasModified(settings.personas)
|
||||
}
|
||||
|
||||
fun applyChanges() {
|
||||
val settings = service<PromptsSettings>().state
|
||||
|
||||
val coreActionsFormState = getFormState<CoreActionPromptDetails>(coreActionsNode)
|
||||
settings.coreActions.apply {
|
||||
editCode = coreActionsFormState[0].toState()
|
||||
fixCompileErrors = coreActionsFormState[1].toState()
|
||||
generateCommitMessage = coreActionsFormState[2].toState()
|
||||
generateNameLookups = coreActionsFormState[3].toState()
|
||||
}
|
||||
settings.chatActions.prompts = getFormState<ChatActionPromptDetails>(chatActionsNode)
|
||||
.map { it.toState() }
|
||||
.toMutableList()
|
||||
val personasFormState = getFormState<PersonaPromptDetails>(personasNode)
|
||||
settings.personas.prompts = personasFormState
|
||||
.map { it.toState() }
|
||||
.toMutableList()
|
||||
settings.personas.selectedPersona =
|
||||
personasFormState.find { it.selected.get() }?.toState() ?: PersonasState.DEFAULT_PERSONA
|
||||
}
|
||||
|
||||
fun resetChanges() {
|
||||
removeAllChildNodes()
|
||||
setupChildNodes()
|
||||
reloadTreeView()
|
||||
}
|
||||
|
||||
private fun removeAllChildNodes() {
|
||||
coreActionsNode.removeAllChildren()
|
||||
chatActionsNode.removeAllChildren()
|
||||
personasNode.removeAllChildren()
|
||||
}
|
||||
|
||||
private fun reloadTreeView() {
|
||||
treeModel.reload()
|
||||
expandAll()
|
||||
selectFirstPersonaNode()
|
||||
}
|
||||
|
||||
private fun selectFirstPersonaNode() {
|
||||
val defaultNode = personasNode.getFirstChild() as? PromptDetailsTreeNode
|
||||
if (defaultNode != null) {
|
||||
tree.selectionPath = TreePath(defaultNode.path)
|
||||
}
|
||||
}
|
||||
|
||||
private fun expandAll() {
|
||||
tree.expandPaths(
|
||||
listOf(
|
||||
TreePath(coreActionsNode.path),
|
||||
TreePath(personasNode.path),
|
||||
TreePath(chatActionsNode.path)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun isCoreActionsModified(settingsState: CoreActionsState): Boolean {
|
||||
val formState = getFormState<CoreActionPromptDetails>(coreActionsNode)
|
||||
|
||||
val stateActions = listOf(
|
||||
settingsState.editCode,
|
||||
settingsState.fixCompileErrors,
|
||||
settingsState.generateCommitMessage,
|
||||
settingsState.generateNameLookups
|
||||
)
|
||||
|
||||
return !stateActions.all { action ->
|
||||
formState.find { it.code == action.code }
|
||||
?.let { details ->
|
||||
details.name == action.name && details.instructions == action.instructions
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
|
||||
private fun isChatActionsModified(settingsState: ChatActionsState): Boolean {
|
||||
val formState = getFormState<ChatActionPromptDetails>(chatActionsNode)
|
||||
|
||||
if (formState.size != settingsState.prompts.size) {
|
||||
return true
|
||||
}
|
||||
|
||||
return !formState.zip(settingsState.prompts)
|
||||
.all { (details, prompt) ->
|
||||
details.id == prompt.id &&
|
||||
details.name == prompt.name &&
|
||||
details.instructions == prompt.instructions
|
||||
}
|
||||
}
|
||||
|
||||
private fun isPersonasModified(settingsState: PersonasState): Boolean {
|
||||
val formState = getFormState<PersonaPromptDetails>(personasNode)
|
||||
|
||||
if (formState.size != settingsState.prompts.size) {
|
||||
return true
|
||||
}
|
||||
|
||||
val selectedDefaultPersona = formState.find { it.selected.get() }
|
||||
if (selectedDefaultPersona?.id != settingsState.selectedPersona.id) {
|
||||
return true
|
||||
}
|
||||
|
||||
return !formState.zip(settingsState.prompts)
|
||||
.all { (details, prompt) ->
|
||||
details.id == prompt.id &&
|
||||
details.name == prompt.name &&
|
||||
details.instructions == prompt.instructions
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupChildNodes() {
|
||||
val settings = service<PromptsSettings>().state
|
||||
|
||||
listOf(
|
||||
settings.coreActions.editCode,
|
||||
settings.coreActions.fixCompileErrors,
|
||||
settings.coreActions.generateCommitMessage,
|
||||
settings.coreActions.generateNameLookups
|
||||
).forEach {
|
||||
coreActionsNode.add(
|
||||
PromptDetailsTreeNode(CoreActionPromptDetails(it), PromptCategory.CORE_ACTIONS)
|
||||
)
|
||||
}
|
||||
|
||||
settings.chatActions.prompts.forEach {
|
||||
chatActionsNode.add(
|
||||
PromptDetailsTreeNode(ChatActionPromptDetails(it), PromptCategory.CHAT_ACTIONS)
|
||||
)
|
||||
}
|
||||
|
||||
settings.personas.prompts.forEach {
|
||||
val formDetails = PersonaPromptDetails(it)
|
||||
formDetails.selected.set(settings.personas.selectedPersona.id == it.id)
|
||||
personasNode.add(
|
||||
PromptDetailsTreeNode(formDetails, PromptCategory.PERSONAS)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createToolbarDecorator(): ToolbarDecorator =
|
||||
ToolbarDecorator.createDecorator(tree)
|
||||
.setAddAction { handleAddAction() }
|
||||
.setAddActionUpdater {
|
||||
val selectedNode = tree.selectionPath?.lastPathComponent
|
||||
if (selectedNode is PromptDetailsTreeNode) {
|
||||
selectedNode.category != PromptCategory.CORE_ACTIONS
|
||||
} else {
|
||||
selectedNode is DefaultMutableTreeNode && selectedNode.userObject != "Core Actions"
|
||||
}
|
||||
}
|
||||
.setRemoveAction { handleRemoveAction() }
|
||||
.setRemoveActionUpdater {
|
||||
val selectedNode = tree.selectionPath?.lastPathComponent
|
||||
selectedNode is PromptDetailsTreeNode
|
||||
&& selectedNode.category != PromptCategory.CORE_ACTIONS
|
||||
&& selectedNode.details.name != "CodeGPT Default"
|
||||
}
|
||||
.addExtraAction(object :
|
||||
AnAction("Duplicate", "Duplicate prompt", AllIcons.Actions.Copy) {
|
||||
|
||||
override fun getActionUpdateThread(): ActionUpdateThread {
|
||||
return ActionUpdateThread.EDT
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
val selectedNode = tree.selectionPath?.lastPathComponent
|
||||
|
||||
e.presentation.isEnabled =
|
||||
selectedNode is PromptDetailsTreeNode && selectedNode.category != PromptCategory.CORE_ACTIONS
|
||||
}
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
handleDuplicateAction()
|
||||
}
|
||||
})
|
||||
.disableUpDownActions()
|
||||
|
||||
private fun handleAddAction() {
|
||||
val category = determineCategory(tree.selectionPath?.lastPathComponent) ?: return
|
||||
|
||||
when (category) {
|
||||
PromptCategory.CHAT_ACTIONS -> {
|
||||
val newNode = PromptDetailsTreeNode(
|
||||
ChatActionPromptDetails(
|
||||
"New Action",
|
||||
"New Prompt",
|
||||
chatActionsNode.childCount.toLong() + 1,
|
||||
null
|
||||
),
|
||||
PromptCategory.CHAT_ACTIONS
|
||||
)
|
||||
insertAndSelectNode(newNode, chatActionsNode)
|
||||
}
|
||||
|
||||
PromptCategory.PERSONAS -> {
|
||||
val newNode = PromptDetailsTreeNode(
|
||||
PersonaPromptDetails(
|
||||
"New Persona",
|
||||
"New Prompt",
|
||||
personasNode.childCount.toLong() + 1
|
||||
),
|
||||
PromptCategory.PERSONAS
|
||||
)
|
||||
insertAndSelectNode(newNode, personasNode)
|
||||
}
|
||||
|
||||
else -> throw IllegalStateException("Could not add new node for category $category")
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDuplicateAction() {
|
||||
val selectedNode = tree.selectionPath?.lastPathComponent as? PromptDetailsTreeNode ?: return
|
||||
|
||||
when (selectedNode.details) {
|
||||
is ChatActionPromptDetails -> {
|
||||
val newNode = PromptDetailsTreeNode(
|
||||
ChatActionPromptDetails(
|
||||
"${selectedNode.details.name} Copy",
|
||||
selectedNode.details.instructions,
|
||||
chatActionsNode.childCount.toLong() + 1,
|
||||
null
|
||||
),
|
||||
PromptCategory.CHAT_ACTIONS
|
||||
)
|
||||
insertAndSelectNode(newNode, chatActionsNode)
|
||||
}
|
||||
|
||||
is PersonaPromptDetails -> {
|
||||
val newNode = PromptDetailsTreeNode(
|
||||
PersonaPromptDetails(
|
||||
"${selectedNode.details.name} Copy",
|
||||
selectedNode.details.instructions,
|
||||
personasNode.childCount.toLong() + 1
|
||||
),
|
||||
PromptCategory.PERSONAS
|
||||
)
|
||||
insertAndSelectNode(newNode, personasNode)
|
||||
}
|
||||
|
||||
else -> throw IllegalStateException("Unknown node $selectedNode")
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDefaultPersonaChanged(promptDetails: PersonaPromptDetails) {
|
||||
val previousDefaultPersonaNode = findPromptDetailsNode {
|
||||
it.details is PersonaPromptDetails && it.details.selected.get()
|
||||
}
|
||||
|
||||
if (previousDefaultPersonaNode != null) {
|
||||
(previousDefaultPersonaNode.details as PersonaPromptDetails).selected.set(false)
|
||||
}
|
||||
promptDetails.selected.set(true)
|
||||
|
||||
treeModel.reload(previousDefaultPersonaNode)
|
||||
treeModel.reload(tree.selectionPath?.lastPathComponent as? PromptDetailsTreeNode)
|
||||
}
|
||||
|
||||
private fun handleRemoveAction() {
|
||||
val selectedNode = tree.selectionPath?.lastPathComponent as? PromptDetailsTreeNode ?: return
|
||||
treeModel.removeNodeFromParent(selectedNode)
|
||||
categoryPanels[selectedNode.category]?.remove(selectedNode.details)
|
||||
|
||||
if (selectedNode.details is PersonaPromptDetails && selectedNode.details.selected.get()) {
|
||||
val defaultPersonaNode = findPromptDetailsNode {
|
||||
it.details is PersonaPromptDetails && it.details.id == 1L
|
||||
}
|
||||
if (defaultPersonaNode != null) {
|
||||
handleDefaultPersonaChanged(defaultPersonaNode.details as PersonaPromptDetails)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findPromptDetailsNode(predicate: (PromptDetailsTreeNode) -> Boolean): PromptDetailsTreeNode? {
|
||||
return personasNode.children().toList()
|
||||
.filterIsInstance<PromptDetailsTreeNode>()
|
||||
.find(predicate)
|
||||
}
|
||||
|
||||
private fun insertAndSelectNode(
|
||||
newNode: PromptDetailsTreeNode,
|
||||
parentNode: DefaultMutableTreeNode
|
||||
) {
|
||||
treeModel.insertNodeInto(newNode, parentNode, parentNode.childCount)
|
||||
tree.selectionPath = TreePath(newNode.path)
|
||||
}
|
||||
|
||||
private fun determineCategory(component: Any?): PromptCategory? = when (component) {
|
||||
is PromptDetailsTreeNode -> component.category
|
||||
personasNode -> PromptCategory.PERSONAS
|
||||
chatActionsNode -> PromptCategory.CHAT_ACTIONS
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts.form
|
||||
|
||||
import com.intellij.ui.render.LabelBasedRenderer
|
||||
import ee.carlrobert.codegpt.Icons
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.details.PersonaPromptDetails
|
||||
import java.awt.Component
|
||||
import java.awt.Font
|
||||
import javax.swing.JTree
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
|
||||
class PromptsFormTreeCellRenderer(
|
||||
private val root: DefaultMutableTreeNode
|
||||
) : LabelBasedRenderer.Tree() {
|
||||
override fun getTreeCellRendererComponent(
|
||||
tree: JTree,
|
||||
value: Any?,
|
||||
selected: Boolean,
|
||||
expanded: Boolean,
|
||||
leaf: Boolean,
|
||||
row: Int,
|
||||
focused: Boolean
|
||||
): Component {
|
||||
super.getTreeCellRendererComponent(
|
||||
tree,
|
||||
value,
|
||||
selected,
|
||||
expanded,
|
||||
leaf,
|
||||
row,
|
||||
focused
|
||||
)
|
||||
|
||||
val node = value as? DefaultMutableTreeNode
|
||||
font = if (node?.parent == root) {
|
||||
font.deriveFont(Font.BOLD)
|
||||
} else {
|
||||
font.deriveFont(Font.PLAIN)
|
||||
}
|
||||
|
||||
if (node is PromptDetailsTreeNode && node.category == PromptCategory.PERSONAS) {
|
||||
val personaDetails = node.details as PersonaPromptDetails
|
||||
icon = if (personaDetails.selected.get()) Icons.GreenCheckmark else null
|
||||
iconTextGap = 6
|
||||
} else {
|
||||
icon = null
|
||||
}
|
||||
horizontalTextPosition = LEFT
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts.form
|
||||
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionPromptDetailsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionPromptDetailsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonaPromptDetailsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.details.ChatActionPromptDetails
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.details.CoreActionPromptDetails
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.details.FormPromptDetails
|
||||
import ee.carlrobert.codegpt.settings.prompts.form.details.PersonaPromptDetails
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
|
||||
object PromptsFormUtil {
|
||||
|
||||
fun CoreActionPromptDetails.toState(): CoreActionPromptDetailsState {
|
||||
val state = CoreActionPromptDetailsState()
|
||||
state.code = this.code
|
||||
state.name = this.name
|
||||
state.instructions = this.instructions
|
||||
return state
|
||||
}
|
||||
|
||||
fun ChatActionPromptDetails.toState(): ChatActionPromptDetailsState {
|
||||
val state = ChatActionPromptDetailsState()
|
||||
state.id = this.id
|
||||
state.code = this.code
|
||||
state.name = this.name
|
||||
state.instructions = this.instructions
|
||||
return state
|
||||
}
|
||||
|
||||
fun PersonaPromptDetails.toState(): PersonaPromptDetailsState {
|
||||
val state = PersonaPromptDetailsState()
|
||||
state.id = this.id
|
||||
state.name = this.name
|
||||
state.instructions = this.instructions
|
||||
return state
|
||||
}
|
||||
|
||||
inline fun <reified T : FormPromptDetails> getFormState(
|
||||
formNode: DefaultMutableTreeNode,
|
||||
): List<T> {
|
||||
return formNode.children().toList()
|
||||
.filterIsInstance<PromptDetailsTreeNode>()
|
||||
.map { it.details }
|
||||
.filterIsInstance<T>()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts.form.details
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.event.DocumentListener
|
||||
import com.intellij.openapi.editor.markup.HighlighterLayer
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter
|
||||
import com.intellij.openapi.editor.markup.TextAttributes
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.ui.JBColor
|
||||
import java.awt.Dimension
|
||||
|
||||
abstract class AbstractEditorPromptPanel(
|
||||
private val details: FormPromptDetails,
|
||||
highlightedPlaceholders: List<String> = emptyList()
|
||||
) : Disposable {
|
||||
protected val editor: Editor = createEditor()
|
||||
private val highlighterMap = mutableMapOf<String, RangeHighlighter>()
|
||||
|
||||
init {
|
||||
highlightedPlaceholders.forEach {
|
||||
highlightPlaceholder(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEditor(): Editor {
|
||||
return service<EditorFactory>()
|
||||
.run {
|
||||
createEditor(createDocument(details.instructions ?: ""))
|
||||
}
|
||||
.apply {
|
||||
settings.additionalLinesCount = 0
|
||||
settings.isWhitespacesShown = true
|
||||
settings.isLineMarkerAreaShown = false
|
||||
settings.isIndentGuidesShown = false
|
||||
settings.isLineNumbersShown = false
|
||||
settings.isFoldingOutlineShown = false
|
||||
settings.isUseSoftWraps = true
|
||||
settings.isAdditionalPageAtBottom = false
|
||||
settings.isVirtualSpace = false
|
||||
settings.setSoftMargins(emptyList<Int>())
|
||||
|
||||
component.preferredSize = Dimension(0, lineHeight * 16)
|
||||
|
||||
document.addDocumentListener(object : DocumentListener {
|
||||
override fun documentChanged(event: DocumentEvent) {
|
||||
details.instructions = event.document.text
|
||||
|
||||
highlighterMap.forEach { (placeholder, highlighter) ->
|
||||
val start = editor.document.text.indexOf(placeholder)
|
||||
if (start == -1) {
|
||||
if (highlighter.isValid) {
|
||||
highlighter.dispose()
|
||||
}
|
||||
} else if (!highlighter.isValid) {
|
||||
highlighterMap[placeholder] =
|
||||
createHighlighter(TextRange.from(start, placeholder.length))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun createHighlighter(range: TextRange): RangeHighlighter {
|
||||
val attributes = TextAttributes().apply {
|
||||
foregroundColor = JBColor(0x00627A, 0xCC7832)
|
||||
}
|
||||
|
||||
return editor.markupModel.addRangeHighlighter(
|
||||
range.startOffset,
|
||||
range.endOffset,
|
||||
HighlighterLayer.SELECTION,
|
||||
attributes,
|
||||
HighlighterTargetArea.EXACT_RANGE
|
||||
)
|
||||
}
|
||||
|
||||
private fun highlightPlaceholder(placeholder: String) {
|
||||
val start = editor.document.text.indexOf(placeholder)
|
||||
if (start >= 0) {
|
||||
highlighterMap[placeholder] =
|
||||
createHighlighter(TextRange.from(start, placeholder.length))
|
||||
}
|
||||
}
|
||||
|
||||
protected fun updateEditorText(text: String?) {
|
||||
runWriteAction {
|
||||
editor.document.setText(text ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
EditorFactory.getInstance().releaseEditor(editor)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts.form.details
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.event.DocumentListener
|
||||
import com.intellij.ui.CardLayoutPanel
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.dsl.builder.Align
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import com.intellij.ui.layout.ComponentPredicate
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionsState.Companion.DEFAULT_EXPLAIN_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionsState.Companion.DEFAULT_FIND_BUGS_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionsState.Companion.DEFAULT_OPTIMIZE_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionsState.Companion.DEFAULT_REFACTOR_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionsState.Companion.DEFAULT_WRITE_TESTS_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
|
||||
class ChatActionsDetailsPanel : PromptDetailsPanel {
|
||||
|
||||
private val cardLayoutPanel =
|
||||
object : CardLayoutPanel<ChatActionPromptDetails, ChatActionPromptDetails, JComponent>() {
|
||||
override fun prepare(key: ChatActionPromptDetails) = key
|
||||
|
||||
override fun create(state: ChatActionPromptDetails): JComponent {
|
||||
val defaultInstructions = when (state.code) {
|
||||
"FIND_BUGS" -> DEFAULT_FIND_BUGS_PROMPT
|
||||
"WRITE_TESTS" -> DEFAULT_WRITE_TESTS_PROMPT
|
||||
"EXPLAIN" -> DEFAULT_EXPLAIN_PROMPT
|
||||
"REFACTOR" -> DEFAULT_REFACTOR_PROMPT
|
||||
"OPTIMIZE" -> DEFAULT_OPTIMIZE_PROMPT
|
||||
else -> null
|
||||
}
|
||||
|
||||
return ChatActionEditorPanel(state, defaultInstructions).getPanel()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
service<PromptsSettings>().state.chatActions.prompts.forEach {
|
||||
cardLayoutPanel.select(ChatActionPromptDetails(it), true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPanel() = cardLayoutPanel
|
||||
|
||||
override fun updateData(details: FormPromptDetails) {
|
||||
if (details !is ChatActionPromptDetails) {
|
||||
return
|
||||
}
|
||||
|
||||
cardLayoutPanel.select(details, true)
|
||||
}
|
||||
|
||||
override fun remove(details: FormPromptDetails) {
|
||||
if (details !is ChatActionPromptDetails) {
|
||||
return
|
||||
}
|
||||
|
||||
cardLayoutPanel.remove(cardLayoutPanel.getValue(details, false))
|
||||
}
|
||||
|
||||
private class ChatActionEditorPanel(
|
||||
private val details: ChatActionPromptDetails,
|
||||
private val defaultInstructions: String? = "",
|
||||
) : AbstractEditorPromptPanel(details, listOf("{SELECTION}")) {
|
||||
|
||||
private val nameField = JBTextField(details.name)
|
||||
private val startInNewChatCheckBox = JBCheckBox(
|
||||
"Start in a new chat window",
|
||||
service<PromptsSettings>().state.chatActions.startInNewWindow
|
||||
)
|
||||
|
||||
fun getPanel(): JPanel = panel {
|
||||
row {
|
||||
cell(BorderLayoutPanel().addToTop(editor.component)).align(Align.FILL)
|
||||
.resizableColumn()
|
||||
}
|
||||
row {
|
||||
link("Revert to default") {
|
||||
updateEditorText(defaultInstructions)
|
||||
}
|
||||
}.visibleIf(object : ComponentPredicate() {
|
||||
override fun addListener(listener: (Boolean) -> Unit) {
|
||||
editor.document.addDocumentListener(object : DocumentListener {
|
||||
override fun documentChanged(event: DocumentEvent) {
|
||||
listener(invoke())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun invoke(): Boolean {
|
||||
if (defaultInstructions == null) {
|
||||
return false
|
||||
}
|
||||
return defaultInstructions != editor.document.text
|
||||
}
|
||||
})
|
||||
row {
|
||||
cell(nameField)
|
||||
.label("Action name:")
|
||||
.align(Align.FILL)
|
||||
.onChanged { details.name = it.text }
|
||||
}
|
||||
row {
|
||||
cell(startInNewChatCheckBox)
|
||||
.comment(
|
||||
"If not checked, the previous chat history will be sent along with each action",
|
||||
60
|
||||
)
|
||||
.onChanged {
|
||||
service<PromptsSettings>().state
|
||||
.chatActions
|
||||
.startInNewWindow = it.isSelected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts.form.details
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.event.DocumentListener
|
||||
import com.intellij.ui.CardLayoutPanel
|
||||
import com.intellij.ui.dsl.builder.Align
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import com.intellij.ui.layout.ComponentPredicate
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel
|
||||
import ee.carlrobert.codegpt.settings.prompts.CommitMessageTemplate
|
||||
import ee.carlrobert.codegpt.settings.prompts.*
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState.Companion.DEFAULT_EDIT_CODE_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState.Companion.DEFAULT_FIX_COMPILE_ERRORS_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState.Companion.DEFAULT_GENERATE_COMMIT_MESSAGE_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState.Companion.DEFAULT_GENERATE_NAME_LOOKUPS_PROMPT
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
|
||||
class CoreActionsDetailsPanel : PromptDetailsPanel {
|
||||
|
||||
private val cardLayoutPanel =
|
||||
object : CardLayoutPanel<CoreActionPromptDetails, CoreActionPromptDetails, JComponent>() {
|
||||
override fun prepare(key: CoreActionPromptDetails) = key
|
||||
|
||||
override fun create(details: CoreActionPromptDetails): JComponent {
|
||||
val editorPanel = when (details.code) {
|
||||
"EDIT_CODE" -> CoreActionEditorPanel(
|
||||
details,
|
||||
DEFAULT_EDIT_CODE_PROMPT,
|
||||
"Template used for the 'Edit Code' feature in the main editor."
|
||||
)
|
||||
|
||||
"FIX_COMPILE_ERRORS" -> CoreActionEditorPanel(
|
||||
details,
|
||||
DEFAULT_FIX_COMPILE_ERRORS_PROMPT,
|
||||
"Template used for resolving compile errors in the code."
|
||||
)
|
||||
|
||||
"GENERATE_COMMIT_MESSAGE" -> CoreActionEditorPanel(
|
||||
details,
|
||||
DEFAULT_GENERATE_COMMIT_MESSAGE_PROMPT,
|
||||
CommitMessageTemplate.getHtmlDescription(),
|
||||
listOf("{BRANCH_NAME}", "{DATE_ISO_8601}")
|
||||
)
|
||||
|
||||
"GENERATE_NAME_LOOKUPS" -> CoreActionEditorPanel(
|
||||
details,
|
||||
DEFAULT_GENERATE_NAME_LOOKUPS_PROMPT,
|
||||
"Template used for generating suitable lookup names for a given method or function body."
|
||||
)
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
return editorPanel?.getPanel() ?: JPanel()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val settings = service<PromptsSettings>().state.coreActions
|
||||
listOf(
|
||||
settings.editCode,
|
||||
settings.fixCompileErrors,
|
||||
settings.generateCommitMessage,
|
||||
settings.generateNameLookups
|
||||
).forEach {
|
||||
cardLayoutPanel.select(CoreActionPromptDetails(it), true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPanel() = cardLayoutPanel
|
||||
|
||||
override fun updateData(details: FormPromptDetails) {
|
||||
if (details !is CoreActionPromptDetails || details.code.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
cardLayoutPanel.select(details, true)
|
||||
}
|
||||
|
||||
override fun remove(details: FormPromptDetails) {
|
||||
TODO("Not implemented")
|
||||
}
|
||||
|
||||
private class CoreActionEditorPanel(
|
||||
details: CoreActionPromptDetails,
|
||||
private val defaultInstructions: String,
|
||||
private val description: String,
|
||||
highlightedPlaceholders: List<String> = emptyList()
|
||||
) : AbstractEditorPromptPanel(details, highlightedPlaceholders) {
|
||||
|
||||
fun getPanel(): JPanel = panel {
|
||||
row {
|
||||
cell(BorderLayoutPanel().addToTop(editor.component))
|
||||
.align(Align.FILL)
|
||||
.resizableColumn()
|
||||
}
|
||||
row {
|
||||
link("Revert to default") {
|
||||
updateEditorText(defaultInstructions)
|
||||
}
|
||||
}.visibleIf(object : ComponentPredicate() {
|
||||
override fun addListener(listener: (Boolean) -> Unit) {
|
||||
editor.document.addDocumentListener(object : DocumentListener {
|
||||
override fun documentChanged(event: DocumentEvent) {
|
||||
listener(invoke())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun invoke(): Boolean = defaultInstructions != editor.document.text
|
||||
})
|
||||
row {
|
||||
comment(description, 60)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts.form.details
|
||||
|
||||
import com.intellij.openapi.observable.properties.AtomicBooleanProperty
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionPromptDetailsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.CoreActionPromptDetailsState
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonaPromptDetailsState
|
||||
import javax.swing.JComponent
|
||||
|
||||
interface PromptDetailsPanel {
|
||||
fun getPanel(): JComponent
|
||||
fun updateData(details: FormPromptDetails)
|
||||
fun remove(details: FormPromptDetails)
|
||||
}
|
||||
|
||||
sealed class FormPromptDetails {
|
||||
abstract var name: String?
|
||||
abstract var instructions: String?
|
||||
}
|
||||
|
||||
data class CoreActionPromptDetails(
|
||||
override var name: String?,
|
||||
override var instructions: String?,
|
||||
val code: String?
|
||||
) : FormPromptDetails() {
|
||||
constructor(state: CoreActionPromptDetailsState) : this(
|
||||
name = state.name,
|
||||
instructions = state.instructions,
|
||||
code = state.code
|
||||
)
|
||||
}
|
||||
|
||||
data class ChatActionPromptDetails(
|
||||
override var name: String?,
|
||||
override var instructions: String?,
|
||||
val id: Long,
|
||||
val code: String?
|
||||
) : FormPromptDetails() {
|
||||
constructor(state: ChatActionPromptDetailsState) : this(
|
||||
name = state.name,
|
||||
instructions = state.instructions,
|
||||
id = state.id,
|
||||
code = state.code
|
||||
)
|
||||
}
|
||||
|
||||
data class PersonaPromptDetails(
|
||||
override var name: String?,
|
||||
override var instructions: String?,
|
||||
val id: Long,
|
||||
var selected: AtomicBooleanProperty = AtomicBooleanProperty(false)
|
||||
) : FormPromptDetails() {
|
||||
constructor(state: PersonaPromptDetailsState) : this(
|
||||
name = state.name,
|
||||
instructions = state.instructions,
|
||||
id = state.id
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package ee.carlrobert.codegpt.settings.prompts.form.details
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.event.DocumentListener
|
||||
import com.intellij.openapi.observable.util.not
|
||||
import com.intellij.ui.CardLayoutPanel
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.dsl.builder.Align
|
||||
import com.intellij.ui.dsl.builder.TopGap
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import com.intellij.ui.layout.ComponentPredicate
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonasState.Companion.DEFAULT_PERSONA_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
|
||||
class PersonasDetailsPanel(onSelected: (PersonaPromptDetails) -> Unit) : PromptDetailsPanel {
|
||||
|
||||
private val cardLayoutPanel =
|
||||
object : CardLayoutPanel<PersonaPromptDetails, PersonaPromptDetails, JComponent>() {
|
||||
override fun prepare(key: PersonaPromptDetails): PersonaPromptDetails = key
|
||||
|
||||
override fun create(state: PersonaPromptDetails): JComponent {
|
||||
return PersonaEditorPanel(state, onSelected).getPanel()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
service<PromptsSettings>().state.personas.prompts.forEach {
|
||||
cardLayoutPanel.select(PersonaPromptDetails(it), true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPanel() = cardLayoutPanel
|
||||
|
||||
override fun updateData(details: FormPromptDetails) {
|
||||
if (details !is PersonaPromptDetails) {
|
||||
return
|
||||
}
|
||||
|
||||
cardLayoutPanel.select(details, true)
|
||||
}
|
||||
|
||||
override fun remove(details: FormPromptDetails) {
|
||||
if (details !is PersonaPromptDetails) {
|
||||
return
|
||||
}
|
||||
|
||||
cardLayoutPanel.remove(cardLayoutPanel.getValue(details, false))
|
||||
}
|
||||
|
||||
private class PersonaEditorPanel(
|
||||
private val details: PersonaPromptDetails,
|
||||
private val onSelected: (PersonaPromptDetails) -> Unit
|
||||
) : AbstractEditorPromptPanel(details) {
|
||||
|
||||
private val nameField = JBTextField(details.name).apply {
|
||||
isEnabled = details.id != 1L
|
||||
}
|
||||
|
||||
fun getPanel(): JPanel = panel {
|
||||
row {
|
||||
cell(BorderLayoutPanel().addToTop(editor.component))
|
||||
.align(Align.FILL)
|
||||
.resizableColumn()
|
||||
}
|
||||
row {
|
||||
link("Revert to default") {
|
||||
updateEditorText(DEFAULT_PERSONA_PROMPT)
|
||||
}
|
||||
}.visibleIf(object : ComponentPredicate() {
|
||||
override fun addListener(listener: (Boolean) -> Unit) {
|
||||
editor.document.addDocumentListener(object : DocumentListener {
|
||||
override fun documentChanged(event: DocumentEvent) {
|
||||
listener(invoke())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun invoke(): Boolean {
|
||||
return details.id == 1L && DEFAULT_PERSONA_PROMPT != editor.document.text
|
||||
}
|
||||
})
|
||||
row {
|
||||
comment(
|
||||
"Set of instructions that serve as the starting point when starting a new chat session. This defines things for the model and helps to focus its capabilities.",
|
||||
60
|
||||
)
|
||||
}
|
||||
row {
|
||||
cell(nameField)
|
||||
.label("Persona name:")
|
||||
.align(Align.FILL)
|
||||
.onChanged { details.name = it.text }
|
||||
}
|
||||
row {
|
||||
button("Set as Default") {
|
||||
onSelected(details)
|
||||
}.enabledIf(details.selected.not())
|
||||
}.topGap(TopGap.SMALL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import com.intellij.ui.components.ActionLink
|
|||
import com.intellij.util.ui.JBUI
|
||||
import ee.carlrobert.codegpt.Icons
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.ChatActionsState
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ResponsePanel
|
||||
import ee.carlrobert.codegpt.ui.UIUtil.createTextPane
|
||||
import java.awt.BorderLayout
|
||||
|
|
@ -81,17 +82,17 @@ enum class LandingPanelAction(
|
|||
FIND_BUGS(
|
||||
"Find Bugs",
|
||||
"Find bugs in this code",
|
||||
"Find bugs and output code with bugs fixed in the selected code: {{selectedCode}}"
|
||||
ChatActionsState.DEFAULT_FIND_BUGS_PROMPT
|
||||
),
|
||||
WRITE_TESTS(
|
||||
"Write Tests",
|
||||
"Write unit tests for this code",
|
||||
"Write unit tests for the selected code: {{selectedCode}}"
|
||||
ChatActionsState.DEFAULT_WRITE_TESTS_PROMPT
|
||||
),
|
||||
EXPLAIN(
|
||||
"Explain",
|
||||
"Explain the selected code",
|
||||
"Explain the selected code: {{selectedCode}}"
|
||||
ChatActionsState.DEFAULT_EXPLAIN_PROMPT
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import ee.carlrobert.codegpt.EncodingManager
|
|||
import ee.carlrobert.codegpt.settings.GeneralSettings
|
||||
import ee.carlrobert.codegpt.settings.documentation.DocumentationSettings
|
||||
import ee.carlrobert.codegpt.settings.documentation.DocumentationsConfigurable
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaDetails
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonasConfigurable
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonaDetails
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsConfigurable
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType
|
||||
import ee.carlrobert.codegpt.ui.AddDocumentationDialog
|
||||
import ee.carlrobert.codegpt.ui.DocumentationDetails
|
||||
|
|
@ -148,7 +148,7 @@ class CreatePersonaActionItem : SuggestionActionItem {
|
|||
override fun execute(project: Project, textPane: PromptTextField) {
|
||||
service<ShowSettingsUtil>().showSettingsDialog(
|
||||
project,
|
||||
PersonasConfigurable::class.java
|
||||
PromptsConfigurable::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,11 @@ import ee.carlrobert.codegpt.CodeGPTBundle
|
|||
import ee.carlrobert.codegpt.Icons
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettings
|
||||
import ee.carlrobert.codegpt.settings.documentation.DocumentationSettings
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaDetails
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonaDetails
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType
|
||||
import ee.carlrobert.codegpt.ui.DocumentationDetails
|
||||
import ee.carlrobert.codegpt.util.GitUtil
|
||||
import ee.carlrobert.codegpt.util.ResourceUtil.getDefaultPersonas
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -84,12 +83,10 @@ class PersonaSuggestionGroupItem : SuggestionGroupItem {
|
|||
override val icon = AllIcons.General.User
|
||||
|
||||
override suspend fun getSuggestions(searchText: String?): List<SuggestionActionItem> {
|
||||
val userCreatedPersonas = service<PersonaSettings>().state.userCreatedPersonas
|
||||
return service<PromptsSettings>().state.personas.prompts
|
||||
.map {
|
||||
PersonaDetails(it.id, it.name ?: "Unknown", it.instructions ?: "Unknown")
|
||||
}
|
||||
.toMutableList()
|
||||
return (userCreatedPersonas + getDefaultPersonas())
|
||||
.filter {
|
||||
searchText.isNullOrEmpty() || it.name.contains(searchText, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ import com.intellij.ui.dsl.builder.AlignX
|
|||
import com.intellij.ui.dsl.builder.panel
|
||||
import com.intellij.ui.dsl.gridLayout.UnscaledGaps
|
||||
import com.intellij.util.ui.JBUI
|
||||
import ee.carlrobert.codegpt.EncodingManager
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.ui.textarea.PromptTextField
|
||||
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.*
|
||||
import ee.carlrobert.codegpt.ui.textarea.suggestion.renderer.SuggestionItemRendererTextUtils.highlightSearchText
|
||||
|
|
@ -115,7 +114,7 @@ class DefaultItemRenderer(textPane: PromptTextField) : BaseItemRenderer(textPane
|
|||
|
||||
private fun getDescription(item: SuggestionItem) =
|
||||
if (item is PersonaSuggestionGroupItem) {
|
||||
service<PersonaSettings>().state.selectedPersona.name
|
||||
service<PromptsSettings>().state.personas.selectedPersona.name
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
package ee.carlrobert.codegpt.util
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaDetails
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil.getResourceContent
|
||||
|
||||
object ResourceUtil {
|
||||
|
||||
fun getDefaultPersonas(): MutableList<PersonaDetails> {
|
||||
return ObjectMapper().readValue(
|
||||
getResourceContent("/prompts.json"),
|
||||
object : TypeReference<MutableList<PersonaDetails>>() {})
|
||||
}
|
||||
}
|
||||
|
|
@ -44,9 +44,9 @@
|
|||
instance="ee.carlrobert.codegpt.settings.service.LlamaServiceConfigurable"/>
|
||||
<applicationConfigurable id="settings.codegpt.services.ollama" parentId="settings.codegpt.services" displayName="Ollama (Local)"
|
||||
instance="ee.carlrobert.codegpt.settings.service.ollama.OllamaSettingsConfigurable"/>
|
||||
<applicationConfigurable id="settings.codegpt.personas" parentId="settings.codegpt" displayName="Personas"
|
||||
instance="ee.carlrobert.codegpt.settings.persona.PersonasConfigurable"/>
|
||||
<applicationConfigurable id="settings.codegpt.dcoumentations" parentId="settings.codegpt" displayName="Documentations"
|
||||
<applicationConfigurable id="settings.codegpt.prompts" parentId="settings.codegpt" displayName="Prompts"
|
||||
instance="ee.carlrobert.codegpt.settings.prompts.PromptsConfigurable"/>
|
||||
<applicationConfigurable id="settings.codegpt.documentations" parentId="settings.codegpt" displayName="Documentations"
|
||||
instance="ee.carlrobert.codegpt.settings.documentation.DocumentationsConfigurable"/>
|
||||
<applicationConfigurable id="settings.codegpt.configuration" parentId="settings.codegpt" displayName="Configuration"
|
||||
instance="ee.carlrobert.codegpt.settings.configuration.ConfigurationConfigurable"/>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
6
src/main/resources/prompts/chat/explain.txt
Normal file
6
src/main/resources/prompts/chat/explain.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Your task is to provide a clear, concise explanation of what this code does. Focus on the main functionality and purpose of the code, avoiding unnecessary details. Explain any complex logic or algorithms if present.
|
||||
|
||||
Provide your explanation in a few sentences, using simple language that a junior programmer could understand. If there are any notable best practices or potential improvements, briefly mention them at the end.
|
||||
|
||||
Here's the code to analyze:
|
||||
{SELECTION}
|
||||
15
src/main/resources/prompts/chat/find-bugs.txt
Normal file
15
src/main/resources/prompts/chat/find-bugs.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Your task is to find potential bugs in the given code snippet.
|
||||
|
||||
Carefully examine the code for potential bugs, logical errors, or common programming mistakes. Consider issues such as:
|
||||
- Syntax errors
|
||||
- Off-by-one errors
|
||||
- Null pointer exceptions
|
||||
- Memory leaks
|
||||
- Infinite loops
|
||||
- Incorrect logic
|
||||
- Unhandled exceptions
|
||||
|
||||
Provide a concise list of potential bugs you've identified. If you don't find any bugs, state that the code appears to be bug-free based on your analysis.
|
||||
|
||||
Here's the code to analyze:
|
||||
{SELECTION}
|
||||
15
src/main/resources/prompts/chat/optimize.txt
Normal file
15
src/main/resources/prompts/chat/optimize.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Your task is to improve the code's efficiency, readability, and adherence to best practices without changing its core functionality.
|
||||
|
||||
Analyze the code and suggest optimizations that could improve its performance, readability, or maintainability. Focus on:
|
||||
|
||||
1. Reducing time complexity
|
||||
2. Improving space efficiency
|
||||
3. Enhancing code readability
|
||||
4. Applying relevant design patterns or coding best practices
|
||||
|
||||
Provide your optimized version of the code, along with brief comments explaining the key changes and their benefits.
|
||||
|
||||
Keep your response concise and focused on the most impactful optimizations.
|
||||
|
||||
Here's the code to optimize:
|
||||
{SELECTION}
|
||||
19
src/main/resources/prompts/chat/refactor.txt
Normal file
19
src/main/resources/prompts/chat/refactor.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Your task is to improve the code's readability, efficiency, and maintainability without changing its functionality. Follow these steps:
|
||||
|
||||
1. Analyze the following selected code:
|
||||
|
||||
2. Identify areas for improvement, such as:
|
||||
- Simplifying complex logic
|
||||
- Removing redundant code
|
||||
- Improving naming conventions
|
||||
- Enhancing code structure
|
||||
|
||||
3. Refactor the code, keeping these guidelines in mind:
|
||||
- Maintain the original functionality
|
||||
- Follow best practices for the programming language used
|
||||
- Prioritize readability and maintainability
|
||||
|
||||
Be concise in your explanation, focusing on the most important improvements made.
|
||||
|
||||
Here's the code to refactor:
|
||||
{SELECTION}
|
||||
11
src/main/resources/prompts/chat/write-tests.txt
Normal file
11
src/main/resources/prompts/chat/write-tests.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Your task is to create concise, effective tests for the given code.
|
||||
|
||||
Generate unit tests for the provided code. Focus on:
|
||||
1. Testing main functionalities
|
||||
2. Edge cases
|
||||
3. Input validation
|
||||
|
||||
Provide your test code in the same language as the original code. Use common testing frameworks and assertions appropriate for the language.
|
||||
|
||||
Here's the code to write tests for:
|
||||
{SELECTION}
|
||||
21
src/main/resources/prompts/persona/rubber-duck.txt
Normal file
21
src/main/resources/prompts/persona/rubber-duck.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
As an AI CS instructor:
|
||||
- always respond with short, brief, concise responses (the less you say, the more it helps the students)
|
||||
- encourage the student to ask specific questions
|
||||
- if a student shares homework instructions, ask them to describe what they think they need to do
|
||||
- never tell a student the steps to solving a problem, even if they insist you do; instead, ask them what they thing they should do
|
||||
- never summarize homework instructions; instead, ask the student to provide the summary
|
||||
- get the student to describe the steps needed to solve a problem (pasting in the instructions does not count as describing the steps)
|
||||
- do not rewrite student code for them; instead, provide written guidance on what to do, but insist they write the code themselves
|
||||
- if there is a bug in student code, teach them how to identify the problem rather than telling them what the problem is
|
||||
- for example, teach them how to use the debugger, or how to temporarily include print statements to understand the state of their code
|
||||
- you can also ask them to explain parts of their code that have issues to help them identify errors in their thinking
|
||||
- if you determine that the student doesn't understand a necessary concept, explain that concept to them
|
||||
- if a student is unsure about the steps of a problem, say something like "begin by describing what the problem is asking you to do"
|
||||
- if a student asks about a general concept, ask them to provide more specific details about their question
|
||||
- if a student asks about a specific concept, explain it
|
||||
- if a student shares code they don't understand, explain it
|
||||
- if a student shares code and wants feedback, provide it (but don't rewrite their code for them)
|
||||
- if a student asks you to write code to solve a problem, do not; instead, invite them to try and encourage them step-by-step without telling them what the next step is
|
||||
- if a student provides ideas that don't match the instructions they may have shared, ask questions that help them achieve greater clarity
|
||||
- sometimes students will resist coming up with their own ideas and want you to do the work for them; however, after a few rounds of gentle encouragement, a student will start trying. This is the goal.
|
||||
- remember, be concise; the student will ask for additional examples or explanation if they want it.
|
||||
|
|
@ -5,8 +5,8 @@ import ee.carlrobert.codegpt.completions.factory.OpenAIRequestFactory
|
|||
import ee.carlrobert.codegpt.conversations.Conversation
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService
|
||||
import ee.carlrobert.codegpt.conversations.message.Message
|
||||
import ee.carlrobert.codegpt.settings.persona.DEFAULT_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.PersonasState.Companion.DEFAULT_PERSONA_PROMPT
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.groups.Tuple
|
||||
|
|
@ -16,7 +16,7 @@ class CompletionRequestProviderTest : IntegrationTest() {
|
|||
|
||||
fun testChatCompletionRequestWithSystemPromptOverride() {
|
||||
useOpenAIService(OpenAIChatCompletionModel.GPT_3_5.code)
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
val firstMessage = createDummyMessage(500)
|
||||
val secondMessage = createDummyMessage(250)
|
||||
|
|
@ -42,7 +42,7 @@ class CompletionRequestProviderTest : IntegrationTest() {
|
|||
|
||||
fun testChatCompletionRequestWithoutSystemPromptOverride() {
|
||||
useOpenAIService(OpenAIChatCompletionModel.GPT_3_5.code)
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = DEFAULT_PROMPT
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = DEFAULT_PERSONA_PROMPT
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
val firstMessage = createDummyMessage(500)
|
||||
val secondMessage = createDummyMessage(250)
|
||||
|
|
@ -57,7 +57,7 @@ class CompletionRequestProviderTest : IntegrationTest() {
|
|||
assertThat(request.messages)
|
||||
.extracting("role", "content")
|
||||
.containsExactly(
|
||||
Tuple.tuple("system", DEFAULT_PROMPT),
|
||||
Tuple.tuple("system", DEFAULT_PERSONA_PROMPT),
|
||||
Tuple.tuple("user", "TEST_PROMPT"),
|
||||
Tuple.tuple("assistant", firstMessage.response),
|
||||
Tuple.tuple("user", "TEST_PROMPT"),
|
||||
|
|
@ -68,7 +68,7 @@ class CompletionRequestProviderTest : IntegrationTest() {
|
|||
|
||||
fun testChatCompletionRequestRetry() {
|
||||
useOpenAIService(OpenAIChatCompletionModel.GPT_3_5.code)
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
val firstMessage = createDummyMessage("FIRST_TEST_PROMPT", 500)
|
||||
val secondMessage = createDummyMessage("SECOND_TEST_PROMPT", 250)
|
||||
|
|
@ -92,7 +92,7 @@ class CompletionRequestProviderTest : IntegrationTest() {
|
|||
|
||||
fun testReducedChatCompletionRequest() {
|
||||
useOpenAIService(OpenAIChatCompletionModel.GPT_3_5.code)
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = DEFAULT_PROMPT
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = DEFAULT_PERSONA_PROMPT
|
||||
val conversation = Conversation()
|
||||
conversation.addMessage(createDummyMessage(50))
|
||||
conversation.addMessage(createDummyMessage(100))
|
||||
|
|
@ -110,7 +110,7 @@ class CompletionRequestProviderTest : IntegrationTest() {
|
|||
assertThat(request.messages)
|
||||
.extracting("role", "content")
|
||||
.containsExactly(
|
||||
Tuple.tuple("system", DEFAULT_PROMPT),
|
||||
Tuple.tuple("system", DEFAULT_PERSONA_PROMPT),
|
||||
Tuple.tuple("user", "TEST_PROMPT"),
|
||||
Tuple.tuple("assistant", remainingMessage.response),
|
||||
Tuple.tuple("user", "TEST_CHAT_COMPLETION_PROMPT")
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import ee.carlrobert.codegpt.conversations.ConversationService
|
|||
import ee.carlrobert.codegpt.conversations.message.Message
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.llm.client.http.RequestEntity
|
||||
import ee.carlrobert.llm.client.http.exchange.NdJsonStreamHttpExchange
|
||||
import ee.carlrobert.llm.client.http.exchange.StreamHttpExchange
|
||||
|
|
@ -18,7 +19,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() {
|
|||
|
||||
fun testOpenAIChatCompletionCall() {
|
||||
useOpenAIService()
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
val message = Message("TEST_PROMPT")
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
expectOpenAI(StreamHttpExchange { request: RequestEntity ->
|
||||
|
|
@ -57,7 +58,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() {
|
|||
|
||||
fun testAzureChatCompletionCall() {
|
||||
useAzureService()
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
val conversationService = ConversationService.getInstance()
|
||||
val prevMessage = Message("TEST_PREV_PROMPT")
|
||||
prevMessage.response = "TEST_PREV_RESPONSE"
|
||||
|
|
@ -103,7 +104,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() {
|
|||
fun testLlamaChatCompletionCall() {
|
||||
useLlamaService()
|
||||
service<ConfigurationSettings>().state.maxTokens = 99
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
val message = Message("TEST_PROMPT")
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
conversation.addMessage(Message("Ping", "Pong"))
|
||||
|
|
@ -144,7 +145,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() {
|
|||
fun testOllamaChatCompletionCall() {
|
||||
useOllamaService()
|
||||
service<ConfigurationSettings>().state.maxTokens = 99
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
val message = Message("TEST_PROMPT")
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
expectOllama(NdJsonStreamHttpExchange { request: RequestEntity ->
|
||||
|
|
@ -183,7 +184,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() {
|
|||
|
||||
fun testGoogleChatCompletionCall() {
|
||||
useGoogleService()
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
val message = Message("TEST_PROMPT")
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
expectGoogle(StreamHttpExchange { request: RequestEntity ->
|
||||
|
|
@ -228,7 +229,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() {
|
|||
|
||||
fun testCodeGPTServiceChatCompletionCall() {
|
||||
useCodeGPTService()
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
val message = Message("TEST_PROMPT")
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
expectCodeGPT(StreamHttpExchange { request: RequestEntity ->
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package ee.carlrobert.codegpt.settings.configuration
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import ee.carlrobert.codegpt.settings.prompts.CommitMessageTemplate
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import git4idea.commands.GitCommand
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import testsupport.VcsTestCase
|
||||
|
|
@ -12,7 +14,7 @@ class CommitMessageTemplateTest : VcsTestCase() {
|
|||
git(GitCommand.INIT)
|
||||
git(GitCommand.CHECKOUT, listOf("-b", "feature/my-cool-feature"))
|
||||
registerRepository()
|
||||
service<ConfigurationSettings>().state.commitMessagePrompt = buildString {
|
||||
service<PromptsSettings>().state.coreActions.generateCommitMessage.instructions = buildString {
|
||||
append("Branch: {BRANCH_NAME}\n")
|
||||
append("Date: {DATE_ISO_8601}")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ import com.intellij.openapi.components.service
|
|||
import ee.carlrobert.codegpt.CodeGPTKeys
|
||||
import ee.carlrobert.codegpt.EncodingManager
|
||||
import ee.carlrobert.codegpt.ReferencedFile
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestUtil.FIX_COMPILE_ERRORS_SYSTEM_PROMPT
|
||||
import ee.carlrobert.codegpt.completions.ConversationType
|
||||
import ee.carlrobert.codegpt.completions.HuggingFaceModel
|
||||
import ee.carlrobert.codegpt.completions.llama.PromptTemplate.LLAMA
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService
|
||||
import ee.carlrobert.codegpt.conversations.message.Message
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
|
||||
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
|
||||
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
|
||||
import ee.carlrobert.llm.client.http.RequestEntity
|
||||
import ee.carlrobert.llm.client.http.exchange.StreamHttpExchange
|
||||
|
|
@ -28,7 +27,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() {
|
|||
|
||||
fun testSendingOpenAIMessage() {
|
||||
useOpenAIService()
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions =
|
||||
"TEST_SYSTEM_PROMPT"
|
||||
val message = Message("Hello!")
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
val panel = ChatToolWindowTabPanel(project, conversation)
|
||||
|
|
@ -104,7 +104,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() {
|
|||
)
|
||||
)
|
||||
useOpenAIService()
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions =
|
||||
"TEST_SYSTEM_PROMPT"
|
||||
val message = Message("TEST_MESSAGE")
|
||||
message.referencedFilePaths =
|
||||
listOf("TEST_FILE_PATH_1", "TEST_FILE_PATH_2", "TEST_FILE_PATH_3")
|
||||
|
|
@ -206,7 +207,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() {
|
|||
Objects.requireNonNull(javaClass.getResource("/images/test-image.png")).path
|
||||
project.putUserData(CodeGPTKeys.IMAGE_ATTACHMENT_FILE_PATH, testImagePath)
|
||||
useOpenAIService("gpt-4-vision-preview")
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions =
|
||||
"TEST_SYSTEM_PROMPT"
|
||||
val message = Message("TEST_MESSAGE")
|
||||
val conversation = ConversationService.getInstance().startConversation()
|
||||
val panel = ChatToolWindowTabPanel(project, conversation)
|
||||
|
|
@ -299,7 +301,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() {
|
|||
)
|
||||
)
|
||||
useOpenAIService()
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions =
|
||||
"TEST_SYSTEM_PROMPT"
|
||||
val message = Message("TEST_MESSAGE")
|
||||
message.referencedFilePaths =
|
||||
listOf("TEST_FILE_PATH_1", "TEST_FILE_PATH_2", "TEST_FILE_PATH_3")
|
||||
|
|
@ -317,7 +320,10 @@ class ChatToolWindowTabPanelTest : IntegrationTest() {
|
|||
.containsExactly(
|
||||
"gpt-4",
|
||||
listOf(
|
||||
mapOf("role" to "system", "content" to FIX_COMPILE_ERRORS_SYSTEM_PROMPT),
|
||||
mapOf(
|
||||
"role" to "system",
|
||||
"content" to service<PromptsSettings>().state.coreActions.fixCompileErrors.instructions
|
||||
),
|
||||
mapOf(
|
||||
"role" to "user", "content" to """
|
||||
Use the following context to answer question at the end:
|
||||
|
|
@ -399,7 +405,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() {
|
|||
fun testSendingLlamaMessage() {
|
||||
useLlamaService()
|
||||
val configurationState = service<ConfigurationSettings>().state
|
||||
service<PersonaSettings>().state.selectedPersona.instructions = "TEST_SYSTEM_PROMPT"
|
||||
service<PromptsSettings>().state.personas.selectedPersona.instructions =
|
||||
"TEST_SYSTEM_PROMPT"
|
||||
configurationState.maxTokens = 1000
|
||||
configurationState.temperature = 0.1f
|
||||
val llamaSettings = LlamaSettings.getCurrentState()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue