mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
PR Feedback
This commit is contained in:
parent
4117b5298b
commit
144f9fb44f
|
@ -658,6 +658,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
const lastInteractedWithNodeConnection = uiStore.lastInteractedWithNodeConnection;
|
const lastInteractedWithNodeConnection = uiStore.lastInteractedWithNodeConnection;
|
||||||
const lastInteractedWithNodeHandle = uiStore.lastInteractedWithNodeHandle;
|
const lastInteractedWithNodeHandle = uiStore.lastInteractedWithNodeHandle;
|
||||||
|
|
||||||
|
let connectedNodes: ReturnType<typeof createConnection> | undefined;
|
||||||
// If we have a specific endpoint to connect to
|
// If we have a specific endpoint to connect to
|
||||||
if (lastInteractedWithNodeHandle) {
|
if (lastInteractedWithNodeHandle) {
|
||||||
const { type: connectionType, mode } = parseCanvasConnectionHandleString(
|
const { type: connectionType, mode } = parseCanvasConnectionHandleString(
|
||||||
|
@ -672,31 +673,24 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mode === CanvasConnectionMode.Input) {
|
if (mode === CanvasConnectionMode.Input) {
|
||||||
createConnection(
|
connectedNodes = createConnection({
|
||||||
{
|
|
||||||
source: nodeId,
|
source: nodeId,
|
||||||
sourceHandle: nodeHandle,
|
sourceHandle: nodeHandle,
|
||||||
target: lastInteractedWithNodeId,
|
target: lastInteractedWithNodeId,
|
||||||
targetHandle: lastInteractedWithNodeHandle,
|
targetHandle: lastInteractedWithNodeHandle,
|
||||||
},
|
});
|
||||||
{ parentIsNew: true },
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
createConnection(
|
connectedNodes = createConnection({
|
||||||
{
|
|
||||||
source: lastInteractedWithNodeId,
|
source: lastInteractedWithNodeId,
|
||||||
sourceHandle: lastInteractedWithNodeHandle,
|
sourceHandle: lastInteractedWithNodeHandle,
|
||||||
target: nodeId,
|
target: nodeId,
|
||||||
targetHandle: nodeHandle,
|
targetHandle: nodeHandle,
|
||||||
},
|
});
|
||||||
{ childIsNew: true },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If a node is last selected then connect between the active and its child ones
|
// If a node is last selected then connect between the active and its child ones
|
||||||
// Connect active node to the newly created one
|
// Connect active node to the newly created one
|
||||||
createConnection(
|
connectedNodes = createConnection({
|
||||||
{
|
|
||||||
source: lastInteractedWithNodeId,
|
source: lastInteractedWithNodeId,
|
||||||
sourceHandle: createCanvasConnectionHandleString({
|
sourceHandle: createCanvasConnectionHandleString({
|
||||||
mode: CanvasConnectionMode.Output,
|
mode: CanvasConnectionMode.Output,
|
||||||
|
@ -709,9 +703,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
type: NodeConnectionType.Main,
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
}),
|
}),
|
||||||
},
|
});
|
||||||
{ childIsNew: true },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastInteractedWithNodeConnection) {
|
if (lastInteractedWithNodeConnection) {
|
||||||
|
@ -719,8 +711,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
|
|
||||||
const targetNode = workflowsStore.getNodeById(lastInteractedWithNodeConnection.target);
|
const targetNode = workflowsStore.getNodeById(lastInteractedWithNodeConnection.target);
|
||||||
if (targetNode) {
|
if (targetNode) {
|
||||||
createConnection(
|
connectedNodes = createConnection({
|
||||||
{
|
|
||||||
source: node.id,
|
source: node.id,
|
||||||
sourceHandle: createCanvasConnectionHandleString({
|
sourceHandle: createCanvasConnectionHandleString({
|
||||||
mode: CanvasConnectionMode.Input,
|
mode: CanvasConnectionMode.Input,
|
||||||
|
@ -729,11 +720,17 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
}),
|
}),
|
||||||
target: lastInteractedWithNodeConnection.target,
|
target: lastInteractedWithNodeConnection.target,
|
||||||
targetHandle: lastInteractedWithNodeConnection.targetHandle,
|
targetHandle: lastInteractedWithNodeConnection.targetHandle,
|
||||||
},
|
});
|
||||||
{ parentIsNew: true },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (connectedNodes) {
|
||||||
|
const { sourceNode, targetNode } = connectedNodes;
|
||||||
|
adjustNewNodes(sourceNode, targetNode, {
|
||||||
|
sourceIsNew: sourceNode.id === node.id,
|
||||||
|
targetIsNew: targetNode.id === node.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackAddNode(nodeData: INodeUi, options: AddNodeOptions) {
|
function trackAddNode(nodeData: INodeUi, options: AddNodeOptions) {
|
||||||
|
@ -1089,7 +1086,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
|
|
||||||
function createConnection(
|
function createConnection(
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
{ trackHistory = false, keepPristine = false, parentIsNew = false, childIsNew = false } = {},
|
{ trackHistory = false, keepPristine = false } = {},
|
||||||
) {
|
) {
|
||||||
const sourceNode = workflowsStore.getNodeById(connection.source);
|
const sourceNode = workflowsStore.getNodeById(connection.source);
|
||||||
const targetNode = workflowsStore.getNodeById(connection.target);
|
const targetNode = workflowsStore.getNodeById(connection.target);
|
||||||
|
@ -1115,7 +1112,6 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
adjustNewNodes(sourceNode, targetNode, { parentIsNew, childIsNew });
|
|
||||||
workflowsStore.addConnection({
|
workflowsStore.addConnection({
|
||||||
connection: mappedConnection,
|
connection: mappedConnection,
|
||||||
});
|
});
|
||||||
|
@ -1128,6 +1124,8 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
if (!keepPristine) {
|
if (!keepPristine) {
|
||||||
uiStore.stateIsDirty = true;
|
uiStore.stateIsDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { sourceNode, targetNode };
|
||||||
}
|
}
|
||||||
|
|
||||||
function revertCreateConnection(connection: [IConnection, IConnection]) {
|
function revertCreateConnection(connection: [IConnection, IConnection]) {
|
||||||
|
|
|
@ -2,11 +2,11 @@ import { AGENT_NODE_TYPE, CHAT_TRIGGER_NODE_TYPE, MANUAL_TRIGGER_NODE_TYPE } fro
|
||||||
import { adjustNewNodes } from '@/utils/connectionNodeUtils';
|
import { adjustNewNodes } from '@/utils/connectionNodeUtils';
|
||||||
import { createPinia, setActivePinia } from 'pinia';
|
import { createPinia, setActivePinia } from 'pinia';
|
||||||
|
|
||||||
const getParentNodesByDepth = vi.fn();
|
const getsourceNodesByDepth = vi.fn();
|
||||||
const getNode = vi.fn();
|
const getNode = vi.fn();
|
||||||
vi.mock('@/stores/workflow.store', () => ({
|
vi.mock('@/stores/workflow.store', () => ({
|
||||||
useWorkflowsStore: vi.fn(() => ({
|
useWorkflowsStore: vi.fn(() => ({
|
||||||
getParentNodesByDepth,
|
getsourceNodesByDepth,
|
||||||
getNode,
|
getNode,
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
@ -21,12 +21,12 @@ describe('adjustNewlyConnectedNodes', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('modifies promptType with ChatTrigger->new Agent', () => {
|
it('modifies promptType with ChatTrigger->new Agent', () => {
|
||||||
const parent = { type: CHAT_TRIGGER_NODE_TYPE };
|
const source = { type: CHAT_TRIGGER_NODE_TYPE };
|
||||||
const child = { type: AGENT_NODE_TYPE };
|
const target = { type: AGENT_NODE_TYPE };
|
||||||
|
|
||||||
adjustNewNodes(parent, child, { parentIsNew: false });
|
adjustNewNodes(source, target, { sourceIsNew: false });
|
||||||
|
|
||||||
expect(child).toEqual({
|
expect(target).toEqual({
|
||||||
type: AGENT_NODE_TYPE,
|
type: AGENT_NODE_TYPE,
|
||||||
parameters: {
|
parameters: {
|
||||||
promptType: 'auto',
|
promptType: 'auto',
|
||||||
|
@ -36,12 +36,12 @@ describe('adjustNewlyConnectedNodes', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('modifies promptType with new ChatTrigger->new Agent', () => {
|
it('modifies promptType with new ChatTrigger->new Agent', () => {
|
||||||
const parent = { type: CHAT_TRIGGER_NODE_TYPE };
|
const source = { type: CHAT_TRIGGER_NODE_TYPE };
|
||||||
const child = { type: AGENT_NODE_TYPE };
|
const target = { type: AGENT_NODE_TYPE };
|
||||||
|
|
||||||
adjustNewNodes(parent, child);
|
adjustNewNodes(source, target);
|
||||||
|
|
||||||
expect(child).toEqual({
|
expect(target).toEqual({
|
||||||
type: AGENT_NODE_TYPE,
|
type: AGENT_NODE_TYPE,
|
||||||
parameters: {
|
parameters: {
|
||||||
promptType: 'auto',
|
promptType: 'auto',
|
||||||
|
@ -51,42 +51,42 @@ describe('adjustNewlyConnectedNodes', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not modify promptType with ManualTrigger->new Agent', () => {
|
it('does not modify promptType with ManualTrigger->new Agent', () => {
|
||||||
const parent = { type: MANUAL_TRIGGER_NODE_TYPE };
|
const source = { type: MANUAL_TRIGGER_NODE_TYPE };
|
||||||
const child = { type: AGENT_NODE_TYPE };
|
const target = { type: AGENT_NODE_TYPE };
|
||||||
|
|
||||||
adjustNewNodes(parent, child, { parentIsNew: false });
|
adjustNewNodes(source, target, { sourceIsNew: false });
|
||||||
|
|
||||||
expect(child).toEqual({
|
expect(target).toEqual({
|
||||||
type: AGENT_NODE_TYPE,
|
type: AGENT_NODE_TYPE,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('modifies sessionId with ChatTrigger->(new Memory->Agent)', () => {
|
it('modifies sessionId with ChatTrigger->(new Memory->Agent)', () => {
|
||||||
const trigger = { type: CHAT_TRIGGER_NODE_TYPE, name: 'trigger' };
|
const trigger = { type: CHAT_TRIGGER_NODE_TYPE, name: 'trigger' };
|
||||||
getParentNodesByDepth.mockReturnValue([{ name: trigger.name }]);
|
getsourceNodesByDepth.mockReturnValue([{ name: trigger.name }]);
|
||||||
getNode.mockReturnValue({ type: trigger.type });
|
getNode.mockReturnValue({ type: trigger.type });
|
||||||
|
|
||||||
const child = { type: AGENT_NODE_TYPE };
|
const target = { type: AGENT_NODE_TYPE };
|
||||||
const parent = { type: '@n8n/n8n-nodes-langchain.memoryBufferWindow' };
|
const source = { type: '@n8n/n8n-nodes-langchain.memoryBufferWindow' };
|
||||||
|
|
||||||
adjustNewNodes(parent, child, { childIsNew: false });
|
adjustNewNodes(source, target, { targetIsNew: false });
|
||||||
|
|
||||||
expect(parent).toEqual({
|
expect(source).toEqual({
|
||||||
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not modify sessionId with ManualTrigger->(new Memory->Agent)', () => {
|
it('does not modify sessionId with ManualTrigger->(new Memory->Agent)', () => {
|
||||||
const trigger = { type: MANUAL_TRIGGER_NODE_TYPE, name: 'trigger' };
|
const trigger = { type: MANUAL_TRIGGER_NODE_TYPE, name: 'trigger' };
|
||||||
getParentNodesByDepth.mockReturnValue([{ name: trigger.name }]);
|
getsourceNodesByDepth.mockReturnValue([{ name: trigger.name }]);
|
||||||
getNode.mockReturnValue({ type: trigger.type });
|
getNode.mockReturnValue({ type: trigger.type });
|
||||||
|
|
||||||
const child = { type: AGENT_NODE_TYPE, name: 'myAgent' };
|
const target = { type: AGENT_NODE_TYPE, name: 'myAgent' };
|
||||||
const parent = { type: '@n8n/n8n-nodes-langchain.memoryBufferWindow' };
|
const source = { type: '@n8n/n8n-nodes-langchain.memoryBufferWindow' };
|
||||||
|
|
||||||
adjustNewNodes(parent, child, { childIsNew: false });
|
adjustNewNodes(source, target, { targetIsNew: false });
|
||||||
|
|
||||||
expect(parent).toEqual({
|
expect(source).toEqual({
|
||||||
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
||||||
parameters: { sessionIdType: 'customKey' },
|
parameters: { sessionIdType: 'customKey' },
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,37 +5,41 @@ import type { AddedNode } from '@/Interface';
|
||||||
|
|
||||||
const PROMPT_PROVIDER_NODE_NAMES = [CHAT_TRIGGER_NODE_TYPE];
|
const PROMPT_PROVIDER_NODE_NAMES = [CHAT_TRIGGER_NODE_TYPE];
|
||||||
|
|
||||||
|
/** Adjust new Source->Target connection */
|
||||||
export function adjustNewNodes(
|
export function adjustNewNodes(
|
||||||
parent: AddedNode,
|
source: AddedNode,
|
||||||
child: AddedNode,
|
target: AddedNode,
|
||||||
{ parentIsNew = true, childIsNew = true } = {},
|
{ sourceIsNew = true, targetIsNew = true } = {},
|
||||||
) {
|
) {
|
||||||
if (childIsNew) adjustNewChild(parent, child);
|
if (sourceIsNew) adjustNewSource(source, target);
|
||||||
if (parentIsNew) adjustNewParent(parent, child);
|
if (targetIsNew) adjustNewTarget(source, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustNewChild(parent: AddedNode, child: AddedNode) {
|
function adjustNewTarget(source: AddedNode, target: AddedNode) {
|
||||||
if (AI_ROOT_NODE_TYPES.includes(child.type) && PROMPT_PROVIDER_NODE_NAMES.includes(parent.type)) {
|
if (
|
||||||
|
AI_ROOT_NODE_TYPES.includes(target.type) &&
|
||||||
|
PROMPT_PROVIDER_NODE_NAMES.includes(source.type)
|
||||||
|
) {
|
||||||
// Need to re-set text to support disabled parameter value for prompt text.
|
// Need to re-set text to support disabled parameter value for prompt text.
|
||||||
Object.assign<AddedNode, Partial<INode>>(child, {
|
Object.assign<AddedNode, Partial<INode>>(target, {
|
||||||
parameters: { ...child.parameters, promptType: 'auto', text: '={{ $json.chatInput }}' },
|
parameters: { ...target.parameters, promptType: 'auto', text: '={{ $json.chatInput }}' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustNewParent(parent: AddedNode, child: AddedNode) {
|
function adjustNewSource(source: AddedNode, target: AddedNode) {
|
||||||
if (AI_MEMORY_NODE_TYPES.includes(parent.type) && child.name) {
|
if (AI_MEMORY_NODE_TYPES.includes(source.type) && target.name) {
|
||||||
const { getCurrentWorkflow } = useWorkflowsStore();
|
const { getCurrentWorkflow } = useWorkflowsStore();
|
||||||
const workflow = getCurrentWorkflow();
|
const workflow = getCurrentWorkflow();
|
||||||
|
|
||||||
// If a memory node is added to an Agent, the memory node is actually a parent since it provides input
|
// If a memory node is added to an Agent, the memory node is actually a parent since it provides input
|
||||||
// So we need to look for the Agent's (other) parents to determine if there is a sessionId provider
|
// So we need to look for the Agent's (other) parents to determine if there is a sessionId provider
|
||||||
const ps = workflow.getParentNodesByDepth(child.name, 1);
|
const ps = workflow.getParentNodesByDepth(target.name, 1);
|
||||||
if (
|
if (
|
||||||
!ps.some((x) => PROMPT_PROVIDER_NODE_NAMES.includes(workflow.getNode(x.name)?.type ?? ''))
|
!ps.some((x) => PROMPT_PROVIDER_NODE_NAMES.includes(workflow.getNode(x.name)?.type ?? ''))
|
||||||
) {
|
) {
|
||||||
Object.assign<AddedNode, Partial<INode>>(parent, {
|
Object.assign<AddedNode, Partial<INode>>(source, {
|
||||||
parameters: { ...parent.parameters, sessionIdType: 'customKey' },
|
parameters: { ...source.parameters, sessionIdType: 'customKey' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue