diff --git a/src/main/java/ee/carlrobert/codegpt/conversations/Conversation.java b/src/main/java/ee/carlrobert/codegpt/conversations/Conversation.java index 3589a5b9..ff56d147 100644 --- a/src/main/java/ee/carlrobert/codegpt/conversations/Conversation.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/Conversation.java @@ -16,6 +16,7 @@ public class Conversation { private LocalDateTime createdOn; private LocalDateTime updatedOn; private boolean discardTokenLimit; + private String projectPath; public Conversation() { this.messages = new ArrayList<>(); @@ -82,4 +83,12 @@ public class Conversation { .filter(message -> !message.getId().equals(messageId)) .toList()); } + + public String getProjectPath() { + return projectPath; + } + + public void setProjectPath(String projectPath) { + this.projectPath = projectPath; + } } diff --git a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java index 874eb17d..22e094d3 100644 --- a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java @@ -3,6 +3,7 @@ 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; import ee.carlrobert.codegpt.completions.ChatCompletionParameters; import ee.carlrobert.codegpt.conversations.message.Message; import java.time.LocalDateTime; @@ -74,8 +75,13 @@ public final class ConversationService { conversationState.setCurrentConversation(conversation); } - public Conversation startConversation() { + public Conversation startConversation(Project project) { + return startConversation(project != null ? project.getBasePath() : null); + } + + private Conversation startConversation(String projectPath) { var conversation = createConversation(); + conversation.setProjectPath(projectPath); conversationState.setCurrentConversation(conversation); addConversation(conversation); return conversation; diff --git a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowContentManager.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowContentManager.java index 110c88fa..3ad9228f 100644 --- a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowContentManager.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowContentManager.java @@ -78,7 +78,7 @@ public final class ChatToolWindowContentManager { .map(item -> { var panel = new ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation()); + ConversationService.getInstance().startConversation(project)); item.addNewTab(panel); return panel; }) @@ -117,7 +117,7 @@ public final class ChatToolWindowContentManager { tabbedPane.clearAll(); tabbedPane.addNewTab(new ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation())); + ConversationService.getInstance().startConversation(project))); }); } 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 f37207e3..d1748915 100644 --- a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowPanel.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowPanel.java @@ -45,11 +45,13 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel { private final ToolWindowFooterNotification imageFileAttachmentNotification; private final ActionLink upgradePlanLink; private final ChatToolWindowTabbedPane tabbedPane; + private final Project project; public ChatToolWindowPanel( @NotNull Project project, @NotNull Disposable parentDisposable) { super(true); + this.project = project; imageFileAttachmentNotification = new ToolWindowFooterNotification(() -> project.putUserData(CodeGPTKeys.IMAGE_ATTACHMENT_FILE_PATH, "")); upgradePlanLink = new ActionLink("Upgrade your plan", event -> { @@ -72,7 +74,7 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel { private Conversation getConversation() { var conversation = ConversationsState.getCurrentConversation(); if (conversation == null) { - return ConversationService.getInstance().startConversation(); + return ConversationService.getInstance().startConversation(project); } return conversation; } @@ -118,7 +120,7 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel { Runnable onAddNewTab = () -> { tabbedPane.addNewTab(new ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation())); + ConversationService.getInstance().startConversation(project))); repaint(); revalidate(); }; 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 d16c8c38..1eb68901 100644 --- a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPane.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPane.java @@ -192,7 +192,7 @@ public class ChatToolWindowTabbedPane extends JBTabbedPane { removeTabAt(getSelectedIndex()); addNewTab(new ChatToolWindowTabPanel( project, - ConversationService.getInstance().startConversation())); + ConversationService.getInstance().startConversation(project))); repaint(); revalidate(); }); diff --git a/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/BaseFilterAction.kt b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/BaseFilterAction.kt new file mode 100644 index 00000000..a5cc0268 --- /dev/null +++ b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/BaseFilterAction.kt @@ -0,0 +1,28 @@ +package ee.carlrobert.codegpt.toolwindow.history + +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.util.Key +import javax.swing.Icon + +abstract class BaseFilterAction( + text: String, + description: String? = null, + icon: Icon? = null +) : AnAction(text, description, icon) { + + companion object { + val KEY: Key = Key.create("SELECTED_STATE") + } + + override fun getActionUpdateThread(): ActionUpdateThread { + return ActionUpdateThread.BGT + } + + override fun update(e: AnActionEvent) { + e.presentation.putClientProperty(KEY, isSelected()) + } + + abstract fun isSelected(): Boolean +} \ No newline at end of file diff --git a/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryItemPanel.kt b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryItemPanel.kt index 510cb549..24a4db74 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryItemPanel.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryItemPanel.kt @@ -10,6 +10,7 @@ import com.intellij.util.ui.UIUtil import com.intellij.util.ui.components.BorderLayoutPanel import ee.carlrobert.codegpt.CodeGPTBundle import ee.carlrobert.codegpt.conversations.Conversation +import ee.carlrobert.codegpt.util.ProjectPathUtils import java.awt.Color import java.awt.Cursor import java.awt.Dimension @@ -195,7 +196,15 @@ class ChatHistoryItemPanel( private fun createMetadataPanel(): JPanel { return panel { row { - label(formatDate()) + val dateText = formatDate() + val projectName = ProjectPathUtils.extractProjectNameTruncated(conversation.projectPath) + val metadataText = if (projectName != null) { + "$dateText • [$projectName]" + } else { + dateText + } + + label(metadataText) .applyToComponent { font = JBFont.regular().deriveFont(11f) foreground = getMetadataColor() 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 b65a316d..82c0593f 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryToolWindow.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/toolwindow/history/ChatHistoryToolWindow.kt @@ -21,6 +21,7 @@ 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 import javax.swing.JPanel import javax.swing.SwingUtilities @@ -41,6 +42,7 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() private val searchField = SearchTextField() private var allConversations = mutableListOf() private var sortOption = SortOption.UPDATED_DATE_DESC + private var projectFilter: ProjectFilterState = ProjectFilterState.AllProjects private val statusLabel = JBLabel().apply { font = JBFont.small() foreground = UIUtil.getContextHelpForeground() @@ -49,6 +51,13 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() private var lastSearchText = "" private var lastFilteredConversations: List? = null private var isDataLoaded = false + private var projectInfoCache: Map = emptyMap() + + data class ProjectInfo( + val path: String, + val name: String, + val conversationCount: Int + ) enum class SortOption(val propertyKey: String) { UPDATED_DATE_DESC("conversation.sortOption.recentlyUpdated"), @@ -62,6 +71,32 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() get() = CodeGPTBundle.get(propertyKey) } + sealed class ProjectFilterState { + object AllProjects : ProjectFilterState() + object CurrentProjectOnly : ProjectFilterState() + data class SelectedProjects(val projectPaths: Set) : ProjectFilterState() + + fun matches(conversationProjectPath: String?, currentProjectPath: String?): Boolean { + return when (this) { + is AllProjects -> true + is CurrentProjectOnly -> conversationProjectPath == currentProjectPath + is SelectedProjects -> projectPaths.contains(conversationProjectPath) + } + } + + fun getDisplayText(): String { + return when (this) { + is AllProjects -> "All Projects" + is CurrentProjectOnly -> "Current Project Only" + is SelectedProjects -> when (projectPaths.size) { + 0 -> "No Projects" + 1 -> "1 Project Selected" + else -> "${projectPaths.size} Projects Selected" + } + } + } + } + init { setupUI() loadConversationsAsync() @@ -154,14 +189,22 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() } private fun filterConversations(searchText: String): List { + val projectFiltered = allConversations.filter { conversation -> + projectFilter.matches(conversation.projectPath, project.basePath) + } + return if (searchText.isBlank()) { lastSearchText = "" lastFilteredConversations = null - allConversations + projectFiltered } else if (searchText == lastSearchText && lastFilteredConversations != null) { - lastFilteredConversations!! + lastFilteredConversations!!.filter { conversation -> + projectFiltered.contains(conversation) + } } else { - val startList = getOptimizedSearchStartList(searchText) + val startList = getOptimizedSearchStartList(searchText).filter { conversation -> + projectFiltered.contains(conversation) + } val filtered = startList.filter { conversation -> matchesSearchText(conversation, searchText) } @@ -247,6 +290,105 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() return sortAction } + private fun createProjectFilterAction(): AnAction { + return object : AnAction( + projectFilter.getDisplayText(), + "Filter conversations by project", + AllIcons.General.Filter + ) { + override fun actionPerformed(e: AnActionEvent) { + val actionGroup = DefaultActionGroup().apply { + add(object : BaseFilterAction("All Projects", null, AllIcons.General.Filter) { + override fun actionPerformed(e: AnActionEvent) { + projectFilter = ProjectFilterState.AllProjects + sortAndFilterConversations() + } + + override fun isSelected(): Boolean { + return projectFilter is ProjectFilterState.AllProjects + } + }) + + add(object : BaseFilterAction("Current Project Only", null, null) { + override fun actionPerformed(e: AnActionEvent) { + projectFilter = ProjectFilterState.CurrentProjectOnly + sortAndFilterConversations() + } + + override fun isSelected(): Boolean { + return projectFilter is ProjectFilterState.CurrentProjectOnly + } + }) + + addSeparator("Available Projects") + + val projects = getProjectsWithConversations() + if (projects.isNotEmpty()) { + projects.forEach { projectInfo -> + val displayName = + "${projectInfo.name} (${projectInfo.conversationCount})" + val isCurrentProject = projectInfo.path == project.basePath + val icon = if (isCurrentProject) AllIcons.Nodes.HomeFolder else null + + add(object : BaseFilterAction(displayName, projectInfo.path, icon) { + override fun actionPerformed(e: AnActionEvent) { + projectFilter = + ProjectFilterState.SelectedProjects(setOf(projectInfo.path)) + sortAndFilterConversations() + } + + override fun isSelected(): Boolean { + return when (val filter = projectFilter) { + is ProjectFilterState.SelectedProjects -> filter.projectPaths.contains( + projectInfo.path + ) + is ProjectFilterState.CurrentProjectOnly -> isCurrentProject + else -> false + } + } + }) + } + } else { + add(object : AnAction("No projects with conversations", null, null) { + override fun actionPerformed(e: AnActionEvent) {} + override fun update(e: AnActionEvent) { + e.presentation.isEnabled = false + } + + override fun getActionUpdateThread(): ActionUpdateThread { + return ActionUpdateThread.BGT + } + }) + } + } + + val popup = JBPopupFactory.getInstance() + .createActionGroupPopup( + "Filter by Project", + actionGroup, + e.dataContext, + JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, + true + ) + + val component = e.inputEvent?.component + if (component != null) { + popup.showUnderneathOf(component) + } else { + popup.showInBestPositionFor(e.dataContext) + } + } + + override fun update(e: AnActionEvent) { + e.presentation.text = projectFilter.getDisplayText() + } + + override fun getActionUpdateThread(): ActionUpdateThread { + return ActionUpdateThread.BGT + } + } + } + private fun setupListeners() { var searchTimer: Timer? = null searchField.addDocumentListener(object : DocumentAdapter() { @@ -282,6 +424,7 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() } }) add(createSortAction()) + add(createProjectFilterAction()) addSeparator() add(DeleteAllConversationsAction { refresh() }) } @@ -306,6 +449,7 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() .toMutableList() SwingUtilities.invokeLater { allConversations = conversations + projectInfoCache = discoverProjects(conversations) lastSearchText = "" lastFilteredConversations = null isDataLoaded = true @@ -345,11 +489,44 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() private fun matchesSearchText(conversation: Conversation, searchText: String): Boolean { val searchLower = searchText.lowercase() - return conversation.title?.lowercase()?.contains(searchLower) == true || - conversation.messages.take(MAX_MESSAGES_TO_SEARCH).any { message -> - message.prompt?.lowercase()?.contains(searchLower) == true || - message.response?.lowercase()?.contains(searchLower) == true + + if (conversation.title?.lowercase()?.contains(searchLower) == true) { + return true + } + + conversation.projectPath?.let { path -> + val projectName = ProjectPathUtils.extractProjectName(path)?.lowercase() + if (projectName?.contains(searchLower) == true) { + return true + } + } + + return conversation.messages.take(MAX_MESSAGES_TO_SEARCH).any { message -> + message.prompt?.lowercase()?.contains(searchLower) == true || + message.response?.lowercase()?.contains(searchLower) == true + } + } + + + private fun discoverProjects(conversations: List): Map { + return conversations + .mapNotNull { conversation -> + conversation.projectPath?.let { path -> + path to (ProjectPathUtils.extractProjectName(path) ?: path) } + } + .groupBy({ it.first }, { it.second }) + .mapValues { (path, names) -> + ProjectInfo( + path = path, + name = names.firstOrNull() ?: path, + conversationCount = conversations.count { it.projectPath == path } + ) + } + } + + private fun getProjectsWithConversations(): List { + return projectInfoCache.values.sortedByDescending { it.conversationCount } } private fun updateList(conversations: List) { @@ -366,6 +543,20 @@ class ChatHistoryToolWindow(private val project: Project) : BorderLayoutPanel() append(getConversationCountMessage(conversations, searchText)) append(" • ") append(CodeGPTBundle.get("conversation.status.sortedBy", sortOption.displayName)) + + when (projectFilter) { + is ProjectFilterState.CurrentProjectOnly -> { + append(" • ") + append("Current project only") + } + + is ProjectFilterState.SelectedProjects -> { + append(" • ") + append(projectFilter.getDisplayText()) + } + + else -> {} + } } } diff --git a/src/main/kotlin/ee/carlrobert/codegpt/util/ProjectPathUtils.kt b/src/main/kotlin/ee/carlrobert/codegpt/util/ProjectPathUtils.kt new file mode 100644 index 00000000..87ec7ec5 --- /dev/null +++ b/src/main/kotlin/ee/carlrobert/codegpt/util/ProjectPathUtils.kt @@ -0,0 +1,28 @@ +package ee.carlrobert.codegpt.util + +object ProjectPathUtils { + private const val PROJECT_NAME_MAX_LENGTH = 30 + + fun extractProjectName(projectPath: String?): String? { + if (projectPath.isNullOrEmpty()) return null + + val separators = listOf('/', '\\') + val lastSeparatorIndex = separators.maxOfOrNull { projectPath.lastIndexOf(it) } ?: -1 + + return if (lastSeparatorIndex >= 0 && lastSeparatorIndex < projectPath.length - 1) { + projectPath.substring(lastSeparatorIndex + 1) + } else { + projectPath + } + } + + fun extractProjectNameTruncated(projectPath: String?): String? { + val projectName = extractProjectName(projectPath) ?: return null + + return if (projectName.length > PROJECT_NAME_MAX_LENGTH) { + projectName.substring(0, PROJECT_NAME_MAX_LENGTH - 3) + "..." + } else { + projectName + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.kt index 54b5f59b..9a2812f0 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.kt @@ -22,7 +22,7 @@ class CompletionRequestProviderTest : IntegrationTest() { instructions = "TEST_SYSTEM_PROMPT" } service().state.personas.selectedPersona = customPersona - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) val firstMessage = createDummyMessage(500) val secondMessage = createDummyMessage(250) conversation.addMessage(firstMessage) @@ -53,7 +53,7 @@ class CompletionRequestProviderTest : IntegrationTest() { instructions = "TEST_SYSTEM_PROMPT" } service().state.personas.selectedPersona = customPersona - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) 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 bece9588..0d21fb16 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt @@ -1,7 +1,6 @@ package ee.carlrobert.codegpt.completions import com.intellij.openapi.components.service -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 @@ -27,7 +26,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) expectOpenAI(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") assertThat(request.method).isEqualTo("POST") @@ -72,7 +71,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) conversation.addMessage(Message("Ping", "Pong")) expectLlama(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/completion") @@ -118,7 +117,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) expectOllama(NdJsonStreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") assertThat(request.method).isEqualTo("POST") @@ -162,7 +161,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) expectGoogle(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/models/gemini-2.0-flash:streamGenerateContent") assertThat(request.method).isEqualTo("POST") @@ -208,7 +207,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { } service().state.personas.selectedPersona = customPersona val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) 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 0ad3679f..3a7c3078 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/completions/OpenAIRequestFactoryIntegrationTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/completions/OpenAIRequestFactoryIntegrationTest.kt @@ -17,7 +17,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() { fun testDefaultPersonaUsesEditModePromptWhenEnabled() { useOpenAIService(OpenAIChatCompletionModel.GPT_4_O.code) service().state.personas.selectedPersona = PersonasState.DEFAULT_PERSONA - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) val message = Message("Please refactor this code") val callParameters = ChatCompletionParameters .builder(conversation, message) @@ -120,7 +120,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() { fun testDefaultPersonaIsFilteredInAskMode() { useOpenAIService(OpenAIChatCompletionModel.GPT_4_O.code) service().state.personas.selectedPersona = PersonasState.DEFAULT_PERSONA - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) val message = Message("Please refactor this code") val callParameters = ChatCompletionParameters .builder(conversation, message) @@ -239,7 +239,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() { instructions = personaPromptWithSearchReplace } service().state.personas.selectedPersona = customPersona - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) val message = Message("Please refactor this code") val callParameters = ChatCompletionParameters .builder(conversation, message) @@ -282,7 +282,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() { """.trimIndent() service().state.personas.selectedPersona.instructions = personaPromptWithSearchReplace - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) 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 7b15d5b7..09a04fa3 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt @@ -11,7 +11,7 @@ import org.assertj.core.api.Assertions.assertThat class ConversationsStateTest : BasePlatformTestCase() { fun testStartNewDefaultConversation() { - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) assertThat(conversation).isEqualTo(ConversationsState.getCurrentConversation()) } @@ -35,8 +35,8 @@ class ConversationsStateTest : BasePlatformTestCase() { fun testGetPreviousConversation() { val service = ConversationService.getInstance() - val firstConversation = service.startConversation() - service.startConversation() + val firstConversation = service.startConversation(project) + service.startConversation(project) val previousConversation = service.previousConversation @@ -46,8 +46,8 @@ class ConversationsStateTest : BasePlatformTestCase() { fun testGetNextConversation() { val service = ConversationService.getInstance() - val firstConversation = service.startConversation() - val secondConversation = service.startConversation() + val firstConversation = service.startConversation(project) + val secondConversation = service.startConversation(project) ConversationsState.getInstance().setCurrentConversation(firstConversation) val nextConversation = service.nextConversation @@ -58,8 +58,8 @@ class ConversationsStateTest : BasePlatformTestCase() { fun testDeleteSelectedConversation() { val service = ConversationService.getInstance() - val firstConversation = service.startConversation() - service.startConversation() + val firstConversation = service.startConversation(project) + service.startConversation(project) service.deleteSelectedConversation() @@ -72,8 +72,8 @@ class ConversationsStateTest : BasePlatformTestCase() { fun testClearAllConversations() { val service = ConversationService.getInstance() - service.startConversation() - service.startConversation() + service.startConversation(project) + service.startConversation(project) service.clearAll() 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 da89600b..654ccb9e 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanelTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanelTest.kt @@ -30,7 +30,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { service().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT" val message = Message("Hello!") - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) val panel = ChatToolWindowTabPanel(project, conversation) expectOpenAI(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") @@ -97,7 +97,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() + val conversation = ConversationService.getInstance().startConversation(project) val panel = ChatToolWindowTabPanel(project, conversation) panel.includeFiles(listOf( LightVirtualFile("TEST_FILE_NAME_1", "TEST_FILE_CONTENT_1"), @@ -196,7 +196,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { service().state.personas.selectedPersona.instructions = "TEST_SYSTEM_PROMPT" val message = Message("TEST_MESSAGE") - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) val panel = ChatToolWindowTabPanel(project, conversation) expectOpenAI(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/v1/chat/completions") @@ -280,7 +280,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() + val conversation = ConversationService.getInstance().startConversation(project) val panel = ChatToolWindowTabPanel(project, conversation) panel.includeFiles( listOf( @@ -391,7 +391,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { llamaSettings.minP = 0.03 llamaSettings.repeatPenalty = 1.3 val message = Message("TEST_PROMPT") - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) val panel = ChatToolWindowTabPanel(project, conversation) expectLlama(StreamHttpExchange { request: RequestEntity -> assertThat(request.uri.path).isEqualTo("/completion") 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 adbaaf97..572ffab9 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPaneTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabbedPaneTest.kt @@ -31,7 +31,7 @@ class ChatToolWindowTabbedPaneTest : BasePlatformTestCase() { fun testResetCurrentlyActiveTabPanel() { val tabbedPane = ChatToolWindowTabbedPane(Disposer.newDisposable()) - val conversation = ConversationService.getInstance().startConversation() + val conversation = ConversationService.getInstance().startConversation(project) 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() + ConversationService.getInstance().startConversation(project) ) } } 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 922a107b..784a4011 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/ConversationTagProcessorTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/ui/textarea/ConversationTagProcessorTest.kt @@ -100,7 +100,7 @@ class ConversationTagProcessorTest : IntegrationTest() { } fun `test should find current conversation by id`() { - val conversation = conversationService.startConversation() + val conversation = conversationService.startConversation(project) conversation.addMessage(Message("Current conversation test").apply { response = "This is the current conversation" }) @@ -134,7 +134,7 @@ class ConversationTagProcessorTest : IntegrationTest() { response = "This is stored" }) conversationService.addConversation(storedConversation) - val currentConversation = conversationService.startConversation() + val currentConversation = conversationService.startConversation(project) currentConversation.id = storedConversation.id currentConversation.addMessage(Message("Current version").apply { response = "This is current"