Skip to content

Commit 33d6aad

Browse files
authored
Merge pull request #596 from devoxx/issue-595
Fix #595 : Increased default chat memory + Removed add user message '…
2 parents 203bc5e + fe6c4b4 commit 33d6aad

File tree

9 files changed

+49
-57
lines changed

9 files changed

+49
-57
lines changed

src/main/java/com/devoxx/genie/model/Constant.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private Constant() {
5454
public static final Integer MAX_OUTPUT_TOKENS = 4000;
5555
public static final Integer MAX_RETRIES = 1;
5656
public static final Integer TIMEOUT = 180;
57-
public static final Integer MAX_MEMORY = 10;
57+
public static final Integer MAX_MEMORY = 50;
5858

5959
// Hide Search Button
6060
public static final Boolean ENABLE_WEB_SEARCH = false;

src/main/java/com/devoxx/genie/service/MessageCreationService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public static MessageCreationService getInstance() {
7070
* @param chatMessageContext the chat message context
7171
*/
7272
public void addUserMessageToContext(@NotNull ChatMessageContext chatMessageContext) {
73+
log.debug("Adding user message to context: userPrompt={}", chatMessageContext.getUserPrompt());
74+
7375
// Check if user message already exists to prevent duplicates
7476
if (chatMessageContext.getUserMessage() != null) {
7577
// Message already exists, skip creating another one

src/main/java/com/devoxx/genie/service/prompt/memory/ChatMemoryManager.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import dev.langchain4j.data.message.SystemMessage;
1515
import dev.langchain4j.data.message.UserMessage;
1616
import dev.langchain4j.memory.ChatMemory;
17-
import dev.langchain4j.model.bedrock.BedrockChatModel;
1817
import lombok.extern.slf4j.Slf4j;
1918
import org.jetbrains.annotations.NotNull;
2019

src/main/java/com/devoxx/genie/service/prompt/memory/ChatMemoryService.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@
2323
@Slf4j
2424
public class ChatMemoryService implements ChatMemoryProvider {
2525

26+
public static final String CHAT_MEMORY_NOT_INITIALIZED_FOR_PROJECT = "Chat memory not initialized for project: ";
27+
public static final String FAILED_TO_REMOVE_MESSAGES_FROM_MEMORY = "Failed to remove messages from memory";
28+
public static final String FAILED_TO_GET_CHAT_MEMORY_FOR_PROJECT_HASH = "Failed to get chat memory for project hash: ";
29+
public static final String FAILED_TO_INITIALIZE_CHAT_MEMORY_FOR_PROJECT = "Failed to initialize chat memory for project: ";
30+
public static final String FAILED_TO_CLEAR_MEMORY = "Failed to clear memory";
31+
public static final String FAILED_TO_ADD_MESSAGE_TO_MEMORY = "Failed to add message to memory";
32+
public static final String FAILED_TO_GET_MESSAGES_FROM_MEMORY = "Failed to get messages from memory";
33+
public static final String FAILED_TO_CHECK_IF_MEMORY_IS_EMPTY = "Failed to check if memory is empty";
34+
public static final String FAILED_TO_REMOVE_LAST_MESSAGE_FROM_MEMORY = "Failed to remove last message from memory";
35+
2636
private final Map<String, MessageWindowChatMemory> projectConversations = new ConcurrentHashMap<>();
2737
private final InMemoryChatMemoryStore inMemoryChatMemoryStore = new InMemoryChatMemoryStore();
2838

@@ -48,7 +58,7 @@ public void initialize(@NotNull Project project, int chatMemorySize) {
4858

4959
createChatMemory(projectHash, chatMemorySize);
5060
} catch (Exception e) {
51-
throw new MemoryException("Failed to initialize chat memory for project: " + projectHash, e);
61+
throw new MemoryException(FAILED_TO_INITIALIZE_CHAT_MEMORY_FOR_PROJECT + projectHash, e);
5262
}
5363
}
5464

@@ -67,7 +77,7 @@ public void clearMemory(@NotNull Project project) {
6777
log.warn("Attempted to clear memory for non-existent project: {}", projectHash);
6878
}
6979
} catch (Exception e) {
70-
throw new MemoryException("Failed to clear memory", e);
80+
throw new MemoryException(FAILED_TO_CLEAR_MEMORY, e);
7181
}
7282
}
7383

@@ -101,11 +111,11 @@ public void addMessage(@NotNull Project project, ChatMessage chatMessage) {
101111
memory.add(chatMessage);
102112
log.debug("Successfully added message to project: {}, message type: {}", projectHash, chatMessage.getClass().getSimpleName());
103113
} else {
104-
throw new MemoryException("Chat memory not initialized for project: " + projectHash);
114+
throw new MemoryException(CHAT_MEMORY_NOT_INITIALIZED_FOR_PROJECT + projectHash);
105115
}
106116
} catch (Exception e) {
107117
if (!(e instanceof MemoryException)) {
108-
throw new MemoryException("Failed to add message to memory", e);
118+
throw new MemoryException(FAILED_TO_ADD_MESSAGE_TO_MEMORY, e);
109119
}
110120
throw e;
111121
}
@@ -123,11 +133,11 @@ public List<ChatMessage> getMessages(@NotNull Project project) {
123133
if (memory != null) {
124134
return memory.messages();
125135
} else {
126-
throw new MemoryException("Chat memory not initialized for project: " + projectHash);
136+
throw new MemoryException(CHAT_MEMORY_NOT_INITIALIZED_FOR_PROJECT + projectHash);
127137
}
128138
} catch (Exception e) {
129139
if (!(e instanceof MemoryException)) {
130-
throw new MemoryException("Failed to get messages from memory", e);
140+
throw new MemoryException(FAILED_TO_GET_MESSAGES_FROM_MEMORY, e);
131141
}
132142
throw e;
133143
}
@@ -149,7 +159,7 @@ public boolean isEmpty(@NotNull Project project) {
149159
return true;
150160
}
151161
} catch (Exception e) {
152-
throw new MemoryException("Failed to check if memory is empty", e);
162+
throw new MemoryException(FAILED_TO_CHECK_IF_MEMORY_IS_EMPTY, e);
153163
}
154164
}
155165

