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:
कारतोफ्फेलस्क्रिप्ट™
2023-10-02 17:33:43 +02:00
committed by GitHub
parent 04dfcd73be
commit 00a4b8b0c6
93 changed files with 6209 additions and 728 deletions

View File

@@ -2,8 +2,8 @@ import { defineComponent } from 'vue';
import { mapStores } from 'pinia';
import type { IExecutionPushResponse, IExecutionResponse, IStartRunData } from '@/Interface';
import type { IRunData, IRunExecutionData, IWorkflowBase } from 'n8n-workflow';
import { NodeHelpers, TelemetryHelpers } from 'n8n-workflow';
import type { IRunData, IRunExecutionData, ITaskData, IWorkflowBase } from 'n8n-workflow';
import { NodeHelpers, NodeConnectionType, TelemetryHelpers } from 'n8n-workflow';
import { externalHooks } from '@/mixins/externalHooks';
import { workflowHelpers } from '@/mixins/workflowHelpers';
@@ -28,7 +28,7 @@ export const workflowRun = defineComponent({
methods: {
// Starts to executes a workflow on server.
async runWorkflowApi(runData: IStartRunData): Promise<IExecutionPushResponse> {
if (this.rootStore.pushConnectionActive === false) {
if (!this.rootStore.pushConnectionActive) {
// Do not start if the connection to server is not active
// because then it can not receive the data as it executes.
throw new Error(this.$locale.baseText('workflowRun.noActiveConnectionToTheServer'));
@@ -57,9 +57,12 @@ export const workflowRun = defineComponent({
return response;
},
async runWorkflow(
nodeName?: string,
source?: string,
options:
| { destinationNode: string; source?: string }
| { triggerNode: string; nodeData: ITaskData; source?: string }
| { source?: string },
): Promise<IExecutionPushResponse | undefined> {
const workflow = this.getCurrentWorkflow();
@@ -74,9 +77,9 @@ export const workflowRun = defineComponent({
try {
// Check first if the workflow has any issues before execute it
const issuesExist = this.workflowsStore.nodesIssuesExist;
if (issuesExist === true) {
if (issuesExist) {
// If issues exist get all of the issues of all nodes
const workflowIssues = this.checkReadyForExecution(workflow, nodeName);
const workflowIssues = this.checkReadyForExecution(workflow, options.destinationNode);
if (workflowIssues !== null) {
const errorMessages = [];
let nodeIssues: string[];
@@ -115,13 +118,17 @@ export const workflowRun = defineComponent({
duration: 0,
});
this.titleSet(workflow.name as string, 'ERROR');
void this.$externalHooks().run('workflowRun.runError', { errorMessages, nodeName });
void this.$externalHooks().run('workflowRun.runError', {
errorMessages,
nodeName: options.destinationNode,
});
await this.getWorkflowDataToSave().then((workflowData) => {
this.$telemetry.track('Workflow execution preflight failed', {
workflow_id: workflow.id,
workflow_name: workflow.name,
execution_type: nodeName ? 'node' : 'workflow',
execution_type:
options.destinationNode || options.triggerNode ? 'node' : 'workflow',
node_graph_string: JSON.stringify(
TelemetryHelpers.generateNodesGraph(
workflowData as IWorkflowBase,
@@ -138,8 +145,12 @@ export const workflowRun = defineComponent({
// Get the direct parents of the node
let directParentNodes: string[] = [];
if (nodeName !== undefined) {
directParentNodes = workflow.getParentNodes(nodeName, 'main', 1);
if (options.destinationNode !== undefined) {
directParentNodes = workflow.getParentNodes(
options.destinationNode,
NodeConnectionType.Main,
1,
);
}
const runData = this.workflowsStore.getWorkflowRunData;
@@ -155,7 +166,7 @@ export const workflowRun = defineComponent({
for (const directParentNode of directParentNodes) {
// Go over the parents of that node so that we can get a start
// node for each of the branches
const parentNodes = workflow.getParentNodes(directParentNode, 'main');
const parentNodes = workflow.getParentNodes(directParentNode, NodeConnectionType.Main);
// Add also the enabled direct parent to be checked
if (workflow.nodes[directParentNode].disabled) continue;
@@ -181,8 +192,22 @@ export const workflowRun = defineComponent({
}
}
if (startNodes.length === 0 && nodeName !== undefined) {
startNodes.push(nodeName);
let executedNode: string | undefined;
if (
startNodes.length === 0 &&
'destinationNode' in options &&
options.destinationNode !== undefined
) {
executedNode = options.destinationNode;
startNodes.push(options.destinationNode);
} else if ('triggerNode' in options && 'nodeData' in options) {
startNodes.push(
...workflow.getChildNodes(options.triggerNode, NodeConnectionType.Main, 1),
);
newRunData = {
[options.triggerNode]: [options.nodeData],
};
executedNode = options.triggerNode;
}
if (this.workflowsStore.isNewWorkflow) {
@@ -197,8 +222,8 @@ export const workflowRun = defineComponent({
pinData: workflowData.pinData,
startNodes,
};
if (nodeName) {
startRunData.destinationNode = nodeName;
if ('destinationNode' in options) {
startRunData.destinationNode = options.destinationNode;
}
// Init the execution data to represent the start of the execution
@@ -211,7 +236,7 @@ export const workflowRun = defineComponent({
startedAt: new Date(),
stoppedAt: undefined,
workflowId: workflow.id,
executedNode: nodeName,
executedNode,
data: {
resultData: {
runData: newRunData || {},
@@ -234,7 +259,10 @@ export const workflowRun = defineComponent({
const runWorkflowApiResponse = await this.runWorkflowApi(startRunData);
await this.$externalHooks().run('workflowRun.runWorkflow', { nodeName, source });
await this.$externalHooks().run('workflowRun.runWorkflow', {
nodeName: options.destinationNode,
source: options.source,
});
return runWorkflowApiResponse;
} catch (error) {