diff --git a/src/main/java/ee/carlrobert/codegpt/actions/editor/OpenNewChatAction.java b/src/main/java/ee/carlrobert/codegpt/actions/editor/OpenNewChatAction.java index dd4882e34..afd0fe077 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/editor/OpenNewChatAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/editor/OpenNewChatAction.java @@ -23,7 +23,7 @@ public void update(@NotNull AnActionEvent event) { public void actionPerformed(@NotNull AnActionEvent event) { var project = event.getProject(); if (project != null) { - ConversationsState.getInstance().setCurrentConversation(null); + ConversationsState.getInstance(project).setCurrentConversation(null); var tabPanel = project.getService(ChatToolWindowContentManager.class).createNewTabPanel(); if (tabPanel != null) { diff --git a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/DeleteAllConversationsAction.java b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/DeleteAllConversationsAction.java index 6490853a6..e00a43f2c 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/DeleteAllConversationsAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/DeleteAllConversationsAction.java @@ -28,7 +28,7 @@ public DeleteAllConversationsAction(Runnable onRefresh) { public void update(@NotNull AnActionEvent event) { var project = event.getProject(); if (project != null) { - var sortedConversations = ConversationService.getInstance().getSortedConversations(); + var sortedConversations = ConversationService.getInstance(project).getSortedConversations(); event.getPresentation().setEnabled(!sortedConversations.isEmpty()); } } @@ -43,7 +43,7 @@ public void actionPerformed(@NotNull AnActionEvent event) { var project = event.getProject(); if (project != null) { try { - ConversationService.getInstance().clearAll(); + ConversationService.getInstance(project).clearAll(); project.getService(ChatToolWindowContentManager.class).resetAll(); } finally { TelemetryAction.IDE_ACTION.createActionMessage() diff --git a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/DeleteConversationAction.java b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/DeleteConversationAction.java index d56d3b594..81fb82116 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/DeleteConversationAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/DeleteConversationAction.java @@ -4,6 +4,7 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import ee.carlrobert.codegpt.actions.ActionType; import ee.carlrobert.codegpt.actions.editor.EditorActionsUtil; @@ -24,7 +25,12 @@ public DeleteConversationAction(Runnable onDelete) { @Override public void update(@NotNull AnActionEvent event) { - event.getPresentation().setEnabled(ConversationsState.getCurrentConversation() != null); + Project project = event.getProject(); + if (project == null) { + event.getPresentation().setEnabled(false); + return; + } + event.getPresentation().setEnabled(ConversationsState.getInstance(project).getCurrentConversation() != null); } @Override diff --git a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveAction.java b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveAction.java index ab3ba2004..b690faaf3 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveAction.java @@ -23,7 +23,12 @@ protected MoveAction(String text, String description, Icon icon, Runnable onRefr @Override public void update(@NotNull AnActionEvent event) { - event.getPresentation().setEnabled(ConversationsState.getCurrentConversation() != null); + Project project = event.getProject(); + if (project == null) { + event.getPresentation().setEnabled(false); + return; + } + event.getPresentation().setEnabled(ConversationsState.getInstance(project).getCurrentConversation() != null); } @Override @@ -32,7 +37,7 @@ public void actionPerformed(@NotNull AnActionEvent event) { if (project != null) { getConversation(project) .ifPresent(conversation -> { - ConversationsState.getInstance().setCurrentConversation(conversation); + ConversationsState.getInstance(project).setCurrentConversation(conversation); onRefresh.run(); }); } diff --git a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveDownAction.java b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveDownAction.java index 9784cac88..8c25c31e7 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveDownAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveDownAction.java @@ -17,6 +17,6 @@ public MoveDownAction(Runnable onRefresh) { @Override protected Optional getConversation(@NotNull Project project) { - return ConversationService.getInstance().getPreviousConversation(); + return ConversationService.getInstance(project).getPreviousConversation(); } } diff --git a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveUpAction.java b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveUpAction.java index 1af04037e..294b19636 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveUpAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/MoveUpAction.java @@ -17,6 +17,6 @@ public MoveUpAction(Runnable onRefresh) { @Override protected Optional getConversation(@NotNull Project project) { - return ConversationService.getInstance().getNextConversation(); + return ConversationService.getInstance(project).getNextConversation(); } } diff --git a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/OpenInEditorAction.java b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/OpenInEditorAction.java index 904ba6f29..1e12d23af 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/OpenInEditorAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/OpenInEditorAction.java @@ -8,6 +8,7 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.testFramework.LightVirtualFile; @@ -29,7 +30,13 @@ public OpenInEditorAction() { @Override public void update(@NotNull AnActionEvent event) { super.update(event); - var currentConversation = ConversationsState.getCurrentConversation(); + Project project = event.getProject(); + if (project == null) { + event.getPresentation().setEnabled(false); + return; + } + + var currentConversation = ConversationsState.getInstance(project).getCurrentConversation(); var isEnabled = currentConversation != null && !currentConversation.getMessages().isEmpty(); event.getPresentation().setEnabled(isEnabled); } @@ -38,8 +45,9 @@ public void update(@NotNull AnActionEvent event) { public void actionPerformed(@NotNull AnActionEvent e) { try { var project = e.getProject(); - var currentConversation = ConversationsState.getCurrentConversation(); - if (project != null && currentConversation != null) { + if (project != null) { + var currentConversation = ConversationsState.getInstance(project).getCurrentConversation(); + if (currentConversation != null) { var dateTimeStamp = currentConversation.getUpdatedOn() .format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")); var fileName = format("proxyai_conversation_%s.md", dateTimeStamp); @@ -55,6 +63,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { ToolWindowManager.getInstance(project).getToolWindow("ProxyAI")); toolWindow.hide(); } + } } finally { TelemetryAction.IDE_ACTION.createActionMessage() .property("action", ActionType.OPEN_CONVERSATION_IN_EDITOR.name()) diff --git a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java index 22e094d3a..4d2480982 100644 --- a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java @@ -1,6 +1,5 @@ package ee.carlrobert.codegpt.conversations; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.Service; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -12,19 +11,23 @@ import java.util.Optional; import java.util.UUID; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -@Service +@Service(Service.Level.PROJECT) public final class ConversationService { private static final Logger LOG = Logger.getInstance(ConversationService.class); - private final ConversationsState conversationState = ConversationsState.getInstance(); + private final Project project; + private final ConversationsState conversationState; - private ConversationService() { + public ConversationService(Project project) { + this.project = project; + this.conversationState = ConversationsState.getInstance(project); } - public static ConversationService getInstance() { - return ApplicationManager.getApplication().getService(ConversationService.class); + public static ConversationService getInstance(@NotNull Project project) { + return project.getService(ConversationService.class); } public List getSortedConversations() { @@ -75,11 +78,8 @@ public void saveConversation(Conversation conversation) { conversationState.setCurrentConversation(conversation); } - public Conversation startConversation(Project project) { - return startConversation(project != null ? project.getBasePath() : null); - } - - private Conversation startConversation(String projectPath) { + public Conversation startConversation() { + var projectPath = project.getBasePath(); var conversation = createConversation(); conversation.setProjectPath(projectPath); conversationState.setCurrentConversation(conversation); @@ -102,7 +102,7 @@ public void deleteSelectedConversation() { nextConversation = getNextConversation(); } - var currentConversation = ConversationsState.getCurrentConversation(); + var currentConversation = getCurrentConversation(); if (currentConversation != null) { deleteConversation(currentConversation); nextConversation.ifPresent(conversationState::setCurrentConversation); @@ -116,6 +116,10 @@ public void discardTokenLimits(Conversation conversation) { saveConversation(conversation); } + public @Nullable Conversation getCurrentConversation() { + return conversationState.getCurrentConversation(); + } + public Optional getPreviousConversation() { return tryGetNextOrPreviousConversation(true); } @@ -125,7 +129,7 @@ public Optional getNextConversation() { } private Optional tryGetNextOrPreviousConversation(boolean isPrevious) { - var currentConversation = ConversationsState.getCurrentConversation(); + var currentConversation = getCurrentConversation(); if (currentConversation != null) { var sortedConversations = getSortedConversations(); for (int i = 0; i < sortedConversations.size(); i++) { diff --git a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java index 50d545f41..bdbe2dba2 100644 --- a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java @@ -1,9 +1,10 @@ package ee.carlrobert.codegpt.conversations; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.Service; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; +import com.intellij.openapi.project.Project; import com.intellij.util.xmlb.XmlSerializerUtil; import com.intellij.util.xmlb.annotations.OptionTag; import ee.carlrobert.codegpt.conversations.converter.ConversationConverter; @@ -16,9 +17,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +@Service(Service.Level.PROJECT) @State( - name = "ee.carlrobert.codegpt.state.conversations.ConversationsState", - storages = @Storage("ChatGPTConversations_170.xml")) + name = "ee.carlrobert.codegpt.conversations.ConversationsState", + storages = @Storage("proxyai_conversations.xml")) public class ConversationsState implements PersistentStateComponent { @Deprecated @@ -33,8 +35,8 @@ public class ConversationsState implements PersistentStateComponent { var panel = new ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation(project)); + ConversationService.getInstance(project).startConversation()); item.addNewTab(panel); return panel; }) @@ -117,7 +117,7 @@ public void resetAll() { tabbedPane.clearAll(); tabbedPane.addNewTab(new ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation(project))); + ConversationService.getInstance(project).startConversation())); }); } @@ -142,4 +142,4 @@ private Optional tryFindFirstChatTabContent() { public void clearAllTags() { tryFindActiveChatTabPanel().ifPresent(ChatToolWindowTabPanel::clearAllTags); } -} \ No newline at end of file +} diff --git a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowPanel.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowPanel.java index d17489155..840cdef57 100644 --- a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowPanel.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowPanel.java @@ -62,7 +62,7 @@ public ChatToolWindowPanel( upgradePlanLink.setVisible(false); var tabPanel = new ChatToolWindowTabPanel(project, getConversation()); - tabbedPane = new ChatToolWindowTabbedPane(parentDisposable); + tabbedPane = new ChatToolWindowTabbedPane(project, parentDisposable); tabbedPane.addNewTab(tabPanel); initToolWindowPanel(project); @@ -72,9 +72,9 @@ public ChatToolWindowPanel( } private Conversation getConversation() { - var conversation = ConversationsState.getCurrentConversation(); + var conversation = ConversationsState.getInstance(project).getCurrentConversation(); if (conversation == null) { - return ConversationService.getInstance().startConversation(project); + return ConversationService.getInstance(project).startConversation(); } return conversation; } @@ -120,7 +120,7 @@ private void initToolWindowPanel(Project project) { Runnable onAddNewTab = () -> { tabbedPane.addNewTab(new ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation(project))); + ConversationService.getInstance(project).startConversation())); repaint(); revalidate(); }; @@ -224,4 +224,4 @@ private PersonaPromptDetailsState getSelectedPersona() { .getSelectedPersona(); } } -} \ No newline at end of file +} diff --git a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanel.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanel.java index 91629b480..438d43848 100644 --- a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanel.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanel.java @@ -89,7 +89,7 @@ public ChatToolWindowTabPanel(@NotNull Project project, @NotNull Conversation co this.project = project; this.conversation = conversation; this.chatSession = new ChatSession(); - conversationService = ConversationService.getInstance(); + conversationService = ConversationService.getInstance(project); toolWindowScrollablePanel = new ChatToolWindowScrollablePanel(); tagManager = new TagManager(); this.psiStructureRepository = new PsiStructureRepository( @@ -220,6 +220,7 @@ private List getHistory(List tags) { .map(it -> { if (it instanceof HistoryTagDetails tagDetails) { return ConversationTagProcessor.Companion.getConversation( + project, tagDetails.getConversationId()); } return null; diff --git a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPane.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPane.java index 1eb689011..c90a9a772 100644 --- a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPane.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPane.java @@ -26,6 +26,7 @@ public class ChatToolWindowTabbedPane extends JBTabbedPane { + private final Project project; private final Map activeTabMapping = new TreeMap<>( (o1, o2) -> { String nums1 = o1.replaceAll("\\D", ""); @@ -48,7 +49,8 @@ public class ChatToolWindowTabbedPane extends JBTabbedPane { }); private final Disposable parentDisposable; - public ChatToolWindowTabbedPane(Disposable parentDisposable) { + public ChatToolWindowTabbedPane(Project project, Disposable parentDisposable) { + this.project = project; this.parentDisposable = parentDisposable; setTabComponentInsets(null); setComponentPopupMenu(new TabPopupMenu()); @@ -180,7 +182,7 @@ private void refreshTabState() { if (toolWindowPanel != null) { var conversation = toolWindowPanel.getConversation(); if (conversation != null) { - ConversationsState.getInstance().setCurrentConversation(conversation); + ConversationsState.getInstance(project).setCurrentConversation(conversation); } } } @@ -192,7 +194,7 @@ public void resetCurrentlyActiveTabPanel(Project project) { removeTabAt(getSelectedIndex()); addNewTab(new ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation(project))); + ConversationService.getInstance(project).startConversation())); repaint(); revalidate(); }); diff --git a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ToolWindowCompletionResponseEventListener.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ToolWindowCompletionResponseEventListener.java index 981e939a2..ecc5feb56 100644 --- a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ToolWindowCompletionResponseEventListener.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ToolWindowCompletionResponseEventListener.java @@ -102,13 +102,13 @@ public void handleError(ErrorDetails error, Throwable ex) { @Override public void handleTokensExceeded(Conversation conversation, Message message) { ApplicationManager.getApplication().invokeLater(() -> { - var answer = OverlayUtil.showTokenLimitExceededDialog(); + var answer = OverlayUtil.showTokenLimitExceededDialog(project); if (answer == OK) { TelemetryAction.IDE_ACTION.createActionMessage() .property("action", "DISCARD_TOKEN_LIMIT") .send(); - ConversationService.getInstance().discardTokenLimits(conversation); + ConversationService.getInstance(project).discardTokenLimits(conversation); handleTokensExceededPolicyAccepted(); } else { stopStreaming(responseContainer); @@ -118,7 +118,7 @@ public void handleTokensExceeded(Conversation conversation, Message message) { @Override public void handleCompleted(String fullMessage, ChatCompletionParameters callParameters) { - ConversationService.getInstance().saveMessage(fullMessage, callParameters); + ConversationService.getInstance(project).saveMessage(fullMessage, callParameters); ApplicationManager.getApplication().invokeLater(() -> { try { diff --git a/src/main/java/ee/carlrobert/codegpt/ui/OverlayUtil.java b/src/main/java/ee/carlrobert/codegpt/ui/OverlayUtil.java index 03796e313..6e2ce2346 100644 --- a/src/main/java/ee/carlrobert/codegpt/ui/OverlayUtil.java +++ b/src/main/java/ee/carlrobert/codegpt/ui/OverlayUtil.java @@ -105,7 +105,7 @@ public static int showDeleteConversationDialog() { Default); } - public static int showTokenLimitExceededDialog() { + public static int showTokenLimitExceededDialog(Project project) { return MessageDialogBuilder.okCancel( CodeGPTBundle.get("dialog.tokenLimitExceeded.title"), CodeGPTBundle.get("dialog.tokenLimitExceeded.description")) @@ -116,7 +116,7 @@ public static int showTokenLimitExceededDialog() { @Override public void rememberChoice(boolean isSelected, int exitCode) { if (isSelected) { - ConversationsState.getInstance().discardAllTokenLimits(); + ConversationsState.getInstance(project).discardAllTokenLimits(); } } diff --git a/src/main/kotlin/ee/carlrobert/codegpt/completions/factory/OpenAIRequestFactory.kt b/src/main/kotlin/ee/carlrobert/codegpt/completions/factory/OpenAIRequestFactory.kt index 5d07362ae..440a5f0de 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/completions/factory/OpenAIRequestFactory.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/completions/factory/OpenAIRequestFactory.kt @@ -1,6 +1,7 @@ package ee.carlrobert.codegpt.completions.factory import com.intellij.openapi.components.service +import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.vfs.readText import ee.carlrobert.codegpt.EncodingManager import ee.carlrobert.codegpt.ReferencedFile @@ -233,7 +234,7 @@ class OpenAIRequestFactory : BaseRequestFactory() { } return tryReducingMessagesOrThrow( messages, - callParameters.conversation.isDiscardTokenLimit, + callParameters.conversation, totalUsage, modelMaxTokens ) @@ -362,16 +363,23 @@ class OpenAIRequestFactory : BaseRequestFactory() { private fun tryReducingMessagesOrThrow( messages: MutableList, - discardTokenLimit: Boolean, + conversation: Conversation, totalInputUsage: Int, modelMaxTokens: Int ): List { val result: MutableList = messages.toMutableList() var totalUsage = totalInputUsage - if (!ConversationsState.getInstance().discardAllTokenLimits) { - if (!discardTokenLimit) { + val project = ProjectManager.getInstance().openProjects.find { it.basePath == conversation.projectPath } + if (project == null) { + if (!conversation.isDiscardTokenLimit) { throw TotalUsageExceededException() } + } else { + if (!ConversationsState.getInstance(project).discardAllTokenLimits) { + if (!conversation.isDiscardTokenLimit) { + throw TotalUsageExceededException() + } + } } val encodingManager = EncodingManager.getInstance() // skip the system prompt diff --git a/src/main/kotlin/ee/carlrobert/codegpt/inlineedit/InlineEditInlay.kt b/src/main/kotlin/ee/carlrobert/codegpt/inlineedit/InlineEditInlay.kt index 4fc34b80a..c89784922 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/inlineedit/InlineEditInlay.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/inlineedit/InlineEditInlay.kt @@ -22,6 +22,7 @@ import ee.carlrobert.codegpt.CodeGPTKeys import ee.carlrobert.codegpt.ReferencedFile import ee.carlrobert.codegpt.actions.editor.EditorComponentInlaysManager import ee.carlrobert.codegpt.conversations.Conversation +import ee.carlrobert.codegpt.conversations.ConversationService import ee.carlrobert.codegpt.conversations.message.Message import ee.carlrobert.codegpt.psistructure.PsiStructureProvider import ee.carlrobert.codegpt.settings.service.FeatureType @@ -290,8 +291,8 @@ class InlineEditInlay(private var editor: Editor) : Disposable { projectPath = sessionConversation.projectPath setMessages(sessionConversation.messages) } - ee.carlrobert.codegpt.conversations.ConversationService.getInstance().addConversation(newConversation) - ee.carlrobert.codegpt.conversations.ConversationService.getInstance().saveConversation(newConversation) + ConversationService.getInstance(project).addConversation(newConversation) + ConversationService.getInstance(project).saveConversation(newConversation) openedChatConversation = newConversation project.service() .displayConversation(newConversation) @@ -526,7 +527,7 @@ class InlineEditInlay(private var editor: Editor) : Disposable { return tags .filter { it.selected && it is HistoryTagDetails } .map { (it as HistoryTagDetails).conversationId } - .mapNotNull { ConversationTagProcessor.getConversation(it) } + .mapNotNull { ConversationTagProcessor.getConversation(project, it) } .distinct() } diff --git a/src/main/kotlin/ee/carlrobert/codegpt/inlineedit/InlineEditSearchReplaceListener.kt b/src/main/kotlin/ee/carlrobert/codegpt/inlineedit/InlineEditSearchReplaceListener.kt index 3bb9b4806..fa56f68ec 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/inlineedit/InlineEditSearchReplaceListener.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/inlineedit/InlineEditSearchReplaceListener.kt @@ -472,8 +472,8 @@ class InlineEditSearchReplaceListener( newConversation.addMessage(copy) } - ConversationService.getInstance().addConversation(newConversation) - ConversationService.getInstance().saveConversation(newConversation) + ConversationService.getInstance(project).addConversation(newConversation) + ConversationService.getInstance(project).saveConversation(newConversation) project.service().displayConversation(newConversation) } diff --git a/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryToolWindow.kt b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryToolWindow.kt index 8ce62f2b6..39eb5e043 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryToolWindow.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryToolWindow.kt @@ -19,7 +19,6 @@ import ee.carlrobert.codegpt.CodeGPTBundle import ee.carlrobert.codegpt.actions.toolwindow.DeleteAllConversationsAction import ee.carlrobert.codegpt.conversations.Conversation import ee.carlrobert.codegpt.conversations.ConversationService -import ee.carlrobert.codegpt.conversations.ConversationsState import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowContentManager import ee.carlrobert.codegpt.util.ProjectPathUtils import javax.swing.JOptionPane @@ -37,7 +36,7 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() private const val MAX_MESSAGES_TO_SEARCH = 5 } - private val conversationService = ConversationService.getInstance() + private val conversationService = project.getService(ConversationService::class.java) private val chatHistoryListPanel = ChatHistoryListPanel() private val searchField = SearchTextField() private var allConversations = mutableListOf() @@ -106,7 +105,7 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() private fun setupUI() { chatHistoryListPanel.apply { setOnConversationSelected { conversation -> - ConversationsState.getInstance().setCurrentConversation(conversation) + conversationService.saveConversation(conversation) } setOnConversationDoubleClicked { conversation -> @@ -580,7 +579,7 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() } private fun updateSelectedConversation(conversations: List) { - ConversationsState.getCurrentConversation()?.let { current -> + conversationService.currentConversation?.let { current -> conversations.find { it.id == current.id }?.let { conversation -> chatHistoryListPanel.setSelectedConversation(conversation) } diff --git a/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/ui/UserMessagePanel.kt b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/ui/UserMessagePanel.kt index 5bfee8a0f..cf3824623 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/ui/UserMessagePanel.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/ui/UserMessagePanel.kt @@ -181,7 +181,7 @@ class UserMessagePanel( layout = BoxLayout(this, BoxLayout.Y_AXIS) isOpaque = false ids.forEach { - ConversationTagProcessor.getConversation(it)?.let { conversation -> + ConversationTagProcessor.getConversation(project, it)?.let { conversation -> val title = HistoryActionItem.getConversationTitle(conversation) val titleLink = ActionLink(title) { project.service() diff --git a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/SearchManager.kt b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/SearchManager.kt index d1109784d..85cd7ec21 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/SearchManager.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/SearchManager.kt @@ -39,7 +39,7 @@ class SearchManager( FilesGroupItem(project, tagManager), FoldersGroupItem(project, tagManager), GitGroupItem(project), - HistoryGroupItem(), + HistoryGroupItem(project), DiagnosticsActionItem(tagManager) ).filter { it.enabled } @@ -47,7 +47,7 @@ class SearchManager( FilesGroupItem(project, tagManager), FoldersGroupItem(project, tagManager), GitGroupItem(project), - HistoryGroupItem(), + HistoryGroupItem(project), PersonasGroupItem(tagManager), DocsGroupItem(tagManager), CodeAnalyzeActionItem(tagManager), diff --git a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/TagProcessorFactory.kt b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/TagProcessorFactory.kt index 4a60fe300..f54c7bc66 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/TagProcessorFactory.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/TagProcessorFactory.kt @@ -228,11 +228,10 @@ class ConversationTagProcessor( ) : TagProcessor { companion object { - fun getConversation(conversationId: UUID) = - ConversationsState.getCurrentConversation()?.takeIf { - it.id.equals(conversationId) - } ?: ConversationsState.getInstance().conversations.find { - it.id.equals(conversationId) + fun getConversation(project: Project, conversationId: UUID): Conversation? { + val state = ConversationsState.getInstance(project) + return state.currentConversation?.takeIf { it.id == conversationId } + ?: state.conversations.find { it.id == conversationId } } fun formatConversation(conversation: Conversation): String { diff --git a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/lookup/group/HistoryGroupItem.kt b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/lookup/group/HistoryGroupItem.kt index 594753389..faadc054d 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/lookup/group/HistoryGroupItem.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/lookup/group/HistoryGroupItem.kt @@ -3,6 +3,7 @@ package ee.carlrobert.codegpt.ui.textarea.lookup.group import com.intellij.codeInsight.lookup.impl.LookupImpl import com.intellij.icons.AllIcons import com.intellij.openapi.application.runInEdt +import com.intellij.openapi.project.Project import ee.carlrobert.codegpt.CodeGPTBundle import ee.carlrobert.codegpt.conversations.ConversationsState import ee.carlrobert.codegpt.ui.textarea.lookup.DynamicLookupGroupItem @@ -12,7 +13,7 @@ import ee.carlrobert.codegpt.ui.textarea.lookup.action.HistoryActionItem import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -class HistoryGroupItem : AbstractLookupGroupItem(), DynamicLookupGroupItem { +class HistoryGroupItem(private val project: Project) : AbstractLookupGroupItem(), DynamicLookupGroupItem { override val displayName: String = CodeGPTBundle.get("suggestionGroupItem.history.displayName") @@ -21,7 +22,7 @@ class HistoryGroupItem : AbstractLookupGroupItem(), DynamicLookupGroupItem { private val addedItems = mutableSetOf() override suspend fun getLookupItems(searchText: String): List { - return ConversationsState.getInstance().conversations + return ConversationsState.getInstance(project).conversations .sortedByDescending { it.updatedOn } .filter { conversation -> if (searchText.isEmpty()) { @@ -55,4 +56,4 @@ class HistoryGroupItem : AbstractLookupGroupItem(), DynamicLookupGroupItem { } } } -} \ No newline at end of file +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 0fd2ef009..c696da4b8 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -44,7 +44,7 @@ - - + + diff --git a/src/test/kotlin/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.kt index c2fabc48a..494d56121 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.kt @@ -23,7 +23,7 @@ class CompletionRequestProviderTest : IntegrationTest() { instructions = "TEST_SYSTEM_PROMPT" } service().state.personas.selectedPersona = customPersona - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val firstMessage = createDummyMessage(500) val secondMessage = createDummyMessage(250) conversation.addMessage(firstMessage) @@ -56,7 +56,7 @@ class CompletionRequestProviderTest : IntegrationTest() { instructions = "TEST_SYSTEM_PROMPT" } service().state.personas.selectedPersona = customPersona - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val firstMessage = createDummyMessage("FIRST_TEST_PROMPT", 500) val secondMessage = createDummyMessage("SECOND_TEST_PROMPT", 250) conversation.addMessage(firstMessage) diff --git a/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt index 0d55932c7..2923b9b51 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt @@ -27,7 +27,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() expectOpenAI(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") assertThat(request.method).isEqualTo("POST") @@ -74,7 +74,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() conversation.addMessage(Message("Ping", "Pong")) expectLlama(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") @@ -122,7 +122,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() expectOllama(NdJsonStreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") assertThat(request.method).isEqualTo("POST") @@ -170,7 +170,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() expectGoogle(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/models/gemini-2.0-flash:streamGenerateContent") assertThat(request.method).isEqualTo("POST") @@ -218,7 +218,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() expectCodeGPT(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") assertThat(request.method).isEqualTo("POST") diff --git a/src/test/kotlin/ee/carlrobert/codegpt/completions/OpenAIRequestFactoryIntegrationTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/completions/OpenAIRequestFactoryIntegrationTest.kt index 41a4e36b6..db34d3395 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/completions/OpenAIRequestFactoryIntegrationTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/completions/OpenAIRequestFactoryIntegrationTest.kt @@ -24,7 +24,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() { fun testDefaultPersonaUsesEditModePromptWhenEnabled() { useOpenAIService(OpenAIChatCompletionModel.GPT_4_O.code) service().state.personas.selectedPersona = PersonasState.DEFAULT_PERSONA - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val message = Message("Please refactor this code") val callParameters = ChatCompletionParameters .builder(conversation, message) @@ -129,7 +129,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() { fun testDefaultPersonaIsFilteredInAskMode() { useOpenAIService(OpenAIChatCompletionModel.GPT_4_O.code) service().state.personas.selectedPersona = PersonasState.DEFAULT_PERSONA - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val message = Message("Please refactor this code") val callParameters = ChatCompletionParameters .builder(conversation, message) @@ -248,7 +248,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() { instructions = personaPromptWithSearchReplace } service().state.personas.selectedPersona = customPersona - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val message = Message("Please refactor this code") val callParameters = ChatCompletionParameters .builder(conversation, message) @@ -293,7 +293,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() { """.trimIndent() service().state.personas.selectedPersona.instructions = personaPromptWithSearchReplace - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val message = Message("Please refactor this code") val callParameters = ChatCompletionParameters .builder(conversation, message) diff --git a/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt index 09a04fa3d..40caa888e 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt @@ -2,22 +2,18 @@ package ee.carlrobert.codegpt.conversations import com.intellij.testFramework.fixtures.BasePlatformTestCase import ee.carlrobert.codegpt.conversations.message.Message -import ee.carlrobert.codegpt.settings.GeneralSettings -import ee.carlrobert.codegpt.settings.service.ServiceType -import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings -import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel import org.assertj.core.api.Assertions.assertThat class ConversationsStateTest : BasePlatformTestCase() { fun testStartNewDefaultConversation() { - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() - assertThat(conversation).isEqualTo(ConversationsState.getCurrentConversation()) + assertThat(conversation).isEqualTo(ConversationService.getInstance(project).currentConversation) } fun testSaveConversation() { - val service = ConversationService.getInstance() + val service = ConversationService.getInstance(project) val conversation = service.createConversation() service.addConversation(conversation) val message = Message("TEST_PROMPT") @@ -26,7 +22,7 @@ class ConversationsStateTest : BasePlatformTestCase() { service.saveConversation(conversation) - val currentConversation = ConversationsState.getCurrentConversation() + val currentConversation = ConversationService.getInstance(project).currentConversation assertThat(currentConversation).isNotNull() assertThat(currentConversation!!.messages) .flatExtracting("prompt", "response") @@ -34,9 +30,9 @@ class ConversationsStateTest : BasePlatformTestCase() { } fun testGetPreviousConversation() { - val service = ConversationService.getInstance() - val firstConversation = service.startConversation(project) - service.startConversation(project) + val service = ConversationService.getInstance(project) + val firstConversation = service.startConversation() + service.startConversation() val previousConversation = service.previousConversation @@ -45,10 +41,10 @@ class ConversationsStateTest : BasePlatformTestCase() { } fun testGetNextConversation() { - val service = ConversationService.getInstance() - val firstConversation = service.startConversation(project) - val secondConversation = service.startConversation(project) - ConversationsState.getInstance().setCurrentConversation(firstConversation) + val service = ConversationService.getInstance(project) + val firstConversation = service.startConversation() + val secondConversation = service.startConversation() + ConversationsState.getInstance(project).setCurrentConversation(firstConversation) val nextConversation = service.nextConversation @@ -57,13 +53,13 @@ class ConversationsStateTest : BasePlatformTestCase() { } fun testDeleteSelectedConversation() { - val service = ConversationService.getInstance() - val firstConversation = service.startConversation(project) - service.startConversation(project) + val service = ConversationService.getInstance(project) + val firstConversation = service.startConversation() + service.startConversation() service.deleteSelectedConversation() - assertThat(ConversationsState.getCurrentConversation()).isEqualTo(firstConversation) + assertThat(ConversationService.getInstance(project).currentConversation).isEqualTo(firstConversation) assertThat(service.sortedConversations.size).isEqualTo(1) assertThat(service.sortedConversations) .extracting("id") @@ -71,13 +67,13 @@ class ConversationsStateTest : BasePlatformTestCase() { } fun testClearAllConversations() { - val service = ConversationService.getInstance() - service.startConversation(project) - service.startConversation(project) + val service = ConversationService.getInstance(project) + service.startConversation() + service.startConversation() service.clearAll() - assertThat(ConversationsState.getCurrentConversation()).isNull() + assertThat(ConversationService.getInstance(project).currentConversation).isNull() assertThat(service.sortedConversations.size).isEqualTo(0) } } diff --git a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanelTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanelTest.kt index 88b364769..c8c7c8db3 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanelTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanelTest.kt @@ -31,7 +31,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { service().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT" val message = Message("Hello!") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val panel = ChatToolWindowTabPanel(project, conversation) expectOpenAI(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") @@ -100,7 +100,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { val message = Message("TEST_MESSAGE") message.referencedFilePaths = listOf("TEST_FILE_PATH_1", "TEST_FILE_PATH_2", "TEST_FILE_PATH_3") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val panel = ChatToolWindowTabPanel(project, conversation) panel.includeFiles(listOf( LightVirtualFile("TEST_FILE_NAME_1", "TEST_FILE_CONTENT_1"), @@ -201,7 +201,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { service().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT" val message = Message("TEST_MESSAGE") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val panel = ChatToolWindowTabPanel(project, conversation) expectOpenAI(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") @@ -287,7 +287,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { val message = Message("TEST_MESSAGE") message.referencedFilePaths = listOf("TEST_FILE_PATH_1", "TEST_FILE_PATH_2", "TEST_FILE_PATH_3") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val panel = ChatToolWindowTabPanel(project, conversation) panel.includeFiles( listOf( @@ -398,7 +398,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { llamaSettings.minP = 0.03 llamaSettings.repeatPenalty = 1.3 val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation(project) + val conversation = ConversationService.getInstance(project).startConversation() val panel = ChatToolWindowTabPanel(project, conversation) expectLlama(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") diff --git a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPaneTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPaneTest.kt index 572ffab96..5f81b7afa 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPaneTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPaneTest.kt @@ -9,7 +9,7 @@ import org.assertj.core.api.Assertions.assertThat class ChatToolWindowTabbedPaneTest : BasePlatformTestCase() { fun testClearAllTabs() { - val tabbedPane = ChatToolWindowTabbedPane(Disposer.newDisposable()) + val tabbedPane = ChatToolWindowTabbedPane(project, Disposer.newDisposable()) tabbedPane.addNewTab(createNewTabPanel()) tabbedPane.clearAll() @@ -19,7 +19,7 @@ class ChatToolWindowTabbedPaneTest : BasePlatformTestCase() { fun testAddingNewTabs() { - val tabbedPane = ChatToolWindowTabbedPane(Disposer.newDisposable()) + val tabbedPane = ChatToolWindowTabbedPane(project, Disposer.newDisposable()) tabbedPane.addNewTab(createNewTabPanel()) tabbedPane.addNewTab(createNewTabPanel()) @@ -30,8 +30,8 @@ class ChatToolWindowTabbedPaneTest : BasePlatformTestCase() { } fun testResetCurrentlyActiveTabPanel() { - val tabbedPane = ChatToolWindowTabbedPane(Disposer.newDisposable()) - val conversation = ConversationService.getInstance().startConversation(project) + val tabbedPane = ChatToolWindowTabbedPane(project, Disposer.newDisposable()) + val conversation = ConversationService.getInstance(project).startConversation() conversation.addMessage(Message("TEST_PROMPT", "TEST_RESPONSE")) tabbedPane.addNewTab(ChatToolWindowTabPanel(project, conversation)) @@ -44,7 +44,7 @@ class ChatToolWindowTabbedPaneTest : BasePlatformTestCase() { private fun createNewTabPanel(): ChatToolWindowTabPanel { return ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation(project) + ConversationService.getInstance(project).startConversation() ) } } diff --git a/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/ConversationTagProcessorTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/ConversationTagProcessorTest.kt index 784a4011f..85da37ca8 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/ConversationTagProcessorTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/ConversationTagProcessorTest.kt @@ -15,8 +15,8 @@ class ConversationTagProcessorTest : IntegrationTest() { public override fun setUp() { super.setUp() - conversationService = service() - ConversationsState.getInstance().conversations.clear() + conversationService = project.service() + ConversationsState.getInstance(project).conversations.clear() } fun `test should format conversation with single message`() { @@ -100,12 +100,12 @@ class ConversationTagProcessorTest : IntegrationTest() { } fun `test should find current conversation by id`() { - val conversation = conversationService.startConversation(project) + val conversation = conversationService.startConversation() conversation.addMessage(Message("Current conversation test").apply { response = "This is the current conversation" }) - val foundConversation = ConversationTagProcessor.getConversation(conversation.id) + val foundConversation = ConversationTagProcessor.getConversation(project, conversation.id) assertThat(foundConversation).isNotNull assertThat(foundConversation!!.id).isEqualTo(conversation.id) @@ -120,7 +120,7 @@ class ConversationTagProcessorTest : IntegrationTest() { }) conversationService.addConversation(conversation) - val foundConversation = ConversationTagProcessor.getConversation(conversation.id) + val foundConversation = ConversationTagProcessor.getConversation(project, conversation.id) assertThat(foundConversation).isNotNull assertThat(foundConversation!!.id).isEqualTo(conversation.id) @@ -134,13 +134,13 @@ class ConversationTagProcessorTest : IntegrationTest() { response = "This is stored" }) conversationService.addConversation(storedConversation) - val currentConversation = conversationService.startConversation(project) + val currentConversation = conversationService.startConversation() currentConversation.id = storedConversation.id currentConversation.addMessage(Message("Current version").apply { response = "This is current" }) - val foundConversation = ConversationTagProcessor.getConversation(storedConversation.id) + val foundConversation = ConversationTagProcessor.getConversation(project, storedConversation.id) assertThat(foundConversation).isNotNull assertThat(foundConversation!!.messages[0].prompt).isEqualTo("Current version") @@ -149,7 +149,7 @@ class ConversationTagProcessorTest : IntegrationTest() { fun `test should return null for non-existent conversation`() { val nonExistentId = UUID.randomUUID() - val foundConversation = ConversationTagProcessor.getConversation(nonExistentId) + val foundConversation = ConversationTagProcessor.getConversation(project, nonExistentId) assertThat(foundConversation).isNull() } @@ -161,7 +161,7 @@ class ConversationTagProcessorTest : IntegrationTest() { }) conversationService.addConversation(conversation) val historyActionItem = HistoryActionItem(conversation) - val foundConversation = ConversationTagProcessor.getConversation(conversation.id) + val foundConversation = ConversationTagProcessor.getConversation(project, conversation.id) val conversationTitle = historyActionItem.displayName val formatted = ConversationTagProcessor.formatConversation(foundConversation!!) @@ -201,4 +201,4 @@ class ConversationTagProcessorTest : IntegrationTest() { val titleInFormatted = formatted.substringAfter("## Conversation: ").substringBefore("\n") assertThat(titleInFormatted).hasSize(60) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/HistorySearchIntegrationTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/HistorySearchIntegrationTest.kt index 7f45a8e33..1184bd883 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/HistorySearchIntegrationTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/HistorySearchIntegrationTest.kt @@ -19,12 +19,12 @@ class HistorySearchIntegrationTest : IntegrationTest() { public override fun setUp() { super.setUp() - conversationService = service() - ConversationsState.getInstance().conversations.clear() - + conversationService = project.service() + ConversationsState.getInstance(project).conversations.clear() + val tagManager = TagManager() searchManager = SearchManager(project, tagManager) - historyGroupItem = HistoryGroupItem() + historyGroupItem = HistoryGroupItem(project) } fun `test should include history group in search manager default groups`() { @@ -44,7 +44,7 @@ class HistorySearchIntegrationTest : IntegrationTest() { } fun `test should filter conversations by search terms`() { - ConversationsState.getInstance().conversations.clear() + ConversationsState.getInstance(project).conversations.clear() createTestConversations() val testCases = mapOf( "java" to 3, @@ -88,8 +88,8 @@ class HistorySearchIntegrationTest : IntegrationTest() { fun `test should handle special characters in search`() { val conversation = conversationService.createConversation() - conversation.addMessage(Message("What is C++ programming?").apply { - response = "C++ is a powerful programming language" + conversation.addMessage(Message("What is C++ programming?").apply { + response = "C++ is a powerful programming language" }) conversationService.addConversation(conversation) @@ -104,13 +104,13 @@ class HistorySearchIntegrationTest : IntegrationTest() { val conversation = conversationService.createConversation() val topic = when (i % 5) { 0 -> "Java" - 1 -> "Python" + 1 -> "Python" 2 -> "JavaScript" 3 -> "Database" else -> "General" } - conversation.addMessage(Message("Question about $topic #$i").apply { - response = "Answer about $topic #$i" + conversation.addMessage(Message("Question about $topic #$i").apply { + response = "Answer about $topic #$i" }) conversationService.addConversation(conversation) } @@ -139,13 +139,13 @@ class HistorySearchIntegrationTest : IntegrationTest() { fun `test should search in conversation titles`() { val conversation1 = conversationService.createConversation() - conversation1.addMessage(Message("How to use Docker containers?").apply { - response = "Docker containers are lightweight virtualization" + conversation1.addMessage(Message("How to use Docker containers?").apply { + response = "Docker containers are lightweight virtualization" }) conversationService.addConversation(conversation1) val conversation2 = conversationService.createConversation() - conversation2.addMessage(Message("What is virtualization?").apply { - response = "Virtualization allows running multiple Docker instances" + conversation2.addMessage(Message("What is virtualization?").apply { + response = "Virtualization allows running multiple Docker instances" }) conversationService.addConversation(conversation2) @@ -160,7 +160,7 @@ class HistorySearchIntegrationTest : IntegrationTest() { fun `test should match history aliases in search manager`() { val historyAliases = listOf("history", "hist", "h") - + historyAliases.forEach { alias -> val matches = searchManager.matchesAnyDefaultGroup(alias) assertThat(matches) @@ -178,7 +178,7 @@ class HistorySearchIntegrationTest : IntegrationTest() { private fun createTestConversations() { val testData = listOf( "How to write Java code?" to "Use Java syntax and compile with javac", - "Python vs JavaScript comparison" to "Python is interpreted, JavaScript runs in browsers", + "Python vs JavaScript comparison" to "Python is interpreted, JavaScript runs in browsers", "What is database normalization?" to "Database normalization reduces redundancy", "Best practices for programming" to "Write clean, readable, and testable code", "JavaScript async/await tutorial" to "Use async/await for asynchronous programming" @@ -190,4 +190,4 @@ class HistorySearchIntegrationTest : IntegrationTest() { conversationService.addConversation(conversation) } } -} \ No newline at end of file +} diff --git a/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/HistoryTagIntegrationTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/HistoryTagIntegrationTest.kt index 38b2d7145..26610d666 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/HistoryTagIntegrationTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/HistoryTagIntegrationTest.kt @@ -21,8 +21,8 @@ class HistoryTagIntegrationTest : IntegrationTest() { public override fun setUp() { super.setUp() - conversationService = service() - ConversationsState.getInstance().conversations.clear() + conversationService = project.service() + ConversationsState.getInstance(project).conversations.clear() } fun testShouldDisplayCorrectNameForHistoryActionItem() { @@ -88,7 +88,7 @@ class HistoryTagIntegrationTest : IntegrationTest() { } fun testShouldFilterConversationsBySearchText() { - val historyGroupItem = HistoryGroupItem() + val historyGroupItem = HistoryGroupItem(project) val javaConversation = conversationService.createConversation() javaConversation.addMessage(Message("How to write Java code?").apply { response = "Use Java syntax" }) conversationService.addConversation(javaConversation) @@ -106,7 +106,7 @@ class HistoryTagIntegrationTest : IntegrationTest() { } fun testShouldHandleEmptyConversationsList() { - val historyGroupItem = HistoryGroupItem() + val historyGroupItem = HistoryGroupItem(project) val results = runBlocking { historyGroupItem.getLookupItems("") } @@ -114,7 +114,7 @@ class HistoryTagIntegrationTest : IntegrationTest() { } fun testShouldPerformCaseInsensitiveSearch() { - val historyGroupItem = HistoryGroupItem() + val historyGroupItem = HistoryGroupItem(project) val conversation = conversationService.createConversation() conversation.addMessage(Message("JavaScript Tutorial").apply { response = "Learn JS" }) conversationService.addConversation(conversation) @@ -165,7 +165,7 @@ class HistoryTagIntegrationTest : IntegrationTest() { conversation.addMessage(Message("Test question").apply { response = "Test answer" }) conversationService.addConversation(conversation) - val foundConversation = ConversationTagProcessor.getConversation(conversation.id) + val foundConversation = ConversationTagProcessor.getConversation(project, conversation.id) assertThat(foundConversation).isNotNull assertThat(foundConversation!!.id).isEqualTo(conversation.id) @@ -176,7 +176,7 @@ class HistoryTagIntegrationTest : IntegrationTest() { fun testShouldReturnNullForNonExistentConversation() { val nonExistentId = UUID.randomUUID() - val foundConversation = ConversationTagProcessor.getConversation(nonExistentId) + val foundConversation = ConversationTagProcessor.getConversation(project, nonExistentId) assertThat(foundConversation).isNull() } @@ -208,7 +208,7 @@ class HistoryTagIntegrationTest : IntegrationTest() { } fun testShouldSortConversationsByUpdatedDateDescending() { - val historyGroupItem = HistoryGroupItem() + val historyGroupItem = HistoryGroupItem(project) val now = LocalDateTime.now() val oldConversation = conversationService.createConversation() oldConversation.updatedOn = now.minusDays(3) @@ -232,4 +232,4 @@ class HistoryTagIntegrationTest : IntegrationTest() { assertThat(displayNames[2]).isEqualTo("Old conversation") } -} \ No newline at end of file +}