From 465feafc9f95357abeff80a99a8d0b2beb52e553 Mon Sep 17 00:00:00 2001 From: Carl-Robert Linnupuu Date: Mon, 16 Jun 2025 19:52:32 +0200 Subject: [PATCH] feat: remove model-conversation dependency --- .../toolwindow/OpenInEditorAction.java | 2 +- .../ChatCompletionEventListener.java | 1 - ...oolwindowChatCompletionRequestHandler.java | 1 - .../codegpt/conversations/Conversation.java | 20 +--- .../conversations/ConversationService.java | 99 ++----------------- .../conversations/ConversationsState.java | 16 ++- .../codegpt/settings/GeneralSettings.java | 56 ----------- .../chat/ChatToolWindowTabbedPane.java | 1 - ...WindowCompletionResponseEventListener.java | 1 - .../conversations/ConversationPanel.java | 8 -- .../codegpt/ui/textarea/UserInputPanel.kt | 8 -- .../conversations/ConversationsStateTest.kt | 8 +- .../settings/state/GeneralSettingsTest.kt | 68 ------------- .../chat/ChatToolWindowTabPanelTest.kt | 45 ++------- .../chat/CompleteOutputParserTest.kt | 0 .../toolwindow/chat/StreamOutputParserTest.kt | 0 16 files changed, 32 insertions(+), 302 deletions(-) delete mode 100644 src/test/kotlin/ee/carlrobert/codegpt/settings/state/GeneralSettingsTest.kt create mode 100644 src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/CompleteOutputParserTest.kt create mode 100644 src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/StreamOutputParserTest.kt 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 2c5804f7..904ba6f2 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/OpenInEditorAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/toolwindow/OpenInEditorAction.java @@ -42,7 +42,7 @@ public class OpenInEditorAction extends AnAction { if (project != null && currentConversation != null) { var dateTimeStamp = currentConversation.getUpdatedOn() .format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")); - var fileName = format("%s_%s.md", currentConversation.getModel(), dateTimeStamp); + var fileName = format("proxyai_conversation_%s.md", dateTimeStamp); var fileContent = currentConversation .getMessages() .stream() diff --git a/src/main/java/ee/carlrobert/codegpt/completions/ChatCompletionEventListener.java b/src/main/java/ee/carlrobert/codegpt/completions/ChatCompletionEventListener.java index dc8aeb92..5ce51354 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/ChatCompletionEventListener.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/ChatCompletionEventListener.java @@ -82,7 +82,6 @@ public class ChatCompletionEventListener implements CompletionEventListener messages = new ArrayList<>(); - private String clientCode; - private String model; private LocalDateTime createdOn; private LocalDateTime updatedOn; private boolean discardTokenLimit; @@ -32,26 +32,10 @@ public class Conversation { this.messages = new ArrayList<>(messages); } - public String getClientCode() { - return clientCode; - } - - public void setClientCode(String clientCode) { - this.clientCode = clientCode; - } - public void addMessage(Message message) { messages.add(message); } - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - public LocalDateTime getCreatedOn() { return createdOn; } diff --git a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java index a6e2f080..8508cea1 100644 --- a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationService.java @@ -5,19 +5,9 @@ import com.intellij.openapi.components.Service; import com.intellij.openapi.diagnostic.Logger; import ee.carlrobert.codegpt.completions.ChatCompletionParameters; 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.anthropic.AnthropicSettings; -import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTServiceSettings; -import ee.carlrobert.codegpt.settings.service.google.GoogleSettings; -import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings; -import ee.carlrobert.codegpt.settings.service.ollama.OllamaSettings; -import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import java.util.ListIterator; import java.util.Optional; import java.util.UUID; import org.jetbrains.annotations.NotNull; @@ -37,32 +27,22 @@ public final class ConversationService { } public List getSortedConversations() { - return conversationState.getConversationsMapping() - .values() + return conversationState.conversations .stream() - .flatMap(List::stream) .sorted(Comparator.comparing(Conversation::getUpdatedOn).reversed()) .toList(); } - public Conversation createConversation(String clientCode) { + public Conversation createConversation() { var conversation = new Conversation(); conversation.setId(UUID.randomUUID()); - conversation.setClientCode(clientCode); conversation.setCreatedOn(LocalDateTime.now()); conversation.setUpdatedOn(LocalDateTime.now()); - conversation.setModel(getModelForSelectedService(GeneralSettings.getSelectedService())); return conversation; } public void addConversation(Conversation conversation) { - var conversationsMapping = conversationState.getConversationsMapping(); - var conversations = conversationsMapping.get(conversation.getClientCode()); - if (conversations == null) { - conversations = new ArrayList<>(); - } - conversations.add(conversation); - conversationsMapping.put(conversation.getClientCode(), conversations); + conversationState.conversations.add(conversation); } public void saveMessage(String response, ChatCompletionParameters callParameters) { @@ -85,62 +65,28 @@ public final class ConversationService { public void saveMessage(@NotNull Conversation conversation, @NotNull Message message) { conversation.setUpdatedOn(LocalDateTime.now()); - var iterator = getIterator(conversation.getClientCode()); - while (iterator.hasNext()) { - var next = iterator.next(); - next.setMessages( - next.getMessages().stream().map(item -> { - if (item.getId() == message.getId()) { - return message; - } - return item; - }).toList()); - if (next.getId().equals(conversation.getId())) { - iterator.set(conversation); - } - } + conversation.addMessage(message); } public void saveConversation(Conversation conversation) { conversation.setUpdatedOn(LocalDateTime.now()); - var iterator = getIterator(conversation.getClientCode()); - while (iterator.hasNext()) { - var next = iterator.next(); - if (next.getId().equals(conversation.getId())) { - iterator.set(conversation); - } - } conversationState.setCurrentConversation(conversation); } public Conversation startConversation() { - var selectedService = GeneralSettings.getSelectedService(); - if (selectedService == null) { - LOG.warn("Selected service is not defined, falling back to ProxyAI."); - selectedService = ServiceType.CODEGPT; - } - - var completionCode = selectedService.getCompletionCode(); - var conversation = createConversation(completionCode); + var conversation = createConversation(); conversationState.setCurrentConversation(conversation); addConversation(conversation); return conversation; } public void clearAll() { - conversationState.getConversationsMapping().clear(); + conversationState.conversations.clear(); conversationState.setCurrentConversation(null); } public void deleteConversation(Conversation conversation) { - var iterator = getIterator(conversation.getClientCode()); - while (iterator.hasNext()) { - var next = iterator.next(); - if (next.getId().equals(conversation.getId())) { - iterator.remove(); - break; - } - } + conversationState.conversations.removeIf(it -> it.getId() == conversation.getId()); } public void deleteSelectedConversation() { @@ -171,12 +117,6 @@ public final class ConversationService { return tryGetNextOrPreviousConversation(false); } - private ListIterator getIterator(String clientCode) { - return conversationState.getConversationsMapping() - .get(clientCode) - .listIterator(); - } - private Optional tryGetNextOrPreviousConversation(boolean isPrevious) { var currentConversation = ConversationsState.getCurrentConversation(); if (currentConversation != null) { @@ -194,29 +134,4 @@ public final class ConversationService { } return Optional.empty(); } - - public String getModelForSelectedService(ServiceType serviceType) { - var application = ApplicationManager.getApplication(); - return switch (serviceType) { - case CODEGPT -> application.getService(CodeGPTServiceSettings.class) - .getState() - .getChatCompletionSettings() - .getModel(); - case OPENAI -> OpenAISettings.getCurrentState().getModel(); - case CUSTOM_OPENAI -> "CustomService"; - case ANTHROPIC -> AnthropicSettings.getCurrentState().getModel(); - case LLAMA_CPP -> { - var llamaSettings = LlamaSettings.getCurrentState(); - yield llamaSettings.isUseCustomModel() - ? llamaSettings.getCustomLlamaModelPath() - : llamaSettings.getHuggingFaceModel().getCode(); - } - case OLLAMA -> application.getService(OllamaSettings.class) - .getState() - .getModel(); - case GOOGLE -> application.getService(GoogleSettings.class) - .getState() - .getModel(); - }; - } } diff --git a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java index 63b130b2..6ea5d43e 100644 --- a/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java +++ b/src/main/java/ee/carlrobert/codegpt/conversations/ConversationsState.java @@ -8,8 +8,10 @@ import com.intellij.util.xmlb.XmlSerializerUtil; import com.intellij.util.xmlb.annotations.OptionTag; import ee.carlrobert.codegpt.conversations.converter.ConversationConverter; import ee.carlrobert.codegpt.conversations.converter.ConversationsConverter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; import java.util.List; -import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,12 +20,15 @@ import org.jetbrains.annotations.Nullable; storages = @Storage("ChatGPTConversations_170.xml")) public class ConversationsState implements PersistentStateComponent { + @Deprecated @OptionTag(converter = ConversationsConverter.class) public ConversationsContainer conversationsContainer = new ConversationsContainer(); @OptionTag(converter = ConversationConverter.class) public Conversation currentConversation; + public List conversations = new ArrayList<>(); + public boolean discardAllTokenLimits; public static ConversationsState getInstance() { @@ -39,6 +44,11 @@ public class ConversationsState implements PersistentStateComponent conversations.add(it)); } public void discardAllTokenLimits() { @@ -52,8 +62,4 @@ public class ConversationsState implements PersistentStateComponent> getConversationsMapping() { - return conversationsContainer.getConversationsMapping(); - } } diff --git a/src/main/java/ee/carlrobert/codegpt/settings/GeneralSettings.java b/src/main/java/ee/carlrobert/codegpt/settings/GeneralSettings.java index de5f5da8..8e3368cf 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/GeneralSettings.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/GeneralSettings.java @@ -4,20 +4,14 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; -import ee.carlrobert.codegpt.CodeGPTKeys; -import ee.carlrobert.codegpt.completions.HuggingFaceModel; import ee.carlrobert.codegpt.completions.llama.LlamaModel; -import ee.carlrobert.codegpt.conversations.Conversation; -import ee.carlrobert.codegpt.settings.service.ProviderChangeNotifier; import ee.carlrobert.codegpt.settings.service.ServiceType; import ee.carlrobert.codegpt.settings.service.anthropic.AnthropicSettings; -import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTService; import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTServiceSettings; import ee.carlrobert.codegpt.settings.service.google.GoogleSettings; import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings; import ee.carlrobert.codegpt.settings.service.ollama.OllamaSettings; import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings; -import ee.carlrobert.codegpt.util.ApplicationUtil; import org.jetbrains.annotations.NotNull; @State(name = "CodeGPT_GeneralSettings_270", storages = @Storage("CodeGPT_GeneralSettings_270.xml")) @@ -52,56 +46,6 @@ public class GeneralSettings implements PersistentStateComponent() - if (conversation.messages.isNotEmpty()) { - conversationService.startConversation() - project.service().createNewTabPanel() - } else { - conversation.model = conversationService.getModelForSelectedService(it) - } }, service().state.selectedService ).createCustomComponent(ActionPlaces.UNKNOWN) diff --git a/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt index 4866a7b6..7b15d5b7 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/conversations/ConversationsStateTest.kt @@ -11,20 +11,14 @@ import org.assertj.core.api.Assertions.assertThat class ConversationsStateTest : BasePlatformTestCase() { fun testStartNewDefaultConversation() { - GeneralSettings.getCurrentState().selectedService = ServiceType.OPENAI - OpenAISettings.getCurrentState().model = OpenAIChatCompletionModel.GPT_3_5.code - val conversation = ConversationService.getInstance().startConversation() assertThat(conversation).isEqualTo(ConversationsState.getCurrentConversation()) - assertThat(conversation) - .extracting("clientCode", "model") - .containsExactly("chat.completion", "gpt-3.5-turbo") } fun testSaveConversation() { val service = ConversationService.getInstance() - val conversation = service.createConversation("chat.completion") + val conversation = service.createConversation() service.addConversation(conversation) val message = Message("TEST_PROMPT") message.response = "TEST_RESPONSE" diff --git a/src/test/kotlin/ee/carlrobert/codegpt/settings/state/GeneralSettingsTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/settings/state/GeneralSettingsTest.kt deleted file mode 100644 index ab3271ce..00000000 --- a/src/test/kotlin/ee/carlrobert/codegpt/settings/state/GeneralSettingsTest.kt +++ /dev/null @@ -1,68 +0,0 @@ -package ee.carlrobert.codegpt.settings.state - -import com.intellij.testFramework.fixtures.BasePlatformTestCase -import ee.carlrobert.codegpt.completions.HuggingFaceModel -import ee.carlrobert.codegpt.conversations.Conversation -import ee.carlrobert.codegpt.settings.GeneralSettings -import ee.carlrobert.codegpt.settings.service.ServiceType -import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings -import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings -import org.assertj.core.api.Assertions.assertThat - -class GeneralSettingsTest : BasePlatformTestCase() { - - fun testOpenAISettingsSync() { - val openAISettings = OpenAISettings.getCurrentState() - openAISettings.model = "gpt-3.5-turbo" - val conversation = Conversation() - conversation.model = "gpt-4" - conversation.clientCode = "chat.completion" - val settings = GeneralSettings.getInstance() - - settings.sync(conversation) - - assertThat(settings.state.selectedService).isEqualTo(ServiceType.OPENAI) - assertThat(openAISettings.model).isEqualTo("gpt-4") - } - - fun testCustomOpenAISettingsSync() { - val conversation = Conversation() - conversation.clientCode = "custom.openai.chat.completion" - val settings = GeneralSettings.getInstance() - settings.state.selectedService = ServiceType.OPENAI - - settings.sync(conversation) - - assertThat(settings.state.selectedService).isEqualTo(ServiceType.CUSTOM_OPENAI) - } - - fun testLlamaSettingsModelPathSync() { - val llamaSettings = LlamaSettings.getCurrentState() - llamaSettings.huggingFaceModel = HuggingFaceModel.WIZARD_CODER_PYTHON_7B_Q3 - val conversation = Conversation() - conversation.model = "TEST_LLAMA_MODEL_PATH" - conversation.clientCode = "llama.chat.completion" - val settings = GeneralSettings.getInstance() - - settings.sync(conversation) - - assertThat(settings.state.selectedService).isEqualTo(ServiceType.LLAMA_CPP) - assertThat(llamaSettings.customLlamaModelPath).isEqualTo("TEST_LLAMA_MODEL_PATH") - assertThat(llamaSettings.isUseCustomModel).isTrue() - } - - fun testLlamaSettingsHuggingFaceModelSync() { - val llamaSettings = LlamaSettings.getCurrentState() - llamaSettings.huggingFaceModel = HuggingFaceModel.WIZARD_CODER_PYTHON_7B_Q3 - val conversation = Conversation() - conversation.model = "CODE_LLAMA_7B_Q3" - conversation.clientCode = "llama.chat.completion" - val settings = GeneralSettings.getInstance() - - settings.sync(conversation) - - assertThat(settings.state.selectedService).isEqualTo(ServiceType.LLAMA_CPP) - assertThat(llamaSettings.huggingFaceModel).isEqualTo(HuggingFaceModel.CODE_LLAMA_7B_Q3) - assertThat(llamaSettings.isUseCustomModel).isFalse() - } -} 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 ae9a5093..24b58317 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanelTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanelTest.kt @@ -81,13 +81,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { ) assertThat(panel.conversation) .isNotNull() - .extracting("id", "model", "clientCode", "discardTokenLimit") - .containsExactly( - conversation.id, - conversation.model, - conversation.clientCode, - false - ) + .extracting("id", "discardTokenLimit") + .containsExactly(conversation.id, false) val messages = panel.conversation.messages assertThat(messages).hasSize(1) assertThat(messages[0]) @@ -179,13 +174,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { ) assertThat(panel.conversation) .isNotNull() - .extracting("id", "model", "clientCode", "discardTokenLimit") - .containsExactly( - conversation.id, - conversation.model, - conversation.clientCode, - false - ) + .extracting("id", "discardTokenLimit") + .containsExactly(conversation.id, false) val messages = panel.conversation.messages assertThat(messages).hasSize(1) assertThat(messages[0]) @@ -269,13 +259,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { ) assertThat(panel.conversation) .isNotNull() - .extracting("id", "model", "clientCode", "discardTokenLimit") - .containsExactly( - conversation.id, - conversation.model, - conversation.clientCode, - false - ) + .extracting("id", "discardTokenLimit") + .containsExactly(conversation.id, false) val messages = panel.conversation.messages assertThat(messages).hasSize(1) assertThat(messages[0]) @@ -377,13 +362,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { ) assertThat(panel.conversation) .isNotNull() - .extracting("id", "model", "clientCode", "discardTokenLimit") - .containsExactly( - conversation.id, - conversation.model, - conversation.clientCode, - false - ) + .extracting("id", "discardTokenLimit") + .containsExactly(conversation.id, false) val messages = panel.conversation.messages assertThat(messages).hasSize(1) assertThat(messages[0]) @@ -459,13 +439,8 @@ class ChatToolWindowTabPanelTest : IntegrationTest() { } assertThat(panel.conversation) .isNotNull() - .extracting("id", "model", "clientCode", "discardTokenLimit") - .containsExactly( - conversation.id, - conversation.model, - conversation.clientCode, - false - ) + .extracting("id", "discardTokenLimit") + .containsExactly(conversation.id, false) val messages = panel.conversation.messages assertThat(messages).hasSize(1) assertThat(messages[0]) diff --git a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/CompleteOutputParserTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/CompleteOutputParserTest.kt new file mode 100644 index 00000000..e69de29b diff --git a/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/StreamOutputParserTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/toolwindow/chat/StreamOutputParserTest.kt new file mode 100644 index 00000000..e69de29b