flowcraft 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -34
- package/dist/analysis.d.ts +3 -1
- package/dist/chunk-33NO4PUJ.js +74 -0
- package/dist/chunk-33NO4PUJ.js.map +1 -0
- package/dist/chunk-BC4G7OM6.js +42 -0
- package/dist/chunk-BC4G7OM6.js.map +1 -0
- package/dist/chunk-BCRWXTWX.js +21 -0
- package/dist/chunk-BCRWXTWX.js.map +1 -0
- package/dist/chunk-BN4MV36K.js +25 -0
- package/dist/chunk-BN4MV36K.js.map +1 -0
- package/dist/{chunk-ZCHFZBGL.js → chunk-C4HYIJI3.js} +120 -5
- package/dist/chunk-C4HYIJI3.js.map +1 -0
- package/dist/chunk-CD3Q4N6V.js +13 -0
- package/dist/chunk-CD3Q4N6V.js.map +1 -0
- package/dist/chunk-CD4FUZOJ.js +114 -0
- package/dist/chunk-CD4FUZOJ.js.map +1 -0
- package/dist/chunk-DL7KVYZF.js +39 -0
- package/dist/chunk-DL7KVYZF.js.map +1 -0
- package/dist/chunk-FRKO3WX4.js +32 -0
- package/dist/chunk-FRKO3WX4.js.map +1 -0
- package/dist/chunk-G53CSLBF.js +54 -0
- package/dist/chunk-G53CSLBF.js.map +1 -0
- package/dist/chunk-G5BGBPFP.js +172 -0
- package/dist/chunk-G5BGBPFP.js.map +1 -0
- package/dist/chunk-HAZ26F3P.js +98 -0
- package/dist/chunk-HAZ26F3P.js.map +1 -0
- package/dist/chunk-HKX7WQLS.js +446 -0
- package/dist/chunk-HKX7WQLS.js.map +1 -0
- package/dist/{chunk-U5V5O5MN.js → chunk-LNK7LZER.js} +5 -3
- package/dist/chunk-LNK7LZER.js.map +1 -0
- package/dist/chunk-MCGK3FXQ.js +143 -0
- package/dist/chunk-MCGK3FXQ.js.map +1 -0
- package/dist/chunk-MKNZBKSR.js +90 -0
- package/dist/chunk-MKNZBKSR.js.map +1 -0
- package/dist/chunk-MUYLRTSR.js +82 -0
- package/dist/chunk-MUYLRTSR.js.map +1 -0
- package/dist/chunk-NVJ3ZO3P.js +3 -0
- package/dist/{chunk-HMR2GEGE.js.map → chunk-NVJ3ZO3P.js.map} +1 -1
- package/dist/chunk-NVLZFLYM.js +3 -0
- package/dist/chunk-NVLZFLYM.js.map +1 -0
- package/dist/chunk-ONH7PIJZ.js +300 -0
- package/dist/chunk-ONH7PIJZ.js.map +1 -0
- package/dist/chunk-QNYXQKFW.js +25 -0
- package/dist/chunk-QNYXQKFW.js.map +1 -0
- package/dist/chunk-RM677CNU.js +52 -0
- package/dist/chunk-RM677CNU.js.map +1 -0
- package/dist/chunk-WWGFIYKW.js +47 -0
- package/dist/chunk-WWGFIYKW.js.map +1 -0
- package/dist/chunk-XNRIM27H.js +76 -0
- package/dist/chunk-XNRIM27H.js.map +1 -0
- package/dist/{chunk-QLGJUDQF.js → chunk-ZNL7ZXPR.js} +26 -11
- package/dist/chunk-ZNL7ZXPR.js.map +1 -0
- package/dist/container-factory.d.ts +17 -0
- package/dist/container-factory.js +13 -0
- package/dist/container-factory.js.map +1 -0
- package/dist/container.d.ts +23 -0
- package/dist/container.js +3 -0
- package/dist/container.js.map +1 -0
- package/dist/context.d.ts +3 -1
- package/dist/errors.d.ts +18 -17
- package/dist/errors.js +1 -1
- package/dist/evaluator.d.ts +3 -1
- package/dist/flow.d.ts +12 -2
- package/dist/flow.js +2 -2
- package/dist/index.d.ts +7 -8
- package/dist/index.js +26 -14
- package/dist/linter.d.ts +3 -1
- package/dist/logger.d.ts +3 -1
- package/dist/node.d.ts +3 -1
- package/dist/node.js +1 -1
- package/dist/nodes/batch-gather.d.ts +9 -0
- package/dist/nodes/batch-gather.js +4 -0
- package/dist/nodes/batch-gather.js.map +1 -0
- package/dist/nodes/batch-scatter.d.ts +9 -0
- package/dist/nodes/batch-scatter.js +4 -0
- package/dist/nodes/batch-scatter.js.map +1 -0
- package/dist/nodes/subflow.d.ts +9 -0
- package/dist/nodes/subflow.js +10 -0
- package/dist/nodes/subflow.js.map +1 -0
- package/dist/nodes/wait.d.ts +9 -0
- package/dist/nodes/wait.js +4 -0
- package/dist/nodes/wait.js.map +1 -0
- package/dist/runtime/adapter.d.ts +3 -5
- package/dist/runtime/adapter.js +19 -9
- package/dist/runtime/execution-context.d.ts +3 -0
- package/dist/runtime/execution-context.js +6 -0
- package/dist/runtime/execution-context.js.map +1 -0
- package/dist/runtime/executors.d.ts +3 -26
- package/dist/runtime/executors.js +2 -2
- package/dist/runtime/index.d.ts +5 -7
- package/dist/runtime/index.js +21 -10
- package/dist/runtime/node-executor-factory.d.ts +12 -0
- package/dist/runtime/node-executor-factory.js +6 -0
- package/dist/runtime/node-executor-factory.js.map +1 -0
- package/dist/runtime/orchestrator.d.ts +9 -0
- package/dist/runtime/orchestrator.js +8 -0
- package/dist/runtime/orchestrator.js.map +1 -0
- package/dist/runtime/orchestrators/step-by-step.d.ts +16 -0
- package/dist/runtime/orchestrators/step-by-step.js +5 -0
- package/dist/runtime/orchestrators/step-by-step.js.map +1 -0
- package/dist/runtime/orchestrators/utils.d.ts +35 -0
- package/dist/runtime/orchestrators/utils.js +4 -0
- package/dist/runtime/orchestrators/utils.js.map +1 -0
- package/dist/runtime/runtime.d.ts +3 -41
- package/dist/runtime/runtime.js +18 -8
- package/dist/runtime/state.d.ts +3 -21
- package/dist/runtime/state.js +2 -1
- package/dist/runtime/traverser.d.ts +3 -26
- package/dist/runtime/traverser.js +1 -2
- package/dist/runtime/types.d.ts +3 -16
- package/dist/runtime/types.js +1 -1
- package/dist/runtime/workflow-logic-handler.d.ts +17 -0
- package/dist/runtime/workflow-logic-handler.js +5 -0
- package/dist/runtime/workflow-logic-handler.js.map +1 -0
- package/dist/sanitizer.d.ts +3 -1
- package/dist/serializer.d.ts +3 -1
- package/dist/testing/event-logger.d.ts +63 -0
- package/dist/testing/event-logger.js +3 -0
- package/dist/testing/event-logger.js.map +1 -0
- package/dist/testing/index.d.ts +6 -0
- package/dist/testing/index.js +31 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/run-with-trace.d.ts +38 -0
- package/dist/testing/run-with-trace.js +29 -0
- package/dist/testing/run-with-trace.js.map +1 -0
- package/dist/testing/stepper.d.ts +79 -0
- package/dist/testing/stepper.js +11 -0
- package/dist/testing/stepper.js.map +1 -0
- package/dist/types-ezHUBdpL.d.ts +564 -0
- package/dist/types.d.ts +3 -1
- package/package.json +55 -51
- package/LICENSE +0 -21
- package/dist/chunk-5ZXV3R5D.js +0 -28
- package/dist/chunk-5ZXV3R5D.js.map +0 -1
- package/dist/chunk-GEKDR2SS.js +0 -201
- package/dist/chunk-GEKDR2SS.js.map +0 -1
- package/dist/chunk-HMR2GEGE.js +0 -3
- package/dist/chunk-M2FRTT2K.js +0 -144
- package/dist/chunk-M2FRTT2K.js.map +0 -1
- package/dist/chunk-OTS5YJ3S.js +0 -494
- package/dist/chunk-OTS5YJ3S.js.map +0 -1
- package/dist/chunk-QLGJUDQF.js.map +0 -1
- package/dist/chunk-U5V5O5MN.js.map +0 -1
- package/dist/chunk-VSGQDLBF.js +0 -61
- package/dist/chunk-VSGQDLBF.js.map +0 -1
- package/dist/chunk-ZCHFZBGL.js.map +0 -1
- package/dist/types-CsTeXTiA.d.ts +0 -222
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AsyncContextView, Context } from './chunk-R3HQXIEL.js';
|
|
2
|
+
import { FlowcraftError } from './chunk-BCRWXTWX.js';
|
|
3
|
+
|
|
4
|
+
// src/runtime/state.ts
|
|
5
|
+
var WorkflowState = class {
|
|
6
|
+
_completedNodes = /* @__PURE__ */ new Set();
|
|
7
|
+
errors = [];
|
|
8
|
+
anyFallbackExecuted = false;
|
|
9
|
+
context;
|
|
10
|
+
_isAwaiting = false;
|
|
11
|
+
_awaitingNodeIds = /* @__PURE__ */ new Set();
|
|
12
|
+
constructor(initialData) {
|
|
13
|
+
this.context = new AsyncContextView(new Context(initialData));
|
|
14
|
+
if (initialData._awaitingNodeIds) {
|
|
15
|
+
this._isAwaiting = true;
|
|
16
|
+
const awaitingIds = initialData._awaitingNodeIds;
|
|
17
|
+
if (Array.isArray(awaitingIds)) {
|
|
18
|
+
for (const id of awaitingIds) {
|
|
19
|
+
this._awaitingNodeIds.add(id);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
for (const key of Object.keys(initialData)) {
|
|
24
|
+
if (key.startsWith("_outputs.")) {
|
|
25
|
+
const nodeId = key.substring("_outputs.".length);
|
|
26
|
+
this._completedNodes.add(nodeId);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async addCompletedNode(nodeId, output) {
|
|
31
|
+
this._completedNodes.add(nodeId);
|
|
32
|
+
await this.context.set(`_outputs.${nodeId}`, output);
|
|
33
|
+
}
|
|
34
|
+
addError(nodeId, error) {
|
|
35
|
+
const flowcraftError = new FlowcraftError(error.message, {
|
|
36
|
+
cause: error,
|
|
37
|
+
nodeId,
|
|
38
|
+
isFatal: false
|
|
39
|
+
});
|
|
40
|
+
this.errors.push({
|
|
41
|
+
...flowcraftError,
|
|
42
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
43
|
+
originalError: error
|
|
44
|
+
// Legacy compatibility
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
clearError(nodeId) {
|
|
48
|
+
this.errors = this.errors.filter((err) => err.nodeId !== nodeId);
|
|
49
|
+
}
|
|
50
|
+
markFallbackExecuted() {
|
|
51
|
+
this.anyFallbackExecuted = true;
|
|
52
|
+
}
|
|
53
|
+
getContext() {
|
|
54
|
+
return this.context;
|
|
55
|
+
}
|
|
56
|
+
getCompletedNodes() {
|
|
57
|
+
return new Set(this._completedNodes);
|
|
58
|
+
}
|
|
59
|
+
getErrors() {
|
|
60
|
+
return this.errors;
|
|
61
|
+
}
|
|
62
|
+
getAnyFallbackExecuted() {
|
|
63
|
+
return this.anyFallbackExecuted;
|
|
64
|
+
}
|
|
65
|
+
markAsAwaiting(nodeId) {
|
|
66
|
+
this._isAwaiting = true;
|
|
67
|
+
this._awaitingNodeIds.add(nodeId);
|
|
68
|
+
const awaitingArray = Array.from(this._awaitingNodeIds);
|
|
69
|
+
this.context.set("_awaitingNodeIds", awaitingArray);
|
|
70
|
+
}
|
|
71
|
+
isAwaiting() {
|
|
72
|
+
return this._isAwaiting && this._awaitingNodeIds.size > 0;
|
|
73
|
+
}
|
|
74
|
+
getAwaitingNodeIds() {
|
|
75
|
+
return Array.from(this._awaitingNodeIds);
|
|
76
|
+
}
|
|
77
|
+
clearAwaiting(nodeId) {
|
|
78
|
+
if (nodeId) {
|
|
79
|
+
this._awaitingNodeIds.delete(nodeId);
|
|
80
|
+
} else {
|
|
81
|
+
this._awaitingNodeIds.clear();
|
|
82
|
+
}
|
|
83
|
+
this._isAwaiting = this._awaitingNodeIds.size > 0;
|
|
84
|
+
const awaitingArray = Array.from(this._awaitingNodeIds);
|
|
85
|
+
if (awaitingArray.length > 0) {
|
|
86
|
+
this.context.set("_awaitingNodeIds", awaitingArray);
|
|
87
|
+
} else {
|
|
88
|
+
this.context.delete("_awaitingNodeIds");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
getStatus(isTraversalComplete = false) {
|
|
92
|
+
if (this._isAwaiting) return "awaiting";
|
|
93
|
+
if (this.anyFallbackExecuted) return "completed";
|
|
94
|
+
if (this.errors.length > 0) return "failed";
|
|
95
|
+
if (isTraversalComplete) return "completed";
|
|
96
|
+
return "stalled";
|
|
97
|
+
}
|
|
98
|
+
async toResult(serializer) {
|
|
99
|
+
const contextJSON = await this.context.toJSON();
|
|
100
|
+
if (!this._isAwaiting && contextJSON._awaitingNodeIds) {
|
|
101
|
+
delete contextJSON._awaitingNodeIds;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
context: contextJSON,
|
|
105
|
+
serializedContext: serializer.serialize(contextJSON),
|
|
106
|
+
status: this.getStatus(),
|
|
107
|
+
errors: this.errors.length > 0 ? this.errors : void 0
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export { WorkflowState };
|
|
113
|
+
//# sourceMappingURL=chunk-CD4FUZOJ.js.map
|
|
114
|
+
//# sourceMappingURL=chunk-CD4FUZOJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/state.ts"],"names":[],"mappings":"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","file":"chunk-CD4FUZOJ.js","sourcesContent":["import { AsyncContextView, Context as SyncContext } from '../context'\nimport { FlowcraftError } from '../errors'\nimport type { IAsyncContext, ISerializer, WorkflowError, WorkflowResult } from '../types'\n\nexport class WorkflowState<TContext extends Record<string, any>> {\n\tprivate _completedNodes = new Set<string>()\n\tprivate errors: WorkflowError[] = []\n\tprivate anyFallbackExecuted = false\n\tprivate context: IAsyncContext<TContext>\n\tprivate _isAwaiting = false\n\tprivate _awaitingNodeIds = new Set<string>()\n\n\tconstructor(initialData: Partial<TContext>) {\n\t\tthis.context = new AsyncContextView(new SyncContext<TContext>(initialData))\n\t\tif ((initialData as any)._awaitingNodeIds) {\n\t\t\tthis._isAwaiting = true\n\t\t\tconst awaitingIds = (initialData as any)._awaitingNodeIds\n\t\t\tif (Array.isArray(awaitingIds)) {\n\t\t\t\tfor (const id of awaitingIds) {\n\t\t\t\t\tthis._awaitingNodeIds.add(id)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (const key of Object.keys(initialData)) {\n\t\t\tif (key.startsWith('_outputs.')) {\n\t\t\t\tconst nodeId = key.substring('_outputs.'.length)\n\t\t\t\tthis._completedNodes.add(nodeId)\n\t\t\t}\n\t\t}\n\t}\n\n\tasync addCompletedNode(nodeId: string, output: any) {\n\t\tthis._completedNodes.add(nodeId)\n\t\tawait this.context.set(`_outputs.${nodeId}` as any, output)\n\t}\n\n\taddError(nodeId: string, error: Error) {\n\t\tconst flowcraftError = new FlowcraftError(error.message, {\n\t\t\tcause: error,\n\t\t\tnodeId,\n\t\t\tisFatal: false,\n\t\t})\n\t\tthis.errors.push({\n\t\t\t...flowcraftError,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\toriginalError: error, // Legacy compatibility\n\t\t})\n\t}\n\n\tclearError(nodeId: string) {\n\t\tthis.errors = this.errors.filter((err) => err.nodeId !== nodeId)\n\t}\n\n\tmarkFallbackExecuted() {\n\t\tthis.anyFallbackExecuted = true\n\t}\n\n\tgetContext(): IAsyncContext<TContext> {\n\t\treturn this.context\n\t}\n\n\tgetCompletedNodes(): Set<string> {\n\t\treturn new Set(this._completedNodes)\n\t}\n\n\tgetErrors(): WorkflowError[] {\n\t\treturn this.errors\n\t}\n\n\tgetAnyFallbackExecuted(): boolean {\n\t\treturn this.anyFallbackExecuted\n\t}\n\n\tmarkAsAwaiting(nodeId: string): void {\n\t\tthis._isAwaiting = true\n\t\tthis._awaitingNodeIds.add(nodeId)\n\t\tconst awaitingArray = Array.from(this._awaitingNodeIds)\n\t\tthis.context.set('_awaitingNodeIds' as any, awaitingArray)\n\t}\n\n\tisAwaiting(): boolean {\n\t\treturn this._isAwaiting && this._awaitingNodeIds.size > 0\n\t}\n\n\tgetAwaitingNodeIds(): string[] {\n\t\treturn Array.from(this._awaitingNodeIds)\n\t}\n\n\tclearAwaiting(nodeId?: string): void {\n\t\tif (nodeId) {\n\t\t\tthis._awaitingNodeIds.delete(nodeId)\n\t\t} else {\n\t\t\tthis._awaitingNodeIds.clear()\n\t\t}\n\t\tthis._isAwaiting = this._awaitingNodeIds.size > 0\n\t\tconst awaitingArray = Array.from(this._awaitingNodeIds)\n\t\tif (awaitingArray.length > 0) {\n\t\t\tthis.context.set('_awaitingNodeIds' as any, awaitingArray)\n\t\t} else {\n\t\t\tthis.context.delete('_awaitingNodeIds' as any)\n\t\t}\n\t}\n\n\tgetStatus(isTraversalComplete = false): WorkflowResult['status'] {\n\t\tif (this._isAwaiting) return 'awaiting'\n\t\tif (this.anyFallbackExecuted) return 'completed'\n\t\tif (this.errors.length > 0) return 'failed'\n\t\tif (isTraversalComplete) return 'completed'\n\t\treturn 'stalled'\n\t}\n\n\tasync toResult(serializer: ISerializer): Promise<WorkflowResult<TContext>> {\n\t\tconst contextJSON = (await this.context.toJSON()) as TContext\n\t\tif (!this._isAwaiting && (contextJSON as any)._awaitingNodeIds) {\n\t\t\tdelete (contextJSON as any)._awaitingNodeIds\n\t\t}\n\t\treturn {\n\t\t\tcontext: contextJSON,\n\t\t\tserializedContext: serializer.serialize(contextJSON),\n\t\t\tstatus: this.getStatus(),\n\t\t\terrors: this.errors.length > 0 ? this.errors : undefined,\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { NodeExecutor, ClassNodeExecutor, FunctionNodeExecutor } from './chunk-ONH7PIJZ.js';
|
|
2
|
+
import { FlowcraftError } from './chunk-BCRWXTWX.js';
|
|
3
|
+
import { isNodeClass } from './chunk-LNK7LZER.js';
|
|
4
|
+
|
|
5
|
+
// src/runtime/node-executor-factory.ts
|
|
6
|
+
var NodeExecutorFactory = class {
|
|
7
|
+
constructor(eventBus) {
|
|
8
|
+
this.eventBus = eventBus;
|
|
9
|
+
}
|
|
10
|
+
createExecutorForNode(nodeId, context) {
|
|
11
|
+
const nodeDef = context.blueprint.nodes.find((n) => n.id === nodeId);
|
|
12
|
+
if (!nodeDef) {
|
|
13
|
+
throw new FlowcraftError(`Node '${nodeId}' not found in blueprint.`, {
|
|
14
|
+
nodeId,
|
|
15
|
+
blueprintId: context.blueprint.id,
|
|
16
|
+
executionId: context.executionId,
|
|
17
|
+
isFatal: false
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
const strategy = this.getExecutionStrategy(nodeDef, context.nodeRegistry);
|
|
21
|
+
return new NodeExecutor({ context, nodeDef, strategy });
|
|
22
|
+
}
|
|
23
|
+
getExecutionStrategy(nodeDef, nodeRegistry) {
|
|
24
|
+
const implementation = nodeRegistry.get(nodeDef.uses);
|
|
25
|
+
if (!implementation) {
|
|
26
|
+
throw new FlowcraftError(`Implementation for '${nodeDef.uses}' not found.`, {
|
|
27
|
+
nodeId: nodeDef.id,
|
|
28
|
+
blueprintId: "",
|
|
29
|
+
isFatal: true
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const maxRetries = nodeDef.config?.maxRetries ?? 1;
|
|
33
|
+
return isNodeClass(implementation) ? new ClassNodeExecutor(implementation, maxRetries, this.eventBus) : new FunctionNodeExecutor(implementation, maxRetries, this.eventBus);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export { NodeExecutorFactory };
|
|
38
|
+
//# sourceMappingURL=chunk-DL7KVYZF.js.map
|
|
39
|
+
//# sourceMappingURL=chunk-DL7KVYZF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/node-executor-factory.ts"],"names":[],"mappings":";;;;;AAOO,IAAM,sBAAN,MAA0B;AAAA,EAChC,YAA6B,QAAA,EAAqB;AAArB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EAAsB;AAAA,EAE5C,qBAAA,CAAsB,QAAgB,OAAA,EAA6D;AACzG,IAAA,MAAM,OAAA,GAAU,QAAQ,SAAA,CAAU,KAAA,CAAM,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,MAAM,CAAA;AACnE,IAAA,IAAI,CAAC,OAAA,EAAS;AACb,MAAA,MAAM,IAAI,cAAA,CAAe,CAAA,MAAA,EAAS,MAAM,CAAA,yBAAA,CAAA,EAA6B;AAAA,QACpE,MAAA;AAAA,QACA,WAAA,EAAa,QAAQ,SAAA,CAAU,EAAA;AAAA,QAC/B,aAAa,OAAA,CAAQ,WAAA;AAAA,QACrB,OAAA,EAAS;AAAA,OACT,CAAA;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,oBAAA,CAAqB,OAAA,EAAS,QAAQ,YAAY,CAAA;AAExE,IAAA,OAAO,IAAI,YAAA,CAAa,EAAE,OAAA,EAAS,OAAA,EAAS,UAAU,CAAA;AAAA,EACvD;AAAA,EAEQ,oBAAA,CACP,SACA,YAAA,EACoB;AACpB,IAAA,MAAM,cAAA,GAAiB,YAAA,CAAa,GAAA,CAAI,OAAA,CAAQ,IAAI,CAAA;AACpD,IAAA,IAAI,CAAC,cAAA,EAAgB;AACpB,MAAA,MAAM,IAAI,cAAA,CAAe,CAAA,oBAAA,EAAuB,OAAA,CAAQ,IAAI,CAAA,YAAA,CAAA,EAAgB;AAAA,QAC3E,QAAQ,OAAA,CAAQ,EAAA;AAAA,QAChB,WAAA,EAAa,EAAA;AAAA,QACb,OAAA,EAAS;AAAA,OACT,CAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,MAAA,EAAQ,UAAA,IAAc,CAAA;AACjD,IAAA,OAAO,WAAA,CAAY,cAAc,CAAA,GAC9B,IAAI,kBAAkB,cAAA,EAAgB,UAAA,EAAY,IAAA,CAAK,QAAQ,IAC/D,IAAI,oBAAA,CAAqB,cAAA,EAAgB,UAAA,EAAY,KAAK,QAAQ,CAAA;AAAA,EACtE;AACD","file":"chunk-DL7KVYZF.js","sourcesContent":["import { FlowcraftError } from '../errors'\nimport { isNodeClass } from '../node'\nimport type { IEventBus, NodeClass, NodeDefinition, NodeFunction } from '../types'\nimport type { ExecutionContext } from './execution-context'\nimport type { ExecutionStrategy } from './executors'\nimport { ClassNodeExecutor, FunctionNodeExecutor, NodeExecutor } from './executors'\n\nexport class NodeExecutorFactory {\n\tconstructor(private readonly eventBus: IEventBus) {}\n\n\tpublic createExecutorForNode(nodeId: string, context: ExecutionContext<any, any>): NodeExecutor<any, any> {\n\t\tconst nodeDef = context.blueprint.nodes.find((n) => n.id === nodeId)\n\t\tif (!nodeDef) {\n\t\t\tthrow new FlowcraftError(`Node '${nodeId}' not found in blueprint.`, {\n\t\t\t\tnodeId,\n\t\t\t\tblueprintId: context.blueprint.id,\n\t\t\t\texecutionId: context.executionId,\n\t\t\t\tisFatal: false,\n\t\t\t})\n\t\t}\n\n\t\tconst strategy = this.getExecutionStrategy(nodeDef, context.nodeRegistry)\n\n\t\treturn new NodeExecutor({ context, nodeDef, strategy })\n\t}\n\n\tprivate getExecutionStrategy(\n\t\tnodeDef: NodeDefinition,\n\t\tnodeRegistry: Map<string, NodeFunction | NodeClass>,\n\t): ExecutionStrategy {\n\t\tconst implementation = nodeRegistry.get(nodeDef.uses)\n\t\tif (!implementation) {\n\t\t\tthrow new FlowcraftError(`Implementation for '${nodeDef.uses}' not found.`, {\n\t\t\t\tnodeId: nodeDef.id,\n\t\t\t\tblueprintId: '',\n\t\t\t\tisFatal: true,\n\t\t\t})\n\t\t}\n\n\t\tconst maxRetries = nodeDef.config?.maxRetries ?? 1\n\t\treturn isNodeClass(implementation)\n\t\t\t? new ClassNodeExecutor(implementation, maxRetries, this.eventBus)\n\t\t\t: new FunctionNodeExecutor(implementation, maxRetries, this.eventBus)\n\t}\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { WorkflowState } from './chunk-CD4FUZOJ.js';
|
|
2
|
+
|
|
3
|
+
// src/runtime/execution-context.ts
|
|
4
|
+
var ExecutionContext = class _ExecutionContext {
|
|
5
|
+
constructor(blueprint, state, nodeRegistry, executionId, runtime, services, signal, concurrency) {
|
|
6
|
+
this.blueprint = blueprint;
|
|
7
|
+
this.state = state;
|
|
8
|
+
this.nodeRegistry = nodeRegistry;
|
|
9
|
+
this.executionId = executionId;
|
|
10
|
+
this.runtime = runtime;
|
|
11
|
+
this.services = services;
|
|
12
|
+
this.signal = signal;
|
|
13
|
+
this.concurrency = concurrency;
|
|
14
|
+
}
|
|
15
|
+
createForSubflow(subBlueprint, initialSubState) {
|
|
16
|
+
const subState = new WorkflowState(initialSubState);
|
|
17
|
+
return new _ExecutionContext(
|
|
18
|
+
subBlueprint,
|
|
19
|
+
subState,
|
|
20
|
+
this.nodeRegistry,
|
|
21
|
+
this.executionId,
|
|
22
|
+
this.runtime,
|
|
23
|
+
this.services,
|
|
24
|
+
this.signal,
|
|
25
|
+
this.concurrency
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export { ExecutionContext };
|
|
31
|
+
//# sourceMappingURL=chunk-FRKO3WX4.js.map
|
|
32
|
+
//# sourceMappingURL=chunk-FRKO3WX4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/execution-context.ts"],"names":[],"mappings":";;;AAkBO,IAAM,gBAAA,GAAN,MAAM,iBAAA,CAAkG;AAAA,EAC9G,WAAA,CACiB,WACA,KAAA,EACA,YAAA,EACA,aACA,OAAA,EACA,QAAA,EAQA,QACA,WAAA,EACf;AAfe,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACA,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAQA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AAAA,EACd;AAAA,EAEI,gBAAA,CACN,cACA,eAAA,EAC4C;AAC5C,IAAA,MAAM,QAAA,GAAW,IAAI,aAAA,CAAwB,eAAe,CAAA;AAC5D,IAAA,OAAO,IAAI,iBAAA;AAAA,MACV,YAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA,CAAK,YAAA;AAAA,MACL,IAAA,CAAK,WAAA;AAAA,MACL,IAAA,CAAK,OAAA;AAAA,MACL,IAAA,CAAK,QAAA;AAAA,MACL,IAAA,CAAK,MAAA;AAAA,MACL,IAAA,CAAK;AAAA,KACN;AAAA,EACD;AACD","file":"chunk-FRKO3WX4.js","sourcesContent":["import type {\n\tIEvaluator,\n\tIEventBus,\n\tILogger,\n\tISerializer,\n\tMiddleware,\n\tNodeClass,\n\tNodeFunction,\n\tRuntimeDependencies,\n\tWorkflowBlueprint,\n} from '../types'\nimport type { FlowRuntime } from './runtime'\nimport { WorkflowState } from './state'\n\n/**\n * A container for all state and dependencies of a single workflow execution.\n * This object is created once per `run` and passed through the execution stack.\n */\nexport class ExecutionContext<TContext extends Record<string, any>, TDependencies extends RuntimeDependencies> {\n\tconstructor(\n\t\tpublic readonly blueprint: WorkflowBlueprint,\n\t\tpublic readonly state: WorkflowState<TContext>,\n\t\tpublic readonly nodeRegistry: Map<string, NodeFunction | NodeClass>,\n\t\tpublic readonly executionId: string,\n\t\tpublic readonly runtime: FlowRuntime<TContext, TDependencies>, // A reference back to the runtime for orchestrating subflows\n\t\tpublic readonly services: {\n\t\t\tlogger: ILogger\n\t\t\teventBus: IEventBus\n\t\t\tserializer: ISerializer\n\t\t\tevaluator: IEvaluator\n\t\t\tmiddleware: Middleware[]\n\t\t\tdependencies: TDependencies\n\t\t},\n\t\tpublic readonly signal?: AbortSignal,\n\t\tpublic readonly concurrency?: number,\n\t) {}\n\n\tpublic createForSubflow(\n\t\tsubBlueprint: WorkflowBlueprint,\n\t\tinitialSubState: Partial<TContext>,\n\t): ExecutionContext<TContext, TDependencies> {\n\t\tconst subState = new WorkflowState<TContext>(initialSubState)\n\t\treturn new ExecutionContext(\n\t\t\tsubBlueprint,\n\t\t\tsubState,\n\t\t\tthis.nodeRegistry,\n\t\t\tthis.executionId,\n\t\t\tthis.runtime,\n\t\t\tthis.services,\n\t\t\tthis.signal,\n\t\t\tthis.concurrency,\n\t\t)\n\t}\n}\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { executeBatch, processResults } from './chunk-HAZ26F3P.js';
|
|
2
|
+
import { FlowcraftError } from './chunk-BCRWXTWX.js';
|
|
3
|
+
|
|
4
|
+
// src/runtime/orchestrators/step-by-step.ts
|
|
5
|
+
var StepByStepOrchestrator = class {
|
|
6
|
+
async run(context, traverser) {
|
|
7
|
+
try {
|
|
8
|
+
context.signal?.throwIfAborted();
|
|
9
|
+
} catch (error) {
|
|
10
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
11
|
+
throw new FlowcraftError("Workflow cancelled", { isFatal: false });
|
|
12
|
+
}
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
if (!traverser.hasMoreWork()) {
|
|
16
|
+
const isTraversalComplete2 = !traverser.hasMoreWork();
|
|
17
|
+
const status2 = context.state.getStatus(isTraversalComplete2);
|
|
18
|
+
const result2 = await context.state.toResult(context.services.serializer);
|
|
19
|
+
result2.status = status2;
|
|
20
|
+
return result2;
|
|
21
|
+
}
|
|
22
|
+
const allReadyNodes = traverser.getReadyNodes();
|
|
23
|
+
const nodesToExecute = context.concurrency ? allReadyNodes.slice(0, context.concurrency) : allReadyNodes;
|
|
24
|
+
const nodesToSkip = context.concurrency ? allReadyNodes.slice(context.concurrency) : [];
|
|
25
|
+
const settledResults = await executeBatch(
|
|
26
|
+
nodesToExecute,
|
|
27
|
+
traverser.getDynamicBlueprint(),
|
|
28
|
+
context.state,
|
|
29
|
+
(nodeId) => context.runtime.getExecutorForNode(nodeId, context),
|
|
30
|
+
context.runtime,
|
|
31
|
+
context.concurrency
|
|
32
|
+
);
|
|
33
|
+
await processResults(
|
|
34
|
+
settledResults,
|
|
35
|
+
traverser,
|
|
36
|
+
context.state,
|
|
37
|
+
context.runtime,
|
|
38
|
+
context.blueprint,
|
|
39
|
+
context.executionId
|
|
40
|
+
);
|
|
41
|
+
for (const { nodeId } of nodesToSkip) {
|
|
42
|
+
traverser.addToFrontier(nodeId);
|
|
43
|
+
}
|
|
44
|
+
const isTraversalComplete = !traverser.hasMoreWork();
|
|
45
|
+
const status = context.state.getStatus(isTraversalComplete);
|
|
46
|
+
const result = await context.state.toResult(context.services.serializer);
|
|
47
|
+
result.status = status;
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { StepByStepOrchestrator };
|
|
53
|
+
//# sourceMappingURL=chunk-G53CSLBF.js.map
|
|
54
|
+
//# sourceMappingURL=chunk-G53CSLBF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/orchestrators/step-by-step.ts"],"names":["isTraversalComplete","status","result"],"mappings":";;;;AAeO,IAAM,yBAAN,MAAsD;AAAA,EAC5D,MAAa,GAAA,CAAI,OAAA,EAAqC,SAAA,EAAyD;AAC9G,IAAA,IAAI;AACH,MAAA,OAAA,CAAQ,QAAQ,cAAA,EAAe;AAAA,IAChC,SAAS,KAAA,EAAO;AACf,MAAA,IAAI,KAAA,YAAiB,YAAA,IAAgB,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc;AACjE,QAAA,MAAM,IAAI,cAAA,CAAe,oBAAA,EAAsB,EAAE,OAAA,EAAS,OAAO,CAAA;AAAA,MAClE;AACA,MAAA,MAAM,KAAA;AAAA,IACP;AAEA,IAAA,IAAI,CAAC,SAAA,CAAU,WAAA,EAAY,EAAG;AAC7B,MAAA,MAAMA,oBAAAA,GAAsB,CAAC,SAAA,CAAU,WAAA,EAAY;AACnD,MAAA,MAAMC,OAAAA,GAAS,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAUD,oBAAmB,CAAA;AAC1D,MAAA,MAAME,UAAS,MAAM,OAAA,CAAQ,MAAM,QAAA,CAAS,OAAA,CAAQ,SAAS,UAAU,CAAA;AACvE,MAAAA,QAAO,MAAA,GAASD,OAAAA;AAChB,MAAA,OAAOC,OAAAA;AAAA,IACR;AAEA,IAAA,MAAM,aAAA,GAAgB,UAAU,aAAA,EAAc;AAC9C,IAAA,MAAM,cAAA,GAAiB,QAAQ,WAAA,GAAc,aAAA,CAAc,MAAM,CAAA,EAAG,OAAA,CAAQ,WAAW,CAAA,GAAI,aAAA;AAC3F,IAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,GAAc,aAAA,CAAc,MAAM,OAAA,CAAQ,WAAW,IAAI,EAAC;AAEtF,IAAA,MAAM,iBAAiB,MAAM,YAAA;AAAA,MAC5B,cAAA;AAAA,MACA,UAAU,mBAAA,EAAoB;AAAA,MAC9B,OAAA,CAAQ,KAAA;AAAA,MACR,CAAC,MAAA,KAAmB,OAAA,CAAQ,OAAA,CAAQ,kBAAA,CAAmB,QAAQ,OAAO,CAAA;AAAA,MACtE,OAAA,CAAQ,OAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACT;AAEA,IAAA,MAAM,cAAA;AAAA,MACL,cAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA,CAAQ,KAAA;AAAA,MACR,OAAA,CAAQ,OAAA;AAAA,MACR,OAAA,CAAQ,SAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACT;AAEA,IAAA,KAAA,MAAW,EAAE,MAAA,EAAO,IAAK,WAAA,EAAa;AACrC,MAAA,SAAA,CAAU,cAAc,MAAM,CAAA;AAAA,IAC/B;AAEA,IAAA,MAAM,mBAAA,GAAsB,CAAC,SAAA,CAAU,WAAA,EAAY;AACnD,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAU,mBAAmB,CAAA;AAC1D,IAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,MAAM,QAAA,CAAS,OAAA,CAAQ,SAAS,UAAU,CAAA;AACvE,IAAA,MAAA,CAAO,MAAA,GAAS,MAAA;AAChB,IAAA,OAAO,MAAA;AAAA,EACR;AACD","file":"chunk-G53CSLBF.js","sourcesContent":["import { FlowcraftError } from '../../errors'\n\nimport type { WorkflowResult } from '../../types'\nimport type { ExecutionContext } from '../execution-context'\nimport type { GraphTraverser } from '../traverser'\nimport type { IOrchestrator } from '../types'\nimport { executeBatch, processResults } from './utils'\n\n/**\n * An orchestrator that executes only one \"tick\" or \"turn\" of the workflow.\n * It processes a single batch of ready nodes from the frontier and then returns,\n * allowing the caller to inspect the intermediate state before proceeding.\n *\n * Useful for debugging, testing, or building interactive tools.\n */\nexport class StepByStepOrchestrator implements IOrchestrator {\n\tpublic async run(context: ExecutionContext<any, any>, traverser: GraphTraverser): Promise<WorkflowResult<any>> {\n\t\ttry {\n\t\t\tcontext.signal?.throwIfAborted()\n\t\t} catch (error) {\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow new FlowcraftError('Workflow cancelled', { isFatal: false })\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\n\t\tif (!traverser.hasMoreWork()) {\n\t\t\tconst isTraversalComplete = !traverser.hasMoreWork()\n\t\t\tconst status = context.state.getStatus(isTraversalComplete)\n\t\t\tconst result = await context.state.toResult(context.services.serializer)\n\t\t\tresult.status = status\n\t\t\treturn result\n\t\t}\n\n\t\tconst allReadyNodes = traverser.getReadyNodes()\n\t\tconst nodesToExecute = context.concurrency ? allReadyNodes.slice(0, context.concurrency) : allReadyNodes\n\t\tconst nodesToSkip = context.concurrency ? allReadyNodes.slice(context.concurrency) : []\n\n\t\tconst settledResults = await executeBatch(\n\t\t\tnodesToExecute,\n\t\t\ttraverser.getDynamicBlueprint(),\n\t\t\tcontext.state,\n\t\t\t(nodeId: string) => context.runtime.getExecutorForNode(nodeId, context),\n\t\t\tcontext.runtime,\n\t\t\tcontext.concurrency,\n\t\t)\n\n\t\tawait processResults(\n\t\t\tsettledResults,\n\t\t\ttraverser,\n\t\t\tcontext.state,\n\t\t\tcontext.runtime,\n\t\t\tcontext.blueprint,\n\t\t\tcontext.executionId,\n\t\t)\n\n\t\tfor (const { nodeId } of nodesToSkip) {\n\t\t\ttraverser.addToFrontier(nodeId)\n\t\t}\n\n\t\tconst isTraversalComplete = !traverser.hasMoreWork()\n\t\tconst status = context.state.getStatus(isTraversalComplete)\n\t\tconst result = await context.state.toResult(context.services.serializer)\n\t\tresult.status = status\n\t\treturn result\n\t}\n}\n"]}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { analyzeBlueprint } from './chunk-233SESC2.js';
|
|
2
|
+
|
|
3
|
+
// src/runtime/traverser.ts
|
|
4
|
+
var GraphTraverser = class _GraphTraverser {
|
|
5
|
+
frontier = /* @__PURE__ */ new Set();
|
|
6
|
+
allPredecessors;
|
|
7
|
+
dynamicBlueprint;
|
|
8
|
+
completedNodes = /* @__PURE__ */ new Set();
|
|
9
|
+
constructor(blueprint, isStrictMode = false) {
|
|
10
|
+
this.dynamicBlueprint = structuredClone(blueprint);
|
|
11
|
+
this.allPredecessors = /* @__PURE__ */ new Map();
|
|
12
|
+
for (const node of this.dynamicBlueprint.nodes) {
|
|
13
|
+
this.allPredecessors.set(node.id, /* @__PURE__ */ new Set());
|
|
14
|
+
}
|
|
15
|
+
for (const edge of this.dynamicBlueprint.edges) {
|
|
16
|
+
this.allPredecessors.get(edge.target)?.add(edge.source);
|
|
17
|
+
}
|
|
18
|
+
const analysis = analyzeBlueprint(blueprint);
|
|
19
|
+
this.frontier = new Set(analysis.startNodeIds.filter((id) => !this.isFallbackNode(id)));
|
|
20
|
+
if (this.frontier.size === 0 && analysis.cycles.length > 0 && !isStrictMode) {
|
|
21
|
+
const uniqueStartNodes = /* @__PURE__ */ new Set();
|
|
22
|
+
const cycleEntryPoints = new Set(blueprint.metadata?.cycleEntryPoints || []);
|
|
23
|
+
for (const cycle of analysis.cycles) {
|
|
24
|
+
if (cycle.length > 0) {
|
|
25
|
+
const entryPoint = cycle.find((node) => cycleEntryPoints.has(node));
|
|
26
|
+
uniqueStartNodes.add(entryPoint || cycle[0]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
this.frontier = new Set(uniqueStartNodes);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Clears all nodes from the execution frontier.
|
|
34
|
+
*/
|
|
35
|
+
clearFrontier() {
|
|
36
|
+
this.frontier.clear();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Creates and initializes a GraphTraverser from a saved workflow state.
|
|
40
|
+
* This is the correct way to prepare a traverser for a `resume` operation.
|
|
41
|
+
* @param blueprint The workflow blueprint.
|
|
42
|
+
* @param state The workflow state being resumed.
|
|
43
|
+
* @returns A configured GraphTraverser instance.
|
|
44
|
+
*/
|
|
45
|
+
static fromState(blueprint, state) {
|
|
46
|
+
const traverser = new _GraphTraverser(blueprint);
|
|
47
|
+
traverser.clearFrontier();
|
|
48
|
+
const completedNodes = state.getCompletedNodes();
|
|
49
|
+
traverser.completedNodes = new Set(completedNodes);
|
|
50
|
+
for (const node of traverser.dynamicBlueprint.nodes) {
|
|
51
|
+
if (traverser.completedNodes.has(node.id)) continue;
|
|
52
|
+
const requiredPredecessors = traverser.allPredecessors.get(node.id);
|
|
53
|
+
const joinStrategy = traverser.getEffectiveJoinStrategy(node.id);
|
|
54
|
+
if (!requiredPredecessors || requiredPredecessors.size === 0) {
|
|
55
|
+
traverser.frontier.add(node.id);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const completedPredecessors = [...requiredPredecessors].filter((p) => traverser.completedNodes.has(p));
|
|
59
|
+
const isReady = joinStrategy === "any" ? completedPredecessors.length > 0 : completedPredecessors.length === requiredPredecessors.size;
|
|
60
|
+
if (isReady) traverser.frontier.add(node.id);
|
|
61
|
+
}
|
|
62
|
+
return traverser;
|
|
63
|
+
}
|
|
64
|
+
isFallbackNode(nodeId) {
|
|
65
|
+
return this.dynamicBlueprint.nodes.some((n) => n.config?.fallback === nodeId);
|
|
66
|
+
}
|
|
67
|
+
getEffectiveJoinStrategy(nodeId) {
|
|
68
|
+
const node = this.dynamicBlueprint.nodes.find((n) => n.id === nodeId);
|
|
69
|
+
const baseJoinStrategy = node?.config?.joinStrategy || "all";
|
|
70
|
+
if (node?.uses === "loop-controller") {
|
|
71
|
+
return "any";
|
|
72
|
+
}
|
|
73
|
+
const predecessors = this.allPredecessors.get(nodeId);
|
|
74
|
+
if (predecessors) {
|
|
75
|
+
for (const predecessorId of predecessors) {
|
|
76
|
+
const predecessorNode = this.dynamicBlueprint.nodes.find((n) => n.id === predecessorId);
|
|
77
|
+
if (predecessorNode?.uses === "loop-controller") {
|
|
78
|
+
return "any";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return baseJoinStrategy;
|
|
83
|
+
}
|
|
84
|
+
getReadyNodes() {
|
|
85
|
+
const readyNodes = [];
|
|
86
|
+
for (const nodeId of this.frontier) {
|
|
87
|
+
const nodeDef = this.dynamicBlueprint.nodes.find((n) => n.id === nodeId);
|
|
88
|
+
if (nodeDef) {
|
|
89
|
+
readyNodes.push({ nodeId, nodeDef });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
this.frontier.clear();
|
|
93
|
+
return readyNodes;
|
|
94
|
+
}
|
|
95
|
+
hasMoreWork() {
|
|
96
|
+
return this.frontier.size > 0;
|
|
97
|
+
}
|
|
98
|
+
markNodeCompleted(nodeId, result, nextNodes) {
|
|
99
|
+
this.completedNodes.add(nodeId);
|
|
100
|
+
if (result.dynamicNodes && result.dynamicNodes.length > 0) {
|
|
101
|
+
const gatherNodeId = result.output?.gatherNodeId;
|
|
102
|
+
for (const dynamicNode of result.dynamicNodes) {
|
|
103
|
+
this.dynamicBlueprint.nodes.push(dynamicNode);
|
|
104
|
+
this.allPredecessors.set(dynamicNode.id, /* @__PURE__ */ new Set([nodeId]));
|
|
105
|
+
if (gatherNodeId) {
|
|
106
|
+
this.allPredecessors.get(gatherNodeId)?.add(dynamicNode.id);
|
|
107
|
+
}
|
|
108
|
+
this.frontier.add(dynamicNode.id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const node of nextNodes) {
|
|
112
|
+
const joinStrategy = this.getEffectiveJoinStrategy(node.id);
|
|
113
|
+
if (joinStrategy !== "any" && this.completedNodes.has(node.id)) continue;
|
|
114
|
+
const requiredPredecessors = this.allPredecessors.get(node.id);
|
|
115
|
+
if (!requiredPredecessors) continue;
|
|
116
|
+
const isReady = joinStrategy === "any" ? requiredPredecessors.has(nodeId) : [...requiredPredecessors].every((p) => this.completedNodes.has(p));
|
|
117
|
+
if (isReady) {
|
|
118
|
+
this.frontier.add(node.id);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (nextNodes.length === 0) {
|
|
122
|
+
for (const [potentialNextId, predecessors] of this.allPredecessors) {
|
|
123
|
+
if (predecessors.has(nodeId) && !this.completedNodes.has(potentialNextId)) {
|
|
124
|
+
const joinStrategy = this.getEffectiveJoinStrategy(potentialNextId);
|
|
125
|
+
const isReady = joinStrategy === "any" ? predecessors.has(nodeId) : [...predecessors].every((p) => this.completedNodes.has(p));
|
|
126
|
+
if (isReady) {
|
|
127
|
+
this.frontier.add(potentialNextId);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
getAllNodeIds() {
|
|
134
|
+
return new Set(this.dynamicBlueprint.nodes.map((n) => n.id));
|
|
135
|
+
}
|
|
136
|
+
getFallbackNodeIds() {
|
|
137
|
+
const fallbackNodeIds = /* @__PURE__ */ new Set();
|
|
138
|
+
for (const node of this.dynamicBlueprint.nodes) {
|
|
139
|
+
if (node.config?.fallback) fallbackNodeIds.add(node.config.fallback);
|
|
140
|
+
}
|
|
141
|
+
return fallbackNodeIds;
|
|
142
|
+
}
|
|
143
|
+
getCompletedNodes() {
|
|
144
|
+
return new Set(this.completedNodes);
|
|
145
|
+
}
|
|
146
|
+
getDynamicBlueprint() {
|
|
147
|
+
return this.dynamicBlueprint;
|
|
148
|
+
}
|
|
149
|
+
getAllPredecessors() {
|
|
150
|
+
return this.allPredecessors;
|
|
151
|
+
}
|
|
152
|
+
addDynamicNode(_nodeId, dynamicNode, predecessorId, gatherNodeId) {
|
|
153
|
+
this.dynamicBlueprint.nodes.push(dynamicNode);
|
|
154
|
+
this.allPredecessors.set(dynamicNode.id, /* @__PURE__ */ new Set([predecessorId]));
|
|
155
|
+
if (gatherNodeId) {
|
|
156
|
+
this.allPredecessors.get(gatherNodeId)?.add(dynamicNode.id);
|
|
157
|
+
}
|
|
158
|
+
this.frontier.add(dynamicNode.id);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Manually adds a node ID back to the execution frontier.
|
|
162
|
+
* Used by orchestrators that need fine-grained control over steps.
|
|
163
|
+
* @param nodeId The ID of the node to add to the frontier.
|
|
164
|
+
*/
|
|
165
|
+
addToFrontier(nodeId) {
|
|
166
|
+
this.frontier.add(nodeId);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export { GraphTraverser };
|
|
171
|
+
//# sourceMappingURL=chunk-G5BGBPFP.js.map
|
|
172
|
+
//# sourceMappingURL=chunk-G5BGBPFP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/traverser.ts"],"names":[],"mappings":"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","file":"chunk-G5BGBPFP.js","sourcesContent":["import { analyzeBlueprint } from '../analysis'\nimport type { NodeDefinition, NodeResult, WorkflowBlueprint } from '../types'\nimport type { WorkflowState } from './state'\n\nexport interface ReadyNode {\n\tnodeId: string\n\tnodeDef: NodeDefinition\n}\n\nexport class GraphTraverser {\n\tprivate frontier = new Set<string>()\n\tprivate allPredecessors: Map<string, Set<string>>\n\tprivate dynamicBlueprint: WorkflowBlueprint\n\tprivate completedNodes = new Set<string>()\n\n\tconstructor(blueprint: WorkflowBlueprint, isStrictMode: boolean = false) {\n\t\tthis.dynamicBlueprint = structuredClone(blueprint) as WorkflowBlueprint\n\t\tthis.allPredecessors = new Map<string, Set<string>>()\n\t\tfor (const node of this.dynamicBlueprint.nodes) {\n\t\t\tthis.allPredecessors.set(node.id, new Set())\n\t\t}\n\t\tfor (const edge of this.dynamicBlueprint.edges) {\n\t\t\tthis.allPredecessors.get(edge.target)?.add(edge.source)\n\t\t}\n\t\tconst analysis = analyzeBlueprint(blueprint)\n\t\tthis.frontier = new Set(analysis.startNodeIds.filter((id) => !this.isFallbackNode(id)))\n\t\tif (this.frontier.size === 0 && analysis.cycles.length > 0 && !isStrictMode) {\n\t\t\tconst uniqueStartNodes = new Set<string>()\n\t\t\tconst cycleEntryPoints = new Set(blueprint.metadata?.cycleEntryPoints || [])\n\t\t\tfor (const cycle of analysis.cycles) {\n\t\t\t\tif (cycle.length > 0) {\n\t\t\t\t\tconst entryPoint = cycle.find((node) => cycleEntryPoints.has(node))\n\t\t\t\t\tuniqueStartNodes.add(entryPoint || cycle[0])\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.frontier = new Set(uniqueStartNodes)\n\t\t}\n\t}\n\n\t/**\n\t * Clears all nodes from the execution frontier.\n\t */\n\tpublic clearFrontier(): void {\n\t\tthis.frontier.clear()\n\t}\n\n\t/**\n\t * Creates and initializes a GraphTraverser from a saved workflow state.\n\t * This is the correct way to prepare a traverser for a `resume` operation.\n\t * @param blueprint The workflow blueprint.\n\t * @param state The workflow state being resumed.\n\t * @returns A configured GraphTraverser instance.\n\t */\n\tpublic static fromState(blueprint: WorkflowBlueprint, state: WorkflowState<any>): GraphTraverser {\n\t\tconst traverser = new GraphTraverser(blueprint)\n\n\t\t// clear auto-populated frontier from constructor\n\t\ttraverser.clearFrontier()\n\n\t\t// re-hydrate the set of completed nodes\n\t\tconst completedNodes = state.getCompletedNodes()\n\t\ttraverser.completedNodes = new Set(completedNodes)\n\n\t\tfor (const node of traverser.dynamicBlueprint.nodes) {\n\t\t\tif (traverser.completedNodes.has(node.id)) continue\n\n\t\t\tconst requiredPredecessors = traverser.allPredecessors.get(node.id)\n\t\t\tconst joinStrategy = traverser.getEffectiveJoinStrategy(node.id)\n\n\t\t\t// if no predecessors and not completed, it's a start node and should be in the frontier\n\t\t\tif (!requiredPredecessors || requiredPredecessors.size === 0) {\n\t\t\t\ttraverser.frontier.add(node.id)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst completedPredecessors = [...requiredPredecessors].filter((p) => traverser.completedNodes.has(p))\n\t\t\tconst isReady =\n\t\t\t\tjoinStrategy === 'any'\n\t\t\t\t\t? completedPredecessors.length > 0\n\t\t\t\t\t: completedPredecessors.length === requiredPredecessors.size\n\n\t\t\tif (isReady) traverser.frontier.add(node.id)\n\t\t}\n\n\t\treturn traverser\n\t}\n\n\tprivate isFallbackNode(nodeId: string): boolean {\n\t\treturn this.dynamicBlueprint.nodes.some((n) => n.config?.fallback === nodeId)\n\t}\n\n\tprivate getEffectiveJoinStrategy(nodeId: string): 'any' | 'all' {\n\t\tconst node = this.dynamicBlueprint.nodes.find((n) => n.id === nodeId)\n\t\tconst baseJoinStrategy = node?.config?.joinStrategy || 'all'\n\n\t\tif (node?.uses === 'loop-controller') {\n\t\t\treturn 'any'\n\t\t}\n\n\t\tconst predecessors = this.allPredecessors.get(nodeId)\n\t\tif (predecessors) {\n\t\t\tfor (const predecessorId of predecessors) {\n\t\t\t\tconst predecessorNode = this.dynamicBlueprint.nodes.find((n) => n.id === predecessorId)\n\t\t\t\tif (predecessorNode?.uses === 'loop-controller') {\n\t\t\t\t\treturn 'any'\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn baseJoinStrategy\n\t}\n\n\tgetReadyNodes(): ReadyNode[] {\n\t\tconst readyNodes: ReadyNode[] = []\n\t\tfor (const nodeId of this.frontier) {\n\t\t\tconst nodeDef = this.dynamicBlueprint.nodes.find((n) => n.id === nodeId)\n\t\t\tif (nodeDef) {\n\t\t\t\treadyNodes.push({ nodeId, nodeDef })\n\t\t\t}\n\t\t}\n\t\tthis.frontier.clear()\n\t\treturn readyNodes\n\t}\n\n\thasMoreWork(): boolean {\n\t\treturn this.frontier.size > 0\n\t}\n\n\tmarkNodeCompleted(nodeId: string, result: NodeResult<any, any>, nextNodes: NodeDefinition[]): void {\n\t\tthis.completedNodes.add(nodeId)\n\n\t\tif (result.dynamicNodes && result.dynamicNodes.length > 0) {\n\t\t\tconst gatherNodeId = result.output?.gatherNodeId\n\t\t\tfor (const dynamicNode of result.dynamicNodes) {\n\t\t\t\tthis.dynamicBlueprint.nodes.push(dynamicNode)\n\t\t\t\tthis.allPredecessors.set(dynamicNode.id, new Set([nodeId]))\n\t\t\t\tif (gatherNodeId) {\n\t\t\t\t\tthis.allPredecessors.get(gatherNodeId)?.add(dynamicNode.id)\n\t\t\t\t}\n\t\t\t\tthis.frontier.add(dynamicNode.id)\n\t\t\t}\n\t\t}\n\n\t\tfor (const node of nextNodes) {\n\t\t\tconst joinStrategy = this.getEffectiveJoinStrategy(node.id)\n\t\t\tif (joinStrategy !== 'any' && this.completedNodes.has(node.id)) continue\n\n\t\t\tconst requiredPredecessors = this.allPredecessors.get(node.id)\n\t\t\tif (!requiredPredecessors) continue\n\n\t\t\tconst isReady =\n\t\t\t\tjoinStrategy === 'any'\n\t\t\t\t\t? requiredPredecessors.has(nodeId)\n\t\t\t\t\t: [...requiredPredecessors].every((p) => this.completedNodes.has(p))\n\n\t\t\tif (isReady) {\n\t\t\t\tthis.frontier.add(node.id)\n\t\t\t}\n\t\t}\n\n\t\tif (nextNodes.length === 0) {\n\t\t\tfor (const [potentialNextId, predecessors] of this.allPredecessors) {\n\t\t\t\tif (predecessors.has(nodeId) && !this.completedNodes.has(potentialNextId)) {\n\t\t\t\t\tconst joinStrategy = this.getEffectiveJoinStrategy(potentialNextId)\n\t\t\t\t\tconst isReady =\n\t\t\t\t\t\tjoinStrategy === 'any'\n\t\t\t\t\t\t\t? predecessors.has(nodeId)\n\t\t\t\t\t\t\t: [...predecessors].every((p) => this.completedNodes.has(p))\n\t\t\t\t\tif (isReady) {\n\t\t\t\t\t\tthis.frontier.add(potentialNextId)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tgetAllNodeIds(): Set<string> {\n\t\treturn new Set(this.dynamicBlueprint.nodes.map((n) => n.id))\n\t}\n\n\tgetFallbackNodeIds(): Set<string> {\n\t\tconst fallbackNodeIds = new Set<string>()\n\t\tfor (const node of this.dynamicBlueprint.nodes) {\n\t\t\tif (node.config?.fallback) fallbackNodeIds.add(node.config.fallback)\n\t\t}\n\t\treturn fallbackNodeIds\n\t}\n\n\tgetCompletedNodes(): Set<string> {\n\t\treturn new Set(this.completedNodes)\n\t}\n\n\tgetDynamicBlueprint(): WorkflowBlueprint {\n\t\treturn this.dynamicBlueprint\n\t}\n\n\tgetAllPredecessors(): Map<string, Set<string>> {\n\t\treturn this.allPredecessors\n\t}\n\n\taddDynamicNode(_nodeId: string, dynamicNode: NodeDefinition, predecessorId: string, gatherNodeId?: string): void {\n\t\tthis.dynamicBlueprint.nodes.push(dynamicNode)\n\t\tthis.allPredecessors.set(dynamicNode.id, new Set([predecessorId]))\n\t\tif (gatherNodeId) {\n\t\t\tthis.allPredecessors.get(gatherNodeId)?.add(dynamicNode.id)\n\t\t}\n\t\tthis.frontier.add(dynamicNode.id)\n\t}\n\n\t/**\n\t * Manually adds a node ID back to the execution frontier.\n\t * Used by orchestrators that need fine-grained control over steps.\n\t * @param nodeId The ID of the node to add to the frontier.\n\t */\n\tpublic addToFrontier(nodeId: string): void {\n\t\tthis.frontier.add(nodeId)\n\t}\n}\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { FlowcraftError } from './chunk-BCRWXTWX.js';
|
|
2
|
+
|
|
3
|
+
// src/runtime/orchestrators/utils.ts
|
|
4
|
+
async function executeBatch(readyNodes, blueprint, state, executorFactory, runtime, maxConcurrency) {
|
|
5
|
+
const concurrency = maxConcurrency || readyNodes.length;
|
|
6
|
+
const results = [];
|
|
7
|
+
for (let i = 0; i < readyNodes.length; i += concurrency) {
|
|
8
|
+
const batch = readyNodes.slice(i, i + concurrency);
|
|
9
|
+
const batchPromises = batch.map(async ({ nodeId }) => {
|
|
10
|
+
try {
|
|
11
|
+
const executor = executorFactory(nodeId);
|
|
12
|
+
if (!executor) throw new Error(`No executor for node ${nodeId}`);
|
|
13
|
+
const executionResult = await executor.execute(
|
|
14
|
+
await runtime.resolveNodeInput(nodeId, blueprint, state.getContext())
|
|
15
|
+
);
|
|
16
|
+
results.push({
|
|
17
|
+
status: "fulfilled",
|
|
18
|
+
value: { nodeId, executionResult }
|
|
19
|
+
});
|
|
20
|
+
} catch (error) {
|
|
21
|
+
results.push({
|
|
22
|
+
status: "rejected",
|
|
23
|
+
reason: { nodeId, error }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
await Promise.all(batchPromises);
|
|
28
|
+
}
|
|
29
|
+
return results;
|
|
30
|
+
}
|
|
31
|
+
async function processResults(settledResults, traverser, state, runtime, _blueprint, executionId) {
|
|
32
|
+
for (const promiseResult of settledResults) {
|
|
33
|
+
if (promiseResult.status === "rejected") {
|
|
34
|
+
const { nodeId: nodeId2, error } = promiseResult.reason;
|
|
35
|
+
if (error instanceof FlowcraftError && error.message.includes("cancelled")) {
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
state.addError(nodeId2, error);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const { nodeId, executionResult } = promiseResult.value;
|
|
42
|
+
if (executionResult.status === "success") {
|
|
43
|
+
const result = executionResult.result;
|
|
44
|
+
state.addCompletedNode(nodeId, result.output);
|
|
45
|
+
if (result._fallbackExecuted) {
|
|
46
|
+
state.markFallbackExecuted();
|
|
47
|
+
}
|
|
48
|
+
if (result.dynamicNodes && result.dynamicNodes.length > 0) {
|
|
49
|
+
const gatherNodeId = result.output?.gatherNodeId;
|
|
50
|
+
for (const dynamicNode of result.dynamicNodes) {
|
|
51
|
+
traverser.addDynamicNode(dynamicNode.id, dynamicNode, nodeId, gatherNodeId);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const matched = await runtime.determineNextNodes(
|
|
55
|
+
traverser.getDynamicBlueprint(),
|
|
56
|
+
nodeId,
|
|
57
|
+
result,
|
|
58
|
+
state.getContext(),
|
|
59
|
+
executionId
|
|
60
|
+
);
|
|
61
|
+
const loopControllerMatch = matched.find(
|
|
62
|
+
(m) => m.node.uses === "loop-controller"
|
|
63
|
+
);
|
|
64
|
+
const finalMatched = loopControllerMatch ? [loopControllerMatch] : matched;
|
|
65
|
+
for (const { node, edge } of finalMatched) {
|
|
66
|
+
await runtime.applyEdgeTransform(edge, result, node, state.getContext(), traverser.getAllPredecessors());
|
|
67
|
+
}
|
|
68
|
+
traverser.markNodeCompleted(
|
|
69
|
+
nodeId,
|
|
70
|
+
result,
|
|
71
|
+
finalMatched.map((m) => m.node)
|
|
72
|
+
);
|
|
73
|
+
} else if (executionResult.status === "failed_with_fallback") {
|
|
74
|
+
const { fallbackNodeId, error } = executionResult;
|
|
75
|
+
const blueprint = traverser.getDynamicBlueprint();
|
|
76
|
+
const fallbackNodeDef = blueprint.nodes.find((n) => n.id === fallbackNodeId);
|
|
77
|
+
if (!fallbackNodeDef) {
|
|
78
|
+
const notFoundError = new FlowcraftError(`Fallback node '${fallbackNodeId}' not found in blueprint.`, {
|
|
79
|
+
nodeId,
|
|
80
|
+
cause: error
|
|
81
|
+
});
|
|
82
|
+
state.addError(nodeId, notFoundError);
|
|
83
|
+
} else {
|
|
84
|
+
state.addCompletedNode(nodeId, null);
|
|
85
|
+
state.markFallbackExecuted();
|
|
86
|
+
traverser.markNodeCompleted(nodeId, { action: "fallback", output: null, _fallbackExecuted: true }, [
|
|
87
|
+
fallbackNodeDef
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
state.addError(nodeId, executionResult.error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { executeBatch, processResults };
|
|
97
|
+
//# sourceMappingURL=chunk-HAZ26F3P.js.map
|
|
98
|
+
//# sourceMappingURL=chunk-HAZ26F3P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/orchestrators/utils.ts"],"names":["nodeId"],"mappings":"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","file":"chunk-HAZ26F3P.js","sourcesContent":["import { FlowcraftError } from '../../errors'\nimport type { NodeDefinition, WorkflowBlueprint } from '../../types'\nimport type { NodeExecutionResult } from '../executors'\nimport type { WorkflowState } from '../state'\nimport type { GraphTraverser } from '../traverser'\n\nexport async function executeBatch(\n\treadyNodes: Array<{ nodeId: string; nodeDef: any }>,\n\tblueprint: WorkflowBlueprint,\n\tstate: WorkflowState<any>,\n\texecutorFactory: (nodeId: string) => any,\n\truntime: any,\n\tmaxConcurrency?: number,\n): Promise<\n\tArray<\n\t\t| { status: 'fulfilled'; value: { nodeId: string; executionResult: NodeExecutionResult } }\n\t\t| { status: 'rejected'; reason: { nodeId: string; error: unknown } }\n\t>\n> {\n\tconst concurrency = maxConcurrency || readyNodes.length\n\tconst results: Array<\n\t\t| { status: 'fulfilled'; value: { nodeId: string; executionResult: NodeExecutionResult } }\n\t\t| { status: 'rejected'; reason: { nodeId: string; error: unknown } }\n\t> = []\n\n\tfor (let i = 0; i < readyNodes.length; i += concurrency) {\n\t\tconst batch = readyNodes.slice(i, i + concurrency)\n\t\tconst batchPromises = batch.map(async ({ nodeId }) => {\n\t\t\ttry {\n\t\t\t\tconst executor = executorFactory(nodeId)\n\t\t\t\tif (!executor) throw new Error(`No executor for node ${nodeId}`)\n\t\t\t\tconst executionResult = await executor.execute(\n\t\t\t\t\tawait runtime.resolveNodeInput(nodeId, blueprint, state.getContext()),\n\t\t\t\t)\n\t\t\t\tresults.push({\n\t\t\t\t\tstatus: 'fulfilled' as const,\n\t\t\t\t\tvalue: { nodeId, executionResult },\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\tresults.push({\n\t\t\t\t\tstatus: 'rejected' as const,\n\t\t\t\t\treason: { nodeId, error },\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\n\t\tawait Promise.all(batchPromises)\n\t}\n\n\treturn results\n}\n\nexport async function processResults(\n\tsettledResults: Array<\n\t\t| { status: 'fulfilled'; value: { nodeId: string; executionResult: NodeExecutionResult } }\n\t\t| { status: 'rejected'; reason: { nodeId: string; error: unknown } }\n\t>,\n\ttraverser: GraphTraverser,\n\tstate: WorkflowState<any>,\n\truntime: any,\n\t_blueprint: WorkflowBlueprint,\n\texecutionId?: string,\n): Promise<void> {\n\tfor (const promiseResult of settledResults) {\n\t\tif (promiseResult.status === 'rejected') {\n\t\t\tconst { nodeId, error } = promiseResult.reason\n\t\t\tif (error instanceof FlowcraftError && error.message.includes('cancelled')) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tstate.addError(nodeId, error as Error)\n\t\t\tcontinue\n\t\t}\n\n\t\tconst { nodeId, executionResult } = promiseResult.value\n\n\t\tif (executionResult.status === 'success') {\n\t\t\tconst result = executionResult.result\n\t\t\tstate.addCompletedNode(nodeId, result.output)\n\t\t\tif (result._fallbackExecuted) {\n\t\t\t\tstate.markFallbackExecuted()\n\t\t\t}\n\n\t\t\tif (result.dynamicNodes && result.dynamicNodes.length > 0) {\n\t\t\t\tconst gatherNodeId = result.output?.gatherNodeId\n\t\t\t\tfor (const dynamicNode of result.dynamicNodes) {\n\t\t\t\t\ttraverser.addDynamicNode(dynamicNode.id, dynamicNode, nodeId, gatherNodeId)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst matched = await runtime.determineNextNodes(\n\t\t\t\ttraverser.getDynamicBlueprint(),\n\t\t\t\tnodeId,\n\t\t\t\tresult,\n\t\t\t\tstate.getContext(),\n\t\t\t\texecutionId,\n\t\t\t)\n\n\t\t\tconst loopControllerMatch = matched.find(\n\t\t\t\t(m: { node: NodeDefinition; edge: any }) => m.node.uses === 'loop-controller',\n\t\t\t)\n\t\t\tconst finalMatched = loopControllerMatch ? [loopControllerMatch] : matched\n\n\t\t\tfor (const { node, edge } of finalMatched) {\n\t\t\t\tawait runtime.applyEdgeTransform(edge, result, node, state.getContext(), traverser.getAllPredecessors())\n\t\t\t}\n\n\t\t\ttraverser.markNodeCompleted(\n\t\t\t\tnodeId,\n\t\t\t\tresult,\n\t\t\t\tfinalMatched.map((m: { node: NodeDefinition; edge: any }) => m.node),\n\t\t\t)\n\t\t} else if (executionResult.status === 'failed_with_fallback') {\n\t\t\tconst { fallbackNodeId, error } = executionResult\n\t\t\tconst blueprint = traverser.getDynamicBlueprint()\n\t\t\tconst fallbackNodeDef = blueprint.nodes.find((n) => n.id === fallbackNodeId)\n\n\t\t\tif (!fallbackNodeDef) {\n\t\t\t\tconst notFoundError = new FlowcraftError(`Fallback node '${fallbackNodeId}' not found in blueprint.`, {\n\t\t\t\t\tnodeId,\n\t\t\t\t\tcause: error,\n\t\t\t\t})\n\t\t\t\tstate.addError(nodeId, notFoundError)\n\t\t\t} else {\n\t\t\t\tstate.addCompletedNode(nodeId, null)\n\t\t\t\tstate.markFallbackExecuted()\n\n\t\t\t\ttraverser.markNodeCompleted(nodeId, { action: 'fallback', output: null, _fallbackExecuted: true }, [\n\t\t\t\t\tfallbackNodeDef,\n\t\t\t\t])\n\t\t\t}\n\t\t} else {\n\t\t\tstate.addError(nodeId, executionResult.error)\n\t\t}\n\t}\n}\n"]}
|