mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
fix(AI Agent Node): Allow removal of system message (#14407)
This commit is contained in:
@@ -263,7 +263,7 @@ export class Agent implements INodeType {
|
|||||||
icon: 'fa:robot',
|
icon: 'fa:robot',
|
||||||
iconColor: 'black',
|
iconColor: 'black',
|
||||||
group: ['transform'],
|
group: ['transform'],
|
||||||
version: [1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8],
|
version: [1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9],
|
||||||
description: 'Generates an action plan and executes it. Can use external tools.',
|
description: 'Generates an action plan and executes it. Can use external tools.',
|
||||||
subtitle:
|
subtitle:
|
||||||
"={{ { toolsAgent: 'Tools Agent', conversationalAgent: 'Conversational Agent', openAiFunctionsAgent: 'OpenAI Functions Agent', reActAgent: 'ReAct Agent', sqlAgent: 'SQL Agent', planAndExecuteAgent: 'Plan and Execute Agent' }[$parameter.agent] }}",
|
"={{ { toolsAgent: 'Tools Agent', conversationalAgent: 'Conversational Agent', openAiFunctionsAgent: 'OpenAI Functions Agent', reActAgent: 'ReAct Agent', sqlAgent: 'SQL Agent', planAndExecuteAgent: 'Plan and Execute Agent' }[$parameter.agent] }}",
|
||||||
|
|||||||
@@ -346,11 +346,20 @@ export async function prepareMessages(
|
|||||||
outputParser?: N8nOutputParser;
|
outputParser?: N8nOutputParser;
|
||||||
},
|
},
|
||||||
): Promise<BaseMessagePromptTemplateLike[]> {
|
): Promise<BaseMessagePromptTemplateLike[]> {
|
||||||
const messages: BaseMessagePromptTemplateLike[] = [
|
const useSystemMessage = options.systemMessage ?? ctx.getNode().typeVersion < 1.9;
|
||||||
['system', `{system_message}${options.outputParser ? '\n\n{formatting_instructions}' : ''}`],
|
|
||||||
['placeholder', '{chat_history}'],
|
const messages: BaseMessagePromptTemplateLike[] = [];
|
||||||
['human', '{input}'],
|
|
||||||
];
|
if (useSystemMessage) {
|
||||||
|
messages.push([
|
||||||
|
'system',
|
||||||
|
`{system_message}${options.outputParser ? '\n\n{formatting_instructions}' : ''}`,
|
||||||
|
]);
|
||||||
|
} else if (options.outputParser) {
|
||||||
|
messages.push(['system', '{formatting_instructions}']);
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.push(['placeholder', '{chat_history}'], ['human', '{input}']);
|
||||||
|
|
||||||
// If there is binary data and the node option permits it, add a binary message
|
// If there is binary data and the node option permits it, add a binary message
|
||||||
const hasBinaryData = ctx.getInputData()?.[itemIndex]?.binary !== undefined;
|
const hasBinaryData = ctx.getInputData()?.[itemIndex]?.binary !== undefined;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Buffer } from 'buffer';
|
|||||||
import { mock } from 'jest-mock-extended';
|
import { mock } from 'jest-mock-extended';
|
||||||
import type { ToolsAgentAction } from 'langchain/dist/agents/tool_calling/output_parser';
|
import type { ToolsAgentAction } from 'langchain/dist/agents/tool_calling/output_parser';
|
||||||
import type { Tool } from 'langchain/tools';
|
import type { Tool } from 'langchain/tools';
|
||||||
import type { IExecuteFunctions } from 'n8n-workflow';
|
import type { IExecuteFunctions, INode } from 'n8n-workflow';
|
||||||
import { NodeOperationError, BINARY_ENCODING, NodeConnectionTypes } from 'n8n-workflow';
|
import { NodeOperationError, BINARY_ENCODING, NodeConnectionTypes } from 'n8n-workflow';
|
||||||
import type { ZodType } from 'zod';
|
import type { ZodType } from 'zod';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@@ -232,6 +232,75 @@ describe('prepareMessages', () => {
|
|||||||
const hasHumanMessage = messages.some((m) => m instanceof HumanMessage);
|
const hasHumanMessage = messages.some((m) => m instanceof HumanMessage);
|
||||||
expect(hasHumanMessage).toBe(false);
|
expect(hasHumanMessage).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not include system_message in prompt templates if not provided after version 1.9', async () => {
|
||||||
|
const fakeItem = { json: {} };
|
||||||
|
const mockNode = mock<INode>();
|
||||||
|
mockNode.typeVersion = 1.9;
|
||||||
|
mockContext.getInputData.mockReturnValue([fakeItem]);
|
||||||
|
mockContext.getNode.mockReturnValue(mockNode);
|
||||||
|
const messages = await prepareMessages(mockContext, 0, {});
|
||||||
|
|
||||||
|
expect(messages.length).toBe(3);
|
||||||
|
expect(messages).not.toContainEqual(['system', '{system_message}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include system_message in prompt templates if provided after version 1.9', async () => {
|
||||||
|
const fakeItem = { json: {} };
|
||||||
|
const mockNode = mock<INode>();
|
||||||
|
mockNode.typeVersion = 1.9;
|
||||||
|
mockContext.getInputData.mockReturnValue([fakeItem]);
|
||||||
|
mockContext.getNode.mockReturnValue(mockNode);
|
||||||
|
|
||||||
|
const messages = await prepareMessages(mockContext, 0, { systemMessage: 'Hello' });
|
||||||
|
|
||||||
|
expect(messages.length).toBe(4);
|
||||||
|
expect(messages).toContainEqual(['system', '{system_message}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include system_message in prompt templates if not provided before version 1.9', async () => {
|
||||||
|
const fakeItem = { json: {} };
|
||||||
|
const mockNode = mock<INode>();
|
||||||
|
mockNode.typeVersion = 1.8;
|
||||||
|
mockContext.getInputData.mockReturnValue([fakeItem]);
|
||||||
|
mockContext.getNode.mockReturnValue(mockNode);
|
||||||
|
|
||||||
|
const messages = await prepareMessages(mockContext, 0, {});
|
||||||
|
|
||||||
|
expect(messages.length).toBe(4);
|
||||||
|
expect(messages).toContainEqual(['system', '{system_message}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include system_message with formatting_instructions in prompt templates if provided before version 1.9', async () => {
|
||||||
|
const fakeItem = { json: {} };
|
||||||
|
const mockNode = mock<INode>();
|
||||||
|
mockNode.typeVersion = 1.8;
|
||||||
|
mockContext.getInputData.mockReturnValue([fakeItem]);
|
||||||
|
mockContext.getNode.mockReturnValue(mockNode);
|
||||||
|
|
||||||
|
const messages = await prepareMessages(mockContext, 0, {
|
||||||
|
systemMessage: 'Hello',
|
||||||
|
outputParser: mock<N8nOutputParser>(),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(messages.length).toBe(4);
|
||||||
|
expect(messages).toContainEqual(['system', '{system_message}\n\n{formatting_instructions}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add formatting instructions when omitting system message after version 1.9', async () => {
|
||||||
|
const fakeItem = { json: {} };
|
||||||
|
const mockNode = mock<INode>();
|
||||||
|
mockNode.typeVersion = 1.9;
|
||||||
|
mockContext.getInputData.mockReturnValue([fakeItem]);
|
||||||
|
mockContext.getNode.mockReturnValue(mockNode);
|
||||||
|
|
||||||
|
const messages = await prepareMessages(mockContext, 0, {
|
||||||
|
outputParser: mock<N8nOutputParser>(),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(messages.length).toBe(4);
|
||||||
|
expect(messages).toContainEqual(['system', '{formatting_instructions}']);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('preparePrompt', () => {
|
describe('preparePrompt', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user