feat: add project-based chat history filtering

This commit is contained in:
Carl-Robert Linnupuu 2025-07-23 14:36:22 +01:00
parent bf48a90003
commit 339a581181
16 changed files with 316 additions and 44 deletions

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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)));
});
}

View file

@ -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();
};

View file

@ -192,7 +192,7 @@ public class ChatToolWindowTabbedPane extends JBTabbedPane {
removeTabAt(getSelectedIndex());
addNewTab(new ChatToolWindowTabPanel(
project,
ConversationService.getInstance().startConversation()));
ConversationService.getInstance().startConversation(project)));
repaint();
revalidate();
});

View file

@ -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<Boolean> = 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
}

View file

@ -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()

View file

@ -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<Conversation>()
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<Conversation>? = null
private var isDataLoaded = false
private var projectInfoCache: Map<String, ProjectInfo> = 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<String>) : 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<Conversation> {
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<Conversation>): Map<String, ProjectInfo> {
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<ProjectInfo> {
return projectInfoCache.values.sortedByDescending { it.conversationCount }
}
private fun updateList(conversations: List<Conversation>) {
@ -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 -> {}
}
}
}

View file

@ -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
}
}
}

View file

@ -22,7 +22,7 @@ class CompletionRequestProviderTest : IntegrationTest() {
instructions = "TEST_SYSTEM_PROMPT"
}
service<PromptsSettings>().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<PromptsSettings>().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)

View file

@ -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<PromptsSettings>().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<PromptsSettings>().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<PromptsSettings>().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<PromptsSettings>().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<PromptsSettings>().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")

View file

@ -17,7 +17,7 @@ class OpenAIRequestFactoryIntegrationTest : IntegrationTest() {
fun testDefaultPersonaUsesEditModePromptWhenEnabled() {
useOpenAIService(OpenAIChatCompletionModel.GPT_4_O.code)
service<PromptsSettings>().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<PromptsSettings>().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<PromptsSettings>().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<PromptsSettings>().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)

View file

@ -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()

View file

@ -30,7 +30,7 @@ class ChatToolWindowTabPanelTest : IntegrationTest() {
service<PromptsSettings>().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<PromptsSettings>().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")

View file

@ -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)
)
}
}

View file

@ -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"