feat(core): Implement partial execution of tool nodes (no-changelog) (#14939)

This commit is contained in:
Benjamin Schroth
2025-04-28 13:24:56 +02:00
committed by GitHub
parent b7c5521942
commit bc6f98928e
10 changed files with 349 additions and 33 deletions

View File

@@ -68,6 +68,8 @@ import {
recreateNodeExecutionStack,
handleCycles,
filterDisabledNodes,
rewireGraph,
isTool,
} from './partial-execution-utils';
import { RoutingNode } from './routing-node';
import { TriggersAndPollers } from './triggers-and-pollers';
@@ -356,41 +358,47 @@ export class WorkflowExecute {
let graph = DirectedGraph.fromWorkflow(workflow);
// Edge Case 1:
// Support executing a single node that is not connected to a trigger
const destinationHasNoParents = graph.getDirectParentConnections(destination).length === 0;
if (destinationHasNoParents) {
// short cut here, only create a subgraph and the stacks
graph = findSubgraph({
graph: filterDisabledNodes(graph),
destination,
trigger: destination,
});
const filteredNodes = graph.getNodes();
runData = cleanRunData(runData, graph, new Set([destination]));
const { nodeExecutionStack, waitingExecution, waitingExecutionSource } =
recreateNodeExecutionStack(graph, new Set([destination]), runData, pinData ?? {});
// Partial execution of nodes as tools
if (isTool(destination, workflow.nodeTypes)) {
graph = rewireGraph(destination, graph);
workflow = graph.toWorkflow({ ...workflow });
} else {
// Edge Case 1:
// Support executing a single node that is not connected to a trigger
const destinationHasNoParents = graph.getDirectParentConnections(destination).length === 0;
if (destinationHasNoParents) {
// short cut here, only create a subgraph and the stacks
graph = findSubgraph({
graph: filterDisabledNodes(graph),
destination,
trigger: destination,
});
const filteredNodes = graph.getNodes();
runData = cleanRunData(runData, graph, new Set([destination]));
const { nodeExecutionStack, waitingExecution, waitingExecutionSource } =
recreateNodeExecutionStack(graph, new Set([destination]), runData, pinData ?? {});
this.status = 'running';
this.runExecutionData = {
startData: {
destinationNode: destinationNodeName,
runNodeFilter: Array.from(filteredNodes.values()).map((node) => node.name),
},
resultData: {
runData,
pinData,
},
executionData: {
contextData: {},
nodeExecutionStack,
metadata: {},
waitingExecution,
waitingExecutionSource,
},
};
this.status = 'running';
this.runExecutionData = {
startData: {
destinationNode: destinationNodeName,
runNodeFilter: Array.from(filteredNodes.values()).map((node) => node.name),
},
resultData: {
runData,
pinData,
},
executionData: {
contextData: {},
nodeExecutionStack,
metadata: {},
waitingExecution,
waitingExecutionSource,
},
};
return this.processRunExecutionData(graph.toWorkflow({ ...workflow }));
return this.processRunExecutionData(graph.toWorkflow({ ...workflow }));
}
}
// 1. Find the Trigger
@@ -1704,6 +1712,13 @@ export class WorkflowExecute {
main: nodeSuccessData,
} as ITaskDataConnections;
// Rewire output data log to the given connectionType
if (executionNode.rewireOutputLogTo) {
taskData.data = {
[executionNode.rewireOutputLogTo]: nodeSuccessData,
} as ITaskDataConnections;
}
this.runExecutionData.resultData.runData[executionNode.name].push(taskData);
if (this.runExecutionData.waitTill) {