@@ -176,11 +186,11 @@ public void removeLastMessage(@NotNull Project project) {
176186
lastMessage.getClass().getSimpleName(), projectHash);
177187
}
178188
} else {
179-
throw new MemoryException("Chat memory not initialized for project: " + projectHash);
189+
throw new MemoryException(CHAT_MEMORY_NOT_INITIALIZED_FOR_PROJECT + projectHash);
180190
}
181191
} catch (Exception e) {
182192
if (!(e instanceof MemoryException)) {
183-
throw new MemoryException("Failed to remove last message from memory", e);
193+
throw new MemoryException(FAILED_TO_REMOVE_LAST_MESSAGE_FROM_MEMORY, e);
184194
}
185195
throw e;
186196
}
@@ -212,11 +222,11 @@ public void removeMessages(@NotNull Project project, List<ChatMessage> messagesT
212222
messagesToRemove.size(), projectHash);
213223
}
214224
} else {
215-
throw new MemoryException("Chat memory not initialized for project: " + projectHash);
225+
throw new MemoryException(CHAT_MEMORY_NOT_INITIALIZED_FOR_PROJECT + projectHash);
216226
}
217227
} catch (Exception e) {
218228
if (!(e instanceof MemoryException)) {
219-
throw new MemoryException("Failed to remove messages from memory", e);
229+
throw new MemoryException(FAILED_TO_REMOVE_MESSAGES_FROM_MEMORY, e);
220230
}
221231
throw e;
222232
}
@@ -242,7 +252,7 @@ public ChatMemory get(Object projectHash) {
242252
try {
243253
return projectConversations.get(projectHash.toString());
244254
} catch (Exception e) {
245-
throw new MemoryException("Failed to get chat memory for project hash: " + projectHash, e);
255+
throw new MemoryException(FAILED_TO_GET_CHAT_MEMORY_FOR_PROJECT_HASH + projectHash, e);
246256
}
247257
}
248258
}

