mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
feat(core): Add support for building LLM applications (#7235)
This extracts all core and editor changes from #7246 and #7137, so that we can get these changes merged first. ADO-1120 [DB Tests](https://github.com/n8n-io/n8n/actions/runs/6379749011) [E2E Tests](https://github.com/n8n-io/n8n/actions/runs/6379751480) [Workflow Tests](https://github.com/n8n-io/n8n/actions/runs/6379752828) --------- Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com> Co-authored-by: Oleg Ivaniv <me@olegivaniv.com> Co-authored-by: Alex Grozav <alex@grozav.com> Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
committed by
GitHub
parent
04dfcd73be
commit
00a4b8b0c6
@@ -30,7 +30,7 @@ import type {
|
||||
INodeProperties,
|
||||
IWorkflowSettings,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeHelpers } from 'n8n-workflow';
|
||||
import { NodeConnectionType, ExpressionEvaluatorProxy, NodeHelpers } from 'n8n-workflow';
|
||||
|
||||
import type {
|
||||
INodeTypesMaxCount,
|
||||
@@ -62,9 +62,45 @@ import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { useWorkflowsEEStore } from '@/stores/workflows.ee.store';
|
||||
import { useEnvironmentsStore } from '@/stores/environments.ee.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { getWorkflowPermissions } from '@/permissions';
|
||||
import type { IPermissions } from '@/permissions';
|
||||
|
||||
export function getParentMainInputNode(workflow: Workflow, node: INode): INode {
|
||||
const nodeType = useNodeTypesStore().getNodeType(node.type);
|
||||
if (nodeType) {
|
||||
const outputs = NodeHelpers.getNodeOutputs(workflow, node, nodeType);
|
||||
|
||||
if (!!outputs.find((output) => output !== NodeConnectionType.Main)) {
|
||||
// Get the first node which is connected to a non-main output
|
||||
const nonMainNodesConnected = outputs?.reduce((acc, outputName) => {
|
||||
const parentNodes = workflow.getChildNodes(node.name, outputName);
|
||||
if (parentNodes.length > 0) {
|
||||
acc.push(...parentNodes);
|
||||
}
|
||||
return acc;
|
||||
}, [] as string[]);
|
||||
|
||||
if (nonMainNodesConnected.length) {
|
||||
const returnNode = workflow.getNode(nonMainNodesConnected[0]);
|
||||
if (returnNode === null) {
|
||||
// This should theoretically never happen as the node is connected
|
||||
// but who knows and it makes TS happy
|
||||
throw new Error(
|
||||
`The node "${nonMainNodesConnected[0]}" which is a connection of "${node.name}" could not be found!`,
|
||||
);
|
||||
}
|
||||
|
||||
// The chain of non-main nodes is potentially not finished yet so
|
||||
// keep on going
|
||||
return getParentMainInputNode(workflow, returnNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
export function resolveParameter(
|
||||
parameter: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
||||
opts: {
|
||||
@@ -77,10 +113,16 @@ export function resolveParameter(
|
||||
): IDataObject | null {
|
||||
let itemIndex = opts?.targetItem?.itemIndex || 0;
|
||||
|
||||
const inputName = 'main';
|
||||
const activeNode = useNDVStore().activeNode;
|
||||
const inputName = NodeConnectionType.Main;
|
||||
let activeNode = useNDVStore().activeNode;
|
||||
|
||||
const workflow = getCurrentWorkflow();
|
||||
|
||||
// Should actually just do that for incoming data and not things like parameters
|
||||
if (activeNode) {
|
||||
activeNode = getParentMainInputNode(workflow, activeNode);
|
||||
}
|
||||
|
||||
const workflowRunData = useWorkflowsStore().getWorkflowRunData;
|
||||
let parentNode = workflow.getParentNodes(activeNode!.name, inputName, 1);
|
||||
const executionData = useWorkflowsStore().getWorkflowExecution;
|
||||
@@ -162,6 +204,10 @@ export function resolveParameter(
|
||||
}
|
||||
const _executeData = executeData(parentNode, activeNode!.name, inputName, runIndexCurrent);
|
||||
|
||||
ExpressionEvaluatorProxy.setEvaluator(
|
||||
useSettingsStore().settings.expressions?.evaluator ?? 'tmpl',
|
||||
);
|
||||
|
||||
return workflow.expression.getParameterValue(
|
||||
parameter,
|
||||
runExecutionData,
|
||||
@@ -222,6 +268,34 @@ function getCurrentWorkflow(copyData?: boolean): Workflow {
|
||||
return useWorkflowsStore().getCurrentWorkflow(copyData);
|
||||
}
|
||||
|
||||
function getConnectedNodes(
|
||||
direction: 'upstream' | 'downstream',
|
||||
workflow: Workflow,
|
||||
nodeName: string,
|
||||
): string[] {
|
||||
let checkNodes: string[];
|
||||
if (direction === 'downstream') {
|
||||
checkNodes = workflow.getChildNodes(nodeName);
|
||||
} else if (direction === 'upstream') {
|
||||
checkNodes = workflow.getParentNodes(nodeName);
|
||||
} else {
|
||||
throw new Error(`The direction "${direction}" is not supported!`);
|
||||
}
|
||||
|
||||
// Find also all nodes which are connected to the child nodes via a non-main input
|
||||
let connectedNodes: string[] = [];
|
||||
checkNodes.forEach((checkNode) => {
|
||||
connectedNodes = [
|
||||
...connectedNodes,
|
||||
checkNode,
|
||||
...workflow.getParentNodes(checkNode, 'ALL_NON_MAIN'),
|
||||
];
|
||||
});
|
||||
|
||||
// Remove duplicates
|
||||
return [...new Set(connectedNodes)];
|
||||
}
|
||||
|
||||
function getNodes(): INodeUi[] {
|
||||
return useWorkflowsStore().getNodes();
|
||||
}
|
||||
@@ -356,11 +430,33 @@ export function executeData(
|
||||
[inputName]: workflowRunData[currentNode][runIndex].source,
|
||||
};
|
||||
} else {
|
||||
const workflow = getCurrentWorkflow();
|
||||
|
||||
let previousNodeOutput: number | undefined;
|
||||
// As the node can be connected through either of the outputs find the correct one
|
||||
// and set it to make pairedItem work on not executed nodes
|
||||
if (workflow.connectionsByDestinationNode[currentNode]?.main) {
|
||||
mainConnections: for (const mainConnections of workflow.connectionsByDestinationNode[
|
||||
currentNode
|
||||
].main) {
|
||||
for (const connection of mainConnections) {
|
||||
if (
|
||||
connection.type === NodeConnectionType.Main &&
|
||||
connection.node === parentNodeName
|
||||
) {
|
||||
previousNodeOutput = connection.index;
|
||||
break mainConnections;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The current node did not get executed in UI yet so build data manually
|
||||
executeData.source = {
|
||||
[inputName]: [
|
||||
{
|
||||
previousNode: parentNodeName,
|
||||
previousNodeOutput,
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -399,7 +495,9 @@ export const workflowHelpers = defineComponent({
|
||||
resolveParameter,
|
||||
resolveRequiredParameters,
|
||||
getCurrentWorkflow,
|
||||
getConnectedNodes,
|
||||
getNodes,
|
||||
getParentMainInputNode,
|
||||
getWorkflow,
|
||||
getNodeTypes,
|
||||
connectionInputData,
|
||||
|
||||
Reference in New Issue
Block a user