mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 10:31:15 +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
@@ -23,6 +23,7 @@ import type {
|
||||
ITaskData,
|
||||
ITaskDataConnections,
|
||||
ITaskDataConnectionsSource,
|
||||
ITaskMetadata,
|
||||
IWaitingForExecution,
|
||||
IWaitingForExecutionSource,
|
||||
NodeApiError,
|
||||
@@ -65,6 +66,7 @@ export class WorkflowExecute {
|
||||
executionData: {
|
||||
contextData: {},
|
||||
nodeExecutionStack: [],
|
||||
metadata: {},
|
||||
waitingExecution: {},
|
||||
waitingExecutionSource: {},
|
||||
},
|
||||
@@ -133,6 +135,7 @@ export class WorkflowExecute {
|
||||
executionData: {
|
||||
contextData: {},
|
||||
nodeExecutionStack,
|
||||
metadata: {},
|
||||
waitingExecution: {},
|
||||
waitingExecutionSource: {},
|
||||
},
|
||||
@@ -160,7 +163,7 @@ export class WorkflowExecute {
|
||||
workflow: Workflow,
|
||||
runData: IRunData,
|
||||
startNodes: string[],
|
||||
destinationNode: string,
|
||||
destinationNode?: string,
|
||||
pinData?: IPinData,
|
||||
): PCancelable<IRun> {
|
||||
let incomingNodeConnections: INodeConnections | undefined;
|
||||
@@ -169,6 +172,7 @@ export class WorkflowExecute {
|
||||
this.status = 'running';
|
||||
|
||||
const runIndex = 0;
|
||||
let runNodeFilter: string[] | undefined;
|
||||
|
||||
// Initialize the nodeExecutionStack and waitingExecution with
|
||||
// the data from runData
|
||||
@@ -182,7 +186,6 @@ export class WorkflowExecute {
|
||||
let incomingSourceData: ITaskDataConnectionsSource | null = null;
|
||||
|
||||
if (incomingNodeConnections === undefined) {
|
||||
// If it has no incoming data add the default empty data
|
||||
incomingData.push([
|
||||
{
|
||||
json: {},
|
||||
@@ -202,6 +205,9 @@ export class WorkflowExecute {
|
||||
if (node && pinData && pinData[node.name]) {
|
||||
incomingData.push(pinData[node.name]);
|
||||
} else {
|
||||
if (!runData[connection.node]) {
|
||||
continue;
|
||||
}
|
||||
const nodeIncomingData =
|
||||
runData[connection.node][runIndex]?.data?.[connection.type][connection.index];
|
||||
if (nodeIncomingData) {
|
||||
@@ -226,56 +232,57 @@ export class WorkflowExecute {
|
||||
|
||||
nodeExecutionStack.push(executeData);
|
||||
|
||||
// Check if the destinationNode has to be added as waiting
|
||||
// because some input data is already fully available
|
||||
incomingNodeConnections = workflow.connectionsByDestinationNode[destinationNode];
|
||||
if (incomingNodeConnections !== undefined) {
|
||||
for (const connections of incomingNodeConnections.main) {
|
||||
for (let inputIndex = 0; inputIndex < connections.length; inputIndex++) {
|
||||
connection = connections[inputIndex];
|
||||
if (destinationNode) {
|
||||
// Check if the destinationNode has to be added as waiting
|
||||
// because some input data is already fully available
|
||||
incomingNodeConnections = workflow.connectionsByDestinationNode[destinationNode];
|
||||
if (incomingNodeConnections !== undefined) {
|
||||
for (const connections of incomingNodeConnections.main) {
|
||||
for (let inputIndex = 0; inputIndex < connections.length; inputIndex++) {
|
||||
connection = connections[inputIndex];
|
||||
|
||||
if (waitingExecution[destinationNode] === undefined) {
|
||||
waitingExecution[destinationNode] = {};
|
||||
waitingExecutionSource[destinationNode] = {};
|
||||
}
|
||||
if (waitingExecution[destinationNode][runIndex] === undefined) {
|
||||
waitingExecution[destinationNode][runIndex] = {};
|
||||
waitingExecutionSource[destinationNode][runIndex] = {};
|
||||
}
|
||||
if (waitingExecution[destinationNode][runIndex][connection.type] === undefined) {
|
||||
waitingExecution[destinationNode][runIndex][connection.type] = [];
|
||||
waitingExecutionSource[destinationNode][runIndex][connection.type] = [];
|
||||
}
|
||||
if (waitingExecution[destinationNode] === undefined) {
|
||||
waitingExecution[destinationNode] = {};
|
||||
waitingExecutionSource[destinationNode] = {};
|
||||
}
|
||||
if (waitingExecution[destinationNode][runIndex] === undefined) {
|
||||
waitingExecution[destinationNode][runIndex] = {};
|
||||
waitingExecutionSource[destinationNode][runIndex] = {};
|
||||
}
|
||||
if (waitingExecution[destinationNode][runIndex][connection.type] === undefined) {
|
||||
waitingExecution[destinationNode][runIndex][connection.type] = [];
|
||||
waitingExecutionSource[destinationNode][runIndex][connection.type] = [];
|
||||
}
|
||||
|
||||
if (runData[connection.node] !== undefined) {
|
||||
// Input data exists so add as waiting
|
||||
// incomingDataDestination.push(runData[connection.node!][runIndex].data![connection.type][connection.index]);
|
||||
waitingExecution[destinationNode][runIndex][connection.type].push(
|
||||
runData[connection.node][runIndex].data![connection.type][connection.index],
|
||||
);
|
||||
waitingExecutionSource[destinationNode][runIndex][connection.type].push({
|
||||
previousNode: connection.node,
|
||||
previousNodeOutput: connection.index || undefined,
|
||||
previousNodeRun: runIndex || undefined,
|
||||
} as ISourceData);
|
||||
} else {
|
||||
waitingExecution[destinationNode][runIndex][connection.type].push(null);
|
||||
waitingExecutionSource[destinationNode][runIndex][connection.type].push(null);
|
||||
if (runData[connection.node] !== undefined) {
|
||||
// Input data exists so add as waiting
|
||||
// incomingDataDestination.push(runData[connection.node!][runIndex].data![connection.type][connection.index]);
|
||||
waitingExecution[destinationNode][runIndex][connection.type].push(
|
||||
runData[connection.node][runIndex].data![connection.type][connection.index],
|
||||
);
|
||||
waitingExecutionSource[destinationNode][runIndex][connection.type].push({
|
||||
previousNode: connection.node,
|
||||
previousNodeOutput: connection.index || undefined,
|
||||
previousNodeRun: runIndex || undefined,
|
||||
} as ISourceData);
|
||||
} else {
|
||||
waitingExecution[destinationNode][runIndex][connection.type].push(null);
|
||||
waitingExecutionSource[destinationNode][runIndex][connection.type].push(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only run the parent nodes and no others
|
||||
// eslint-disable-next-line prefer-const
|
||||
runNodeFilter = workflow
|
||||
.getParentNodes(destinationNode)
|
||||
.filter((parentNodeName) => !workflow.getNode(parentNodeName)?.disabled);
|
||||
|
||||
runNodeFilter.push(destinationNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Only run the parent nodes and no others
|
||||
let runNodeFilter: string[] | undefined;
|
||||
// eslint-disable-next-line prefer-const
|
||||
runNodeFilter = workflow
|
||||
.getParentNodes(destinationNode)
|
||||
.filter((parentNodeName) => !workflow.getNode(parentNodeName)?.disabled);
|
||||
|
||||
runNodeFilter.push(destinationNode);
|
||||
|
||||
this.runExecutionData = {
|
||||
startData: {
|
||||
destinationNode,
|
||||
@@ -288,6 +295,7 @@ export class WorkflowExecute {
|
||||
executionData: {
|
||||
contextData: {},
|
||||
nodeExecutionStack,
|
||||
metadata: {},
|
||||
waitingExecution,
|
||||
waitingExecutionSource,
|
||||
},
|
||||
@@ -309,6 +317,22 @@ export class WorkflowExecute {
|
||||
return this.additionalData.hooks.executeHookFunctions(hookName, parameters);
|
||||
}
|
||||
|
||||
moveNodeMetadata(): void {
|
||||
const metadata = get(this.runExecutionData, 'executionData.metadata');
|
||||
|
||||
if (metadata) {
|
||||
const runData = get(this.runExecutionData, 'resultData.runData');
|
||||
|
||||
let index: number;
|
||||
let metaRunData: ITaskMetadata;
|
||||
for (const nodeName of Object.keys(metadata)) {
|
||||
for ([index, metaRunData] of metadata[nodeName].entries()) {
|
||||
runData[nodeName][index].metadata = metaRunData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the incoming connection does not receive any data
|
||||
*/
|
||||
@@ -1533,6 +1557,9 @@ export class WorkflowExecute {
|
||||
// Static data of workflow changed
|
||||
newStaticData = workflow.staticData;
|
||||
}
|
||||
|
||||
this.moveNodeMetadata();
|
||||
|
||||
await this.executeHook('workflowExecuteAfter', [fullRunData, newStaticData]).catch(
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
(error) => {
|
||||
@@ -1601,6 +1628,9 @@ export class WorkflowExecute {
|
||||
// Static data of workflow changed
|
||||
newStaticData = workflow.staticData;
|
||||
}
|
||||
|
||||
this.moveNodeMetadata();
|
||||
|
||||
await this.executeHook('workflowExecuteAfter', [fullRunData, newStaticData]);
|
||||
|
||||
if (closeFunction) {
|
||||
|
||||
Reference in New Issue
Block a user