src/main/java/com/devoxx/genie/service/prompt/strategy/AbstractPromptExecutionStrategy.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
import com.devoxx.genie.service.prompt.error.ExecutionException;
66
import com.devoxx.genie.service.prompt.error.PromptErrorHandler;
77
import com.devoxx.genie.service.prompt.memory.ChatMemoryManager;
8+
import com.devoxx.genie.service.prompt.memory.ChatMemoryService;
89
import com.devoxx.genie.service.prompt.result.PromptResult;
910
import com.devoxx.genie.service.prompt.threading.PromptTask;
1011
import com.devoxx.genie.service.prompt.threading.ThreadPoolManager;
1112
import com.devoxx.genie.ui.panel.PromptOutputPanel;
1213
import com.intellij.openapi.project.Project;
14+
import dev.langchain4j.data.message.UserMessage;
1315
import lombok.extern.slf4j.Slf4j;
1416
import org.jetbrains.annotations.NotNull;
1517

@@ -126,11 +128,18 @@ protected abstract void executeStrategySpecific(ChatMessageContext context,
126128
public void prepareMemory(ChatMessageContext context) {
127129
// Prepare memory with system message if needed and add user message
128130
log.debug("Before memory preparation - context ID: {}", context.getId());
131+
129132
chatMemoryManager.prepareMemory(context);
133+
130134
// Add context information to the user message before adding to memory
131135
messageCreationService.addUserMessageToContext(context);
132-
// Now add the enriched user message to chat memory
133-
chatMemoryManager.addUserMessage(context);
136+
137+
// Check if user message was properly created
138+
if (context.getUserMessage() == null) {
139+
log.error("Failed to create user message for context ID: {}", context.getId());
140+
// Create a fallback user message if needed
141+
context.setUserMessage(UserMessage.from(context.getUserPrompt()));
142+
}
134143
}
135144

136145
/**

src/main/resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<Li>Feat #586 : Added Gemini 2.5 Pro model by @stephanj</LI>
4141
<LI>Fix #588 : [Regression] Fix streaming responses by @stephanj</LI>
4242
<LI>Feat #590 : User can now configure which keys to use for newline by @stephanj</LI>
43+
<LI>Fix #595 : At least one message is required by @stephanj</LI>
4344
</UL>
4445
<h2>v0.5.2</h2>
4546
<UL>

src/test/java/com/devoxx/genie/service/prompt/strategy/AbstractPromptExecutionStrategyTest.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -83,21 +83,6 @@ private void mockStaticDependencies() {
8383
}
8484
}
8585

86-
@Test
87-
void prepareMemory_shouldCallMessageCreationServiceBeforeChatMemoryManager() {
88-
// Arrange
89-
when(mockProject.getName()).thenReturn("TestProject");
90-
91-
// Act
92-
testStrategy.prepareMemory(mockChatMessageContext);
93-
94-
// Assert - verify correct order of operations
95-
InOrder inOrder = inOrder(mockChatMemoryManager, mockMessageCreationService);
96-
inOrder.verify(mockChatMemoryManager).prepareMemory(mockChatMessageContext);
97-
inOrder.verify(mockMessageCreationService).addUserMessageToContext(mockChatMessageContext);
98-
inOrder.verify(mockChatMemoryManager).addUserMessage(mockChatMessageContext);
99-
}
100-
10186
/**
10287
* Test implementation of the abstract class
10388
*/

src/test/java/com/devoxx/genie/service/prompt/strategy/NonStreamingPromptStrategyTest.java

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -155,30 +155,6 @@ void setUp() {
155155
);
156156
}
157157

