mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-14 00:24:07 -08:00
feat(editor): Restrict when a ChatTrigger Node is added automatically (#11523)
This commit is contained in:
parent
3e0c6cb3d2
commit
93a6f858fa
|
@ -359,6 +359,14 @@ describe('Langchain Integration', () => {
|
|||
getConnectionBySourceAndTarget(CHAT_TRIGGER_NODE_DISPLAY_NAME, AGENT_NODE_NAME).should('exist');
|
||||
getNodes().should('have.length', 3);
|
||||
});
|
||||
it('should not auto-add nodes if ChatTrigger is already present', () => {
|
||||
addNodeToCanvas(MANUAL_CHAT_TRIGGER_NODE_NAME, true);
|
||||
addNodeToCanvas(AGENT_NODE_NAME, true);
|
||||
|
||||
addNodeToCanvas(AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME, true);
|
||||
getConnectionBySourceAndTarget(CHAT_TRIGGER_NODE_DISPLAY_NAME, AGENT_NODE_NAME).should('exist');
|
||||
getNodes().should('have.length', 3);
|
||||
});
|
||||
it('should render runItems for sub-nodes and allow switching between them', () => {
|
||||
const workflowPage = new WorkflowPage();
|
||||
const ndv = new NDV();
|
||||
|
|
|
@ -19,7 +19,6 @@ import {
|
|||
AI_CATEGORY_LANGUAGE_MODELS,
|
||||
BASIC_CHAIN_NODE_TYPE,
|
||||
CHAT_TRIGGER_NODE_TYPE,
|
||||
MANUAL_CHAT_TRIGGER_NODE_TYPE,
|
||||
MANUAL_TRIGGER_NODE_TYPE,
|
||||
NODE_CREATOR_OPEN_SOURCES,
|
||||
NO_OP_NODE_TYPE,
|
||||
|
@ -204,8 +203,6 @@ export const useActions = () => {
|
|||
);
|
||||
}
|
||||
function shouldPrependChatTrigger(addedNodes: AddedNode[]): boolean {
|
||||
const { allNodes } = useWorkflowsStore();
|
||||
|
||||
const COMPATIBLE_CHAT_NODES = [
|
||||
QA_CHAIN_NODE_TYPE,
|
||||
AGENT_NODE_TYPE,
|
||||
|
@ -214,13 +211,25 @@ export const useActions = () => {
|
|||
OPEN_AI_NODE_MESSAGE_ASSISTANT_TYPE,
|
||||
];
|
||||
|
||||
const isChatTriggerMissing =
|
||||
allNodes.find((node) =>
|
||||
[MANUAL_CHAT_TRIGGER_NODE_TYPE, CHAT_TRIGGER_NODE_TYPE].includes(node.type),
|
||||
) === undefined;
|
||||
const isCompatibleNode = addedNodes.some((node) => COMPATIBLE_CHAT_NODES.includes(node.type));
|
||||
|
||||
return isCompatibleNode && isChatTriggerMissing;
|
||||
if (!isCompatibleNode) return false;
|
||||
|
||||
const { allNodes, getNodeTypes } = useWorkflowsStore();
|
||||
const { getByNameAndVersion } = getNodeTypes();
|
||||
|
||||
// We want to add a trigger if there are no triggers other than Manual Triggers
|
||||
// Performance here should be fine as `getByNameAndVersion` fetches nodeTypes once in bulk
|
||||
// and `every` aborts on first `false`
|
||||
const shouldAddChatTrigger = allNodes.every((node) => {
|
||||
const nodeType = getByNameAndVersion(node.type, node.typeVersion);
|
||||
|
||||
return (
|
||||
!nodeType.description.group.includes('trigger') || node.type === MANUAL_TRIGGER_NODE_TYPE
|
||||
);
|
||||
});
|
||||
|
||||
return shouldAddChatTrigger;
|
||||
}
|
||||
|
||||
// AI-226: Prepend LLM Chain node when adding a language model
|
||||
|
|
|
@ -5,6 +5,8 @@ import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
|||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useActions } from './composables/useActions';
|
||||
import {
|
||||
AGENT_NODE_TYPE,
|
||||
GITHUB_TRIGGER_NODE_TYPE,
|
||||
HTTP_REQUEST_NODE_TYPE,
|
||||
MANUAL_TRIGGER_NODE_TYPE,
|
||||
NODE_CREATOR_OPEN_SOURCES,
|
||||
|
@ -15,6 +17,7 @@ import {
|
|||
TRIGGER_NODE_CREATOR_VIEW,
|
||||
WEBHOOK_NODE_TYPE,
|
||||
} from '@/constants';
|
||||
import { CHAT_TRIGGER_NODE_TYPE } from 'n8n-workflow';
|
||||
|
||||
describe('useActions', () => {
|
||||
beforeAll(() => {
|
||||
|
@ -54,6 +57,9 @@ describe('useActions', () => {
|
|||
vi.spyOn(workflowsStore, 'workflowTriggerNodes', 'get').mockReturnValue([
|
||||
{ type: SCHEDULE_TRIGGER_NODE_TYPE } as never,
|
||||
]);
|
||||
vi.spyOn(workflowsStore, 'getNodeTypes').mockReturnValue({
|
||||
getByNameAndVersion: () => ({ description: { group: ['trigger'] } }),
|
||||
} as never);
|
||||
vi.spyOn(nodeCreatorStore, 'openSource', 'get').mockReturnValue(
|
||||
NODE_CREATOR_OPEN_SOURCES.ADD_NODE_BUTTON,
|
||||
);
|
||||
|
@ -67,6 +73,100 @@ describe('useActions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('should insert a ChatTrigger node when an AI Agent is added without trigger', () => {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
vi.spyOn(workflowsStore, 'workflowTriggerNodes', 'get').mockReturnValue([]);
|
||||
|
||||
const { getAddedNodesAndConnections } = useActions();
|
||||
|
||||
expect(getAddedNodesAndConnections([{ type: AGENT_NODE_TYPE }])).toEqual({
|
||||
connections: [
|
||||
{
|
||||
from: {
|
||||
nodeIndex: 0,
|
||||
},
|
||||
to: {
|
||||
nodeIndex: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
nodes: [
|
||||
{ type: CHAT_TRIGGER_NODE_TYPE, isAutoAdd: true },
|
||||
{ type: AGENT_NODE_TYPE, openDetail: true },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('should insert a ChatTrigger node when an AI Agent is added with only a Manual Trigger', () => {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
vi.spyOn(workflowsStore, 'workflowTriggerNodes', 'get').mockReturnValue([
|
||||
{ type: MANUAL_TRIGGER_NODE_TYPE } as never,
|
||||
]);
|
||||
vi.spyOn(workflowsStore, 'getNodeTypes').mockReturnValue({
|
||||
getByNameAndVersion: () => ({ description: { group: ['trigger'] } }),
|
||||
} as never);
|
||||
|
||||
const { getAddedNodesAndConnections } = useActions();
|
||||
|
||||
expect(getAddedNodesAndConnections([{ type: AGENT_NODE_TYPE }])).toEqual({
|
||||
connections: [
|
||||
{
|
||||
from: {
|
||||
nodeIndex: 0,
|
||||
},
|
||||
to: {
|
||||
nodeIndex: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
nodes: [
|
||||
{ type: CHAT_TRIGGER_NODE_TYPE, isAutoAdd: true },
|
||||
{ type: AGENT_NODE_TYPE, openDetail: true },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('should not insert a ChatTrigger node when an AI Agent is added with a trigger already present', () => {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
vi.spyOn(workflowsStore, 'allNodes', 'get').mockReturnValue([
|
||||
{ type: GITHUB_TRIGGER_NODE_TYPE } as never,
|
||||
]);
|
||||
vi.spyOn(workflowsStore, 'getNodeTypes').mockReturnValue({
|
||||
getByNameAndVersion: () => ({ description: { group: ['trigger'] } }),
|
||||
} as never);
|
||||
|
||||
const { getAddedNodesAndConnections } = useActions();
|
||||
|
||||
expect(getAddedNodesAndConnections([{ type: AGENT_NODE_TYPE }])).toEqual({
|
||||
connections: [],
|
||||
nodes: [{ type: AGENT_NODE_TYPE, openDetail: true }],
|
||||
});
|
||||
});
|
||||
|
||||
test('should not insert a ChatTrigger node when an AI Agent is added with a Chat Trigger already present', () => {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
vi.spyOn(workflowsStore, 'workflowTriggerNodes', 'get').mockReturnValue([
|
||||
{ type: CHAT_TRIGGER_NODE_TYPE } as never,
|
||||
]);
|
||||
vi.spyOn(workflowsStore, 'allNodes', 'get').mockReturnValue([
|
||||
{ type: CHAT_TRIGGER_NODE_TYPE } as never,
|
||||
]);
|
||||
vi.spyOn(workflowsStore, 'getNodeTypes').mockReturnValue({
|
||||
getByNameAndVersion: () => ({ description: { group: ['trigger'] } }),
|
||||
} as never);
|
||||
|
||||
const { getAddedNodesAndConnections } = useActions();
|
||||
|
||||
expect(getAddedNodesAndConnections([{ type: AGENT_NODE_TYPE }])).toEqual({
|
||||
connections: [],
|
||||
nodes: [{ type: AGENT_NODE_TYPE, openDetail: true }],
|
||||
});
|
||||
});
|
||||
|
||||
test('should insert a No Op node when a Loop Over Items Node is added', () => {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const nodeCreatorStore = useNodeCreatorStore();
|
||||
|
|
Loading…
Reference in a new issue