fix(Chat Memory Manager Node): Fix simplifyMessages to not overwrite consecutive messages of same type (#16168)

This commit is contained in:
Yiorgis Gozadinos
2025-06-11 09:54:49 +02:00
committed by GitHub
parent cdab4c1bc6
commit 5015290dbe
2 changed files with 127 additions and 17 deletions

View File

@@ -1,6 +1,7 @@
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
import type { BaseChatMemory } from '@langchain/community/memory/chat_memory';
import { AIMessage, SystemMessage, HumanMessage, type BaseMessage } from '@langchain/core/messages';
import type { MessageContent, BaseMessage } from '@langchain/core/messages';
import { AIMessage, SystemMessage, HumanMessage } from '@langchain/core/messages';
import { NodeConnectionTypes } from 'n8n-workflow';
import type {
IDataObject,
@@ -17,24 +18,31 @@ interface MessageRecord {
hideFromUI: boolean;
}
function simplifyMessages(messages: BaseMessage[]) {
const chunkedMessages = [];
for (let i = 0; i < messages.length; i += 2) {
chunkedMessages.push([messages[i], messages[i + 1]]);
export function simplifyMessages(messages: BaseMessage[]): Array<Record<string, MessageContent>> {
if (messages.length === 0) return [];
const result: Array<Record<string, MessageContent>> = [];
let index = 0;
while (index < messages.length) {
const currentGroup: Record<string, MessageContent> = {};
do {
const message = messages[index];
const messageType = message.getType();
if (messageType in currentGroup) {
break;
}
const transformedMessages = chunkedMessages.map((exchange) => {
const simplified = {
[exchange[0]._getType()]: exchange[0].content,
};
currentGroup[messageType] = message.content;
index++;
} while (index < messages.length);
if (exchange[1]) {
simplified[exchange[1]._getType()] = exchange[1].content;
result.push(currentGroup);
}
return simplified;
});
return transformedMessages;
return result;
}
const prepareOutputSetup = (ctx: IExecuteFunctions, version: number, memory: BaseChatMemory) => {

View File

@@ -0,0 +1,102 @@
import { AIMessage, HumanMessage, SystemMessage } from '@langchain/core/messages';
import { simplifyMessages } from '../MemoryManager.node';
describe('simplifyMessages', () => {
it('should handle single message', () => {
const messages = [new HumanMessage('Hello')];
const result = simplifyMessages(messages);
expect(result).toEqual([{ human: 'Hello' }]);
});
it('should group different message types together', () => {
const messages = [
new HumanMessage('Hello, how are you?'),
new AIMessage("I'm doing well, thank you for asking! How about you?"),
];
const result = simplifyMessages(messages);
expect(result).toEqual([
{
human: 'Hello, how are you?',
ai: "I'm doing well, thank you for asking! How about you?",
},
]);
});
it('should separate consecutive messages of same type into different groups', () => {
const messages = [
new HumanMessage('First human message'),
new HumanMessage('Second human message'),
new AIMessage('AI response'),
];
const result = simplifyMessages(messages);
expect(result).toEqual([
{ human: 'First human message' },
{ human: 'Second human message', ai: 'AI response' },
]);
});
it('should handle three consecutive messages of same type', () => {
const messages = [new HumanMessage('1'), new HumanMessage('2'), new HumanMessage('3')];
const result = simplifyMessages(messages);
expect(result).toEqual([{ human: '1' }, { human: '2' }, { human: '3' }]);
});
it('should handle mixed message types with grouping', () => {
const messages = [
new SystemMessage('System message'),
new HumanMessage('Hello'),
new AIMessage('Hi there'),
new HumanMessage('Another human message'),
new AIMessage('Another AI message'),
];
const result = simplifyMessages(messages);
expect(result).toEqual([
{
system: 'System message',
human: 'Hello',
ai: 'Hi there',
},
{
human: 'Another human message',
ai: 'Another AI message',
},
]);
});
it('should handle system messages correctly', () => {
const messages = [
new SystemMessage('System instruction'),
new HumanMessage('User question'),
new AIMessage('AI response'),
];
const result = simplifyMessages(messages);
expect(result).toEqual([
{
system: 'System instruction',
human: 'User question',
ai: 'AI response',
},
]);
});
it('should handle alternating same types correctly', () => {
const messages = [
new HumanMessage('Human 1'),
new AIMessage('AI 1'),
new HumanMessage('Human 2'),
new AIMessage('AI 2'),
];
const result = simplifyMessages(messages);
expect(result).toEqual([
{
human: 'Human 1',
ai: 'AI 1',
},
{
human: 'Human 2',
ai: 'AI 2',
},
]);
});
});