158-
159-
@Test
160-
void executeStrategySpecific_shouldNotCallAddUserMessageToContextAgain() {
161-
// Arrange
162-
// Setup to execute the actual prepareMemory method which will call addUserMessageToContext
163-
doCallRealMethod().when(mockChatMemoryManager).prepareMemory(any());
164-
165-
// Act
166-
strategy.executeStrategySpecific(mockChatMessageContext, mockPanel, mockResultTask);
167-
168-
// Assert - verify addUserMessageToContext is called exactly once (by the parent class's prepareMemory method)
169-
// The NonStreamingPromptExecutionService should not call it again
170-
verify(mockMessageCreationService, times(1)).addUserMessageToContext(mockChatMessageContext);
171-
}
172-
173-
@Test
174-
void executeStrategySpecific_shouldUseChatMemoryManagerToAddUserMessage() {
175-
// Act
176-
strategy.executeStrategySpecific(mockChatMessageContext, mockPanel, mockResultTask);
177-
178-
// Assert - verify prepareMemory is called, which internally handles addUserMessage
179-
verify(mockChatMemoryManager).prepareMemory(mockChatMessageContext);
180-
}
181-
182158
@org.junit.jupiter.api.AfterEach
183159
void tearDown() {
184160
// Close all static mocks to prevent memory leaks

src/test/java/com/devoxx/genie/service/prompt/strategy/StreamingPromptStrategyTest.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void setUp() {
105105
// Setup services in the application
106106
when(mockApplication.getService(ChatMemoryManager.class)).thenReturn(mockChatMemoryManager);
107107
when(mockApplication.getService(ThreadPoolManager.class)).thenReturn(mockThreadPoolManager);
108-
when(mockApplication.getService(MessageCreationService.class)).thenReturn(mockMessageCreationService);
108+
// when(mockApplication.getService(MessageCreationService.class)).thenReturn(mockMessageCreationService);
109109
when(mockApplication.getService(ChatMemoryService.class)).thenReturn(mockChatMemoryService);
110110

111111
// Setup static getInstance methods
@@ -122,6 +122,16 @@ void setUp() {
122122
when(mockThreadPoolManager.getPromptExecutionPool()).thenReturn(mockExecutor);
123123
when(mockChatMessageContext.getProject()).thenReturn(mockProject);
124124
when(mockChatMessageContext.getStreamingChatLanguageModel()).thenReturn(mockStreamingModel);
125+
// Mock userPrompt to prevent "text cannot be null or blank" exception
126+
when(mockChatMessageContext.getUserPrompt()).thenReturn("Test user prompt");
127+
128+
// Mock the behavior of addUserMessageToContext to set a user message on the context
129+
doAnswer(invocation -> {
130+
ChatMessageContext ctx = invocation.getArgument(0);
131+
when(ctx.getUserMessage()).thenReturn(dev.langchain4j.data.message.UserMessage.from("Test user prompt"));
132+
return null;
133+
}).when(mockMessageCreationService).addUserMessageToContext(any(ChatMessageContext.class));
134+
125135
List<ChatMessage> messages = new ArrayList<>();
126136
when(mockChatMemoryService.getMessages(any(Project.class))).thenReturn(messages);
127137

@@ -150,7 +160,7 @@ void setUp() {
150160
void executeStrategySpecific_shouldFollowCorrectMessageFlowOrder() {
151161
// Arrange
152162
// Use inOrder to verify the exact sequence of method calls
153-
org.mockito.InOrder inOrder = inOrder(mockChatMemoryManager, mockMessageCreationService);
163+
org.mockito.InOrder inOrder = inOrder(mockChatMemoryManager);
154164

155165
// Act
156166
strategy.executeStrategySpecific(mockChatMessageContext, mockPanel, mockResultTask);

0 commit comments

Comments
 (0)