@codemation/core 0.0.5 → 0.0.11
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/dist/{InMemoryLiveWorkflowRepository-DL7LmC9S.d.ts → InMemoryLiveWorkflowRepository-DxoualoC.d.ts} +6 -2
- package/dist/{InMemoryLiveWorkflowRepository-D6eiiXxF.d.cts → InMemoryLiveWorkflowRepository-orY1VsWG.d.cts} +6 -2
- package/dist/{RunIntentService-NKobsfMQ.d.cts → RunIntentService-ByuUYsAL.d.cts} +8 -3
- package/dist/{RunIntentService-BFVbsOcg.js → RunIntentService-CYnn140t.js} +9 -4
- package/dist/RunIntentService-CYnn140t.js.map +1 -0
- package/dist/{RunIntentService-2ivFmNQh.cjs → RunIntentService-DlQH5eZ2.cjs} +9 -4
- package/dist/RunIntentService-DlQH5eZ2.cjs.map +1 -0
- package/dist/{WorkflowSnapshotCodec-DTdWkoW_.d.cts → WorkflowSnapshotCodec-DSEzKyt3.d.cts} +2 -2
- package/dist/bootstrap/index.cjs +133 -4
- package/dist/bootstrap/index.cjs.map +1 -1
- package/dist/bootstrap/index.d.cts +4 -3
- package/dist/bootstrap/index.d.ts +3 -2
- package/dist/bootstrap/index.js +133 -4
- package/dist/bootstrap/index.js.map +1 -1
- package/dist/{index-9g6Pfe9Z.d.ts → index-CTjfVHJh.d.ts} +8 -3
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.ts +1 -1
- package/package.json +6 -1
- package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +10 -2
- package/src/contracts/runtimeTypes.ts +5 -0
- package/src/execution/NodeActivationRequestComposer.ts +15 -4
- package/src/orchestration/Engine.ts +12 -1
- package/src/orchestration/NodeExecutionRequestHandlerService.ts +179 -0
- package/src/runtime/EngineFactory.ts +13 -0
- package/dist/EngineExecutionLimitsPolicy-8MEFIYx1.d.cts +0 -160
- package/dist/EngineExecutionLimitsPolicy-BWAXW9D6.d.cts +0 -160
- package/dist/EngineExecutionLimitsPolicy-Bp8PS1Ss.d.cts +0 -159
- package/dist/EngineExecutionLimitsPolicy-CLxcN-D2.d.ts +0 -159
- package/dist/EngineExecutionLimitsPolicy-DZXuix51.d.ts +0 -160
- package/dist/EngineExecutionLimitsPolicy-Gfz6ngFd.d.ts +0 -160
- package/dist/EngineFactory-CBnntY3J.cjs +0 -3152
- package/dist/EngineFactory-CBnntY3J.cjs.map +0 -1
- package/dist/EngineFactory-Cwn3R2YA.js +0 -3087
- package/dist/EngineFactory-Cwn3R2YA.js.map +0 -1
- package/dist/EngineFactory-DWCnNocp.js +0 -3063
- package/dist/EngineFactory-DWCnNocp.js.map +0 -1
- package/dist/EngineFactory-DhPFou4p.cjs +0 -3188
- package/dist/EngineFactory-DhPFou4p.cjs.map +0 -1
- package/dist/EngineFactory-l_9xmBtv.cjs +0 -3190
- package/dist/EngineFactory-l_9xmBtv.cjs.map +0 -1
- package/dist/EngineFactory-w-aOWuqh.js +0 -3089
- package/dist/EngineFactory-w-aOWuqh.js.map +0 -1
- package/dist/InMemoryLiveWorkflowRepository-1J9MHN_I.js +0 -18
- package/dist/InMemoryLiveWorkflowRepository-1J9MHN_I.js.map +0 -1
- package/dist/InMemoryLiveWorkflowRepository-CULNqv96.d.ts +0 -1300
- package/dist/InMemoryLiveWorkflowRepository-D7l8cjdZ.d.cts +0 -1130
- package/dist/InMemoryLiveWorkflowRepository-jnv-OnOP.d.ts +0 -1300
- package/dist/InMemoryLiveWorkflowRepository-xny1_Z6i.cjs +0 -24
- package/dist/InMemoryLiveWorkflowRepository-xny1_Z6i.cjs.map +0 -1
- package/dist/InMemoryLiveWorkflowRepository-xr7b4kvi.d.ts +0 -1338
- package/dist/InMemoryWorkflowCatalog-BIdFpwbK.d.ts +0 -1205
- package/dist/InMemoryWorkflowCatalog-BW00_3N3.d.cts +0 -12
- package/dist/InMemoryWorkflowCatalog-BiYHGoPw.cjs +0 -24
- package/dist/InMemoryWorkflowCatalog-BiYHGoPw.cjs.map +0 -1
- package/dist/InMemoryWorkflowCatalog-BrG0ApMO.d.cts +0 -1115
- package/dist/InMemoryWorkflowCatalog-BzrAr--Y.js +0 -139
- package/dist/InMemoryWorkflowCatalog-BzrAr--Y.js.map +0 -1
- package/dist/InMemoryWorkflowCatalog-C-EJlJ7y.d.cts +0 -1120
- package/dist/InMemoryWorkflowCatalog-C4482bpw.cjs +0 -24
- package/dist/InMemoryWorkflowCatalog-C4482bpw.cjs.map +0 -1
- package/dist/InMemoryWorkflowCatalog-CZ0kZpOv.d.ts +0 -1289
- package/dist/InMemoryWorkflowCatalog-C_ACeLyW.d.cts +0 -1119
- package/dist/InMemoryWorkflowCatalog-CiHWIu5E.d.cts +0 -12
- package/dist/InMemoryWorkflowCatalog-CkH7gkya.js +0 -18
- package/dist/InMemoryWorkflowCatalog-CkH7gkya.js.map +0 -1
- package/dist/InMemoryWorkflowCatalog-CnpZVJM9.d.ts +0 -1205
- package/dist/InMemoryWorkflowCatalog-Cu68S8YR.js +0 -18
- package/dist/InMemoryWorkflowCatalog-Cu68S8YR.js.map +0 -1
- package/dist/InMemoryWorkflowCatalog-D2w9nMj2.cjs +0 -151
- package/dist/InMemoryWorkflowCatalog-D2w9nMj2.cjs.map +0 -1
- package/dist/InMemoryWorkflowCatalog-D5eMxEf7.js +0 -18
- package/dist/InMemoryWorkflowCatalog-D5eMxEf7.js.map +0 -1
- package/dist/InMemoryWorkflowCatalog-D5nCp2yZ.d.ts +0 -1267
- package/dist/InMemoryWorkflowCatalog-DIq0bjqN.d.ts +0 -12
- package/dist/InMemoryWorkflowCatalog-DLgaEaw_.d.ts +0 -1288
- package/dist/InMemoryWorkflowCatalog-DNBFdK-x.d.cts +0 -1120
- package/dist/InMemoryWorkflowCatalog-DQBkCzb7.cjs +0 -24
- package/dist/InMemoryWorkflowCatalog-DQBkCzb7.cjs.map +0 -1
- package/dist/InMemoryWorkflowCatalog-DS4-eX6i.d.cts +0 -1118
- package/dist/InMemoryWorkflowCatalog-DdVfy8MY.d.ts +0 -12
- package/dist/InMemoryWorkflowCatalog-DeVZu3g8.d.ts +0 -12
- package/dist/InMemoryWorkflowCatalog-GxkQjvt5.d.ts +0 -1200
- package/dist/InMemoryWorkflowCatalog-qaVRn1Lc.d.cts +0 -1115
- package/dist/InMemoryWorkflowCatalog-z1aIT4TC.d.cts +0 -12
- package/dist/InMemoryWorkflowRegistry-BBuOovLL.d.ts +0 -1007
- package/dist/InMemoryWorkflowRegistry-BIFnSl3k.d.ts +0 -1201
- package/dist/InMemoryWorkflowRegistry-BnGilthz.d.ts +0 -1137
- package/dist/InMemoryWorkflowRegistry-CEp5I8No.d.ts +0 -1146
- package/dist/InMemoryWorkflowRegistry-CHyMB9jW.d.cts +0 -976
- package/dist/InMemoryWorkflowRegistry-CUN7K86m.d.cts +0 -1061
- package/dist/InMemoryWorkflowRegistry-CVfHyELh.d.cts +0 -971
- package/dist/InMemoryWorkflowRegistry-CXXJrwAr.d.cts +0 -1052
- package/dist/InMemoryWorkflowRegistry-DDGfPTJy.d.ts +0 -1013
- package/dist/InMemoryWorkflowRegistry-DnYSOoT5.d.ts +0 -1120
- package/dist/InMemoryWorkflowRegistry-Dp5GiFF2.d.cts +0 -1035
- package/dist/InMemoryWorkflowRegistry-DypDBeOw.d.cts +0 -1116
- package/dist/InMemoryWorkflowRegistry-SzwJCAxT.d.ts +0 -1012
- package/dist/InMemoryWorkflowRegistry-jupvqyGc.d.cts +0 -977
- package/dist/InMemoryWorkflowRegistry-rAdKVWYT.d.ts +0 -1117
- package/dist/InProcessRetryRunner-BBNPkXjy.d.cts +0 -292
- package/dist/PersistedWorkflowSnapshotFactory-7RkOL3Kg.d.ts +0 -14
- package/dist/PersistedWorkflowSnapshotFactory-BmANa46W.cjs +0 -141
- package/dist/PersistedWorkflowSnapshotFactory-BmANa46W.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-Bwb_etSt.js +0 -118
- package/dist/PersistedWorkflowSnapshotFactory-Bwb_etSt.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-CRkKGNV6.js +0 -123
- package/dist/PersistedWorkflowSnapshotFactory-CRkKGNV6.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-CZolnGy5.js +0 -101
- package/dist/PersistedWorkflowSnapshotFactory-CZolnGy5.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-Ca_oysOv.cjs +0 -131
- package/dist/PersistedWorkflowSnapshotFactory-Ca_oysOv.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-CqIcShnX.js +0 -103
- package/dist/PersistedWorkflowSnapshotFactory-CqIcShnX.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-D-tBk4_G.js +0 -119
- package/dist/PersistedWorkflowSnapshotFactory-D-tBk4_G.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-D4cXl2e2.cjs +0 -131
- package/dist/PersistedWorkflowSnapshotFactory-D4cXl2e2.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-DINoP12r.cjs +0 -131
- package/dist/PersistedWorkflowSnapshotFactory-DINoP12r.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-DJAwSuHU.js +0 -103
- package/dist/PersistedWorkflowSnapshotFactory-DJAwSuHU.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-DSUjVCcf.cjs +0 -131
- package/dist/PersistedWorkflowSnapshotFactory-DSUjVCcf.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-DdHuhkDb.cjs +0 -107
- package/dist/PersistedWorkflowSnapshotFactory-DdHuhkDb.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-Dqc6NHis.js +0 -119
- package/dist/PersistedWorkflowSnapshotFactory-Dqc6NHis.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-Dxa2dSrw.cjs +0 -130
- package/dist/PersistedWorkflowSnapshotFactory-Dxa2dSrw.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-Ep79Ah1G.js +0 -123
- package/dist/PersistedWorkflowSnapshotFactory-Ep79Ah1G.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-GyLfRuiJ.js +0 -119
- package/dist/PersistedWorkflowSnapshotFactory-GyLfRuiJ.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-HTpBsBzn.js +0 -102
- package/dist/PersistedWorkflowSnapshotFactory-HTpBsBzn.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-LVmaaf3t.cjs +0 -141
- package/dist/PersistedWorkflowSnapshotFactory-LVmaaf3t.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-PZCpo2ZS.js +0 -119
- package/dist/PersistedWorkflowSnapshotFactory-PZCpo2ZS.js.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-UjQ1SJev.cjs +0 -109
- package/dist/PersistedWorkflowSnapshotFactory-UjQ1SJev.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-Y8kCrhcy.cjs +0 -109
- package/dist/PersistedWorkflowSnapshotFactory-Y8kCrhcy.cjs.map +0 -1
- package/dist/PersistedWorkflowSnapshotFactory-Z_nB-fmB.cjs +0 -108
- package/dist/PersistedWorkflowSnapshotFactory-Z_nB-fmB.cjs.map +0 -1
- package/dist/RunIntentService-1EE6N8ZL.cjs +0 -963
- package/dist/RunIntentService-1EE6N8ZL.cjs.map +0 -1
- package/dist/RunIntentService-2ivFmNQh.cjs.map +0 -1
- package/dist/RunIntentService-B0sUL5q-.js +0 -761
- package/dist/RunIntentService-B0sUL5q-.js.map +0 -1
- package/dist/RunIntentService-BFVbsOcg.js.map +0 -1
- package/dist/RunIntentService-BsBOwpVN.cjs +0 -1051
- package/dist/RunIntentService-BsBOwpVN.cjs.map +0 -1
- package/dist/RunIntentService-CSk3ETyn.js +0 -858
- package/dist/RunIntentService-CSk3ETyn.js.map +0 -1
- package/dist/RunIntentService-Ckn3u3tA.d.cts +0 -326
- package/dist/RunIntentService-DEo6GTTo.d.cts +0 -289
- package/dist/RunIntentService-DKrGtL0B.js +0 -782
- package/dist/RunIntentService-DKrGtL0B.js.map +0 -1
- package/dist/RunIntentService-DNOJc1R7.cjs +0 -942
- package/dist/RunIntentService-DNOJc1R7.cjs.map +0 -1
- package/dist/RunIntentService-Dq3pV53j.d.cts +0 -289
- package/dist/WorkflowSnapshotCodec-C3fuuS_R.d.cts +0 -22
- package/dist/WorkflowSnapshotCodec-CUudUo6f.js +0 -123
- package/dist/WorkflowSnapshotCodec-CUudUo6f.js.map +0 -1
- package/dist/WorkflowSnapshotCodec-CuCPQZTc.cjs +0 -129
- package/dist/WorkflowSnapshotCodec-CuCPQZTc.cjs.map +0 -1
- package/dist/WorkflowSnapshotCodec-DLiXQNvV.d.cts +0 -22
- package/dist/WorkflowSnapshotCodec-DNtdrZ7l.d.cts +0 -22
- package/dist/credentialTypes-B5h3dI7r.d.cts +0 -1107
- package/dist/credentialTypes-B9okPCVo.d.cts +0 -963
- package/dist/credentialTypes-BFL70rgZ.d.cts +0 -964
- package/dist/credentialTypes-BGkh1O07.d.ts +0 -1010
- package/dist/credentialTypes-BNLi4Q7u.d.ts +0 -1030
- package/dist/credentialTypes-CeSoZGj3.d.cts +0 -994
- package/dist/credentialTypes-CpHc32Ig.d.cts +0 -984
- package/dist/credentialTypes-D0m7MQQl.d.cts +0 -1107
- package/dist/credentialTypes-D4nL2sUd.d.ts +0 -1000
- package/dist/credentialTypes-DBYK2Qbu.d.ts +0 -999
- package/dist/credentialTypes-DMJVy0r1.d.ts +0 -1000
- package/dist/credentialTypes-DhUAjYQp.d.ts +0 -1020
- package/dist/credentialTypes-gGITj5KL.d.cts +0 -964
- package/dist/credentialTypes-r3KVBJBE.d.cts +0 -974
- package/dist/diTokens-ClO27tjK.cjs +0 -34
- package/dist/diTokens-ClO27tjK.cjs.map +0 -1
- package/dist/diTokens-CoHBkwG6.js +0 -28
- package/dist/diTokens-CoHBkwG6.js.map +0 -1
- package/dist/index-6Doxmfnd.d.ts +0 -857
- package/dist/index-AZ72Ej-K.d.ts +0 -920
- package/dist/index-BEk9V-q-.d.ts +0 -667
- package/dist/index-Bjt7_7oS.d.ts +0 -1192
- package/dist/index-CFGxsYXy.d.ts +0 -708
- package/dist/index-C_u8xFgn.d.ts +0 -690
- package/dist/index-CpbfsvOJ.d.ts +0 -1192
- package/dist/index-CsReNJN_.d.ts +0 -859
- package/dist/index-D5iNnXaW.d.ts +0 -667
- package/dist/index-DD_Eft1q.d.ts +0 -708
- package/dist/index-DiSYUe0G.d.ts +0 -1192
- package/dist/index-gIcH60sp.d.ts +0 -674
- package/dist/runtime-BIvd-1JA.cjs +0 -4112
- package/dist/runtime-BIvd-1JA.cjs.map +0 -1
- package/dist/runtime-D3eWKSQK.cjs +0 -3986
- package/dist/runtime-D3eWKSQK.cjs.map +0 -1
- package/dist/runtime-Dvp4xAjg.js +0 -3799
- package/dist/runtime-Dvp4xAjg.js.map +0 -1
- package/dist/runtime-vc76SSAa.js +0 -3685
- package/dist/runtime-vc76SSAa.js.map +0 -1
- package/dist/runtimeTypes-BK0b8SaG.d.cts +0 -884
- package/dist/runtimeTypes-CoYZkYQq.d.cts +0 -851
- package/dist/runtimeTypes-D-Pm0Uas.d.cts +0 -849
- package/dist/types-Cb5UK7Y6.d.ts +0 -857
|
@@ -1,3152 +0,0 @@
|
|
|
1
|
-
const require_PersistedWorkflowSnapshotFactory = require('./PersistedWorkflowSnapshotFactory-UjQ1SJev.cjs');
|
|
2
|
-
|
|
3
|
-
//#region src/engine/materialization/MissingRuntimeTriggerToken.ts
|
|
4
|
-
var MissingRuntimeTriggerToken = class {};
|
|
5
|
-
|
|
6
|
-
//#endregion
|
|
7
|
-
//#region src/engine/policies/EngineExecutionLimitsPolicy.ts
|
|
8
|
-
/** Framework defaults for {@link EngineExecutionLimitsPolicy} (merged with host `runtime.engineExecutionLimits`). */
|
|
9
|
-
const ENGINE_EXECUTION_LIMITS_DEFAULTS = {
|
|
10
|
-
defaultMaxNodeActivations: 1e5,
|
|
11
|
-
hardMaxNodeActivations: 1e5,
|
|
12
|
-
defaultMaxSubworkflowDepth: 32,
|
|
13
|
-
hardMaxSubworkflowDepth: 32
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* Resolves per-run execution limits: defaults, hard ceilings, and subworkflow depth for new runs.
|
|
17
|
-
*/
|
|
18
|
-
var EngineExecutionLimitsPolicy = class {
|
|
19
|
-
constructor(config = ENGINE_EXECUTION_LIMITS_DEFAULTS) {
|
|
20
|
-
this.config = config;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Effective options for a new root run (depth 0): defaults merged with engine ceilings.
|
|
24
|
-
* Replaces a separate one-method factory for root-run bootstrap.
|
|
25
|
-
*/
|
|
26
|
-
createRootExecutionOptions() {
|
|
27
|
-
return this.mergeExecutionOptionsForNewRun(void 0, void 0);
|
|
28
|
-
}
|
|
29
|
-
mergeExecutionOptionsForNewRun(parent, user) {
|
|
30
|
-
const subworkflowDepth = parent === void 0 ? 0 : (parent.subworkflowDepth ?? 0) + 1;
|
|
31
|
-
const inheritedMaxNode = parent?.engineMaxNodeActivations;
|
|
32
|
-
const inheritedMaxSub = parent?.engineMaxSubworkflowDepth;
|
|
33
|
-
const maxNodeActivations = this.capNumber(user?.maxNodeActivations ?? inheritedMaxNode, this.config.defaultMaxNodeActivations, this.config.hardMaxNodeActivations);
|
|
34
|
-
const maxSubworkflowDepth = this.capNumber(user?.maxSubworkflowDepth ?? inheritedMaxSub, this.config.defaultMaxSubworkflowDepth, this.config.hardMaxSubworkflowDepth);
|
|
35
|
-
if (subworkflowDepth > maxSubworkflowDepth) throw new Error(`Subworkflow nesting depth ${subworkflowDepth} exceeds maxSubworkflowDepth ${maxSubworkflowDepth} (run would be a child of parent run).`);
|
|
36
|
-
return {
|
|
37
|
-
...user,
|
|
38
|
-
subworkflowDepth,
|
|
39
|
-
maxNodeActivations,
|
|
40
|
-
maxSubworkflowDepth
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
capNumber(requested, defaultValue, hardCeiling) {
|
|
44
|
-
const base = requested === void 0 ? defaultValue : requested;
|
|
45
|
-
return Math.min(base, hardCeiling);
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
//#endregion
|
|
50
|
-
//#region src/engine/materialization/MissingRuntimeNodeToken.ts
|
|
51
|
-
var MissingRuntimeNodeToken = class {};
|
|
52
|
-
|
|
53
|
-
//#endregion
|
|
54
|
-
//#region src/engine/api/Engine.ts
|
|
55
|
-
/**
|
|
56
|
-
* Runtime facade for orchestration, continuation, triggers, and webhook routing.
|
|
57
|
-
* Prefer {@link import("../intents/RunIntentService").RunIntentService} for host/HTTP invocation boundaries.
|
|
58
|
-
* The class token is exported from `@codemation/core/bootstrap` (not the main `@codemation/core` barrel).
|
|
59
|
-
*/
|
|
60
|
-
var Engine = class {
|
|
61
|
-
constructor(deps) {
|
|
62
|
-
this.deps = deps;
|
|
63
|
-
}
|
|
64
|
-
loadWorkflows(workflows) {
|
|
65
|
-
this.deps.tokenRegistry.registerFromWorkflows?.(workflows);
|
|
66
|
-
this.deps.workflowCatalog.setWorkflows(workflows);
|
|
67
|
-
this.deps.webhookTriggerMatcher.onEngineWorkflowsLoaded?.();
|
|
68
|
-
}
|
|
69
|
-
getTokenRegistry() {
|
|
70
|
-
return this.deps.tokenRegistry;
|
|
71
|
-
}
|
|
72
|
-
resolveWorkflowSnapshot(args) {
|
|
73
|
-
return this.deps.workflowSnapshotResolver.resolve(args);
|
|
74
|
-
}
|
|
75
|
-
async startTriggers() {
|
|
76
|
-
return await this.deps.triggerRuntime.startTriggers();
|
|
77
|
-
}
|
|
78
|
-
async syncWorkflowTriggersForActivation(workflowId) {
|
|
79
|
-
await this.deps.triggerRuntime.syncWorkflowTriggersForActivation(workflowId);
|
|
80
|
-
this.deps.webhookTriggerMatcher.reloadWebhookRoutes?.();
|
|
81
|
-
}
|
|
82
|
-
async start(workflows) {
|
|
83
|
-
await this.stop();
|
|
84
|
-
this.loadWorkflows(workflows);
|
|
85
|
-
await this.startTriggers();
|
|
86
|
-
}
|
|
87
|
-
async stop() {
|
|
88
|
-
await this.deps.triggerRuntime.stop();
|
|
89
|
-
this.deps.webhookTriggerMatcher.onEngineStopped?.();
|
|
90
|
-
}
|
|
91
|
-
resolveWebhookTrigger(args) {
|
|
92
|
-
const entry = this.deps.webhookTriggerMatcher.lookup(args.endpointPath);
|
|
93
|
-
if (!entry) return { status: "notFound" };
|
|
94
|
-
if (!entry.methods.includes(args.method)) return {
|
|
95
|
-
status: "methodNotAllowed",
|
|
96
|
-
match: entry
|
|
97
|
-
};
|
|
98
|
-
return {
|
|
99
|
-
status: "ok",
|
|
100
|
-
match: entry
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
async createTriggerTestItems(args) {
|
|
104
|
-
return await this.deps.triggerRuntime.createTriggerTestItems(args);
|
|
105
|
-
}
|
|
106
|
-
async runWorkflow(wf, startAt, items, parent, executionOptions, persistedStateOverrides) {
|
|
107
|
-
return await this.deps.workflowRunStarter.runWorkflow(wf, startAt, items, parent, executionOptions, persistedStateOverrides);
|
|
108
|
-
}
|
|
109
|
-
async runWorkflowFromState(request) {
|
|
110
|
-
return await this.deps.currentStateRunStarter.runWorkflowFromState(request);
|
|
111
|
-
}
|
|
112
|
-
async markNodeRunning(args) {
|
|
113
|
-
return await this.deps.runContinuationService.markNodeRunning(args);
|
|
114
|
-
}
|
|
115
|
-
async resumeFromNodeResult(args) {
|
|
116
|
-
return await this.deps.runContinuationService.resumeFromNodeResult(args);
|
|
117
|
-
}
|
|
118
|
-
async resumeFromNodeError(args) {
|
|
119
|
-
return await this.deps.runContinuationService.resumeFromNodeError(args);
|
|
120
|
-
}
|
|
121
|
-
async resumeFromStepResult(args) {
|
|
122
|
-
return await this.deps.runContinuationService.resumeFromStepResult(args);
|
|
123
|
-
}
|
|
124
|
-
async resumeFromStepError(args) {
|
|
125
|
-
return await this.deps.runContinuationService.resumeFromStepError(args);
|
|
126
|
-
}
|
|
127
|
-
async waitForCompletion(runId) {
|
|
128
|
-
return await this.deps.runContinuationService.waitForCompletion(runId);
|
|
129
|
-
}
|
|
130
|
-
async waitForWebhookResponse(runId) {
|
|
131
|
-
return await this.deps.runContinuationService.waitForWebhookResponse(runId);
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
//#endregion
|
|
136
|
-
//#region src/engine/materialization/MissingRuntimeNodeConfig.ts
|
|
137
|
-
var MissingRuntimeNodeConfig = class {
|
|
138
|
-
kind = "node";
|
|
139
|
-
type = MissingRuntimeNodeToken;
|
|
140
|
-
constructor(name, missingTokenId, missingRuntime = true) {
|
|
141
|
-
this.name = name;
|
|
142
|
-
this.missingTokenId = missingTokenId;
|
|
143
|
-
this.missingRuntime = missingRuntime;
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
//#endregion
|
|
148
|
-
//#region src/engine/materialization/MissingRuntimeTriggerConfig.ts
|
|
149
|
-
var MissingRuntimeTriggerConfig = class {
|
|
150
|
-
kind = "trigger";
|
|
151
|
-
type = MissingRuntimeTriggerToken;
|
|
152
|
-
constructor(name, missingTokenId, missingRuntime = true) {
|
|
153
|
-
this.name = name;
|
|
154
|
-
this.missingTokenId = missingTokenId;
|
|
155
|
-
this.missingRuntime = missingRuntime;
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
//#endregion
|
|
160
|
-
//#region src/engine/materialization/MissingRuntimeNodeDefinitionFactory.ts
|
|
161
|
-
var MissingRuntimeNodeDefinitionFactory = class {
|
|
162
|
-
create(snapshotNode) {
|
|
163
|
-
if (snapshotNode.kind === "trigger") {
|
|
164
|
-
const config$1 = new MissingRuntimeTriggerConfig(snapshotNode.name ?? snapshotNode.id, snapshotNode.nodeTokenId);
|
|
165
|
-
return {
|
|
166
|
-
id: snapshotNode.id,
|
|
167
|
-
kind: "trigger",
|
|
168
|
-
name: snapshotNode.name,
|
|
169
|
-
type: MissingRuntimeTriggerToken,
|
|
170
|
-
config: config$1
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
const config = new MissingRuntimeNodeConfig(snapshotNode.name ?? snapshotNode.id, snapshotNode.nodeTokenId);
|
|
174
|
-
return {
|
|
175
|
-
id: snapshotNode.id,
|
|
176
|
-
kind: "node",
|
|
177
|
-
name: snapshotNode.name,
|
|
178
|
-
type: MissingRuntimeNodeToken,
|
|
179
|
-
config
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
//#endregion
|
|
185
|
-
//#region src/engine/materialization/PersistedWorkflowConfigHydrator.ts
|
|
186
|
-
var PersistedWorkflowConfigHydrator = class {
|
|
187
|
-
constructor(tokenRegistry) {
|
|
188
|
-
this.tokenRegistry = tokenRegistry;
|
|
189
|
-
}
|
|
190
|
-
hydrate(snapshotNode, liveConfig) {
|
|
191
|
-
const hydrated = this.mergeValue(liveConfig, snapshotNode.config);
|
|
192
|
-
const configToken = this.tokenRegistry.resolve(snapshotNode.configTokenId);
|
|
193
|
-
Object.assign(hydrated, {
|
|
194
|
-
type: configToken ?? liveConfig.type,
|
|
195
|
-
kind: snapshotNode.kind
|
|
196
|
-
});
|
|
197
|
-
if (snapshotNode.name && !("name" in hydrated && hydrated.name)) Object.assign(hydrated, { name: snapshotNode.name });
|
|
198
|
-
return hydrated;
|
|
199
|
-
}
|
|
200
|
-
mergeValue(liveValue, snapshotValue) {
|
|
201
|
-
const liveRecord = this.asRecord(liveValue);
|
|
202
|
-
const snapshotRecord = this.asRecord(snapshotValue);
|
|
203
|
-
const hydrated = Object.create(liveValue && typeof liveValue === "object" ? Object.getPrototypeOf(liveValue) ?? Object.prototype : Object.prototype);
|
|
204
|
-
for (const [key, value] of Object.entries(snapshotRecord)) hydrated[key] = this.mergeNestedValue(liveRecord[key], value);
|
|
205
|
-
this.restoreNonSerializableProperties(liveRecord, hydrated);
|
|
206
|
-
this.restoreTypeProperty(hydrated);
|
|
207
|
-
return hydrated;
|
|
208
|
-
}
|
|
209
|
-
mergeNestedValue(liveValue, snapshotValue) {
|
|
210
|
-
if (Array.isArray(snapshotValue)) {
|
|
211
|
-
const liveArray = Array.isArray(liveValue) ? liveValue : [];
|
|
212
|
-
return snapshotValue.map((entry, index) => this.mergeNestedValue(liveArray[index], entry));
|
|
213
|
-
}
|
|
214
|
-
if (snapshotValue && typeof snapshotValue === "object") return this.mergeValue(liveValue, snapshotValue);
|
|
215
|
-
return snapshotValue;
|
|
216
|
-
}
|
|
217
|
-
restoreNonSerializableProperties(liveRecord, hydrated) {
|
|
218
|
-
for (const [key, value] of Object.entries(liveRecord)) if (typeof value === "function" || typeof value === "symbol") hydrated[key] = value;
|
|
219
|
-
}
|
|
220
|
-
restoreTypeProperty(record) {
|
|
221
|
-
const tokenId = typeof record.tokenId === "string" ? record.tokenId : void 0;
|
|
222
|
-
if (!tokenId) return;
|
|
223
|
-
const type = this.tokenRegistry.resolve(tokenId);
|
|
224
|
-
if (type) record.type = type;
|
|
225
|
-
}
|
|
226
|
-
asRecord(value) {
|
|
227
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
228
|
-
return { ...value };
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
//#endregion
|
|
233
|
-
//#region src/engine/materialization/PersistedWorkflowResolver.ts
|
|
234
|
-
var PersistedWorkflowResolver = class {
|
|
235
|
-
constructor(workflowRepository, tokenRegistry, configHydrator, missingNodeDefinitionFactory) {
|
|
236
|
-
this.workflowRepository = workflowRepository;
|
|
237
|
-
this.tokenRegistry = tokenRegistry;
|
|
238
|
-
this.configHydrator = configHydrator;
|
|
239
|
-
this.missingNodeDefinitionFactory = missingNodeDefinitionFactory;
|
|
240
|
-
}
|
|
241
|
-
resolve(args) {
|
|
242
|
-
const liveWorkflow = this.workflowRepository.get(args.workflowId);
|
|
243
|
-
if (!args.workflowSnapshot) return liveWorkflow;
|
|
244
|
-
if (!liveWorkflow) return this.rebuildWorkflow(args.workflowSnapshot, void 0);
|
|
245
|
-
return this.rebuildWorkflow(args.workflowSnapshot, liveWorkflow);
|
|
246
|
-
}
|
|
247
|
-
rebuildWorkflow(snapshot, liveWorkflow) {
|
|
248
|
-
const liveNodesById = new Map((liveWorkflow?.nodes ?? []).map((node) => [node.id, node]));
|
|
249
|
-
const nodes = snapshot.nodes.map((snapshotNode) => {
|
|
250
|
-
const liveNode = liveNodesById.get(snapshotNode.id);
|
|
251
|
-
if (!this.isCompatibleLiveNode(liveNode, snapshotNode)) return this.missingNodeDefinitionFactory.create(snapshotNode);
|
|
252
|
-
return {
|
|
253
|
-
id: snapshotNode.id,
|
|
254
|
-
kind: snapshotNode.kind,
|
|
255
|
-
name: snapshotNode.name ?? liveNode.name,
|
|
256
|
-
type: liveNode.type,
|
|
257
|
-
config: this.configHydrator.hydrate(snapshotNode, liveNode.config)
|
|
258
|
-
};
|
|
259
|
-
});
|
|
260
|
-
const nodeIds = new Set(nodes.map((node) => node.id));
|
|
261
|
-
const connectionsFromSnapshot = snapshot.connections?.map((connection) => ({
|
|
262
|
-
...connection,
|
|
263
|
-
childNodeIds: connection.childNodeIds.filter((childId) => nodeIds.has(childId))
|
|
264
|
-
})).filter((connection) => connection.childNodeIds.length > 0) ?? [];
|
|
265
|
-
return {
|
|
266
|
-
id: snapshot.id,
|
|
267
|
-
name: snapshot.name,
|
|
268
|
-
nodes,
|
|
269
|
-
edges: snapshot.edges.filter((edge) => nodeIds.has(edge.from.nodeId) && nodeIds.has(edge.to.nodeId)),
|
|
270
|
-
...connectionsFromSnapshot.length > 0 ? { connections: connectionsFromSnapshot } : {},
|
|
271
|
-
...liveWorkflow?.discoveryPathSegments !== void 0 ? { discoveryPathSegments: liveWorkflow.discoveryPathSegments } : {}
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
isCompatibleLiveNode(liveNode, snapshotNode) {
|
|
275
|
-
if (!liveNode || liveNode.kind !== snapshotNode.kind) return false;
|
|
276
|
-
if (!snapshotNode.nodeTokenId || !snapshotNode.configTokenId) throw new Error(`Persisted workflow snapshot node "${snapshotNode.id}" is missing stable token ids.`);
|
|
277
|
-
const liveNodeTokenId = this.resolveLiveTokenId(liveNode.type);
|
|
278
|
-
const liveConfigTokenId = this.resolveLiveTokenId(liveNode.config.type);
|
|
279
|
-
return liveNodeTokenId === snapshotNode.nodeTokenId && liveConfigTokenId === snapshotNode.configTokenId;
|
|
280
|
-
}
|
|
281
|
-
resolveLiveTokenId(type) {
|
|
282
|
-
const registeredTokenId = this.tokenRegistry.getTokenId(type);
|
|
283
|
-
if (registeredTokenId) return registeredTokenId;
|
|
284
|
-
if (typeof type === "function" && type.name) return type.name;
|
|
285
|
-
if (typeof type === "string") return type;
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
//#endregion
|
|
290
|
-
//#region src/engine/state/InputPortMapFactory.ts
|
|
291
|
-
var InputPortMap = class {
|
|
292
|
-
static empty() {
|
|
293
|
-
return {};
|
|
294
|
-
}
|
|
295
|
-
static fromRequest(request) {
|
|
296
|
-
if (request.kind === "multi") return request.inputsByPort;
|
|
297
|
-
return { in: request.input };
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
//#endregion
|
|
302
|
-
//#region src/engine/state/NodeSnapshotFactory.ts
|
|
303
|
-
var NodeSnapshotFactory = class {
|
|
304
|
-
static queued(args) {
|
|
305
|
-
return {
|
|
306
|
-
runId: args.runId,
|
|
307
|
-
workflowId: args.workflowId,
|
|
308
|
-
nodeId: args.nodeId,
|
|
309
|
-
activationId: args.activationId,
|
|
310
|
-
parent: args.parent,
|
|
311
|
-
status: "queued",
|
|
312
|
-
queuedAt: args.queuedAt,
|
|
313
|
-
updatedAt: args.queuedAt,
|
|
314
|
-
inputsByPort: args.inputsByPort
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
static running(args) {
|
|
318
|
-
return {
|
|
319
|
-
runId: args.runId,
|
|
320
|
-
workflowId: args.workflowId,
|
|
321
|
-
nodeId: args.nodeId,
|
|
322
|
-
activationId: args.activationId,
|
|
323
|
-
parent: args.parent,
|
|
324
|
-
status: "running",
|
|
325
|
-
queuedAt: args.previous?.queuedAt,
|
|
326
|
-
startedAt: args.startedAt,
|
|
327
|
-
updatedAt: args.startedAt,
|
|
328
|
-
inputsByPort: args.inputsByPort,
|
|
329
|
-
outputs: args.previous?.outputs,
|
|
330
|
-
error: void 0
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
static completed(args) {
|
|
334
|
-
const fromPinnedOutput = args.fromPinnedOutput ?? false;
|
|
335
|
-
const startedAt = fromPinnedOutput ? args.previous?.startedAt ?? args.finishedAt : args.previous?.startedAt;
|
|
336
|
-
return {
|
|
337
|
-
runId: args.runId,
|
|
338
|
-
workflowId: args.workflowId,
|
|
339
|
-
nodeId: args.nodeId,
|
|
340
|
-
activationId: args.activationId,
|
|
341
|
-
parent: args.parent,
|
|
342
|
-
status: "completed",
|
|
343
|
-
queuedAt: args.previous?.queuedAt,
|
|
344
|
-
startedAt,
|
|
345
|
-
finishedAt: args.finishedAt,
|
|
346
|
-
updatedAt: args.finishedAt,
|
|
347
|
-
inputsByPort: args.inputsByPort,
|
|
348
|
-
outputs: args.outputs,
|
|
349
|
-
usedPinnedOutput: fromPinnedOutput,
|
|
350
|
-
error: void 0
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
static skipped(args) {
|
|
354
|
-
return {
|
|
355
|
-
runId: args.runId,
|
|
356
|
-
workflowId: args.workflowId,
|
|
357
|
-
nodeId: args.nodeId,
|
|
358
|
-
activationId: args.activationId,
|
|
359
|
-
parent: args.parent,
|
|
360
|
-
status: "skipped",
|
|
361
|
-
queuedAt: args.previous?.queuedAt,
|
|
362
|
-
startedAt: args.previous?.startedAt,
|
|
363
|
-
finishedAt: args.finishedAt,
|
|
364
|
-
updatedAt: args.finishedAt,
|
|
365
|
-
inputsByPort: args.inputsByPort,
|
|
366
|
-
outputs: args.outputs,
|
|
367
|
-
error: void 0
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
static failed(args) {
|
|
371
|
-
return {
|
|
372
|
-
runId: args.runId,
|
|
373
|
-
workflowId: args.workflowId,
|
|
374
|
-
nodeId: args.nodeId,
|
|
375
|
-
activationId: args.activationId,
|
|
376
|
-
parent: args.parent,
|
|
377
|
-
status: "failed",
|
|
378
|
-
queuedAt: args.previous?.queuedAt,
|
|
379
|
-
startedAt: args.previous?.startedAt,
|
|
380
|
-
finishedAt: args.finishedAt,
|
|
381
|
-
updatedAt: args.finishedAt,
|
|
382
|
-
inputsByPort: args.inputsByPort,
|
|
383
|
-
outputs: void 0,
|
|
384
|
-
error: {
|
|
385
|
-
message: args.error.message,
|
|
386
|
-
name: args.error.name,
|
|
387
|
-
stack: args.error.stack
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
//#endregion
|
|
394
|
-
//#region src/engine/execution/ActivationEnqueueService.ts
|
|
395
|
-
var ActivationEnqueueService = class {
|
|
396
|
-
constructor(activationScheduler, runStore, nodeEventPublisher) {
|
|
397
|
-
this.activationScheduler = activationScheduler;
|
|
398
|
-
this.runStore = runStore;
|
|
399
|
-
this.nodeEventPublisher = nodeEventPublisher;
|
|
400
|
-
}
|
|
401
|
-
async enqueueActivation(args) {
|
|
402
|
-
const { result, queuedSnapshot } = await this.enqueueActivationWithSnapshot(args);
|
|
403
|
-
await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
|
|
404
|
-
return result;
|
|
405
|
-
}
|
|
406
|
-
async enqueueActivationWithSnapshot(args) {
|
|
407
|
-
const receipt = await this.activationScheduler.enqueue(args.request);
|
|
408
|
-
const inputsByPort = InputPortMap.fromRequest(args.request);
|
|
409
|
-
const itemsIn = args.request.kind === "multi" ? args.planner.sumItemsByPort(args.request.inputsByPort) : args.request.input.length;
|
|
410
|
-
const enqueuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
411
|
-
const pending = {
|
|
412
|
-
runId: args.runId,
|
|
413
|
-
activationId: args.request.activationId,
|
|
414
|
-
workflowId: args.workflowId,
|
|
415
|
-
nodeId: args.request.nodeId,
|
|
416
|
-
itemsIn,
|
|
417
|
-
inputsByPort,
|
|
418
|
-
receiptId: receipt.receiptId,
|
|
419
|
-
queue: receipt.queue,
|
|
420
|
-
batchId: args.request.batchId,
|
|
421
|
-
enqueuedAt
|
|
422
|
-
};
|
|
423
|
-
const queuedSnapshot = NodeSnapshotFactory.queued({
|
|
424
|
-
runId: args.runId,
|
|
425
|
-
workflowId: args.workflowId,
|
|
426
|
-
nodeId: args.request.nodeId,
|
|
427
|
-
activationId: args.request.activationId,
|
|
428
|
-
parent: args.parent,
|
|
429
|
-
queuedAt: enqueuedAt,
|
|
430
|
-
inputsByPort
|
|
431
|
-
});
|
|
432
|
-
await this.runStore.save({
|
|
433
|
-
runId: args.runId,
|
|
434
|
-
workflowId: args.workflowId,
|
|
435
|
-
startedAt: args.startedAt,
|
|
436
|
-
parent: args.parent,
|
|
437
|
-
executionOptions: args.executionOptions,
|
|
438
|
-
control: args.control,
|
|
439
|
-
workflowSnapshot: args.workflowSnapshot,
|
|
440
|
-
mutableState: args.mutableState,
|
|
441
|
-
policySnapshot: args.policySnapshot,
|
|
442
|
-
engineCounters: args.engineCounters,
|
|
443
|
-
connectionInvocations: args.connectionInvocations ? [...args.connectionInvocations] : [],
|
|
444
|
-
status: "pending",
|
|
445
|
-
pending,
|
|
446
|
-
queue: args.pendingQueue.map((entry) => ({ ...entry })),
|
|
447
|
-
outputsByNode: args.request.ctx.data.dump(),
|
|
448
|
-
nodeSnapshotsByNodeId: {
|
|
449
|
-
...args.previousNodeSnapshotsByNodeId,
|
|
450
|
-
[args.request.nodeId]: queuedSnapshot
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
this.notifyPendingStatePersisted(args.runId);
|
|
454
|
-
return {
|
|
455
|
-
result: {
|
|
456
|
-
runId: args.runId,
|
|
457
|
-
workflowId: args.workflowId,
|
|
458
|
-
startedAt: args.startedAt,
|
|
459
|
-
status: "pending",
|
|
460
|
-
pending
|
|
461
|
-
},
|
|
462
|
-
queuedSnapshot
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
notifyPendingStatePersisted(runId) {
|
|
466
|
-
this.activationScheduler.notifyPendingStatePersisted?.(runId);
|
|
467
|
-
}
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
//#endregion
|
|
471
|
-
//#region src/workflow/WorkflowExecutableNodeClassifier.ts
|
|
472
|
-
/**
|
|
473
|
-
* Derives which workflow nodes participate in the main execution graph vs connection-only children.
|
|
474
|
-
*/
|
|
475
|
-
var WorkflowExecutableNodeClassifier = class {
|
|
476
|
-
connectionOwnedIds;
|
|
477
|
-
constructor(workflow) {
|
|
478
|
-
this.connectionOwnedIds = this.collectConnectionOwnedIds(workflow);
|
|
479
|
-
}
|
|
480
|
-
isConnectionOwnedNodeId(nodeId) {
|
|
481
|
-
return this.connectionOwnedIds.has(nodeId);
|
|
482
|
-
}
|
|
483
|
-
isExecutableNodeId(nodeId) {
|
|
484
|
-
return !this.connectionOwnedIds.has(nodeId);
|
|
485
|
-
}
|
|
486
|
-
filterExecutableNodeDefinitions(nodes) {
|
|
487
|
-
return nodes.filter((n) => this.isExecutableNodeId(n.id));
|
|
488
|
-
}
|
|
489
|
-
collectConnectionOwnedIds(workflow) {
|
|
490
|
-
const ids = /* @__PURE__ */ new Set();
|
|
491
|
-
for (const connection of workflow.connections ?? []) for (const childId of connection.childNodeIds) ids.add(childId);
|
|
492
|
-
return ids;
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Resolves the default start node: first trigger, else first executable node with no incoming edges from executable nodes.
|
|
496
|
-
*/
|
|
497
|
-
findDefaultExecutableStartNodeId(workflow) {
|
|
498
|
-
const firstTrigger = workflow.nodes.find((n) => n.kind === "trigger" && this.isExecutableNodeId(n.id))?.id;
|
|
499
|
-
if (firstTrigger) return firstTrigger;
|
|
500
|
-
const incoming = /* @__PURE__ */ new Map();
|
|
501
|
-
for (const n of workflow.nodes) if (this.isExecutableNodeId(n.id)) incoming.set(n.id, 0);
|
|
502
|
-
for (const e of workflow.edges) {
|
|
503
|
-
if (!this.isExecutableNodeId(e.from.nodeId) || !this.isExecutableNodeId(e.to.nodeId)) continue;
|
|
504
|
-
incoming.set(e.to.nodeId, (incoming.get(e.to.nodeId) ?? 0) + 1);
|
|
505
|
-
}
|
|
506
|
-
return workflow.nodes.find((n) => this.isExecutableNodeId(n.id) && (incoming.get(n.id) ?? 0) === 0)?.id ?? workflow.nodes.find((n) => this.isExecutableNodeId(n.id))?.id ?? (() => {
|
|
507
|
-
throw new Error(`Workflow ${workflow.id} has no executable nodes`);
|
|
508
|
-
})();
|
|
509
|
-
}
|
|
510
|
-
firstExecutableNodeIdInDefinitionOrder(workflow) {
|
|
511
|
-
return workflow.nodes.find((n) => this.isExecutableNodeId(n.id))?.id;
|
|
512
|
-
}
|
|
513
|
-
lastExecutableNodeIdInDefinitionOrder(workflow) {
|
|
514
|
-
for (let i = workflow.nodes.length - 1; i >= 0; i--) {
|
|
515
|
-
const n = workflow.nodes[i];
|
|
516
|
-
if (this.isExecutableNodeId(n.id)) return n.id;
|
|
517
|
-
}
|
|
518
|
-
throw new Error(`Workflow ${workflow.id} has no executable nodes`);
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
//#endregion
|
|
523
|
-
//#region src/workflow/workflowExecutableNodeClassifier.types.ts
|
|
524
|
-
function createWorkflowExecutableNodeClassifier(workflow) {
|
|
525
|
-
return new WorkflowExecutableNodeClassifier(workflow);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
//#endregion
|
|
529
|
-
//#region src/engine/planning/DependencySatisfactionResolver.ts
|
|
530
|
-
var DependencySatisfactionResolver = class {
|
|
531
|
-
constructor(topology, currentState) {
|
|
532
|
-
this.topology = topology;
|
|
533
|
-
this.currentState = currentState;
|
|
534
|
-
}
|
|
535
|
-
isNodeSatisfied(nodeId) {
|
|
536
|
-
return this.hasOutputs(nodeId) || this.hasCompletedSnapshot(nodeId);
|
|
537
|
-
}
|
|
538
|
-
isNodeSatisfiedByOutputsOnly(nodeId) {
|
|
539
|
-
return this.hasOutputs(nodeId) && !this.hasCompletedSnapshot(nodeId);
|
|
540
|
-
}
|
|
541
|
-
isEdgeSatisfied(args) {
|
|
542
|
-
const incomingEdge = (this.topology.incomingByNode.get(args.nodeId) ?? []).find((edge) => edge.input === args.input);
|
|
543
|
-
if (!incomingEdge) return false;
|
|
544
|
-
return this.hasOutputPort(incomingEdge.from.nodeId, incomingEdge.from.output);
|
|
545
|
-
}
|
|
546
|
-
resolveInput(args) {
|
|
547
|
-
const incomingEdge = (this.topology.incomingByNode.get(args.nodeId) ?? []).find((edge) => edge.input === args.input);
|
|
548
|
-
if (!incomingEdge) return [];
|
|
549
|
-
return this.resolveOutputItems(incomingEdge.from.nodeId, incomingEdge.from.output);
|
|
550
|
-
}
|
|
551
|
-
hasOutputs(nodeId) {
|
|
552
|
-
return Object.prototype.hasOwnProperty.call(this.currentState.outputsByNode, nodeId);
|
|
553
|
-
}
|
|
554
|
-
hasCompletedSnapshot(nodeId) {
|
|
555
|
-
const snapshot = this.currentState.nodeSnapshotsByNodeId[nodeId];
|
|
556
|
-
return snapshot?.status === "completed" || snapshot?.status === "skipped";
|
|
557
|
-
}
|
|
558
|
-
hasOutputPort(nodeId, output) {
|
|
559
|
-
const outputs = this.currentState.outputsByNode[nodeId];
|
|
560
|
-
if (!outputs) return false;
|
|
561
|
-
return Object.prototype.hasOwnProperty.call(outputs, output);
|
|
562
|
-
}
|
|
563
|
-
resolveOutputItems(nodeId, output) {
|
|
564
|
-
return this.currentState.outputsByNode[nodeId]?.[output] ?? [];
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
//#endregion
|
|
569
|
-
//#region src/engine/planning/FrontierQueueBuilder.ts
|
|
570
|
-
var FrontierQueueBuilder = class {
|
|
571
|
-
constructor(topology, satisfactionResolver) {
|
|
572
|
-
this.topology = topology;
|
|
573
|
-
this.satisfactionResolver = satisfactionResolver;
|
|
574
|
-
}
|
|
575
|
-
build(args) {
|
|
576
|
-
const incomingEdges = this.topology.incomingByNode.get(args.nodeId) ?? [];
|
|
577
|
-
if (incomingEdges.length === 0) return [];
|
|
578
|
-
const expectedInputs = this.topology.expectedInputsByNode.get(args.nodeId) ?? [];
|
|
579
|
-
if (expectedInputs.length !== 1 || expectedInputs[0] !== "in") {
|
|
580
|
-
const received = {};
|
|
581
|
-
for (const input$1 of expectedInputs) received[input$1] = this.satisfactionResolver.resolveInput({
|
|
582
|
-
nodeId: args.nodeId,
|
|
583
|
-
input: input$1
|
|
584
|
-
});
|
|
585
|
-
return [{
|
|
586
|
-
nodeId: args.nodeId,
|
|
587
|
-
input: [],
|
|
588
|
-
batchId: "batch_1",
|
|
589
|
-
collect: {
|
|
590
|
-
expectedInputs,
|
|
591
|
-
received
|
|
592
|
-
}
|
|
593
|
-
}];
|
|
594
|
-
}
|
|
595
|
-
const input = expectedInputs[0] ?? "in";
|
|
596
|
-
const incomingEdge = incomingEdges.find((edge) => edge.input === input);
|
|
597
|
-
return [{
|
|
598
|
-
nodeId: args.nodeId,
|
|
599
|
-
input: this.satisfactionResolver.resolveInput({
|
|
600
|
-
nodeId: args.nodeId,
|
|
601
|
-
input
|
|
602
|
-
}),
|
|
603
|
-
toInput: input,
|
|
604
|
-
batchId: "batch_1",
|
|
605
|
-
from: incomingEdge?.from
|
|
606
|
-
}];
|
|
607
|
-
}
|
|
608
|
-
};
|
|
609
|
-
|
|
610
|
-
//#endregion
|
|
611
|
-
//#region src/engine/planning/PinnedOutputResolver.ts
|
|
612
|
-
var PinnedOutputResolver = class {
|
|
613
|
-
constructor(currentState) {
|
|
614
|
-
this.currentState = currentState;
|
|
615
|
-
}
|
|
616
|
-
overlayPinnedOutputs() {
|
|
617
|
-
const outputsByNode = { ...this.currentState.outputsByNode };
|
|
618
|
-
for (const [nodeId, nodeState] of Object.entries(this.currentState.mutableState?.nodesById ?? {})) {
|
|
619
|
-
const pinnedOutputs = this.resolvePinnedOutputs(nodeState);
|
|
620
|
-
if (!pinnedOutputs) continue;
|
|
621
|
-
outputsByNode[nodeId] = pinnedOutputs;
|
|
622
|
-
}
|
|
623
|
-
return {
|
|
624
|
-
outputsByNode,
|
|
625
|
-
nodeSnapshotsByNodeId: { ...this.currentState.nodeSnapshotsByNodeId },
|
|
626
|
-
mutableState: this.currentState.mutableState
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
hasPinnedOutputs(nodeId) {
|
|
630
|
-
return this.getPinnedOutputs(nodeId) !== void 0;
|
|
631
|
-
}
|
|
632
|
-
getPinnedOutputs(nodeId) {
|
|
633
|
-
const nodeState = this.currentState.mutableState?.nodesById?.[nodeId];
|
|
634
|
-
return this.resolvePinnedOutputs(nodeState);
|
|
635
|
-
}
|
|
636
|
-
resolvePinnedOutputs(nodeState) {
|
|
637
|
-
if (!nodeState) return;
|
|
638
|
-
return nodeState.pinnedOutputsByPort;
|
|
639
|
-
}
|
|
640
|
-
};
|
|
641
|
-
|
|
642
|
-
//#endregion
|
|
643
|
-
//#region src/engine/planning/RequiredNodeCollector.ts
|
|
644
|
-
var RequiredNodeCollector = class {
|
|
645
|
-
requiredNodeIds = /* @__PURE__ */ new Set();
|
|
646
|
-
constructor(topology, satisfactionResolver) {
|
|
647
|
-
this.topology = topology;
|
|
648
|
-
this.satisfactionResolver = satisfactionResolver;
|
|
649
|
-
}
|
|
650
|
-
collect(stopCondition) {
|
|
651
|
-
if (stopCondition.kind === "workflowCompleted") {
|
|
652
|
-
for (const nodeId of this.topology.defsById.keys()) if (!this.satisfactionResolver.isNodeSatisfied(nodeId)) this.collectNode(nodeId);
|
|
653
|
-
return this.requiredNodeIds;
|
|
654
|
-
}
|
|
655
|
-
if (!this.topology.defsById.has(stopCondition.nodeId)) throw new Error(`Unknown stop nodeId: ${stopCondition.nodeId}`);
|
|
656
|
-
this.collectNode(stopCondition.nodeId);
|
|
657
|
-
return this.requiredNodeIds;
|
|
658
|
-
}
|
|
659
|
-
collectNode(nodeId) {
|
|
660
|
-
if (this.requiredNodeIds.has(nodeId)) return;
|
|
661
|
-
if (this.satisfactionResolver.isNodeSatisfied(nodeId) && !this.satisfactionResolver.isNodeSatisfiedByOutputsOnly(nodeId)) return;
|
|
662
|
-
this.requiredNodeIds.add(nodeId);
|
|
663
|
-
for (const edge of this.topology.incomingByNode.get(nodeId) ?? []) if (!this.satisfactionResolver.isEdgeSatisfied({
|
|
664
|
-
nodeId,
|
|
665
|
-
input: edge.input
|
|
666
|
-
}) || this.satisfactionResolver.isNodeSatisfiedByOutputsOnly(edge.from.nodeId)) this.collectNode(edge.from.nodeId);
|
|
667
|
-
}
|
|
668
|
-
};
|
|
669
|
-
|
|
670
|
-
//#endregion
|
|
671
|
-
//#region src/engine/planning/RootNodeInputResolver.ts
|
|
672
|
-
var RootNodeInputResolver = class {
|
|
673
|
-
resolve(args) {
|
|
674
|
-
if (args.items) return args.items;
|
|
675
|
-
if (args.nodeKind === "trigger") return [];
|
|
676
|
-
return [{ json: {} }];
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
|
|
680
|
-
//#endregion
|
|
681
|
-
//#region src/engine/planning/RunCurrentStateFactory.ts
|
|
682
|
-
var RunCurrentStateFactory = class {
|
|
683
|
-
static empty() {
|
|
684
|
-
return {
|
|
685
|
-
outputsByNode: {},
|
|
686
|
-
nodeSnapshotsByNodeId: {},
|
|
687
|
-
connectionInvocations: [],
|
|
688
|
-
mutableState: void 0
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
static clone(currentState) {
|
|
692
|
-
if (!currentState) return this.empty();
|
|
693
|
-
return {
|
|
694
|
-
outputsByNode: { ...currentState.outputsByNode },
|
|
695
|
-
nodeSnapshotsByNodeId: { ...currentState.nodeSnapshotsByNodeId },
|
|
696
|
-
connectionInvocations: currentState.connectionInvocations ? [...currentState.connectionInvocations] : void 0,
|
|
697
|
-
mutableState: currentState.mutableState
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
};
|
|
701
|
-
|
|
702
|
-
//#endregion
|
|
703
|
-
//#region src/workflow/ConnectionNodeIdFactory.ts
|
|
704
|
-
/**
|
|
705
|
-
* Deterministic ids for workflow connection-owned child nodes (LLM slot, tools, etc.).
|
|
706
|
-
* These are stable across loads.
|
|
707
|
-
*/
|
|
708
|
-
var ConnectionNodeIdFactory = class {
|
|
709
|
-
static connectionSegment = "__conn__";
|
|
710
|
-
static languageModelConnectionNodeId(parentNodeId) {
|
|
711
|
-
return `${parentNodeId}${this.connectionSegment}llm`;
|
|
712
|
-
}
|
|
713
|
-
static toolConnectionNodeId(parentNodeId, toolName) {
|
|
714
|
-
const normalized = this.normalizeToolName(toolName);
|
|
715
|
-
return `${parentNodeId}${this.connectionSegment}tool${this.connectionSegment}${normalized}`;
|
|
716
|
-
}
|
|
717
|
-
static isLanguageModelConnectionNodeId(nodeId) {
|
|
718
|
-
return nodeId.endsWith(`${this.connectionSegment}llm`);
|
|
719
|
-
}
|
|
720
|
-
static isToolConnectionNodeId(nodeId) {
|
|
721
|
-
return nodeId.includes(`${this.connectionSegment}tool${this.connectionSegment}`);
|
|
722
|
-
}
|
|
723
|
-
/** True when `nodeId` is a connection-owned child of `parentNodeId` (LLM or tool slot). */
|
|
724
|
-
static isConnectionOwnedDescendantOf(parentNodeId, nodeId) {
|
|
725
|
-
return nodeId.startsWith(`${parentNodeId}${this.connectionSegment}`);
|
|
726
|
-
}
|
|
727
|
-
/** Normalizes a tool display name to a stable id segment. */
|
|
728
|
-
static normalizeToolName(toolName) {
|
|
729
|
-
return toolName.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "tool";
|
|
730
|
-
}
|
|
731
|
-
};
|
|
732
|
-
|
|
733
|
-
//#endregion
|
|
734
|
-
//#region src/engine/planning/RunStateResetter.ts
|
|
735
|
-
var RunStateResetter = class {
|
|
736
|
-
constructor(topology, pinnedOutputResolver) {
|
|
737
|
-
this.topology = topology;
|
|
738
|
-
this.pinnedOutputResolver = pinnedOutputResolver;
|
|
739
|
-
}
|
|
740
|
-
apply(args) {
|
|
741
|
-
if (!args.reset) return {
|
|
742
|
-
currentState: args.currentState,
|
|
743
|
-
clearedNodeIds: [],
|
|
744
|
-
preservedPinnedNodeIds: []
|
|
745
|
-
};
|
|
746
|
-
const outputsByNode = { ...args.currentState.outputsByNode };
|
|
747
|
-
const nodeSnapshotsByNodeId = { ...args.currentState.nodeSnapshotsByNodeId };
|
|
748
|
-
const clearedNodeIds = [];
|
|
749
|
-
const preservedPinnedNodeIds = [];
|
|
750
|
-
const descendants = this.collectDescendants(args.reset.clearFromNodeId);
|
|
751
|
-
const runtimeDescendants = this.collectRuntimeDescendants(args.currentState, descendants);
|
|
752
|
-
const clearedIdSet = new Set([...descendants, ...runtimeDescendants]);
|
|
753
|
-
for (const nodeId of [...descendants, ...runtimeDescendants]) {
|
|
754
|
-
if (this.pinnedOutputResolver.hasPinnedOutputs(nodeId)) {
|
|
755
|
-
const pinnedOutputs = this.pinnedOutputResolver.getPinnedOutputs(nodeId);
|
|
756
|
-
if (pinnedOutputs) outputsByNode[nodeId] = pinnedOutputs;
|
|
757
|
-
delete nodeSnapshotsByNodeId[nodeId];
|
|
758
|
-
preservedPinnedNodeIds.push(nodeId);
|
|
759
|
-
continue;
|
|
760
|
-
}
|
|
761
|
-
delete outputsByNode[nodeId];
|
|
762
|
-
delete nodeSnapshotsByNodeId[nodeId];
|
|
763
|
-
clearedNodeIds.push(nodeId);
|
|
764
|
-
}
|
|
765
|
-
return {
|
|
766
|
-
currentState: {
|
|
767
|
-
outputsByNode,
|
|
768
|
-
nodeSnapshotsByNodeId,
|
|
769
|
-
connectionInvocations: this.filterConnectionInvocations(args.currentState.connectionInvocations, clearedIdSet),
|
|
770
|
-
mutableState: args.currentState.mutableState
|
|
771
|
-
},
|
|
772
|
-
clearedNodeIds,
|
|
773
|
-
preservedPinnedNodeIds
|
|
774
|
-
};
|
|
775
|
-
}
|
|
776
|
-
filterConnectionInvocations(invocations, clearedIdSet) {
|
|
777
|
-
if (!invocations || invocations.length === 0) return invocations;
|
|
778
|
-
const kept = invocations.filter((inv) => !clearedIdSet.has(inv.parentAgentNodeId) && !clearedIdSet.has(inv.connectionNodeId));
|
|
779
|
-
return kept.length === invocations.length ? invocations : kept;
|
|
780
|
-
}
|
|
781
|
-
collectDescendants(startNodeId) {
|
|
782
|
-
const pendingNodeIds = [startNodeId];
|
|
783
|
-
const descendants = /* @__PURE__ */ new Set();
|
|
784
|
-
while (pendingNodeIds.length > 0) {
|
|
785
|
-
const nodeId = pendingNodeIds.pop();
|
|
786
|
-
if (!nodeId || descendants.has(nodeId)) continue;
|
|
787
|
-
descendants.add(nodeId);
|
|
788
|
-
for (const edge of this.topology.outgoingByNode.get(nodeId) ?? []) pendingNodeIds.push(edge.to.nodeId);
|
|
789
|
-
}
|
|
790
|
-
return [...descendants];
|
|
791
|
-
}
|
|
792
|
-
collectRuntimeDescendants(currentState, descendantNodeIds) {
|
|
793
|
-
const descendantSet = new Set(descendantNodeIds);
|
|
794
|
-
const runtimeNodeIds = /* @__PURE__ */ new Set();
|
|
795
|
-
for (const nodeId of [
|
|
796
|
-
...Object.keys(currentState.outputsByNode),
|
|
797
|
-
...Object.keys(currentState.nodeSnapshotsByNodeId),
|
|
798
|
-
...Object.keys(currentState.mutableState?.nodesById ?? {})
|
|
799
|
-
]) {
|
|
800
|
-
if (!this.isRuntimeDescendant(nodeId, descendantSet)) continue;
|
|
801
|
-
runtimeNodeIds.add(nodeId);
|
|
802
|
-
}
|
|
803
|
-
return [...runtimeNodeIds];
|
|
804
|
-
}
|
|
805
|
-
isRuntimeDescendant(nodeId, descendantNodeIds) {
|
|
806
|
-
for (const descendantNodeId of descendantNodeIds) {
|
|
807
|
-
if (nodeId === descendantNodeId) return false;
|
|
808
|
-
if (ConnectionNodeIdFactory.isConnectionOwnedDescendantOf(descendantNodeId, nodeId)) return true;
|
|
809
|
-
}
|
|
810
|
-
return false;
|
|
811
|
-
}
|
|
812
|
-
};
|
|
813
|
-
|
|
814
|
-
//#endregion
|
|
815
|
-
//#region src/engine/planning/CurrentStateFrontierPlanner.ts
|
|
816
|
-
var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
|
|
817
|
-
rootNodeInputResolver = new RootNodeInputResolver();
|
|
818
|
-
constructor(topology) {
|
|
819
|
-
this.topology = topology;
|
|
820
|
-
}
|
|
821
|
-
/** Composition-root-friendly factory (avoids `new` at orchestration call sites under ESLint manual-DI rules). */
|
|
822
|
-
static createFromTopology(topology) {
|
|
823
|
-
return new CurrentStateFrontierPlanner(topology);
|
|
824
|
-
}
|
|
825
|
-
plan(args) {
|
|
826
|
-
const stopCondition = args.stopCondition ?? { kind: "workflowCompleted" };
|
|
827
|
-
const normalizedState = new PinnedOutputResolver(RunCurrentStateFactory.clone(args.currentState)).overlayPinnedOutputs();
|
|
828
|
-
const resetResult = new RunStateResetter(this.topology, new PinnedOutputResolver(normalizedState)).apply({
|
|
829
|
-
currentState: normalizedState,
|
|
830
|
-
reset: args.reset
|
|
831
|
-
});
|
|
832
|
-
const satisfactionResolver = new DependencySatisfactionResolver(this.topology, resetResult.currentState);
|
|
833
|
-
const requiredNodeIds = new RequiredNodeCollector(this.topology, satisfactionResolver).collect(stopCondition);
|
|
834
|
-
const satisfiedNodeIds = this.collectSatisfiedNodeIds(satisfactionResolver);
|
|
835
|
-
const skippedNodeIds = [...new Set([...[...requiredNodeIds].filter((nodeId) => satisfactionResolver.isNodeSatisfied(nodeId)), ...resetResult.preservedPinnedNodeIds.filter((nodeId) => requiredNodeIds.has(nodeId))])];
|
|
836
|
-
const frontierNodeIds = this.collectFrontierNodeIds(requiredNodeIds, satisfactionResolver);
|
|
837
|
-
const rootNodeIds = frontierNodeIds.filter((nodeId) => (this.topology.incomingByNode.get(nodeId) ?? []).length === 0);
|
|
838
|
-
if (rootNodeIds.length > 1) throw new Error(`Ambiguous execution frontier. Multiple root nodes require input: ${rootNodeIds.join(", ")}`);
|
|
839
|
-
if (frontierNodeIds.length === 0) return {
|
|
840
|
-
queue: [],
|
|
841
|
-
currentState: resetResult.currentState,
|
|
842
|
-
stopCondition,
|
|
843
|
-
satisfiedNodeIds,
|
|
844
|
-
skippedNodeIds,
|
|
845
|
-
clearedNodeIds: resetResult.clearedNodeIds,
|
|
846
|
-
preservedPinnedNodeIds: resetResult.preservedPinnedNodeIds
|
|
847
|
-
};
|
|
848
|
-
if (rootNodeIds.length === 1) {
|
|
849
|
-
const rootNodeId = rootNodeIds[0];
|
|
850
|
-
const definition = this.topology.defsById.get(rootNodeId);
|
|
851
|
-
if (!definition) throw new Error(`Unknown frontier nodeId: ${rootNodeId}`);
|
|
852
|
-
return {
|
|
853
|
-
rootNodeId,
|
|
854
|
-
rootNodeInput: this.rootNodeInputResolver.resolve({
|
|
855
|
-
nodeKind: definition.kind,
|
|
856
|
-
items: args.items
|
|
857
|
-
}),
|
|
858
|
-
queue: [],
|
|
859
|
-
currentState: resetResult.currentState,
|
|
860
|
-
stopCondition,
|
|
861
|
-
satisfiedNodeIds,
|
|
862
|
-
skippedNodeIds,
|
|
863
|
-
clearedNodeIds: resetResult.clearedNodeIds,
|
|
864
|
-
preservedPinnedNodeIds: resetResult.preservedPinnedNodeIds
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
const queueBuilder = new FrontierQueueBuilder(this.topology, satisfactionResolver);
|
|
868
|
-
const queue = [];
|
|
869
|
-
for (const nodeId of frontierNodeIds) queue.push(...queueBuilder.build({ nodeId }));
|
|
870
|
-
return {
|
|
871
|
-
queue,
|
|
872
|
-
currentState: resetResult.currentState,
|
|
873
|
-
stopCondition,
|
|
874
|
-
satisfiedNodeIds,
|
|
875
|
-
skippedNodeIds,
|
|
876
|
-
clearedNodeIds: resetResult.clearedNodeIds,
|
|
877
|
-
preservedPinnedNodeIds: resetResult.preservedPinnedNodeIds
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
collectSatisfiedNodeIds(satisfactionResolver) {
|
|
881
|
-
const satisfiedNodeIds = [];
|
|
882
|
-
for (const nodeId of this.topology.defsById.keys()) if (satisfactionResolver.isNodeSatisfied(nodeId)) satisfiedNodeIds.push(nodeId);
|
|
883
|
-
return satisfiedNodeIds;
|
|
884
|
-
}
|
|
885
|
-
collectFrontierNodeIds(requiredNodeIds, satisfactionResolver) {
|
|
886
|
-
const frontierNodeIds = [];
|
|
887
|
-
for (const nodeId of this.topology.defsById.keys()) {
|
|
888
|
-
if (!requiredNodeIds.has(nodeId) || satisfactionResolver.isNodeSatisfied(nodeId)) continue;
|
|
889
|
-
if ((this.topology.incomingByNode.get(nodeId) ?? []).every((edge) => satisfactionResolver.isEdgeSatisfied({
|
|
890
|
-
nodeId,
|
|
891
|
-
input: edge.input
|
|
892
|
-
}))) frontierNodeIds.push(nodeId);
|
|
893
|
-
}
|
|
894
|
-
return frontierNodeIds;
|
|
895
|
-
}
|
|
896
|
-
};
|
|
897
|
-
|
|
898
|
-
//#endregion
|
|
899
|
-
//#region src/engine/planning/WorkflowTopologyPlanner.ts
|
|
900
|
-
var WorkflowTopology = class WorkflowTopology {
|
|
901
|
-
constructor(defsById, outgoingByNode, incomingByNode, expectedInputsByNode, rootNodeIds) {
|
|
902
|
-
this.defsById = defsById;
|
|
903
|
-
this.outgoingByNode = outgoingByNode;
|
|
904
|
-
this.incomingByNode = incomingByNode;
|
|
905
|
-
this.expectedInputsByNode = expectedInputsByNode;
|
|
906
|
-
this.rootNodeIds = rootNodeIds;
|
|
907
|
-
}
|
|
908
|
-
static fromWorkflow(wf) {
|
|
909
|
-
const classifier = createWorkflowExecutableNodeClassifier(wf);
|
|
910
|
-
const defs = /* @__PURE__ */ new Map();
|
|
911
|
-
for (const n of wf.nodes) if (classifier.isExecutableNodeId(n.id)) defs.set(n.id, n);
|
|
912
|
-
const outgoing = /* @__PURE__ */ new Map();
|
|
913
|
-
for (const e of wf.edges) {
|
|
914
|
-
if (!classifier.isExecutableNodeId(e.from.nodeId) || !classifier.isExecutableNodeId(e.to.nodeId)) continue;
|
|
915
|
-
const list = outgoing.get(e.from.nodeId) ?? [];
|
|
916
|
-
list.push({
|
|
917
|
-
output: e.from.output,
|
|
918
|
-
to: {
|
|
919
|
-
nodeId: e.to.nodeId,
|
|
920
|
-
input: e.to.input
|
|
921
|
-
}
|
|
922
|
-
});
|
|
923
|
-
outgoing.set(e.from.nodeId, list);
|
|
924
|
-
}
|
|
925
|
-
const incomingByNode = /* @__PURE__ */ new Map();
|
|
926
|
-
for (const e of wf.edges) {
|
|
927
|
-
if (!classifier.isExecutableNodeId(e.from.nodeId) || !classifier.isExecutableNodeId(e.to.nodeId)) continue;
|
|
928
|
-
const list = incomingByNode.get(e.to.nodeId) ?? [];
|
|
929
|
-
list.push({
|
|
930
|
-
from: {
|
|
931
|
-
nodeId: e.from.nodeId,
|
|
932
|
-
output: e.from.output
|
|
933
|
-
},
|
|
934
|
-
input: e.to.input
|
|
935
|
-
});
|
|
936
|
-
incomingByNode.set(e.to.nodeId, list);
|
|
937
|
-
}
|
|
938
|
-
const expected = /* @__PURE__ */ new Map();
|
|
939
|
-
for (const [toNodeId, inputs] of incomingByNode.entries()) {
|
|
940
|
-
const counts = /* @__PURE__ */ new Map();
|
|
941
|
-
for (const edge of inputs) counts.set(edge.input, (counts.get(edge.input) ?? 0) + 1);
|
|
942
|
-
for (const [k, n] of counts.entries()) if (n > 1) throw new Error(`Node ${toNodeId} has multiple edges into input '${k}'. Use a Merge node upstream.`);
|
|
943
|
-
const order = [];
|
|
944
|
-
const seen = /* @__PURE__ */ new Set();
|
|
945
|
-
for (const edge of inputs) {
|
|
946
|
-
if (seen.has(edge.input)) continue;
|
|
947
|
-
seen.add(edge.input);
|
|
948
|
-
order.push(edge.input);
|
|
949
|
-
}
|
|
950
|
-
expected.set(toNodeId, order);
|
|
951
|
-
}
|
|
952
|
-
return new WorkflowTopology(defs, outgoing, incomingByNode, expected, wf.nodes.filter((node) => classifier.isExecutableNodeId(node.id) && !incomingByNode.has(node.id)).map((node) => node.id));
|
|
953
|
-
}
|
|
954
|
-
};
|
|
955
|
-
|
|
956
|
-
//#endregion
|
|
957
|
-
//#region src/engine/policies/RunPolicySnapshotFactory.ts
|
|
958
|
-
var RunPolicySnapshotFactory = class {
|
|
959
|
-
static create(workflow, defaults) {
|
|
960
|
-
const prune = workflow.prunePolicy;
|
|
961
|
-
return {
|
|
962
|
-
retentionSeconds: prune?.runDataRetentionSeconds ?? defaults?.retentionSeconds,
|
|
963
|
-
binaryRetentionSeconds: prune?.binaryRetentionSeconds ?? defaults?.binaryRetentionSeconds,
|
|
964
|
-
storagePolicy: typeof workflow.storagePolicy === "string" ? workflow.storagePolicy : defaults?.storagePolicy ?? "ALL"
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
};
|
|
968
|
-
|
|
969
|
-
//#endregion
|
|
970
|
-
//#region src/engine/execution/CurrentStateRunStarter.ts
|
|
971
|
-
var CurrentStateRunStarter = class {
|
|
972
|
-
constructor(runIdFactory, runStore, runDataFactory, workflowSnapshotFactory, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, workflowPolicyRuntimeDefaults, executionLimitsPolicy) {
|
|
973
|
-
this.runIdFactory = runIdFactory;
|
|
974
|
-
this.runStore = runStore;
|
|
975
|
-
this.runDataFactory = runDataFactory;
|
|
976
|
-
this.workflowSnapshotFactory = workflowSnapshotFactory;
|
|
977
|
-
this.planningFactory = planningFactory;
|
|
978
|
-
this.nodeStatePublisherFactory = nodeStatePublisherFactory;
|
|
979
|
-
this.runExecutionContextFactory = runExecutionContextFactory;
|
|
980
|
-
this.nodeActivationRequestComposer = nodeActivationRequestComposer;
|
|
981
|
-
this.activationEnqueueService = activationEnqueueService;
|
|
982
|
-
this.semantics = semantics;
|
|
983
|
-
this.waiters = waiters;
|
|
984
|
-
this.workflowPolicyRuntimeDefaults = workflowPolicyRuntimeDefaults;
|
|
985
|
-
this.executionLimitsPolicy = executionLimitsPolicy;
|
|
986
|
-
}
|
|
987
|
-
async runWorkflowFromState(request) {
|
|
988
|
-
const runId = this.runIdFactory.makeRunId();
|
|
989
|
-
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
990
|
-
const workflowSnapshot = request.workflowSnapshot ?? this.workflowSnapshotFactory.create(request.workflow);
|
|
991
|
-
const mutableState = request.mutableState ?? request.currentState?.mutableState;
|
|
992
|
-
const policySnapshot = RunPolicySnapshotFactory.create(request.workflow, this.workflowPolicyRuntimeDefaults);
|
|
993
|
-
const control = { stopCondition: request.stopCondition ?? { kind: "workflowCompleted" } };
|
|
994
|
-
const mergedExecutionOptions = this.executionLimitsPolicy.mergeExecutionOptionsForNewRun(request.parent, request.executionOptions);
|
|
995
|
-
await this.runStore.createRun({
|
|
996
|
-
runId,
|
|
997
|
-
workflowId: request.workflow.id,
|
|
998
|
-
startedAt,
|
|
999
|
-
parent: request.parent,
|
|
1000
|
-
executionOptions: mergedExecutionOptions,
|
|
1001
|
-
control,
|
|
1002
|
-
workflowSnapshot,
|
|
1003
|
-
mutableState,
|
|
1004
|
-
policySnapshot,
|
|
1005
|
-
engineCounters: { completedNodeActivations: 0 }
|
|
1006
|
-
});
|
|
1007
|
-
const { topology, planner } = this.planningFactory.create(request.workflow);
|
|
1008
|
-
const plan = CurrentStateFrontierPlanner.createFromTopology(topology).plan({
|
|
1009
|
-
currentState: this.createRunCurrentState(request.currentState, mutableState),
|
|
1010
|
-
stopCondition: control.stopCondition,
|
|
1011
|
-
reset: request.reset,
|
|
1012
|
-
items: request.items
|
|
1013
|
-
});
|
|
1014
|
-
const data = this.runDataFactory.create(plan.currentState.outputsByNode);
|
|
1015
|
-
const base = this.runExecutionContextFactory.create({
|
|
1016
|
-
runId,
|
|
1017
|
-
workflowId: request.workflow.id,
|
|
1018
|
-
nodeId: createWorkflowExecutableNodeClassifier(request.workflow).firstExecutableNodeIdInDefinitionOrder(request.workflow) ?? "unknown_node",
|
|
1019
|
-
parent: request.parent,
|
|
1020
|
-
subworkflowDepth: mergedExecutionOptions.subworkflowDepth ?? 0,
|
|
1021
|
-
engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations,
|
|
1022
|
-
engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth,
|
|
1023
|
-
data,
|
|
1024
|
-
nodeState: this.nodeStatePublisherFactory.create(runId, request.workflow.id, request.parent)
|
|
1025
|
-
});
|
|
1026
|
-
return await this.scheduleInitialPlan({
|
|
1027
|
-
runId,
|
|
1028
|
-
startedAt,
|
|
1029
|
-
workflow: request.workflow,
|
|
1030
|
-
workflowSnapshot,
|
|
1031
|
-
mutableState,
|
|
1032
|
-
policySnapshot,
|
|
1033
|
-
executionOptions: mergedExecutionOptions,
|
|
1034
|
-
control,
|
|
1035
|
-
parent: request.parent,
|
|
1036
|
-
planner,
|
|
1037
|
-
plan,
|
|
1038
|
-
base,
|
|
1039
|
-
data
|
|
1040
|
-
});
|
|
1041
|
-
}
|
|
1042
|
-
createRunCurrentState(currentState, mutableState) {
|
|
1043
|
-
return {
|
|
1044
|
-
outputsByNode: { ...currentState?.outputsByNode ?? {} },
|
|
1045
|
-
nodeSnapshotsByNodeId: { ...currentState?.nodeSnapshotsByNodeId ?? {} },
|
|
1046
|
-
connectionInvocations: currentState?.connectionInvocations ? [...currentState.connectionInvocations] : void 0,
|
|
1047
|
-
mutableState: mutableState ?? currentState?.mutableState
|
|
1048
|
-
};
|
|
1049
|
-
}
|
|
1050
|
-
async scheduleInitialPlan(args) {
|
|
1051
|
-
const initialNodeSnapshotsByNodeId = this.semantics.applySkippedSnapshots({
|
|
1052
|
-
runId: args.runId,
|
|
1053
|
-
workflowId: args.workflow.id,
|
|
1054
|
-
parent: args.parent,
|
|
1055
|
-
currentState: args.plan.currentState,
|
|
1056
|
-
skippedNodeIds: args.plan.skippedNodeIds,
|
|
1057
|
-
preservedPinnedNodeIds: args.plan.preservedPinnedNodeIds,
|
|
1058
|
-
finishedAt: args.startedAt
|
|
1059
|
-
});
|
|
1060
|
-
if (args.plan.rootNodeId) {
|
|
1061
|
-
const startDef = WorkflowTopology.fromWorkflow(args.workflow).defsById.get(args.plan.rootNodeId);
|
|
1062
|
-
if (!startDef) throw new Error(`Unknown frontier nodeId: ${args.plan.rootNodeId}`);
|
|
1063
|
-
const startItems = args.plan.rootNodeInput ?? [];
|
|
1064
|
-
if (startDef.kind === "trigger") {
|
|
1065
|
-
const request$1 = this.nodeActivationRequestComposer.createSingleFromDefinition({
|
|
1066
|
-
runId: args.runId,
|
|
1067
|
-
workflowId: args.workflow.id,
|
|
1068
|
-
definition: startDef,
|
|
1069
|
-
parent: args.parent,
|
|
1070
|
-
executionOptions: args.executionOptions,
|
|
1071
|
-
batchId: "batch_1",
|
|
1072
|
-
input: startItems,
|
|
1073
|
-
base: args.base,
|
|
1074
|
-
data: args.data
|
|
1075
|
-
});
|
|
1076
|
-
return await this.activationEnqueueService.enqueueActivation({
|
|
1077
|
-
runId: args.runId,
|
|
1078
|
-
workflowId: args.workflow.id,
|
|
1079
|
-
startedAt: args.startedAt,
|
|
1080
|
-
parent: args.parent,
|
|
1081
|
-
executionOptions: args.executionOptions,
|
|
1082
|
-
control: args.control,
|
|
1083
|
-
workflowSnapshot: args.workflowSnapshot,
|
|
1084
|
-
mutableState: args.mutableState,
|
|
1085
|
-
policySnapshot: args.policySnapshot,
|
|
1086
|
-
pendingQueue: [],
|
|
1087
|
-
request: request$1,
|
|
1088
|
-
previousNodeSnapshotsByNodeId: initialNodeSnapshotsByNodeId,
|
|
1089
|
-
planner: args.planner,
|
|
1090
|
-
engineCounters: { completedNodeActivations: 0 },
|
|
1091
|
-
connectionInvocations: args.plan.currentState.connectionInvocations ?? []
|
|
1092
|
-
});
|
|
1093
|
-
}
|
|
1094
|
-
const request = this.nodeActivationRequestComposer.createSingleFromDefinition({
|
|
1095
|
-
runId: args.runId,
|
|
1096
|
-
workflowId: args.workflow.id,
|
|
1097
|
-
definition: startDef,
|
|
1098
|
-
parent: args.parent,
|
|
1099
|
-
executionOptions: args.executionOptions,
|
|
1100
|
-
batchId: "batch_1",
|
|
1101
|
-
input: startItems,
|
|
1102
|
-
base: args.base,
|
|
1103
|
-
data: args.data
|
|
1104
|
-
});
|
|
1105
|
-
return await this.activationEnqueueService.enqueueActivation({
|
|
1106
|
-
runId: args.runId,
|
|
1107
|
-
workflowId: args.workflow.id,
|
|
1108
|
-
startedAt: args.startedAt,
|
|
1109
|
-
parent: args.parent,
|
|
1110
|
-
executionOptions: args.executionOptions,
|
|
1111
|
-
control: args.control,
|
|
1112
|
-
workflowSnapshot: args.workflowSnapshot,
|
|
1113
|
-
mutableState: args.mutableState,
|
|
1114
|
-
policySnapshot: args.policySnapshot,
|
|
1115
|
-
pendingQueue: [],
|
|
1116
|
-
request,
|
|
1117
|
-
previousNodeSnapshotsByNodeId: initialNodeSnapshotsByNodeId,
|
|
1118
|
-
planner: args.planner,
|
|
1119
|
-
connectionInvocations: args.plan.currentState.connectionInvocations ?? []
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1122
|
-
return await this.scheduleQueuedPlan({
|
|
1123
|
-
runId: args.runId,
|
|
1124
|
-
workflowId: args.workflow.id,
|
|
1125
|
-
startedAt: args.startedAt,
|
|
1126
|
-
parent: args.parent,
|
|
1127
|
-
executionOptions: args.executionOptions,
|
|
1128
|
-
control: args.control,
|
|
1129
|
-
workflowSnapshot: args.workflowSnapshot,
|
|
1130
|
-
mutableState: args.mutableState,
|
|
1131
|
-
policySnapshot: args.policySnapshot,
|
|
1132
|
-
workflow: args.workflow,
|
|
1133
|
-
planner: args.planner,
|
|
1134
|
-
queue: [...args.plan.queue],
|
|
1135
|
-
base: args.base,
|
|
1136
|
-
data: args.data,
|
|
1137
|
-
nodeSnapshotsByNodeId: initialNodeSnapshotsByNodeId,
|
|
1138
|
-
connectionInvocations: args.plan.currentState.connectionInvocations ?? []
|
|
1139
|
-
});
|
|
1140
|
-
}
|
|
1141
|
-
async scheduleQueuedPlan(args) {
|
|
1142
|
-
this.semantics.applyPinnedQueueSkips({
|
|
1143
|
-
runId: args.runId,
|
|
1144
|
-
workflowId: args.workflowId,
|
|
1145
|
-
parent: args.parent,
|
|
1146
|
-
mutableState: args.mutableState,
|
|
1147
|
-
planner: args.planner,
|
|
1148
|
-
queue: args.queue,
|
|
1149
|
-
data: args.data,
|
|
1150
|
-
nodeSnapshotsByNodeId: args.nodeSnapshotsByNodeId,
|
|
1151
|
-
finishedAt: args.startedAt
|
|
1152
|
-
});
|
|
1153
|
-
const next = args.planner.nextActivation(args.queue);
|
|
1154
|
-
if (!next) return await this.completeRun({
|
|
1155
|
-
runId: args.runId,
|
|
1156
|
-
workflowId: args.workflowId,
|
|
1157
|
-
startedAt: args.startedAt,
|
|
1158
|
-
parent: args.parent,
|
|
1159
|
-
executionOptions: args.executionOptions,
|
|
1160
|
-
control: args.control,
|
|
1161
|
-
workflowSnapshot: args.workflowSnapshot,
|
|
1162
|
-
mutableState: args.mutableState,
|
|
1163
|
-
policySnapshot: args.policySnapshot,
|
|
1164
|
-
workflow: args.workflow,
|
|
1165
|
-
data: args.data,
|
|
1166
|
-
nodeSnapshotsByNodeId: args.nodeSnapshotsByNodeId,
|
|
1167
|
-
connectionInvocations: args.connectionInvocations
|
|
1168
|
-
});
|
|
1169
|
-
const definition = WorkflowTopology.fromWorkflow(args.workflow).defsById.get(next.nodeId);
|
|
1170
|
-
if (!definition || definition.kind !== "node") throw new Error(`Node ${next.nodeId} is not a runnable node`);
|
|
1171
|
-
const request = this.nodeActivationRequestComposer.createFromPlannedActivation({
|
|
1172
|
-
next,
|
|
1173
|
-
base: args.base,
|
|
1174
|
-
data: args.data,
|
|
1175
|
-
runId: args.runId,
|
|
1176
|
-
workflowId: args.workflowId,
|
|
1177
|
-
parent: args.parent,
|
|
1178
|
-
executionOptions: args.executionOptions,
|
|
1179
|
-
nodeDefinition: definition
|
|
1180
|
-
});
|
|
1181
|
-
return await this.activationEnqueueService.enqueueActivation({
|
|
1182
|
-
runId: args.runId,
|
|
1183
|
-
workflowId: args.workflowId,
|
|
1184
|
-
startedAt: args.startedAt,
|
|
1185
|
-
parent: args.parent,
|
|
1186
|
-
executionOptions: args.executionOptions,
|
|
1187
|
-
control: args.control,
|
|
1188
|
-
workflowSnapshot: args.workflowSnapshot,
|
|
1189
|
-
mutableState: args.mutableState,
|
|
1190
|
-
policySnapshot: args.policySnapshot,
|
|
1191
|
-
pendingQueue: args.queue,
|
|
1192
|
-
request,
|
|
1193
|
-
previousNodeSnapshotsByNodeId: args.nodeSnapshotsByNodeId,
|
|
1194
|
-
planner: args.planner,
|
|
1195
|
-
engineCounters: { completedNodeActivations: 0 },
|
|
1196
|
-
connectionInvocations: args.connectionInvocations ?? []
|
|
1197
|
-
});
|
|
1198
|
-
}
|
|
1199
|
-
async completeRun(args) {
|
|
1200
|
-
await this.runStore.save({
|
|
1201
|
-
runId: args.runId,
|
|
1202
|
-
workflowId: args.workflowId,
|
|
1203
|
-
startedAt: args.startedAt,
|
|
1204
|
-
parent: args.parent,
|
|
1205
|
-
executionOptions: args.executionOptions,
|
|
1206
|
-
control: args.control,
|
|
1207
|
-
workflowSnapshot: args.workflowSnapshot,
|
|
1208
|
-
mutableState: args.mutableState,
|
|
1209
|
-
policySnapshot: args.policySnapshot,
|
|
1210
|
-
engineCounters: { completedNodeActivations: 0 },
|
|
1211
|
-
connectionInvocations: args.connectionInvocations ? [...args.connectionInvocations] : [],
|
|
1212
|
-
status: "completed",
|
|
1213
|
-
pending: void 0,
|
|
1214
|
-
queue: [],
|
|
1215
|
-
outputsByNode: args.data.dump(),
|
|
1216
|
-
nodeSnapshotsByNodeId: args.nodeSnapshotsByNodeId
|
|
1217
|
-
});
|
|
1218
|
-
const result = {
|
|
1219
|
-
runId: args.runId,
|
|
1220
|
-
workflowId: args.workflowId,
|
|
1221
|
-
startedAt: args.startedAt,
|
|
1222
|
-
status: "completed",
|
|
1223
|
-
outputs: this.semantics.resolveResultOutputs(args.workflow, args.control?.stopCondition, args.data.dump())
|
|
1224
|
-
};
|
|
1225
|
-
this.waiters.resolveRunCompletion(result);
|
|
1226
|
-
return result;
|
|
1227
|
-
}
|
|
1228
|
-
};
|
|
1229
|
-
|
|
1230
|
-
//#endregion
|
|
1231
|
-
//#region src/engine/execution/NodeActivationRequestComposer.ts
|
|
1232
|
-
/**
|
|
1233
|
-
* Builds {@link NodeActivationRequest} values shared by workflow starters and continuation.
|
|
1234
|
-
*/
|
|
1235
|
-
var NodeActivationRequestComposer = class {
|
|
1236
|
-
constructor(activationIdFactory, credentialResolverFactory) {
|
|
1237
|
-
this.activationIdFactory = activationIdFactory;
|
|
1238
|
-
this.credentialResolverFactory = credentialResolverFactory;
|
|
1239
|
-
}
|
|
1240
|
-
createSingleFromDefinition(args) {
|
|
1241
|
-
const activationId = this.activationIdFactory.makeActivationId();
|
|
1242
|
-
const ctx = {
|
|
1243
|
-
...args.base,
|
|
1244
|
-
data: args.data,
|
|
1245
|
-
nodeId: args.definition.id,
|
|
1246
|
-
activationId,
|
|
1247
|
-
config: args.definition.config,
|
|
1248
|
-
binary: args.base.binary.forNode({
|
|
1249
|
-
nodeId: args.definition.id,
|
|
1250
|
-
activationId
|
|
1251
|
-
}),
|
|
1252
|
-
getCredential: this.credentialResolverFactory.create(args.workflowId, args.definition.id, args.definition.config)
|
|
1253
|
-
};
|
|
1254
|
-
return {
|
|
1255
|
-
kind: "single",
|
|
1256
|
-
runId: args.runId,
|
|
1257
|
-
activationId,
|
|
1258
|
-
workflowId: args.workflowId,
|
|
1259
|
-
nodeId: args.definition.id,
|
|
1260
|
-
parent: args.parent,
|
|
1261
|
-
executionOptions: args.executionOptions,
|
|
1262
|
-
batchId: args.batchId,
|
|
1263
|
-
input: args.input,
|
|
1264
|
-
ctx
|
|
1265
|
-
};
|
|
1266
|
-
}
|
|
1267
|
-
createFromPlannedActivation(args) {
|
|
1268
|
-
const activationId = this.activationIdFactory.makeActivationId();
|
|
1269
|
-
const ctx = {
|
|
1270
|
-
...args.base,
|
|
1271
|
-
data: args.data,
|
|
1272
|
-
nodeId: args.nodeDefinition.id,
|
|
1273
|
-
activationId,
|
|
1274
|
-
config: args.nodeDefinition.config,
|
|
1275
|
-
binary: args.base.binary.forNode({
|
|
1276
|
-
nodeId: args.nodeDefinition.id,
|
|
1277
|
-
activationId
|
|
1278
|
-
}),
|
|
1279
|
-
getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeDefinition.id, args.nodeDefinition.config)
|
|
1280
|
-
};
|
|
1281
|
-
if (args.next.kind === "multi") return {
|
|
1282
|
-
kind: "multi",
|
|
1283
|
-
runId: args.runId,
|
|
1284
|
-
activationId,
|
|
1285
|
-
workflowId: args.workflowId,
|
|
1286
|
-
nodeId: args.nodeDefinition.id,
|
|
1287
|
-
parent: args.parent,
|
|
1288
|
-
executionOptions: args.executionOptions,
|
|
1289
|
-
batchId: args.next.batchId,
|
|
1290
|
-
inputsByPort: args.next.inputsByPort,
|
|
1291
|
-
ctx
|
|
1292
|
-
};
|
|
1293
|
-
return {
|
|
1294
|
-
kind: "single",
|
|
1295
|
-
runId: args.runId,
|
|
1296
|
-
activationId,
|
|
1297
|
-
workflowId: args.workflowId,
|
|
1298
|
-
nodeId: args.nodeDefinition.id,
|
|
1299
|
-
parent: args.parent,
|
|
1300
|
-
executionOptions: args.executionOptions,
|
|
1301
|
-
batchId: args.next.batchId,
|
|
1302
|
-
input: args.next.input,
|
|
1303
|
-
ctx
|
|
1304
|
-
};
|
|
1305
|
-
}
|
|
1306
|
-
};
|
|
1307
|
-
|
|
1308
|
-
//#endregion
|
|
1309
|
-
//#region src/engine/execution/PersistedRunStateTerminalBuilder.ts
|
|
1310
|
-
/**
|
|
1311
|
-
* Merges common terminal-run fields onto a loaded {@link PersistedRunState} without repeating object literals.
|
|
1312
|
-
*/
|
|
1313
|
-
var PersistedRunStateTerminalBuilder = class {
|
|
1314
|
-
mergeTerminal(args) {
|
|
1315
|
-
return {
|
|
1316
|
-
...args.state,
|
|
1317
|
-
engineCounters: args.engineCounters,
|
|
1318
|
-
status: args.status,
|
|
1319
|
-
pending: void 0,
|
|
1320
|
-
queue: args.queue,
|
|
1321
|
-
outputsByNode: args.outputsByNode,
|
|
1322
|
-
nodeSnapshotsByNodeId: args.nodeSnapshotsByNodeId
|
|
1323
|
-
};
|
|
1324
|
-
}
|
|
1325
|
-
};
|
|
1326
|
-
|
|
1327
|
-
//#endregion
|
|
1328
|
-
//#region src/engine/state/RuntimeContinuationDiagnosticsReporter.ts
|
|
1329
|
-
var RuntimeContinuationDiagnostics = class {
|
|
1330
|
-
static formatNodeLabel(args) {
|
|
1331
|
-
const tokenName = typeof args.definition?.type === "function" ? args.definition.type.name : "Node";
|
|
1332
|
-
return args.definition?.name ? `"${args.definition.name}" (${tokenName}:${args.nodeId})` : `${tokenName}:${args.nodeId}`;
|
|
1333
|
-
}
|
|
1334
|
-
static formatOutputCounts(outputs) {
|
|
1335
|
-
const entries = Object.entries(outputs ?? {});
|
|
1336
|
-
if (entries.length === 0) return "no outputs";
|
|
1337
|
-
return entries.map(([port, items]) => `${port}=${items?.length ?? 0}`).join(", ");
|
|
1338
|
-
}
|
|
1339
|
-
};
|
|
1340
|
-
|
|
1341
|
-
//#endregion
|
|
1342
|
-
//#region src/engine/execution/RunContinuationService.ts
|
|
1343
|
-
var RunContinuationService = class {
|
|
1344
|
-
constructor(activationIdFactory, runStore, runDataFactory, runExecutionContextFactory, workflowSnapshotResolver, planningFactory, nodeStatePublisherFactory, credentialResolverFactory, nodeActivationRequestComposer, persistedRunStateTerminalBuilder, activationEnqueueService, nodeEventPublisher, semantics, waiters, policyErrorServices, terminalPersistence, executionLimitsPolicy) {
|
|
1345
|
-
this.activationIdFactory = activationIdFactory;
|
|
1346
|
-
this.runStore = runStore;
|
|
1347
|
-
this.runDataFactory = runDataFactory;
|
|
1348
|
-
this.runExecutionContextFactory = runExecutionContextFactory;
|
|
1349
|
-
this.workflowSnapshotResolver = workflowSnapshotResolver;
|
|
1350
|
-
this.planningFactory = planningFactory;
|
|
1351
|
-
this.nodeStatePublisherFactory = nodeStatePublisherFactory;
|
|
1352
|
-
this.credentialResolverFactory = credentialResolverFactory;
|
|
1353
|
-
this.nodeActivationRequestComposer = nodeActivationRequestComposer;
|
|
1354
|
-
this.persistedRunStateTerminalBuilder = persistedRunStateTerminalBuilder;
|
|
1355
|
-
this.activationEnqueueService = activationEnqueueService;
|
|
1356
|
-
this.nodeEventPublisher = nodeEventPublisher;
|
|
1357
|
-
this.semantics = semantics;
|
|
1358
|
-
this.waiters = waiters;
|
|
1359
|
-
this.policyErrorServices = policyErrorServices;
|
|
1360
|
-
this.terminalPersistence = terminalPersistence;
|
|
1361
|
-
this.executionLimitsPolicy = executionLimitsPolicy;
|
|
1362
|
-
}
|
|
1363
|
-
async markNodeRunning(args) {
|
|
1364
|
-
const state = await this.runStore.load(args.runId);
|
|
1365
|
-
if (!state?.pending) return;
|
|
1366
|
-
if (state.pending.activationId !== args.activationId || state.pending.nodeId !== args.nodeId) return;
|
|
1367
|
-
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1368
|
-
const previous = state.nodeSnapshotsByNodeId?.[args.nodeId];
|
|
1369
|
-
const snapshot = NodeSnapshotFactory.running({
|
|
1370
|
-
previous,
|
|
1371
|
-
runId: state.runId,
|
|
1372
|
-
workflowId: state.workflowId,
|
|
1373
|
-
nodeId: args.nodeId,
|
|
1374
|
-
activationId: args.activationId,
|
|
1375
|
-
parent: state.parent,
|
|
1376
|
-
startedAt,
|
|
1377
|
-
inputsByPort: args.inputsByPort
|
|
1378
|
-
});
|
|
1379
|
-
await this.runStore.save({
|
|
1380
|
-
...state,
|
|
1381
|
-
nodeSnapshotsByNodeId: {
|
|
1382
|
-
...state.nodeSnapshotsByNodeId ?? {},
|
|
1383
|
-
[args.nodeId]: snapshot
|
|
1384
|
-
}
|
|
1385
|
-
});
|
|
1386
|
-
await this.nodeEventPublisher.publish("nodeStarted", snapshot);
|
|
1387
|
-
}
|
|
1388
|
-
async resumeFromNodeResult(args) {
|
|
1389
|
-
const state = await this.runStore.load(args.runId);
|
|
1390
|
-
if (!state) throw new Error(`Unknown runId: ${args.runId}`);
|
|
1391
|
-
if (state.status !== "pending" || !state.pending) throw new Error(`Run ${args.runId} is not pending`);
|
|
1392
|
-
if (state.pending.activationId !== args.activationId) throw new Error(`activationId mismatch for run ${args.runId}`);
|
|
1393
|
-
if (state.pending.nodeId !== args.nodeId) throw new Error(`nodeId mismatch for run ${args.runId}`);
|
|
1394
|
-
const wf = this.resolvePersistedWorkflow(state);
|
|
1395
|
-
if (!wf) throw new Error(`Unknown workflowId: ${state.workflowId}`);
|
|
1396
|
-
const { topology, planner } = this.planningFactory.create(wf);
|
|
1397
|
-
const data = this.runDataFactory.create(state.outputsByNode);
|
|
1398
|
-
const limits = this.resolveEngineLimitsFromState(state);
|
|
1399
|
-
const base = this.runExecutionContextFactory.create({
|
|
1400
|
-
runId: state.runId,
|
|
1401
|
-
workflowId: state.workflowId,
|
|
1402
|
-
nodeId: args.nodeId,
|
|
1403
|
-
parent: state.parent,
|
|
1404
|
-
subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
|
|
1405
|
-
engineMaxNodeActivations: limits.engineMaxNodeActivations,
|
|
1406
|
-
engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
|
|
1407
|
-
data,
|
|
1408
|
-
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent)
|
|
1409
|
-
});
|
|
1410
|
-
data.setOutputs(args.nodeId, args.outputs);
|
|
1411
|
-
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1412
|
-
const completedSnapshot = this.semantics.createFinishedSnapshot({
|
|
1413
|
-
workflow: wf,
|
|
1414
|
-
previous: state.nodeSnapshotsByNodeId?.[args.nodeId],
|
|
1415
|
-
runId: state.runId,
|
|
1416
|
-
workflowId: state.workflowId,
|
|
1417
|
-
nodeId: args.nodeId,
|
|
1418
|
-
activationId: args.activationId,
|
|
1419
|
-
parent: state.parent,
|
|
1420
|
-
finishedAt: completedAt,
|
|
1421
|
-
inputsByPort: state.pending.inputsByPort,
|
|
1422
|
-
outputs: args.outputs
|
|
1423
|
-
});
|
|
1424
|
-
const completedActivations = (state.engineCounters?.completedNodeActivations ?? 0) + 1;
|
|
1425
|
-
const engineCounters = { completedNodeActivations: completedActivations };
|
|
1426
|
-
const maxNodeActivations = state.executionOptions?.maxNodeActivations ?? Number.MAX_SAFE_INTEGER;
|
|
1427
|
-
if (this.semantics.isStopConditionSatisfied(state.control?.stopCondition, args.nodeId)) {
|
|
1428
|
-
const completedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
1429
|
-
state,
|
|
1430
|
-
engineCounters,
|
|
1431
|
-
status: "completed",
|
|
1432
|
-
queue: [],
|
|
1433
|
-
outputsByNode: data.dump(),
|
|
1434
|
-
nodeSnapshotsByNodeId: {
|
|
1435
|
-
...state.nodeSnapshotsByNodeId ?? {},
|
|
1436
|
-
[args.nodeId]: completedSnapshot
|
|
1437
|
-
}
|
|
1438
|
-
});
|
|
1439
|
-
await this.runStore.save(completedState);
|
|
1440
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1441
|
-
await this.terminalPersistence.maybeDeleteAfterTerminalState({
|
|
1442
|
-
workflow: wf,
|
|
1443
|
-
state: completedState,
|
|
1444
|
-
finalStatus: "completed",
|
|
1445
|
-
finishedAt: completedAt
|
|
1446
|
-
});
|
|
1447
|
-
const result$1 = {
|
|
1448
|
-
runId: state.runId,
|
|
1449
|
-
workflowId: state.workflowId,
|
|
1450
|
-
startedAt: state.startedAt,
|
|
1451
|
-
status: "completed",
|
|
1452
|
-
outputs: this.semantics.resolveResultOutputs(wf, state.control?.stopCondition, data.dump())
|
|
1453
|
-
};
|
|
1454
|
-
this.waiters.resolveRunCompletion(result$1);
|
|
1455
|
-
return result$1;
|
|
1456
|
-
}
|
|
1457
|
-
const batchId = state.pending.batchId ?? "batch_1";
|
|
1458
|
-
const queue = (state.queue ?? []).map((q) => ({
|
|
1459
|
-
...q,
|
|
1460
|
-
batchId: q.batchId ?? batchId
|
|
1461
|
-
}));
|
|
1462
|
-
const nextNodeSnapshotsByNodeId = {
|
|
1463
|
-
...state.nodeSnapshotsByNodeId ?? {},
|
|
1464
|
-
[args.nodeId]: completedSnapshot
|
|
1465
|
-
};
|
|
1466
|
-
planner.applyOutputs(queue, {
|
|
1467
|
-
fromNodeId: args.nodeId,
|
|
1468
|
-
outputs: args.outputs,
|
|
1469
|
-
batchId
|
|
1470
|
-
});
|
|
1471
|
-
this.semantics.applyPinnedQueueSkips({
|
|
1472
|
-
runId: state.runId,
|
|
1473
|
-
workflowId: state.workflowId,
|
|
1474
|
-
parent: state.parent,
|
|
1475
|
-
mutableState: state.mutableState,
|
|
1476
|
-
planner,
|
|
1477
|
-
queue,
|
|
1478
|
-
data,
|
|
1479
|
-
nodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId,
|
|
1480
|
-
finishedAt: completedAt
|
|
1481
|
-
});
|
|
1482
|
-
let next;
|
|
1483
|
-
try {
|
|
1484
|
-
next = planner.nextActivation(queue);
|
|
1485
|
-
} catch (cause) {
|
|
1486
|
-
const completedDefinition = topology.defsById.get(args.nodeId);
|
|
1487
|
-
const completedNodeLabel = RuntimeContinuationDiagnostics.formatNodeLabel({
|
|
1488
|
-
definition: completedDefinition,
|
|
1489
|
-
nodeId: args.nodeId
|
|
1490
|
-
});
|
|
1491
|
-
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
1492
|
-
throw new Error(`After completing ${completedNodeLabel}, the engine could not plan the next activation. ${reason} Outputs: ${RuntimeContinuationDiagnostics.formatOutputCounts(args.outputs)}.`, { cause });
|
|
1493
|
-
}
|
|
1494
|
-
if (!next) {
|
|
1495
|
-
const lastNodeId = createWorkflowExecutableNodeClassifier(wf).lastExecutableNodeIdInDefinitionOrder(wf);
|
|
1496
|
-
const outputs = data.getOutputItems(lastNodeId, "main");
|
|
1497
|
-
const completedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
1498
|
-
state,
|
|
1499
|
-
engineCounters,
|
|
1500
|
-
status: "completed",
|
|
1501
|
-
queue: [],
|
|
1502
|
-
outputsByNode: data.dump(),
|
|
1503
|
-
nodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId
|
|
1504
|
-
});
|
|
1505
|
-
await this.runStore.save(completedState);
|
|
1506
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1507
|
-
await this.terminalPersistence.maybeDeleteAfterTerminalState({
|
|
1508
|
-
workflow: wf,
|
|
1509
|
-
state: completedState,
|
|
1510
|
-
finalStatus: "completed",
|
|
1511
|
-
finishedAt: completedAt
|
|
1512
|
-
});
|
|
1513
|
-
const result$1 = {
|
|
1514
|
-
runId: state.runId,
|
|
1515
|
-
workflowId: state.workflowId,
|
|
1516
|
-
startedAt: state.startedAt,
|
|
1517
|
-
status: "completed",
|
|
1518
|
-
outputs
|
|
1519
|
-
};
|
|
1520
|
-
this.waiters.resolveRunCompletion(result$1);
|
|
1521
|
-
return result$1;
|
|
1522
|
-
}
|
|
1523
|
-
if (completedActivations >= maxNodeActivations) {
|
|
1524
|
-
const message = `Run exceeded maxNodeActivations (${maxNodeActivations}) after ${completedActivations} completed node activations (next would be ${next.nodeId}).`;
|
|
1525
|
-
const failedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
1526
|
-
state,
|
|
1527
|
-
engineCounters,
|
|
1528
|
-
status: "failed",
|
|
1529
|
-
queue: queue.map((q) => ({ ...q })),
|
|
1530
|
-
outputsByNode: data.dump(),
|
|
1531
|
-
nodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId
|
|
1532
|
-
});
|
|
1533
|
-
await this.runStore.save(failedState);
|
|
1534
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1535
|
-
await this.terminalPersistence.maybeDeleteAfterTerminalState({
|
|
1536
|
-
workflow: wf,
|
|
1537
|
-
state: failedState,
|
|
1538
|
-
finalStatus: "failed",
|
|
1539
|
-
finishedAt: completedAt
|
|
1540
|
-
});
|
|
1541
|
-
const result$1 = {
|
|
1542
|
-
runId: state.runId,
|
|
1543
|
-
workflowId: state.workflowId,
|
|
1544
|
-
startedAt: state.startedAt,
|
|
1545
|
-
status: "failed",
|
|
1546
|
-
error: { message }
|
|
1547
|
-
};
|
|
1548
|
-
this.waiters.resolveRunCompletion(result$1);
|
|
1549
|
-
return result$1;
|
|
1550
|
-
}
|
|
1551
|
-
const def = topology.defsById.get(next.nodeId);
|
|
1552
|
-
if (!def || def.kind !== "node") throw new Error(`Node ${next.nodeId} is not a runnable node`);
|
|
1553
|
-
const request = this.nodeActivationRequestComposer.createFromPlannedActivation({
|
|
1554
|
-
next,
|
|
1555
|
-
base,
|
|
1556
|
-
data,
|
|
1557
|
-
runId: state.runId,
|
|
1558
|
-
workflowId: state.workflowId,
|
|
1559
|
-
parent: state.parent,
|
|
1560
|
-
executionOptions: state.executionOptions,
|
|
1561
|
-
nodeDefinition: def
|
|
1562
|
-
});
|
|
1563
|
-
const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
|
|
1564
|
-
runId: state.runId,
|
|
1565
|
-
workflowId: state.workflowId,
|
|
1566
|
-
startedAt: state.startedAt,
|
|
1567
|
-
parent: state.parent,
|
|
1568
|
-
executionOptions: state.executionOptions,
|
|
1569
|
-
control: state.control,
|
|
1570
|
-
workflowSnapshot: state.workflowSnapshot,
|
|
1571
|
-
mutableState: state.mutableState,
|
|
1572
|
-
policySnapshot: state.policySnapshot,
|
|
1573
|
-
pendingQueue: queue,
|
|
1574
|
-
request,
|
|
1575
|
-
previousNodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId,
|
|
1576
|
-
planner,
|
|
1577
|
-
engineCounters,
|
|
1578
|
-
connectionInvocations: state.connectionInvocations ?? []
|
|
1579
|
-
});
|
|
1580
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1581
|
-
await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
|
|
1582
|
-
return result;
|
|
1583
|
-
}
|
|
1584
|
-
async resumeFromNodeError(args) {
|
|
1585
|
-
const state = await this.runStore.load(args.runId);
|
|
1586
|
-
if (!state) throw new Error(`Unknown runId: ${args.runId}`);
|
|
1587
|
-
if (state.status !== "pending" || !state.pending) throw new Error(`Run ${args.runId} is not pending`);
|
|
1588
|
-
if (state.pending.activationId !== args.activationId) throw new Error(`activationId mismatch for run ${args.runId}`);
|
|
1589
|
-
if (state.pending.nodeId !== args.nodeId) throw new Error(`nodeId mismatch for run ${args.runId}`);
|
|
1590
|
-
const wf = this.resolvePersistedWorkflow(state);
|
|
1591
|
-
if (!wf) throw new Error(`Unknown workflowId: ${state.workflowId}`);
|
|
1592
|
-
const failedDefinition = WorkflowTopology.fromWorkflow(wf).defsById.get(args.nodeId);
|
|
1593
|
-
const webhookControlSignal = state.executionOptions?.webhook && failedDefinition?.kind === "trigger" ? this.asWebhookControlSignal(args.error) : void 0;
|
|
1594
|
-
if (webhookControlSignal) return await this.resumeFromWebhookControl({
|
|
1595
|
-
state,
|
|
1596
|
-
workflow: wf,
|
|
1597
|
-
args,
|
|
1598
|
-
signal: webhookControlSignal
|
|
1599
|
-
});
|
|
1600
|
-
if (failedDefinition && failedDefinition.kind === "node") {
|
|
1601
|
-
const nodeHandler = this.policyErrorServices.resolveNodeErrorHandler(failedDefinition.config.nodeErrorHandler);
|
|
1602
|
-
if (nodeHandler) try {
|
|
1603
|
-
const ctx = this.buildNodeExecutionContextForPending(state, wf, failedDefinition, args.nodeId);
|
|
1604
|
-
const inputsByPort = state.pending.inputsByPort;
|
|
1605
|
-
const portKeys = Object.keys(inputsByPort);
|
|
1606
|
-
const kind = portKeys.length === 1 && portKeys[0] === "in" ? "single" : "multi";
|
|
1607
|
-
const items = inputsByPort.in ?? [];
|
|
1608
|
-
const recovered = await nodeHandler.handle({
|
|
1609
|
-
kind,
|
|
1610
|
-
items,
|
|
1611
|
-
inputsByPort: kind === "multi" ? inputsByPort : void 0,
|
|
1612
|
-
ctx,
|
|
1613
|
-
error: args.error
|
|
1614
|
-
});
|
|
1615
|
-
return await this.resumeFromNodeResult({
|
|
1616
|
-
runId: args.runId,
|
|
1617
|
-
activationId: args.activationId,
|
|
1618
|
-
nodeId: args.nodeId,
|
|
1619
|
-
outputs: recovered
|
|
1620
|
-
});
|
|
1621
|
-
} catch {}
|
|
1622
|
-
}
|
|
1623
|
-
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1624
|
-
const message = args.error?.message ?? String(args.error);
|
|
1625
|
-
const failedSnapshot = NodeSnapshotFactory.failed({
|
|
1626
|
-
previous: state.nodeSnapshotsByNodeId?.[args.nodeId],
|
|
1627
|
-
runId: state.runId,
|
|
1628
|
-
workflowId: state.workflowId,
|
|
1629
|
-
nodeId: args.nodeId,
|
|
1630
|
-
activationId: args.activationId,
|
|
1631
|
-
parent: state.parent,
|
|
1632
|
-
finishedAt,
|
|
1633
|
-
inputsByPort: state.pending.inputsByPort,
|
|
1634
|
-
error: args.error
|
|
1635
|
-
});
|
|
1636
|
-
const failedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
1637
|
-
state,
|
|
1638
|
-
engineCounters: state.engineCounters ?? { completedNodeActivations: 0 },
|
|
1639
|
-
status: "failed",
|
|
1640
|
-
queue: (state.queue ?? []).map((q) => ({ ...q })),
|
|
1641
|
-
outputsByNode: state.outputsByNode,
|
|
1642
|
-
nodeSnapshotsByNodeId: {
|
|
1643
|
-
...state.nodeSnapshotsByNodeId ?? {},
|
|
1644
|
-
[args.nodeId]: failedSnapshot
|
|
1645
|
-
}
|
|
1646
|
-
});
|
|
1647
|
-
await this.runStore.save(failedState);
|
|
1648
|
-
await this.nodeEventPublisher.publish("nodeFailed", failedSnapshot);
|
|
1649
|
-
const wfErr = this.policyErrorServices.resolveWorkflowErrorHandler(wf.workflowErrorHandler);
|
|
1650
|
-
if (wfErr) await Promise.resolve(wfErr.onError({
|
|
1651
|
-
runId: state.runId,
|
|
1652
|
-
workflowId: state.workflowId,
|
|
1653
|
-
workflow: wf,
|
|
1654
|
-
failedNodeId: args.nodeId,
|
|
1655
|
-
error: args.error,
|
|
1656
|
-
startedAt: state.startedAt,
|
|
1657
|
-
finishedAt
|
|
1658
|
-
}));
|
|
1659
|
-
await this.terminalPersistence.maybeDeleteAfterTerminalState({
|
|
1660
|
-
workflow: wf,
|
|
1661
|
-
state: failedState,
|
|
1662
|
-
finalStatus: "failed",
|
|
1663
|
-
finishedAt
|
|
1664
|
-
});
|
|
1665
|
-
const result = {
|
|
1666
|
-
runId: state.runId,
|
|
1667
|
-
workflowId: state.workflowId,
|
|
1668
|
-
startedAt: state.startedAt,
|
|
1669
|
-
status: "failed",
|
|
1670
|
-
error: { message }
|
|
1671
|
-
};
|
|
1672
|
-
this.waiters.resolveRunCompletion(result);
|
|
1673
|
-
return result;
|
|
1674
|
-
}
|
|
1675
|
-
async resumeFromStepResult(args) {
|
|
1676
|
-
return await this.resumeFromNodeResult(args);
|
|
1677
|
-
}
|
|
1678
|
-
async resumeFromStepError(args) {
|
|
1679
|
-
return await this.resumeFromNodeError(args);
|
|
1680
|
-
}
|
|
1681
|
-
async waitForCompletion(runId) {
|
|
1682
|
-
const existing = await this.runStore.load(runId);
|
|
1683
|
-
if (existing?.status === "completed") {
|
|
1684
|
-
const wf = this.resolvePersistedWorkflow(existing);
|
|
1685
|
-
const outputs = wf ? this.semantics.resolveResultOutputs(wf, existing.control?.stopCondition, existing.outputsByNode) : [];
|
|
1686
|
-
return {
|
|
1687
|
-
runId: existing.runId,
|
|
1688
|
-
workflowId: existing.workflowId,
|
|
1689
|
-
startedAt: existing.startedAt,
|
|
1690
|
-
status: "completed",
|
|
1691
|
-
outputs
|
|
1692
|
-
};
|
|
1693
|
-
}
|
|
1694
|
-
if (existing?.status === "failed") return {
|
|
1695
|
-
runId: existing.runId,
|
|
1696
|
-
workflowId: existing.workflowId,
|
|
1697
|
-
startedAt: existing.startedAt,
|
|
1698
|
-
status: "failed",
|
|
1699
|
-
error: { message: "Run failed" }
|
|
1700
|
-
};
|
|
1701
|
-
const result = await this.waiters.waitForCompletion(runId);
|
|
1702
|
-
if (result.status !== "completed" && result.status !== "failed") throw new Error(`Unexpected run completion status: ${result.status}`);
|
|
1703
|
-
return result;
|
|
1704
|
-
}
|
|
1705
|
-
async waitForWebhookResponse(runId) {
|
|
1706
|
-
return await this.waiters.waitForWebhookResponse(runId);
|
|
1707
|
-
}
|
|
1708
|
-
async resumeFromWebhookControl(args) {
|
|
1709
|
-
const data = this.runDataFactory.create(args.state.outputsByNode);
|
|
1710
|
-
const { topology, planner } = this.planningFactory.create(args.workflow);
|
|
1711
|
-
const triggerOutputs = { main: args.signal.kind === "respondNowAndContinue" ? args.signal.continueItems ?? [] : args.signal.responseItems };
|
|
1712
|
-
data.setOutputs(args.args.nodeId, triggerOutputs);
|
|
1713
|
-
const completedSnapshot = this.semantics.createFinishedSnapshot({
|
|
1714
|
-
workflow: args.workflow,
|
|
1715
|
-
previous: args.state.nodeSnapshotsByNodeId?.[args.args.nodeId],
|
|
1716
|
-
runId: args.state.runId,
|
|
1717
|
-
workflowId: args.state.workflowId,
|
|
1718
|
-
nodeId: args.args.nodeId,
|
|
1719
|
-
activationId: args.args.activationId,
|
|
1720
|
-
parent: args.state.parent,
|
|
1721
|
-
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1722
|
-
inputsByPort: args.state.pending?.inputsByPort ?? InputPortMap.empty(),
|
|
1723
|
-
outputs: triggerOutputs
|
|
1724
|
-
});
|
|
1725
|
-
const completedActivations = (args.state.engineCounters?.completedNodeActivations ?? 0) + 1;
|
|
1726
|
-
const engineCounters = { completedNodeActivations: completedActivations };
|
|
1727
|
-
const maxNodeActivations = args.state.executionOptions?.maxNodeActivations ?? Number.MAX_SAFE_INTEGER;
|
|
1728
|
-
if (this.semantics.isStopConditionSatisfied(args.state.control?.stopCondition, args.args.nodeId)) {
|
|
1729
|
-
const completedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
1730
|
-
state: args.state,
|
|
1731
|
-
engineCounters,
|
|
1732
|
-
status: "completed",
|
|
1733
|
-
queue: [],
|
|
1734
|
-
outputsByNode: data.dump(),
|
|
1735
|
-
nodeSnapshotsByNodeId: {
|
|
1736
|
-
...args.state.nodeSnapshotsByNodeId ?? {},
|
|
1737
|
-
[args.args.nodeId]: completedSnapshot
|
|
1738
|
-
}
|
|
1739
|
-
});
|
|
1740
|
-
await this.runStore.save(completedState);
|
|
1741
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1742
|
-
await this.terminalPersistence.maybeDeleteAfterTerminalState({
|
|
1743
|
-
workflow: args.workflow,
|
|
1744
|
-
state: completedState,
|
|
1745
|
-
finalStatus: "completed",
|
|
1746
|
-
finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
|
|
1747
|
-
});
|
|
1748
|
-
this.waiters.resolveWebhookResponse({
|
|
1749
|
-
runId: args.state.runId,
|
|
1750
|
-
workflowId: args.state.workflowId,
|
|
1751
|
-
startedAt: args.state.startedAt,
|
|
1752
|
-
runStatus: "completed",
|
|
1753
|
-
response: args.signal.responseItems
|
|
1754
|
-
});
|
|
1755
|
-
const result$1 = {
|
|
1756
|
-
runId: args.state.runId,
|
|
1757
|
-
workflowId: args.state.workflowId,
|
|
1758
|
-
startedAt: args.state.startedAt,
|
|
1759
|
-
status: "completed",
|
|
1760
|
-
outputs: this.semantics.resolveResultOutputs(args.workflow, args.state.control?.stopCondition, data.dump())
|
|
1761
|
-
};
|
|
1762
|
-
this.waiters.resolveRunCompletion(result$1);
|
|
1763
|
-
return result$1;
|
|
1764
|
-
}
|
|
1765
|
-
if (args.signal.kind === "respondNow") {
|
|
1766
|
-
const completedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
1767
|
-
state: args.state,
|
|
1768
|
-
engineCounters,
|
|
1769
|
-
status: "completed",
|
|
1770
|
-
queue: [],
|
|
1771
|
-
outputsByNode: data.dump(),
|
|
1772
|
-
nodeSnapshotsByNodeId: {
|
|
1773
|
-
...args.state.nodeSnapshotsByNodeId ?? {},
|
|
1774
|
-
[args.args.nodeId]: completedSnapshot
|
|
1775
|
-
}
|
|
1776
|
-
});
|
|
1777
|
-
await this.runStore.save(completedState);
|
|
1778
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1779
|
-
await this.terminalPersistence.maybeDeleteAfterTerminalState({
|
|
1780
|
-
workflow: args.workflow,
|
|
1781
|
-
state: completedState,
|
|
1782
|
-
finalStatus: "completed",
|
|
1783
|
-
finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
|
|
1784
|
-
});
|
|
1785
|
-
const result$1 = {
|
|
1786
|
-
runId: args.state.runId,
|
|
1787
|
-
workflowId: args.state.workflowId,
|
|
1788
|
-
startedAt: args.state.startedAt,
|
|
1789
|
-
status: "completed",
|
|
1790
|
-
outputs: args.signal.responseItems
|
|
1791
|
-
};
|
|
1792
|
-
this.waiters.resolveWebhookResponse({
|
|
1793
|
-
runId: args.state.runId,
|
|
1794
|
-
workflowId: args.state.workflowId,
|
|
1795
|
-
startedAt: args.state.startedAt,
|
|
1796
|
-
runStatus: "completed",
|
|
1797
|
-
response: args.signal.responseItems
|
|
1798
|
-
});
|
|
1799
|
-
this.waiters.resolveRunCompletion(result$1);
|
|
1800
|
-
return result$1;
|
|
1801
|
-
}
|
|
1802
|
-
const batchId = args.state.pending?.batchId ?? "batch_1";
|
|
1803
|
-
const queue = (args.state.queue ?? []).map((entry) => ({
|
|
1804
|
-
...entry,
|
|
1805
|
-
batchId: entry.batchId ?? batchId
|
|
1806
|
-
}));
|
|
1807
|
-
planner.applyOutputs(queue, {
|
|
1808
|
-
fromNodeId: args.args.nodeId,
|
|
1809
|
-
outputs: triggerOutputs,
|
|
1810
|
-
batchId
|
|
1811
|
-
});
|
|
1812
|
-
const next = planner.nextActivation(queue);
|
|
1813
|
-
if (!next) {
|
|
1814
|
-
const lastNodeId = createWorkflowExecutableNodeClassifier(args.workflow).lastExecutableNodeIdInDefinitionOrder(args.workflow);
|
|
1815
|
-
const outputs = data.getOutputItems(lastNodeId, "main");
|
|
1816
|
-
const completedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
1817
|
-
state: args.state,
|
|
1818
|
-
engineCounters,
|
|
1819
|
-
status: "completed",
|
|
1820
|
-
queue: [],
|
|
1821
|
-
outputsByNode: data.dump(),
|
|
1822
|
-
nodeSnapshotsByNodeId: {
|
|
1823
|
-
...args.state.nodeSnapshotsByNodeId ?? {},
|
|
1824
|
-
[args.args.nodeId]: completedSnapshot
|
|
1825
|
-
}
|
|
1826
|
-
});
|
|
1827
|
-
await this.runStore.save(completedState);
|
|
1828
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1829
|
-
await this.terminalPersistence.maybeDeleteAfterTerminalState({
|
|
1830
|
-
workflow: args.workflow,
|
|
1831
|
-
state: completedState,
|
|
1832
|
-
finalStatus: "completed",
|
|
1833
|
-
finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
|
|
1834
|
-
});
|
|
1835
|
-
const result$1 = {
|
|
1836
|
-
runId: args.state.runId,
|
|
1837
|
-
workflowId: args.state.workflowId,
|
|
1838
|
-
startedAt: args.state.startedAt,
|
|
1839
|
-
status: "completed",
|
|
1840
|
-
outputs
|
|
1841
|
-
};
|
|
1842
|
-
this.waiters.resolveWebhookResponse({
|
|
1843
|
-
runId: args.state.runId,
|
|
1844
|
-
workflowId: args.state.workflowId,
|
|
1845
|
-
startedAt: args.state.startedAt,
|
|
1846
|
-
runStatus: "completed",
|
|
1847
|
-
response: args.signal.responseItems
|
|
1848
|
-
});
|
|
1849
|
-
this.waiters.resolveRunCompletion(result$1);
|
|
1850
|
-
return result$1;
|
|
1851
|
-
}
|
|
1852
|
-
if (completedActivations >= maxNodeActivations) {
|
|
1853
|
-
const message = `Run exceeded maxNodeActivations (${maxNodeActivations}) after ${completedActivations} completed node activations (next would be ${next.nodeId}).`;
|
|
1854
|
-
const failedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
1855
|
-
state: args.state,
|
|
1856
|
-
engineCounters,
|
|
1857
|
-
status: "failed",
|
|
1858
|
-
queue: queue.map((q) => ({ ...q })),
|
|
1859
|
-
outputsByNode: data.dump(),
|
|
1860
|
-
nodeSnapshotsByNodeId: {
|
|
1861
|
-
...args.state.nodeSnapshotsByNodeId ?? {},
|
|
1862
|
-
[args.args.nodeId]: completedSnapshot
|
|
1863
|
-
}
|
|
1864
|
-
});
|
|
1865
|
-
await this.runStore.save(failedState);
|
|
1866
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1867
|
-
await this.terminalPersistence.maybeDeleteAfterTerminalState({
|
|
1868
|
-
workflow: args.workflow,
|
|
1869
|
-
state: failedState,
|
|
1870
|
-
finalStatus: "failed",
|
|
1871
|
-
finishedAt: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
|
|
1872
|
-
});
|
|
1873
|
-
const result$1 = {
|
|
1874
|
-
runId: args.state.runId,
|
|
1875
|
-
workflowId: args.state.workflowId,
|
|
1876
|
-
startedAt: args.state.startedAt,
|
|
1877
|
-
status: "failed",
|
|
1878
|
-
error: { message }
|
|
1879
|
-
};
|
|
1880
|
-
this.waiters.resolveWebhookResponse({
|
|
1881
|
-
runId: args.state.runId,
|
|
1882
|
-
workflowId: args.state.workflowId,
|
|
1883
|
-
startedAt: args.state.startedAt,
|
|
1884
|
-
runStatus: "pending",
|
|
1885
|
-
response: args.signal.responseItems
|
|
1886
|
-
});
|
|
1887
|
-
this.waiters.resolveRunCompletion(result$1);
|
|
1888
|
-
return result$1;
|
|
1889
|
-
}
|
|
1890
|
-
const nextDefinition = topology.defsById.get(next.nodeId);
|
|
1891
|
-
if (!nextDefinition || nextDefinition.kind !== "node") throw new Error(`Node ${next.nodeId} is not a runnable node`);
|
|
1892
|
-
const webhookLimits = this.resolveEngineLimitsFromState(args.state);
|
|
1893
|
-
const base = this.runExecutionContextFactory.create({
|
|
1894
|
-
runId: args.state.runId,
|
|
1895
|
-
workflowId: args.state.workflowId,
|
|
1896
|
-
nodeId: nextDefinition.id,
|
|
1897
|
-
parent: args.state.parent,
|
|
1898
|
-
subworkflowDepth: args.state.executionOptions?.subworkflowDepth ?? 0,
|
|
1899
|
-
engineMaxNodeActivations: webhookLimits.engineMaxNodeActivations,
|
|
1900
|
-
engineMaxSubworkflowDepth: webhookLimits.engineMaxSubworkflowDepth,
|
|
1901
|
-
data,
|
|
1902
|
-
nodeState: this.nodeStatePublisherFactory.create(args.state.runId, args.state.workflowId, args.state.parent)
|
|
1903
|
-
});
|
|
1904
|
-
const request = this.nodeActivationRequestComposer.createFromPlannedActivation({
|
|
1905
|
-
next,
|
|
1906
|
-
base,
|
|
1907
|
-
data,
|
|
1908
|
-
runId: args.state.runId,
|
|
1909
|
-
workflowId: args.state.workflowId,
|
|
1910
|
-
parent: args.state.parent,
|
|
1911
|
-
executionOptions: args.state.executionOptions,
|
|
1912
|
-
nodeDefinition: nextDefinition
|
|
1913
|
-
});
|
|
1914
|
-
const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
|
|
1915
|
-
runId: args.state.runId,
|
|
1916
|
-
workflowId: args.state.workflowId,
|
|
1917
|
-
startedAt: args.state.startedAt,
|
|
1918
|
-
parent: args.state.parent,
|
|
1919
|
-
executionOptions: args.state.executionOptions,
|
|
1920
|
-
control: args.state.control,
|
|
1921
|
-
workflowSnapshot: args.state.workflowSnapshot,
|
|
1922
|
-
mutableState: args.state.mutableState,
|
|
1923
|
-
policySnapshot: args.state.policySnapshot,
|
|
1924
|
-
pendingQueue: queue,
|
|
1925
|
-
request,
|
|
1926
|
-
previousNodeSnapshotsByNodeId: {
|
|
1927
|
-
...args.state.nodeSnapshotsByNodeId ?? {},
|
|
1928
|
-
[args.args.nodeId]: completedSnapshot
|
|
1929
|
-
},
|
|
1930
|
-
planner,
|
|
1931
|
-
engineCounters,
|
|
1932
|
-
connectionInvocations: args.state.connectionInvocations ?? []
|
|
1933
|
-
});
|
|
1934
|
-
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
1935
|
-
await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
|
|
1936
|
-
this.waiters.resolveWebhookResponse({
|
|
1937
|
-
runId: args.state.runId,
|
|
1938
|
-
workflowId: args.state.workflowId,
|
|
1939
|
-
startedAt: args.state.startedAt,
|
|
1940
|
-
runStatus: "pending",
|
|
1941
|
-
response: args.signal.responseItems
|
|
1942
|
-
});
|
|
1943
|
-
return result;
|
|
1944
|
-
}
|
|
1945
|
-
asWebhookControlSignal(error) {
|
|
1946
|
-
const candidate = error;
|
|
1947
|
-
if (!candidate || candidate.__webhookControl !== true) return void 0;
|
|
1948
|
-
if (candidate.kind !== "respondNow" && candidate.kind !== "respondNowAndContinue") return void 0;
|
|
1949
|
-
if (!Array.isArray(candidate.responseItems)) return void 0;
|
|
1950
|
-
return candidate;
|
|
1951
|
-
}
|
|
1952
|
-
resolvePersistedWorkflow(state) {
|
|
1953
|
-
return this.workflowSnapshotResolver.resolve({
|
|
1954
|
-
workflowId: state.workflowId,
|
|
1955
|
-
workflowSnapshot: state.workflowSnapshot
|
|
1956
|
-
});
|
|
1957
|
-
}
|
|
1958
|
-
buildNodeExecutionContextForPending(state, wf, def, nodeId) {
|
|
1959
|
-
const data = this.runDataFactory.create(state.outputsByNode);
|
|
1960
|
-
const limits = this.resolveEngineLimitsFromState(state);
|
|
1961
|
-
const base = this.runExecutionContextFactory.create({
|
|
1962
|
-
runId: state.runId,
|
|
1963
|
-
workflowId: state.workflowId,
|
|
1964
|
-
nodeId,
|
|
1965
|
-
parent: state.parent,
|
|
1966
|
-
subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
|
|
1967
|
-
engineMaxNodeActivations: limits.engineMaxNodeActivations,
|
|
1968
|
-
engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
|
|
1969
|
-
data,
|
|
1970
|
-
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent)
|
|
1971
|
-
});
|
|
1972
|
-
const activationId = state.pending.activationId;
|
|
1973
|
-
return {
|
|
1974
|
-
...base,
|
|
1975
|
-
data,
|
|
1976
|
-
nodeId,
|
|
1977
|
-
activationId,
|
|
1978
|
-
config: def.config,
|
|
1979
|
-
binary: base.binary.forNode({
|
|
1980
|
-
nodeId,
|
|
1981
|
-
activationId
|
|
1982
|
-
}),
|
|
1983
|
-
getCredential: this.credentialResolverFactory.create(wf.id, nodeId, def.config)
|
|
1984
|
-
};
|
|
1985
|
-
}
|
|
1986
|
-
resolveEngineLimitsFromState(state) {
|
|
1987
|
-
const fb = this.executionLimitsPolicy.createRootExecutionOptions();
|
|
1988
|
-
return {
|
|
1989
|
-
engineMaxNodeActivations: state.executionOptions?.maxNodeActivations ?? fb.maxNodeActivations,
|
|
1990
|
-
engineMaxSubworkflowDepth: state.executionOptions?.maxSubworkflowDepth ?? fb.maxSubworkflowDepth
|
|
1991
|
-
};
|
|
1992
|
-
}
|
|
1993
|
-
};
|
|
1994
|
-
|
|
1995
|
-
//#endregion
|
|
1996
|
-
//#region src/engine/materialization/MissingRuntimeExecutionMarkerFactory.ts
|
|
1997
|
-
var MissingRuntimeExecutionMarker = class {
|
|
1998
|
-
static isMarked(config) {
|
|
1999
|
-
return Boolean(config?.missingRuntime);
|
|
2000
|
-
}
|
|
2001
|
-
};
|
|
2002
|
-
|
|
2003
|
-
//#endregion
|
|
2004
|
-
//#region src/engine/execution/RunStateSemantics.ts
|
|
2005
|
-
var RunStateSemantics = class {
|
|
2006
|
-
isStopConditionSatisfied(stopCondition, nodeId) {
|
|
2007
|
-
if (!stopCondition || stopCondition.kind === "workflowCompleted") return false;
|
|
2008
|
-
return stopCondition.nodeId === nodeId;
|
|
2009
|
-
}
|
|
2010
|
-
resolveResultOutputs(workflow, stopCondition, outputsByNode) {
|
|
2011
|
-
if (stopCondition?.kind === "nodeCompleted") return outputsByNode[stopCondition.nodeId]?.main ?? [];
|
|
2012
|
-
return outputsByNode[createWorkflowExecutableNodeClassifier(workflow).lastExecutableNodeIdInDefinitionOrder(workflow)]?.main ?? [];
|
|
2013
|
-
}
|
|
2014
|
-
applySkippedSnapshots(args) {
|
|
2015
|
-
const snapshots = { ...args.currentState.nodeSnapshotsByNodeId };
|
|
2016
|
-
const skippedPinnedNodeIds = new Set(args.preservedPinnedNodeIds.filter((nodeId) => args.skippedNodeIds.includes(nodeId)));
|
|
2017
|
-
for (const nodeId of args.skippedNodeIds) if (args.currentState.mutableState?.nodesById?.[nodeId]?.pinnedOutputsByPort) skippedPinnedNodeIds.add(nodeId);
|
|
2018
|
-
for (const nodeId of skippedPinnedNodeIds) {
|
|
2019
|
-
const previous = snapshots[nodeId];
|
|
2020
|
-
snapshots[nodeId] = NodeSnapshotFactory.completed({
|
|
2021
|
-
previous,
|
|
2022
|
-
runId: args.runId,
|
|
2023
|
-
workflowId: args.workflowId,
|
|
2024
|
-
nodeId,
|
|
2025
|
-
activationId: previous?.activationId ?? `synthetic_${nodeId}`,
|
|
2026
|
-
parent: args.parent,
|
|
2027
|
-
finishedAt: args.finishedAt,
|
|
2028
|
-
inputsByPort: previous?.inputsByPort ?? InputPortMap.empty(),
|
|
2029
|
-
outputs: args.currentState.outputsByNode[nodeId] ?? {},
|
|
2030
|
-
fromPinnedOutput: true
|
|
2031
|
-
});
|
|
2032
|
-
}
|
|
2033
|
-
return snapshots;
|
|
2034
|
-
}
|
|
2035
|
-
applyPinnedQueueSkips(args) {
|
|
2036
|
-
let changed = true;
|
|
2037
|
-
while (changed) {
|
|
2038
|
-
changed = false;
|
|
2039
|
-
for (let index = 0; index < args.queue.length; index += 1) {
|
|
2040
|
-
const queueEntry = args.queue[index];
|
|
2041
|
-
const pinnedOutputs = args.mutableState?.nodesById?.[queueEntry.nodeId]?.pinnedOutputsByPort;
|
|
2042
|
-
if (!pinnedOutputs) continue;
|
|
2043
|
-
args.queue.splice(index, 1);
|
|
2044
|
-
const previous = args.nodeSnapshotsByNodeId[queueEntry.nodeId];
|
|
2045
|
-
args.nodeSnapshotsByNodeId[queueEntry.nodeId] = NodeSnapshotFactory.completed({
|
|
2046
|
-
previous,
|
|
2047
|
-
runId: args.runId,
|
|
2048
|
-
workflowId: args.workflowId,
|
|
2049
|
-
nodeId: queueEntry.nodeId,
|
|
2050
|
-
activationId: previous?.activationId ?? `synthetic_${queueEntry.nodeId}`,
|
|
2051
|
-
parent: args.parent,
|
|
2052
|
-
finishedAt: args.finishedAt,
|
|
2053
|
-
inputsByPort: this.resolveQueueEntryInputsByPort(queueEntry),
|
|
2054
|
-
outputs: pinnedOutputs,
|
|
2055
|
-
fromPinnedOutput: true
|
|
2056
|
-
});
|
|
2057
|
-
args.data.setOutputs(queueEntry.nodeId, pinnedOutputs);
|
|
2058
|
-
args.planner.applyOutputs(args.queue, {
|
|
2059
|
-
fromNodeId: queueEntry.nodeId,
|
|
2060
|
-
outputs: pinnedOutputs,
|
|
2061
|
-
batchId: queueEntry.batchId ?? "batch_1"
|
|
2062
|
-
});
|
|
2063
|
-
changed = true;
|
|
2064
|
-
break;
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
createFinishedSnapshot(args) {
|
|
2069
|
-
const definition = args.workflow.nodes.find((node) => node.id === args.nodeId);
|
|
2070
|
-
if (MissingRuntimeExecutionMarker.isMarked(definition?.config)) return NodeSnapshotFactory.skipped(args);
|
|
2071
|
-
return NodeSnapshotFactory.completed(args);
|
|
2072
|
-
}
|
|
2073
|
-
resolveQueueEntryInputsByPort(queueEntry) {
|
|
2074
|
-
if (queueEntry.collect) return queueEntry.collect.received;
|
|
2075
|
-
return { [queueEntry.toInput ?? "in"]: queueEntry.input };
|
|
2076
|
-
}
|
|
2077
|
-
};
|
|
2078
|
-
|
|
2079
|
-
//#endregion
|
|
2080
|
-
//#region src/engine/execution/WorkflowRunExecutionContextFactory.ts
|
|
2081
|
-
/**
|
|
2082
|
-
* Shared {@link ExecutionContextFactory#create} wiring for workflow runners (base context before node-specific fields).
|
|
2083
|
-
*/
|
|
2084
|
-
var WorkflowRunExecutionContextFactory = class {
|
|
2085
|
-
constructor(executionContextFactory, credentialResolverFactory) {
|
|
2086
|
-
this.executionContextFactory = executionContextFactory;
|
|
2087
|
-
this.credentialResolverFactory = credentialResolverFactory;
|
|
2088
|
-
}
|
|
2089
|
-
create(args) {
|
|
2090
|
-
return this.executionContextFactory.create({
|
|
2091
|
-
runId: args.runId,
|
|
2092
|
-
workflowId: args.workflowId,
|
|
2093
|
-
parent: args.parent,
|
|
2094
|
-
subworkflowDepth: args.subworkflowDepth,
|
|
2095
|
-
engineMaxNodeActivations: args.engineMaxNodeActivations,
|
|
2096
|
-
engineMaxSubworkflowDepth: args.engineMaxSubworkflowDepth,
|
|
2097
|
-
data: args.data,
|
|
2098
|
-
nodeState: args.nodeState,
|
|
2099
|
-
getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId)
|
|
2100
|
-
});
|
|
2101
|
-
}
|
|
2102
|
-
};
|
|
2103
|
-
|
|
2104
|
-
//#endregion
|
|
2105
|
-
//#region src/engine/execution/WorkflowRunStarter.ts
|
|
2106
|
-
var WorkflowRunStarter = class {
|
|
2107
|
-
constructor(runIdFactory, runStore, runDataFactory, workflowSnapshotFactory, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, waiters, workflowPolicyRuntimeDefaults, executionLimitsPolicy) {
|
|
2108
|
-
this.runIdFactory = runIdFactory;
|
|
2109
|
-
this.runStore = runStore;
|
|
2110
|
-
this.runDataFactory = runDataFactory;
|
|
2111
|
-
this.workflowSnapshotFactory = workflowSnapshotFactory;
|
|
2112
|
-
this.planningFactory = planningFactory;
|
|
2113
|
-
this.nodeStatePublisherFactory = nodeStatePublisherFactory;
|
|
2114
|
-
this.runExecutionContextFactory = runExecutionContextFactory;
|
|
2115
|
-
this.nodeActivationRequestComposer = nodeActivationRequestComposer;
|
|
2116
|
-
this.activationEnqueueService = activationEnqueueService;
|
|
2117
|
-
this.waiters = waiters;
|
|
2118
|
-
this.workflowPolicyRuntimeDefaults = workflowPolicyRuntimeDefaults;
|
|
2119
|
-
this.executionLimitsPolicy = executionLimitsPolicy;
|
|
2120
|
-
}
|
|
2121
|
-
async runWorkflow(wf, startAt, items, parent, executionOptions, persistedStateOverrides) {
|
|
2122
|
-
const runId = this.runIdFactory.makeRunId();
|
|
2123
|
-
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2124
|
-
const workflowSnapshot = persistedStateOverrides?.workflowSnapshot ?? this.workflowSnapshotFactory.create(wf);
|
|
2125
|
-
const mutableState = persistedStateOverrides?.mutableState;
|
|
2126
|
-
const policySnapshot = RunPolicySnapshotFactory.create(wf, this.workflowPolicyRuntimeDefaults);
|
|
2127
|
-
const mergedExecutionOptions = this.executionLimitsPolicy.mergeExecutionOptionsForNewRun(parent, executionOptions);
|
|
2128
|
-
await this.runStore.createRun({
|
|
2129
|
-
runId,
|
|
2130
|
-
workflowId: wf.id,
|
|
2131
|
-
startedAt,
|
|
2132
|
-
parent,
|
|
2133
|
-
executionOptions: mergedExecutionOptions,
|
|
2134
|
-
workflowSnapshot,
|
|
2135
|
-
mutableState,
|
|
2136
|
-
policySnapshot,
|
|
2137
|
-
engineCounters: { completedNodeActivations: 0 }
|
|
2138
|
-
});
|
|
2139
|
-
const data = this.runDataFactory.create();
|
|
2140
|
-
const base = this.runExecutionContextFactory.create({
|
|
2141
|
-
runId,
|
|
2142
|
-
workflowId: wf.id,
|
|
2143
|
-
nodeId: startAt,
|
|
2144
|
-
parent,
|
|
2145
|
-
subworkflowDepth: mergedExecutionOptions.subworkflowDepth ?? 0,
|
|
2146
|
-
engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations,
|
|
2147
|
-
engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth,
|
|
2148
|
-
data,
|
|
2149
|
-
nodeState: this.nodeStatePublisherFactory.create(runId, wf.id, parent)
|
|
2150
|
-
});
|
|
2151
|
-
const { topology, planner } = this.planningFactory.create(wf);
|
|
2152
|
-
const startDef = topology.defsById.get(startAt);
|
|
2153
|
-
if (!startDef) throw new Error(`Unknown start nodeId: ${startAt}`);
|
|
2154
|
-
const batchId = "batch_1";
|
|
2155
|
-
const queue = [];
|
|
2156
|
-
const initialNodeSnapshotsByNodeId = {};
|
|
2157
|
-
if (startDef.kind === "trigger") {
|
|
2158
|
-
const request$1 = this.nodeActivationRequestComposer.createSingleFromDefinition({
|
|
2159
|
-
runId,
|
|
2160
|
-
workflowId: wf.id,
|
|
2161
|
-
definition: startDef,
|
|
2162
|
-
parent,
|
|
2163
|
-
executionOptions: mergedExecutionOptions,
|
|
2164
|
-
batchId,
|
|
2165
|
-
input: items,
|
|
2166
|
-
base,
|
|
2167
|
-
data
|
|
2168
|
-
});
|
|
2169
|
-
return await this.activationEnqueueService.enqueueActivation({
|
|
2170
|
-
runId,
|
|
2171
|
-
workflowId: wf.id,
|
|
2172
|
-
startedAt,
|
|
2173
|
-
parent,
|
|
2174
|
-
executionOptions: mergedExecutionOptions,
|
|
2175
|
-
workflowSnapshot,
|
|
2176
|
-
mutableState,
|
|
2177
|
-
policySnapshot,
|
|
2178
|
-
control: void 0,
|
|
2179
|
-
pendingQueue: [],
|
|
2180
|
-
request: request$1,
|
|
2181
|
-
previousNodeSnapshotsByNodeId: initialNodeSnapshotsByNodeId,
|
|
2182
|
-
planner,
|
|
2183
|
-
engineCounters: { completedNodeActivations: 0 },
|
|
2184
|
-
connectionInvocations: []
|
|
2185
|
-
});
|
|
2186
|
-
}
|
|
2187
|
-
queue.push({
|
|
2188
|
-
nodeId: startAt,
|
|
2189
|
-
input: items,
|
|
2190
|
-
toInput: "in",
|
|
2191
|
-
batchId
|
|
2192
|
-
});
|
|
2193
|
-
const next = planner.nextActivation(queue);
|
|
2194
|
-
if (!next) {
|
|
2195
|
-
const lastNodeId = createWorkflowExecutableNodeClassifier(wf).lastExecutableNodeIdInDefinitionOrder(wf);
|
|
2196
|
-
const outputs = data.getOutputItems(lastNodeId, "main");
|
|
2197
|
-
await this.runStore.save({
|
|
2198
|
-
runId,
|
|
2199
|
-
workflowId: wf.id,
|
|
2200
|
-
startedAt,
|
|
2201
|
-
parent,
|
|
2202
|
-
executionOptions: mergedExecutionOptions,
|
|
2203
|
-
workflowSnapshot,
|
|
2204
|
-
mutableState,
|
|
2205
|
-
policySnapshot,
|
|
2206
|
-
engineCounters: { completedNodeActivations: 0 },
|
|
2207
|
-
connectionInvocations: [],
|
|
2208
|
-
status: "completed",
|
|
2209
|
-
pending: void 0,
|
|
2210
|
-
queue: [],
|
|
2211
|
-
outputsByNode: data.dump(),
|
|
2212
|
-
nodeSnapshotsByNodeId: initialNodeSnapshotsByNodeId
|
|
2213
|
-
});
|
|
2214
|
-
const result = {
|
|
2215
|
-
runId,
|
|
2216
|
-
workflowId: wf.id,
|
|
2217
|
-
startedAt,
|
|
2218
|
-
status: "completed",
|
|
2219
|
-
outputs
|
|
2220
|
-
};
|
|
2221
|
-
this.waiters.resolveRunCompletion(result);
|
|
2222
|
-
return result;
|
|
2223
|
-
}
|
|
2224
|
-
const def = topology.defsById.get(next.nodeId);
|
|
2225
|
-
if (!def || def.kind !== "node") throw new Error(`Node ${next.nodeId} is not a runnable node`);
|
|
2226
|
-
const request = this.nodeActivationRequestComposer.createFromPlannedActivation({
|
|
2227
|
-
next,
|
|
2228
|
-
base,
|
|
2229
|
-
data,
|
|
2230
|
-
runId,
|
|
2231
|
-
workflowId: wf.id,
|
|
2232
|
-
parent,
|
|
2233
|
-
executionOptions: mergedExecutionOptions,
|
|
2234
|
-
nodeDefinition: def
|
|
2235
|
-
});
|
|
2236
|
-
return await this.activationEnqueueService.enqueueActivation({
|
|
2237
|
-
runId,
|
|
2238
|
-
workflowId: wf.id,
|
|
2239
|
-
startedAt,
|
|
2240
|
-
parent,
|
|
2241
|
-
executionOptions: mergedExecutionOptions,
|
|
2242
|
-
control: void 0,
|
|
2243
|
-
workflowSnapshot,
|
|
2244
|
-
mutableState,
|
|
2245
|
-
policySnapshot,
|
|
2246
|
-
pendingQueue: queue,
|
|
2247
|
-
request,
|
|
2248
|
-
previousNodeSnapshotsByNodeId: initialNodeSnapshotsByNodeId,
|
|
2249
|
-
planner,
|
|
2250
|
-
engineCounters: { completedNodeActivations: 0 },
|
|
2251
|
-
connectionInvocations: []
|
|
2252
|
-
});
|
|
2253
|
-
}
|
|
2254
|
-
};
|
|
2255
|
-
|
|
2256
|
-
//#endregion
|
|
2257
|
-
//#region src/engine/policies/RunTerminalPersistenceCoordinator.ts
|
|
2258
|
-
var RunTerminalPersistenceCoordinator = class {
|
|
2259
|
-
constructor(runStore, storageEvaluator) {
|
|
2260
|
-
this.runStore = runStore;
|
|
2261
|
-
this.storageEvaluator = storageEvaluator;
|
|
2262
|
-
}
|
|
2263
|
-
async maybeDeleteAfterTerminalState(args) {
|
|
2264
|
-
if (await this.storageEvaluator.shouldPersist(args.workflow, args.state.policySnapshot, {
|
|
2265
|
-
runId: args.state.runId,
|
|
2266
|
-
workflowId: args.state.workflowId,
|
|
2267
|
-
workflow: args.workflow,
|
|
2268
|
-
finalStatus: args.finalStatus,
|
|
2269
|
-
startedAt: args.state.startedAt,
|
|
2270
|
-
finishedAt: args.finishedAt
|
|
2271
|
-
})) return;
|
|
2272
|
-
if (!this.runStore.deleteRun) return;
|
|
2273
|
-
await this.runStore.deleteRun(args.state.runId);
|
|
2274
|
-
}
|
|
2275
|
-
};
|
|
2276
|
-
|
|
2277
|
-
//#endregion
|
|
2278
|
-
//#region src/engine/policies/WorkflowPolicyErrorServices.ts
|
|
2279
|
-
var WorkflowPolicyErrorServices = class {
|
|
2280
|
-
constructor(nodeResolver) {
|
|
2281
|
-
this.nodeResolver = nodeResolver;
|
|
2282
|
-
}
|
|
2283
|
-
resolveNodeErrorHandler(spec) {
|
|
2284
|
-
if (!spec) return void 0;
|
|
2285
|
-
if (typeof spec === "object" && spec !== null && "handle" in spec && typeof spec.handle === "function") return spec;
|
|
2286
|
-
return this.nodeResolver.resolve(spec);
|
|
2287
|
-
}
|
|
2288
|
-
resolveWorkflowErrorHandler(spec) {
|
|
2289
|
-
if (!spec) return void 0;
|
|
2290
|
-
if (typeof spec === "object" && spec !== null && "onError" in spec && typeof spec.onError === "function") return spec;
|
|
2291
|
-
return this.nodeResolver.resolve(spec);
|
|
2292
|
-
}
|
|
2293
|
-
};
|
|
2294
|
-
|
|
2295
|
-
//#endregion
|
|
2296
|
-
//#region src/engine/policies/WorkflowStoragePolicyEvaluator.ts
|
|
2297
|
-
var WorkflowStoragePolicyEvaluator = class {
|
|
2298
|
-
constructor(nodeResolver) {
|
|
2299
|
-
this.nodeResolver = nodeResolver;
|
|
2300
|
-
}
|
|
2301
|
-
async shouldPersist(workflow, snapshot, args) {
|
|
2302
|
-
const spec = workflow.storagePolicy;
|
|
2303
|
-
if (spec === void 0) return this.modeMatches(snapshot?.storagePolicy ?? "ALL", args);
|
|
2304
|
-
if (typeof spec === "string") return this.modeMatches(spec, args);
|
|
2305
|
-
const resolver = this.nodeResolver.resolve(spec);
|
|
2306
|
-
return Boolean(await resolver.shouldPersist(args));
|
|
2307
|
-
}
|
|
2308
|
-
modeMatches(mode, args) {
|
|
2309
|
-
if (mode === "ALL") return true;
|
|
2310
|
-
if (mode === "NEVER") return false;
|
|
2311
|
-
if (mode === "SUCCESS") return args.finalStatus === "completed";
|
|
2312
|
-
if (mode === "ERROR") return args.finalStatus === "failed";
|
|
2313
|
-
return true;
|
|
2314
|
-
}
|
|
2315
|
-
};
|
|
2316
|
-
|
|
2317
|
-
//#endregion
|
|
2318
|
-
//#region src/engine/credentials/CredentialResolverFactory.ts
|
|
2319
|
-
var CredentialResolverFactory = class {
|
|
2320
|
-
constructor(credentialSessions) {
|
|
2321
|
-
this.credentialSessions = credentialSessions;
|
|
2322
|
-
}
|
|
2323
|
-
create(workflowId, nodeId, config) {
|
|
2324
|
-
const acceptedTypesBySlot = /* @__PURE__ */ new Map();
|
|
2325
|
-
for (const requirement of config?.getCredentialRequirements?.() ?? []) acceptedTypesBySlot.set(requirement.slotKey, requirement.acceptedTypes);
|
|
2326
|
-
return async (slotKey) => {
|
|
2327
|
-
try {
|
|
2328
|
-
return await this.credentialSessions.getSession({
|
|
2329
|
-
workflowId,
|
|
2330
|
-
nodeId,
|
|
2331
|
-
slotKey
|
|
2332
|
-
});
|
|
2333
|
-
} catch (error) {
|
|
2334
|
-
const acceptedTypes = acceptedTypesBySlot.get(slotKey) ?? [];
|
|
2335
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2336
|
-
const alreadyListsAcceptedTypes = message.includes("Accepted types:") || message.includes("Accepted credential types:") || message.includes("binding points at an unknown type");
|
|
2337
|
-
const acceptedTypesSuffix = acceptedTypes.length > 0 && !alreadyListsAcceptedTypes ? ` Accepted types: ${acceptedTypes.join(", ")}.` : "";
|
|
2338
|
-
throw new Error(`Failed to resolve credential for workflow ${workflowId} node ${nodeId} slot "${slotKey}". ${message}${acceptedTypesSuffix}`, { cause: error });
|
|
2339
|
-
}
|
|
2340
|
-
};
|
|
2341
|
-
}
|
|
2342
|
-
};
|
|
2343
|
-
|
|
2344
|
-
//#endregion
|
|
2345
|
-
//#region src/events/NodeEventPublisher.ts
|
|
2346
|
-
/** Publishes node lifecycle snapshots onto the run {@link RunEventBus}. */
|
|
2347
|
-
var NodeEventPublisher = class {
|
|
2348
|
-
constructor(eventBus) {
|
|
2349
|
-
this.eventBus = eventBus;
|
|
2350
|
-
}
|
|
2351
|
-
async publish(kind, snapshot) {
|
|
2352
|
-
if (!this.eventBus) return;
|
|
2353
|
-
await this.eventBus.publish({
|
|
2354
|
-
kind,
|
|
2355
|
-
runId: snapshot.runId,
|
|
2356
|
-
workflowId: snapshot.workflowId,
|
|
2357
|
-
parent: snapshot.parent,
|
|
2358
|
-
at: snapshot.updatedAt,
|
|
2359
|
-
snapshot
|
|
2360
|
-
});
|
|
2361
|
-
}
|
|
2362
|
-
};
|
|
2363
|
-
|
|
2364
|
-
//#endregion
|
|
2365
|
-
//#region src/engine/planning/RunQueuePlannerDiagnostics.ts
|
|
2366
|
-
var RunQueuePlannerDiagnostics = class {
|
|
2367
|
-
constructor(topology, nodeInstances) {
|
|
2368
|
-
this.topology = topology;
|
|
2369
|
-
this.nodeInstances = nodeInstances;
|
|
2370
|
-
}
|
|
2371
|
-
describeUnsatisfiedCollect(queueEntry) {
|
|
2372
|
-
const batchId = queueEntry.batchId ?? "batch_1";
|
|
2373
|
-
const expectedInputs = queueEntry.collect?.expectedInputs ?? [];
|
|
2374
|
-
const receivedInputs = Object.keys(queueEntry.collect?.received ?? {});
|
|
2375
|
-
const missingInputs = expectedInputs.filter((input) => !receivedInputs.includes(input));
|
|
2376
|
-
const mergeNodeLabel = this.formatNodeLabel(queueEntry.nodeId);
|
|
2377
|
-
const receivedSummary = this.describeReceivedInputs(queueEntry);
|
|
2378
|
-
const missingSummary = this.describeMissingInputs(queueEntry.nodeId, missingInputs);
|
|
2379
|
-
return [
|
|
2380
|
-
`Multi-input collect is stuck at ${mergeNodeLabel} (batchId=${batchId}).`,
|
|
2381
|
-
`Expected inputs: ${this.formatInputList(expectedInputs)}.`,
|
|
2382
|
-
`Received inputs: ${receivedSummary}.`,
|
|
2383
|
-
`Missing inputs: ${missingSummary}.`
|
|
2384
|
-
].join(" ");
|
|
2385
|
-
}
|
|
2386
|
-
describeReceivedInputs(queueEntry) {
|
|
2387
|
-
const received = queueEntry.collect?.received ?? {};
|
|
2388
|
-
const receivedEntries = Object.entries(received);
|
|
2389
|
-
if (receivedEntries.length === 0) return "none";
|
|
2390
|
-
return receivedEntries.map(([input, items]) => `${input} (${items.length} item${items.length === 1 ? "" : "s"})`).join(", ");
|
|
2391
|
-
}
|
|
2392
|
-
describeMissingInputs(nodeId, missingInputs) {
|
|
2393
|
-
if (missingInputs.length === 0) return "none";
|
|
2394
|
-
return missingInputs.map((input) => {
|
|
2395
|
-
const sources = this.findSources(nodeId, input);
|
|
2396
|
-
if (sources.length === 0) return input;
|
|
2397
|
-
return `${input} from ${sources.join(" or ")}`;
|
|
2398
|
-
}).join(", ");
|
|
2399
|
-
}
|
|
2400
|
-
findSources(nodeId, input) {
|
|
2401
|
-
const matches = [];
|
|
2402
|
-
for (const [sourceNodeId, edges] of this.topology.outgoingByNode.entries()) for (const edge of edges) if (edge.to.nodeId === nodeId && edge.to.input === input) matches.push(this.formatNodeLabel(sourceNodeId));
|
|
2403
|
-
return matches;
|
|
2404
|
-
}
|
|
2405
|
-
formatInputList(inputs) {
|
|
2406
|
-
return inputs.length > 0 ? `[${inputs.join(", ")}]` : "[]";
|
|
2407
|
-
}
|
|
2408
|
-
formatNodeLabel(nodeId) {
|
|
2409
|
-
const definition = this.topology.defsById.get(nodeId);
|
|
2410
|
-
const instance = this.nodeInstances.get(nodeId);
|
|
2411
|
-
const typeName = definition?.type && typeof definition.type === "function" ? definition.type.name : instance && typeof instance === "object" && "constructor" in instance ? instance.constructor.name ?? "Node" : "Node";
|
|
2412
|
-
return definition?.name ? `"${definition.name}" (${typeName}:${nodeId})` : `${typeName}:${nodeId}`;
|
|
2413
|
-
}
|
|
2414
|
-
};
|
|
2415
|
-
|
|
2416
|
-
//#endregion
|
|
2417
|
-
//#region src/engine/planning/RunQueuePlanner.ts
|
|
2418
|
-
var RunQueuePlanner = class {
|
|
2419
|
-
diagnostics;
|
|
2420
|
-
constructor(topology, nodeInstances) {
|
|
2421
|
-
this.topology = topology;
|
|
2422
|
-
this.nodeInstances = nodeInstances;
|
|
2423
|
-
this.diagnostics = new RunQueuePlannerDiagnostics(topology, nodeInstances);
|
|
2424
|
-
}
|
|
2425
|
-
validateNodeKinds() {
|
|
2426
|
-
for (const [toNodeId, inputs] of this.topology.expectedInputsByNode.entries()) {
|
|
2427
|
-
if (inputs.length <= 1) {
|
|
2428
|
-
const only = inputs[0];
|
|
2429
|
-
if (only && only !== "in") {
|
|
2430
|
-
const inst$1 = this.nodeInstances.get(toNodeId);
|
|
2431
|
-
if (!this.isMultiInputNode(inst$1)) throw new Error(`Node ${toNodeId} only supports input 'in' (got '${only}').`);
|
|
2432
|
-
}
|
|
2433
|
-
continue;
|
|
2434
|
-
}
|
|
2435
|
-
const inst = this.nodeInstances.get(toNodeId);
|
|
2436
|
-
if (!this.isMultiInputNode(inst)) throw new Error(`Node ${toNodeId} has ${inputs.length} inbound edges. Insert a Merge node to combine branches.`);
|
|
2437
|
-
}
|
|
2438
|
-
}
|
|
2439
|
-
seedFromTrigger(args) {
|
|
2440
|
-
const queue = [];
|
|
2441
|
-
for (const e of this.topology.outgoingByNode.get(args.startNodeId) ?? []) {
|
|
2442
|
-
if (e.output !== "main") continue;
|
|
2443
|
-
this.enqueueEdge(queue, {
|
|
2444
|
-
batchId: args.batchId,
|
|
2445
|
-
to: e.to,
|
|
2446
|
-
from: {
|
|
2447
|
-
nodeId: args.startNodeId,
|
|
2448
|
-
output: "main"
|
|
2449
|
-
},
|
|
2450
|
-
items: args.items
|
|
2451
|
-
});
|
|
2452
|
-
}
|
|
2453
|
-
return queue;
|
|
2454
|
-
}
|
|
2455
|
-
applyOutputs(queue, args) {
|
|
2456
|
-
for (const e of this.topology.outgoingByNode.get(args.fromNodeId) ?? []) {
|
|
2457
|
-
const outItems = args.outputs[e.output] ?? [];
|
|
2458
|
-
this.enqueueEdge(queue, {
|
|
2459
|
-
batchId: args.batchId,
|
|
2460
|
-
to: e.to,
|
|
2461
|
-
from: {
|
|
2462
|
-
nodeId: args.fromNodeId,
|
|
2463
|
-
output: e.output
|
|
2464
|
-
},
|
|
2465
|
-
items: outItems
|
|
2466
|
-
});
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
nextActivation(queue) {
|
|
2470
|
-
const readyCollect = this.resolveReadyCollect(queue);
|
|
2471
|
-
if (readyCollect) return readyCollect;
|
|
2472
|
-
const jobIdx = queue.findIndex((q) => !q.collect);
|
|
2473
|
-
if (jobIdx === -1) {
|
|
2474
|
-
if (queue.length === 0) return null;
|
|
2475
|
-
const sealedCollect = this.resolveSealedCollect(queue);
|
|
2476
|
-
if (sealedCollect) return sealedCollect;
|
|
2477
|
-
const stuck = queue[0];
|
|
2478
|
-
throw new Error(this.diagnostics.describeUnsatisfiedCollect(stuck));
|
|
2479
|
-
}
|
|
2480
|
-
const job = queue.splice(jobIdx, 1)[0];
|
|
2481
|
-
const def = this.topology.defsById.get(job.nodeId);
|
|
2482
|
-
if (!def || def.kind !== "node") return this.nextActivation(queue);
|
|
2483
|
-
return {
|
|
2484
|
-
kind: "single",
|
|
2485
|
-
nodeId: job.nodeId,
|
|
2486
|
-
input: job.input,
|
|
2487
|
-
batchId: job.batchId ?? "batch_1"
|
|
2488
|
-
};
|
|
2489
|
-
}
|
|
2490
|
-
sumItemsByPort(inputsByPort) {
|
|
2491
|
-
let n = 0;
|
|
2492
|
-
for (const v of Object.values(inputsByPort)) n += v?.length ?? 0;
|
|
2493
|
-
return n;
|
|
2494
|
-
}
|
|
2495
|
-
resolveReadyCollect(queue) {
|
|
2496
|
-
for (let i = 0; i < queue.length; i++) {
|
|
2497
|
-
const ready = this.tryDequeueCollect(queue, i);
|
|
2498
|
-
if (ready) return ready;
|
|
2499
|
-
}
|
|
2500
|
-
return null;
|
|
2501
|
-
}
|
|
2502
|
-
resolveSealedCollect(queue) {
|
|
2503
|
-
for (let i = 0; i < queue.length; i++) {
|
|
2504
|
-
const queueEntry = queue[i];
|
|
2505
|
-
if (!queueEntry.collect) continue;
|
|
2506
|
-
const received = queueEntry.collect.received;
|
|
2507
|
-
if (Object.keys(received).length === 0) continue;
|
|
2508
|
-
this.fillMissingCollectInputs(queueEntry);
|
|
2509
|
-
const ready = this.tryDequeueCollect(queue, i);
|
|
2510
|
-
if (ready) return ready;
|
|
2511
|
-
}
|
|
2512
|
-
return null;
|
|
2513
|
-
}
|
|
2514
|
-
tryDequeueCollect(queue, index) {
|
|
2515
|
-
const queueEntry = queue[index];
|
|
2516
|
-
if (!queueEntry.collect) return null;
|
|
2517
|
-
const batchId = queueEntry.batchId ?? "batch_1";
|
|
2518
|
-
const expected = queueEntry.collect.expectedInputs ?? [];
|
|
2519
|
-
const received = queueEntry.collect.received;
|
|
2520
|
-
for (const input of expected) if (!(input in received)) return null;
|
|
2521
|
-
queue.splice(index, 1);
|
|
2522
|
-
return {
|
|
2523
|
-
kind: "multi",
|
|
2524
|
-
nodeId: queueEntry.nodeId,
|
|
2525
|
-
inputsByPort: received,
|
|
2526
|
-
batchId
|
|
2527
|
-
};
|
|
2528
|
-
}
|
|
2529
|
-
fillMissingCollectInputs(queueEntry) {
|
|
2530
|
-
if (!queueEntry.collect) return;
|
|
2531
|
-
const received = queueEntry.collect.received;
|
|
2532
|
-
for (const input of queueEntry.collect.expectedInputs ?? []) if (!(input in received)) received[input] = [];
|
|
2533
|
-
}
|
|
2534
|
-
enqueueEdge(queue, args) {
|
|
2535
|
-
const target = this.nodeInstances.get(args.to.nodeId);
|
|
2536
|
-
if (!this.isMultiInputNode(target)) {
|
|
2537
|
-
if (args.items.length === 0) {
|
|
2538
|
-
if (this.shouldContinueAfterEmptyOutputFromSource(args.from.nodeId)) {
|
|
2539
|
-
queue.push({
|
|
2540
|
-
nodeId: args.to.nodeId,
|
|
2541
|
-
input: args.items,
|
|
2542
|
-
toInput: args.to.input,
|
|
2543
|
-
batchId: args.batchId,
|
|
2544
|
-
from: args.from
|
|
2545
|
-
});
|
|
2546
|
-
return;
|
|
2547
|
-
}
|
|
2548
|
-
this.propagateEmptyPath(queue, args.to.nodeId, args.batchId);
|
|
2549
|
-
return;
|
|
2550
|
-
}
|
|
2551
|
-
queue.push({
|
|
2552
|
-
nodeId: args.to.nodeId,
|
|
2553
|
-
input: args.items,
|
|
2554
|
-
toInput: args.to.input,
|
|
2555
|
-
batchId: args.batchId,
|
|
2556
|
-
from: args.from
|
|
2557
|
-
});
|
|
2558
|
-
return;
|
|
2559
|
-
}
|
|
2560
|
-
const expected = this.topology.expectedInputsByNode.get(args.to.nodeId) ?? [];
|
|
2561
|
-
let collect = queue.find((q) => q.nodeId === args.to.nodeId && (q.batchId ?? "batch_1") === args.batchId && !!q.collect);
|
|
2562
|
-
if (!collect) {
|
|
2563
|
-
collect = {
|
|
2564
|
-
nodeId: args.to.nodeId,
|
|
2565
|
-
input: [],
|
|
2566
|
-
batchId: args.batchId,
|
|
2567
|
-
collect: {
|
|
2568
|
-
expectedInputs: expected,
|
|
2569
|
-
received: {}
|
|
2570
|
-
}
|
|
2571
|
-
};
|
|
2572
|
-
queue.push(collect);
|
|
2573
|
-
}
|
|
2574
|
-
const received = collect.collect.received;
|
|
2575
|
-
received[args.to.input] = args.items;
|
|
2576
|
-
}
|
|
2577
|
-
shouldContinueAfterEmptyOutputFromSource(fromNodeId) {
|
|
2578
|
-
const def = this.topology.defsById.get(fromNodeId);
|
|
2579
|
-
if (!def) return false;
|
|
2580
|
-
return def.config.continueWhenEmptyOutput === true;
|
|
2581
|
-
}
|
|
2582
|
-
propagateEmptyPath(queue, nodeId, batchId) {
|
|
2583
|
-
for (const edge of this.topology.outgoingByNode.get(nodeId) ?? []) this.enqueueEdge(queue, {
|
|
2584
|
-
batchId,
|
|
2585
|
-
to: edge.to,
|
|
2586
|
-
from: {
|
|
2587
|
-
nodeId,
|
|
2588
|
-
output: edge.output
|
|
2589
|
-
},
|
|
2590
|
-
items: []
|
|
2591
|
-
});
|
|
2592
|
-
}
|
|
2593
|
-
isMultiInputNode(n) {
|
|
2594
|
-
return typeof n?.executeMulti === "function";
|
|
2595
|
-
}
|
|
2596
|
-
};
|
|
2597
|
-
|
|
2598
|
-
//#endregion
|
|
2599
|
-
//#region src/engine/planning/EngineWorkflowPlanningFactory.ts
|
|
2600
|
-
var EngineWorkflowPlanningFactory = class {
|
|
2601
|
-
constructor(workflowNodeInstanceFactory, directedCycleDetector) {
|
|
2602
|
-
this.workflowNodeInstanceFactory = workflowNodeInstanceFactory;
|
|
2603
|
-
this.directedCycleDetector = directedCycleDetector;
|
|
2604
|
-
}
|
|
2605
|
-
create(workflow) {
|
|
2606
|
-
this.directedCycleDetector.validateAcyclic(workflow);
|
|
2607
|
-
const topology = WorkflowTopology.fromWorkflow(workflow);
|
|
2608
|
-
const planner = new RunQueuePlanner(topology, this.workflowNodeInstanceFactory.createNodes(workflow));
|
|
2609
|
-
planner.validateNodeKinds();
|
|
2610
|
-
return {
|
|
2611
|
-
topology,
|
|
2612
|
-
planner
|
|
2613
|
-
};
|
|
2614
|
-
}
|
|
2615
|
-
};
|
|
2616
|
-
|
|
2617
|
-
//#endregion
|
|
2618
|
-
//#region src/engine/planning/DirectedCycleDetector.ts
|
|
2619
|
-
/**
|
|
2620
|
-
* Rejects workflow definitions whose edges contain a directed cycle (including self-loops).
|
|
2621
|
-
*/
|
|
2622
|
-
var DirectedCycleDetector = class {
|
|
2623
|
-
validateAcyclic(workflow) {
|
|
2624
|
-
const classifier = createWorkflowExecutableNodeClassifier(workflow);
|
|
2625
|
-
const outgoing = this.buildOutgoingAdjacency(workflow, classifier);
|
|
2626
|
-
const state = /* @__PURE__ */ new Map();
|
|
2627
|
-
for (const n of workflow.nodes) if (classifier.isExecutableNodeId(n.id)) state.set(n.id, "unvisited");
|
|
2628
|
-
for (const n of workflow.nodes) if (classifier.isExecutableNodeId(n.id) && state.get(n.id) === "unvisited") this.depthFirstSearch(n.id, outgoing, state);
|
|
2629
|
-
}
|
|
2630
|
-
buildOutgoingAdjacency(workflow, classifier) {
|
|
2631
|
-
const map = /* @__PURE__ */ new Map();
|
|
2632
|
-
for (const e of workflow.edges) {
|
|
2633
|
-
if (!classifier.isExecutableNodeId(e.from.nodeId) || !classifier.isExecutableNodeId(e.to.nodeId)) continue;
|
|
2634
|
-
const list = map.get(e.from.nodeId) ?? [];
|
|
2635
|
-
list.push(e.to.nodeId);
|
|
2636
|
-
map.set(e.from.nodeId, list);
|
|
2637
|
-
}
|
|
2638
|
-
return map;
|
|
2639
|
-
}
|
|
2640
|
-
depthFirstSearch(nodeId, outgoing, visitState) {
|
|
2641
|
-
visitState.set(nodeId, "visiting");
|
|
2642
|
-
for (const toId of outgoing.get(nodeId) ?? []) {
|
|
2643
|
-
const s = visitState.get(toId);
|
|
2644
|
-
if (s === "visiting") throw new Error(`Workflow graph contains a directed cycle (edge ${nodeId} -> ${toId}).`);
|
|
2645
|
-
if (s === "unvisited") this.depthFirstSearch(toId, outgoing, visitState);
|
|
2646
|
-
}
|
|
2647
|
-
visitState.set(nodeId, "done");
|
|
2648
|
-
}
|
|
2649
|
-
};
|
|
2650
|
-
|
|
2651
|
-
//#endregion
|
|
2652
|
-
//#region src/engine/state/BoundNodeExecutionStatePublisher.ts
|
|
2653
|
-
var BoundNodeExecutionStatePublisher = class {
|
|
2654
|
-
chain = Promise.resolve();
|
|
2655
|
-
constructor(runStore, runId, workflowId, parent, publishNodeEvent) {
|
|
2656
|
-
this.runStore = runStore;
|
|
2657
|
-
this.runId = runId;
|
|
2658
|
-
this.workflowId = workflowId;
|
|
2659
|
-
this.parent = parent;
|
|
2660
|
-
this.publishNodeEvent = publishNodeEvent;
|
|
2661
|
-
}
|
|
2662
|
-
markQueued(args) {
|
|
2663
|
-
return this.enqueue(async () => {
|
|
2664
|
-
const state = await this.loadState();
|
|
2665
|
-
const previous = state.nodeSnapshotsByNodeId?.[args.nodeId];
|
|
2666
|
-
const queuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2667
|
-
const snapshot = NodeSnapshotFactory.queued({
|
|
2668
|
-
runId: this.runId,
|
|
2669
|
-
workflowId: this.workflowId,
|
|
2670
|
-
nodeId: args.nodeId,
|
|
2671
|
-
activationId: args.activationId ?? previous?.activationId ?? `synthetic_${args.nodeId}`,
|
|
2672
|
-
parent: this.parent,
|
|
2673
|
-
queuedAt,
|
|
2674
|
-
inputsByPort: args.inputsByPort ?? previous?.inputsByPort ?? InputPortMap.empty()
|
|
2675
|
-
});
|
|
2676
|
-
await this.saveSnapshot(state, snapshot);
|
|
2677
|
-
await this.publishNodeEvent("nodeQueued", snapshot);
|
|
2678
|
-
});
|
|
2679
|
-
}
|
|
2680
|
-
markRunning(args) {
|
|
2681
|
-
return this.enqueue(async () => {
|
|
2682
|
-
const state = await this.loadState();
|
|
2683
|
-
const previous = state.nodeSnapshotsByNodeId?.[args.nodeId];
|
|
2684
|
-
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2685
|
-
const snapshot = NodeSnapshotFactory.running({
|
|
2686
|
-
previous,
|
|
2687
|
-
runId: this.runId,
|
|
2688
|
-
workflowId: this.workflowId,
|
|
2689
|
-
nodeId: args.nodeId,
|
|
2690
|
-
activationId: args.activationId ?? previous?.activationId ?? `synthetic_${args.nodeId}`,
|
|
2691
|
-
parent: this.parent,
|
|
2692
|
-
startedAt,
|
|
2693
|
-
inputsByPort: args.inputsByPort ?? previous?.inputsByPort ?? InputPortMap.empty()
|
|
2694
|
-
});
|
|
2695
|
-
await this.saveSnapshot(state, snapshot);
|
|
2696
|
-
await this.publishNodeEvent("nodeStarted", snapshot);
|
|
2697
|
-
});
|
|
2698
|
-
}
|
|
2699
|
-
markCompleted(args) {
|
|
2700
|
-
return this.enqueue(async () => {
|
|
2701
|
-
const state = await this.loadState();
|
|
2702
|
-
const previous = state.nodeSnapshotsByNodeId?.[args.nodeId];
|
|
2703
|
-
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2704
|
-
const snapshot = NodeSnapshotFactory.completed({
|
|
2705
|
-
previous,
|
|
2706
|
-
runId: this.runId,
|
|
2707
|
-
workflowId: this.workflowId,
|
|
2708
|
-
nodeId: args.nodeId,
|
|
2709
|
-
activationId: args.activationId ?? previous?.activationId ?? `synthetic_${args.nodeId}`,
|
|
2710
|
-
parent: this.parent,
|
|
2711
|
-
finishedAt,
|
|
2712
|
-
inputsByPort: args.inputsByPort ?? previous?.inputsByPort ?? InputPortMap.empty(),
|
|
2713
|
-
outputs: args.outputs ?? previous?.outputs ?? {}
|
|
2714
|
-
});
|
|
2715
|
-
await this.saveSnapshot(state, snapshot);
|
|
2716
|
-
await this.publishNodeEvent("nodeCompleted", snapshot);
|
|
2717
|
-
});
|
|
2718
|
-
}
|
|
2719
|
-
markFailed(args) {
|
|
2720
|
-
return this.enqueue(async () => {
|
|
2721
|
-
const state = await this.loadState();
|
|
2722
|
-
const previous = state.nodeSnapshotsByNodeId?.[args.nodeId];
|
|
2723
|
-
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2724
|
-
const snapshot = NodeSnapshotFactory.failed({
|
|
2725
|
-
previous,
|
|
2726
|
-
runId: this.runId,
|
|
2727
|
-
workflowId: this.workflowId,
|
|
2728
|
-
nodeId: args.nodeId,
|
|
2729
|
-
activationId: args.activationId ?? previous?.activationId ?? `synthetic_${args.nodeId}`,
|
|
2730
|
-
parent: this.parent,
|
|
2731
|
-
finishedAt,
|
|
2732
|
-
inputsByPort: args.inputsByPort ?? previous?.inputsByPort ?? InputPortMap.empty(),
|
|
2733
|
-
error: args.error
|
|
2734
|
-
});
|
|
2735
|
-
await this.saveSnapshot(state, snapshot);
|
|
2736
|
-
await this.publishNodeEvent("nodeFailed", snapshot);
|
|
2737
|
-
});
|
|
2738
|
-
}
|
|
2739
|
-
appendConnectionInvocation(args) {
|
|
2740
|
-
return this.enqueue(async () => {
|
|
2741
|
-
const state = await this.loadState();
|
|
2742
|
-
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2743
|
-
const record = {
|
|
2744
|
-
invocationId: args.invocationId,
|
|
2745
|
-
runId: this.runId,
|
|
2746
|
-
workflowId: this.workflowId,
|
|
2747
|
-
connectionNodeId: args.connectionNodeId,
|
|
2748
|
-
parentAgentNodeId: args.parentAgentNodeId,
|
|
2749
|
-
parentAgentActivationId: args.parentAgentActivationId,
|
|
2750
|
-
status: args.status,
|
|
2751
|
-
managedInput: args.managedInput,
|
|
2752
|
-
managedOutput: args.managedOutput,
|
|
2753
|
-
error: args.error,
|
|
2754
|
-
queuedAt: args.queuedAt,
|
|
2755
|
-
startedAt: args.startedAt,
|
|
2756
|
-
finishedAt: args.finishedAt,
|
|
2757
|
-
updatedAt
|
|
2758
|
-
};
|
|
2759
|
-
await this.runStore.save({
|
|
2760
|
-
...state,
|
|
2761
|
-
connectionInvocations: [...state.connectionInvocations ?? [], record]
|
|
2762
|
-
});
|
|
2763
|
-
});
|
|
2764
|
-
}
|
|
2765
|
-
enqueue(work) {
|
|
2766
|
-
const next = this.chain.then(work);
|
|
2767
|
-
this.chain = next.catch(() => void 0);
|
|
2768
|
-
return next;
|
|
2769
|
-
}
|
|
2770
|
-
async loadState() {
|
|
2771
|
-
const state = await this.runStore.load(this.runId);
|
|
2772
|
-
if (!state) throw new Error(`Unknown runId: ${this.runId}`);
|
|
2773
|
-
return state;
|
|
2774
|
-
}
|
|
2775
|
-
async saveSnapshot(state, snapshot) {
|
|
2776
|
-
await this.runStore.save({
|
|
2777
|
-
...state,
|
|
2778
|
-
nodeSnapshotsByNodeId: {
|
|
2779
|
-
...state.nodeSnapshotsByNodeId ?? {},
|
|
2780
|
-
[snapshot.nodeId]: snapshot
|
|
2781
|
-
}
|
|
2782
|
-
});
|
|
2783
|
-
}
|
|
2784
|
-
};
|
|
2785
|
-
|
|
2786
|
-
//#endregion
|
|
2787
|
-
//#region src/engine/state/NodeExecutionStatePublisherFactory.ts
|
|
2788
|
-
var NodeExecutionStatePublisherFactory = class {
|
|
2789
|
-
constructor(runStore, nodeEventPublisher) {
|
|
2790
|
-
this.runStore = runStore;
|
|
2791
|
-
this.nodeEventPublisher = nodeEventPublisher;
|
|
2792
|
-
}
|
|
2793
|
-
create(runId, workflowId, parent) {
|
|
2794
|
-
return new BoundNodeExecutionStatePublisher(this.runStore, runId, workflowId, parent, async (kind, snapshot) => {
|
|
2795
|
-
await this.nodeEventPublisher.publish(kind, snapshot);
|
|
2796
|
-
});
|
|
2797
|
-
}
|
|
2798
|
-
};
|
|
2799
|
-
|
|
2800
|
-
//#endregion
|
|
2801
|
-
//#region src/engine/triggers/TriggerRuntimeService.ts
|
|
2802
|
-
var TriggerRuntimeService = class {
|
|
2803
|
-
credentialResolverFactory;
|
|
2804
|
-
triggerCleanupHandlesByKey = /* @__PURE__ */ new Map();
|
|
2805
|
-
constructor(workflowRepository, workflowActivationPolicy, runIdFactory, runDataFactory, executionContextFactory, credentialResolverFactory, nodeExecutionStatePublisherFactory, nodeResolver, triggerSetupStateStore, emitHandler, executionLimitsPolicy, diagnostics) {
|
|
2806
|
-
this.workflowRepository = workflowRepository;
|
|
2807
|
-
this.workflowActivationPolicy = workflowActivationPolicy;
|
|
2808
|
-
this.runIdFactory = runIdFactory;
|
|
2809
|
-
this.runDataFactory = runDataFactory;
|
|
2810
|
-
this.executionContextFactory = executionContextFactory;
|
|
2811
|
-
this.nodeExecutionStatePublisherFactory = nodeExecutionStatePublisherFactory;
|
|
2812
|
-
this.nodeResolver = nodeResolver;
|
|
2813
|
-
this.triggerSetupStateStore = triggerSetupStateStore;
|
|
2814
|
-
this.emitHandler = emitHandler;
|
|
2815
|
-
this.executionLimitsPolicy = executionLimitsPolicy;
|
|
2816
|
-
this.diagnostics = diagnostics;
|
|
2817
|
-
this.credentialResolverFactory = credentialResolverFactory;
|
|
2818
|
-
}
|
|
2819
|
-
async startTriggers() {
|
|
2820
|
-
for (const wf of this.workflowRepository.list()) {
|
|
2821
|
-
if (!this.workflowActivationPolicy.isActive(wf.id)) {
|
|
2822
|
-
const summaries = this.formatTriggerSummaries(wf);
|
|
2823
|
-
if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}) is inactive; skipping trigger setup — ${summaries.join("; ")}.`);
|
|
2824
|
-
continue;
|
|
2825
|
-
}
|
|
2826
|
-
await this.startTriggersForWorkflow(wf);
|
|
2827
|
-
}
|
|
2828
|
-
}
|
|
2829
|
-
async syncWorkflowTriggersForActivation(workflowId) {
|
|
2830
|
-
const wf = this.workflowRepository.get(workflowId);
|
|
2831
|
-
if (!wf) return;
|
|
2832
|
-
const summaries = this.formatTriggerSummaries(wf);
|
|
2833
|
-
if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}): stopping triggers — ${summaries.join("; ")}.`);
|
|
2834
|
-
await this.stopTriggersForWorkflow(wf);
|
|
2835
|
-
if (this.workflowActivationPolicy.isActive(workflowId)) {
|
|
2836
|
-
if (summaries.length > 0) this.logInfo(`Workflow "${wf.name}" (${wf.id}): activation on; starting triggers — ${summaries.join("; ")}.`);
|
|
2837
|
-
await this.startTriggersForWorkflow(wf);
|
|
2838
|
-
} else this.logInfo(`Workflow "${wf.name}" (${wf.id}): activation off; triggers not started.`);
|
|
2839
|
-
}
|
|
2840
|
-
async stop() {
|
|
2841
|
-
for (const workflow of this.workflowRepository.list()) await this.stopTriggersForWorkflow(workflow);
|
|
2842
|
-
}
|
|
2843
|
-
async createTriggerTestItems(args) {
|
|
2844
|
-
const definition = args.workflow.nodes.find((node$1) => node$1.id === args.nodeId);
|
|
2845
|
-
if (!definition) throw new Error(`Unknown trigger nodeId: ${args.nodeId}`);
|
|
2846
|
-
if (definition.kind !== "trigger") throw new Error(`Node ${args.nodeId} is not a trigger`);
|
|
2847
|
-
const node = this.nodeResolver.resolve(definition.type);
|
|
2848
|
-
if (!this.isTestableTriggerNode(node)) return;
|
|
2849
|
-
const data = this.runDataFactory.create();
|
|
2850
|
-
const runId = this.runIdFactory.makeRunId();
|
|
2851
|
-
const trigger = {
|
|
2852
|
-
workflowId: args.workflow.id,
|
|
2853
|
-
nodeId: definition.id
|
|
2854
|
-
};
|
|
2855
|
-
const previousState = await this.triggerSetupStateStore.load(trigger);
|
|
2856
|
-
return await node.getTestItems({
|
|
2857
|
-
...this.createExecutionContext({
|
|
2858
|
-
runId,
|
|
2859
|
-
workflowId: args.workflow.id,
|
|
2860
|
-
nodeId: definition.id,
|
|
2861
|
-
data
|
|
2862
|
-
}),
|
|
2863
|
-
trigger,
|
|
2864
|
-
nodeId: definition.id,
|
|
2865
|
-
config: definition.config,
|
|
2866
|
-
previousState: previousState?.state
|
|
2867
|
-
});
|
|
2868
|
-
}
|
|
2869
|
-
async startTriggersForWorkflow(wf) {
|
|
2870
|
-
for (const def of wf.nodes) {
|
|
2871
|
-
if (def.kind !== "trigger") continue;
|
|
2872
|
-
const node = this.nodeResolver.resolve(def.type);
|
|
2873
|
-
const data = this.runDataFactory.create();
|
|
2874
|
-
const triggerRunId = this.runIdFactory.makeRunId();
|
|
2875
|
-
const trigger = {
|
|
2876
|
-
workflowId: wf.id,
|
|
2877
|
-
nodeId: def.id
|
|
2878
|
-
};
|
|
2879
|
-
await this.stopTrigger(trigger);
|
|
2880
|
-
const previousState = await this.triggerSetupStateStore.load(trigger);
|
|
2881
|
-
let nextState;
|
|
2882
|
-
try {
|
|
2883
|
-
nextState = await node.setup({
|
|
2884
|
-
...this.createExecutionContext({
|
|
2885
|
-
runId: triggerRunId,
|
|
2886
|
-
workflowId: wf.id,
|
|
2887
|
-
nodeId: def.id,
|
|
2888
|
-
data
|
|
2889
|
-
}),
|
|
2890
|
-
trigger,
|
|
2891
|
-
config: def.config,
|
|
2892
|
-
previousState: previousState?.state,
|
|
2893
|
-
registerCleanup: (cleanup) => {
|
|
2894
|
-
this.registerTriggerCleanupHandle(trigger, cleanup);
|
|
2895
|
-
},
|
|
2896
|
-
emit: async (items) => {
|
|
2897
|
-
await this.emitHandler.emit(wf, def.id, items);
|
|
2898
|
-
}
|
|
2899
|
-
});
|
|
2900
|
-
} catch (triggerError) {
|
|
2901
|
-
await this.stopTrigger(trigger);
|
|
2902
|
-
const message = triggerError instanceof Error ? triggerError.message : String(triggerError);
|
|
2903
|
-
this.logWarn(`Skipping trigger setup for workflow ${wf.id} node ${def.id}: ${message}`);
|
|
2904
|
-
continue;
|
|
2905
|
-
}
|
|
2906
|
-
if (nextState === void 0) await this.triggerSetupStateStore.delete(trigger);
|
|
2907
|
-
else await this.triggerSetupStateStore.save({
|
|
2908
|
-
trigger,
|
|
2909
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2910
|
-
state: nextState
|
|
2911
|
-
});
|
|
2912
|
-
}
|
|
2913
|
-
}
|
|
2914
|
-
async stopTriggersForWorkflow(workflow) {
|
|
2915
|
-
for (const node of workflow.nodes) {
|
|
2916
|
-
if (node.kind !== "trigger") continue;
|
|
2917
|
-
await this.stopTrigger({
|
|
2918
|
-
workflowId: workflow.id,
|
|
2919
|
-
nodeId: node.id
|
|
2920
|
-
});
|
|
2921
|
-
}
|
|
2922
|
-
}
|
|
2923
|
-
createExecutionContext(args) {
|
|
2924
|
-
const nodeState = this.nodeExecutionStatePublisherFactory.create(args.runId, args.workflowId, void 0);
|
|
2925
|
-
const rootLimits = this.executionLimitsPolicy.createRootExecutionOptions();
|
|
2926
|
-
return this.executionContextFactory.create({
|
|
2927
|
-
runId: args.runId,
|
|
2928
|
-
workflowId: args.workflowId,
|
|
2929
|
-
parent: void 0,
|
|
2930
|
-
subworkflowDepth: rootLimits.subworkflowDepth ?? 0,
|
|
2931
|
-
engineMaxNodeActivations: rootLimits.maxNodeActivations,
|
|
2932
|
-
engineMaxSubworkflowDepth: rootLimits.maxSubworkflowDepth,
|
|
2933
|
-
data: args.data,
|
|
2934
|
-
nodeState,
|
|
2935
|
-
getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId)
|
|
2936
|
-
});
|
|
2937
|
-
}
|
|
2938
|
-
registerTriggerCleanupHandle(trigger, cleanup) {
|
|
2939
|
-
const key = this.toTriggerKey(trigger);
|
|
2940
|
-
const cleanups = this.triggerCleanupHandlesByKey.get(key) ?? [];
|
|
2941
|
-
cleanups.push(cleanup);
|
|
2942
|
-
this.triggerCleanupHandlesByKey.set(key, cleanups);
|
|
2943
|
-
}
|
|
2944
|
-
async stopTrigger(trigger) {
|
|
2945
|
-
const key = this.toTriggerKey(trigger);
|
|
2946
|
-
const cleanups = this.triggerCleanupHandlesByKey.get(key) ?? [];
|
|
2947
|
-
this.triggerCleanupHandlesByKey.delete(key);
|
|
2948
|
-
for (const cleanup of [...cleanups].reverse()) await cleanup.stop();
|
|
2949
|
-
}
|
|
2950
|
-
toTriggerKey(trigger) {
|
|
2951
|
-
return `${trigger.workflowId}:${trigger.nodeId}`;
|
|
2952
|
-
}
|
|
2953
|
-
formatTriggerSummaries(wf) {
|
|
2954
|
-
const out = [];
|
|
2955
|
-
for (const def of wf.nodes) {
|
|
2956
|
-
if (def.kind !== "trigger") continue;
|
|
2957
|
-
out.push(this.describeTriggerNode(def));
|
|
2958
|
-
}
|
|
2959
|
-
return out;
|
|
2960
|
-
}
|
|
2961
|
-
describeTriggerNode(def) {
|
|
2962
|
-
const label = def.name !== void 0 && def.name.trim().length > 0 ? def.name.trim() : String(def.id);
|
|
2963
|
-
const cfg = def.config;
|
|
2964
|
-
if (typeof cfg.endpointKey === "string" && cfg.endpointKey.trim().length > 0) return `${label} (webhook "${cfg.endpointKey.trim()}")`;
|
|
2965
|
-
return label;
|
|
2966
|
-
}
|
|
2967
|
-
logInfo(message) {
|
|
2968
|
-
if (this.diagnostics) this.diagnostics.info(message);
|
|
2969
|
-
}
|
|
2970
|
-
logWarn(message) {
|
|
2971
|
-
if (this.diagnostics) this.diagnostics.warn(message);
|
|
2972
|
-
else console.warn(`[engine] ${message}`);
|
|
2973
|
-
}
|
|
2974
|
-
isTestableTriggerNode(node) {
|
|
2975
|
-
return typeof node.getTestItems === "function";
|
|
2976
|
-
}
|
|
2977
|
-
};
|
|
2978
|
-
|
|
2979
|
-
//#endregion
|
|
2980
|
-
//#region src/engine/waiters/EngineWaiters.ts
|
|
2981
|
-
var EngineWaiters = class {
|
|
2982
|
-
completionWaiters = /* @__PURE__ */ new Map();
|
|
2983
|
-
webhookResponseWaiters = /* @__PURE__ */ new Map();
|
|
2984
|
-
waitForCompletion(runId) {
|
|
2985
|
-
return new Promise((resolve) => {
|
|
2986
|
-
const list = this.completionWaiters.get(runId) ?? [];
|
|
2987
|
-
list.push(resolve);
|
|
2988
|
-
this.completionWaiters.set(runId, list);
|
|
2989
|
-
});
|
|
2990
|
-
}
|
|
2991
|
-
waitForWebhookResponse(runId) {
|
|
2992
|
-
return new Promise((resolve) => {
|
|
2993
|
-
const list = this.webhookResponseWaiters.get(runId) ?? [];
|
|
2994
|
-
list.push(resolve);
|
|
2995
|
-
this.webhookResponseWaiters.set(runId, list);
|
|
2996
|
-
});
|
|
2997
|
-
}
|
|
2998
|
-
resolveRunCompletion(result) {
|
|
2999
|
-
if (result.status !== "completed" && result.status !== "failed") return;
|
|
3000
|
-
const list = this.completionWaiters.get(result.runId);
|
|
3001
|
-
if (!list || list.length === 0) return;
|
|
3002
|
-
this.completionWaiters.delete(result.runId);
|
|
3003
|
-
for (const r of list) r(result);
|
|
3004
|
-
}
|
|
3005
|
-
resolveWebhookResponse(result) {
|
|
3006
|
-
const list = this.webhookResponseWaiters.get(result.runId);
|
|
3007
|
-
if (!list || list.length === 0) return;
|
|
3008
|
-
this.webhookResponseWaiters.delete(result.runId);
|
|
3009
|
-
for (const resolve of list) resolve(result);
|
|
3010
|
-
}
|
|
3011
|
-
};
|
|
3012
|
-
|
|
3013
|
-
//#endregion
|
|
3014
|
-
//#region src/engine/api/EngineFactory.ts
|
|
3015
|
-
/**
|
|
3016
|
-
* Composes the {@link Engine} graph from {@link EngineCompositionDeps}. Production wiring usually goes through
|
|
3017
|
-
* {@link import("../runtime/EngineRuntimeRegistrar").EngineRuntimeRegistrar}; this factory remains for tests and custom composition.
|
|
3018
|
-
* Exported from `@codemation/core/bootstrap` (not the main `@codemation/core` barrel).
|
|
3019
|
-
*/
|
|
3020
|
-
var EngineFactory = class {
|
|
3021
|
-
create(deps) {
|
|
3022
|
-
const waiters = new EngineWaiters();
|
|
3023
|
-
const credentialResolverFactory = new CredentialResolverFactory(deps.credentialSessions);
|
|
3024
|
-
const nodeEventPublisher = new NodeEventPublisher(deps.eventBus);
|
|
3025
|
-
const nodeStatePublisherFactory = new NodeExecutionStatePublisherFactory(deps.runStore, nodeEventPublisher);
|
|
3026
|
-
const planningFactory = new EngineWorkflowPlanningFactory(deps.workflowNodeInstanceFactory, new DirectedCycleDetector());
|
|
3027
|
-
const executionLimitsPolicy = deps.executionLimitsPolicy ?? new EngineExecutionLimitsPolicy();
|
|
3028
|
-
const workflowSnapshotFactory = new require_PersistedWorkflowSnapshotFactory.PersistedWorkflowSnapshotFactory(deps.tokenRegistry);
|
|
3029
|
-
const persistedWorkflowConfigHydrator = deps.persistedWorkflowConfigHydrator ?? new PersistedWorkflowConfigHydrator(deps.tokenRegistry);
|
|
3030
|
-
const missingRuntimeNodeDefinitionFactory = deps.missingRuntimeNodeDefinitionFactory ?? new MissingRuntimeNodeDefinitionFactory();
|
|
3031
|
-
const workflowSnapshotResolver = new PersistedWorkflowResolver(deps.workflowRepository, deps.tokenRegistry, persistedWorkflowConfigHydrator, missingRuntimeNodeDefinitionFactory);
|
|
3032
|
-
const semantics = new RunStateSemantics();
|
|
3033
|
-
const activationEnqueueService = new ActivationEnqueueService(deps.activationScheduler, deps.runStore, nodeEventPublisher);
|
|
3034
|
-
const runExecutionContextFactory = new WorkflowRunExecutionContextFactory(deps.executionContextFactory, credentialResolverFactory);
|
|
3035
|
-
const nodeActivationRequestComposer = new NodeActivationRequestComposer(deps.activationIdFactory, credentialResolverFactory);
|
|
3036
|
-
const persistedRunStateTerminalBuilder = new PersistedRunStateTerminalBuilder();
|
|
3037
|
-
const storagePolicyEvaluator = new WorkflowStoragePolicyEvaluator(deps.nodeResolver);
|
|
3038
|
-
const terminalPersistence = new RunTerminalPersistenceCoordinator(deps.runStore, storagePolicyEvaluator);
|
|
3039
|
-
const policyErrorServices = new WorkflowPolicyErrorServices(deps.nodeResolver);
|
|
3040
|
-
const workflowRunStarter = new WorkflowRunStarter(deps.runIdFactory, deps.runStore, deps.runDataFactory, workflowSnapshotFactory, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, waiters, deps.workflowPolicyRuntimeDefaults, executionLimitsPolicy);
|
|
3041
|
-
const currentStateRunStarter = new CurrentStateRunStarter(deps.runIdFactory, deps.runStore, deps.runDataFactory, workflowSnapshotFactory, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, deps.workflowPolicyRuntimeDefaults, executionLimitsPolicy);
|
|
3042
|
-
const runContinuationService = new RunContinuationService(deps.activationIdFactory, deps.runStore, deps.runDataFactory, runExecutionContextFactory, workflowSnapshotResolver, planningFactory, nodeStatePublisherFactory, credentialResolverFactory, nodeActivationRequestComposer, persistedRunStateTerminalBuilder, activationEnqueueService, nodeEventPublisher, semantics, waiters, policyErrorServices, terminalPersistence, executionLimitsPolicy);
|
|
3043
|
-
const triggerRuntime = new TriggerRuntimeService(deps.workflowRepository, deps.workflowActivationPolicy, deps.runIdFactory, deps.runDataFactory, deps.executionContextFactory, credentialResolverFactory, nodeStatePublisherFactory, deps.nodeResolver, deps.triggerSetupStateStore, { emit: async (workflow, triggerNodeId, items) => {
|
|
3044
|
-
await workflowRunStarter.runWorkflow(workflow, triggerNodeId, items, void 0);
|
|
3045
|
-
} }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics);
|
|
3046
|
-
const engine = new Engine({
|
|
3047
|
-
workflowCatalog: deps.workflowCatalog,
|
|
3048
|
-
tokenRegistry: deps.tokenRegistry,
|
|
3049
|
-
webhookTriggerMatcher: deps.webhookTriggerMatcher,
|
|
3050
|
-
workflowSnapshotResolver,
|
|
3051
|
-
triggerRuntime,
|
|
3052
|
-
workflowRunStarter,
|
|
3053
|
-
currentStateRunStarter,
|
|
3054
|
-
runContinuationService
|
|
3055
|
-
});
|
|
3056
|
-
deps.activationScheduler.setContinuation?.(engine);
|
|
3057
|
-
return engine;
|
|
3058
|
-
}
|
|
3059
|
-
};
|
|
3060
|
-
|
|
3061
|
-
//#endregion
|
|
3062
|
-
Object.defineProperty(exports, 'ConnectionNodeIdFactory', {
|
|
3063
|
-
enumerable: true,
|
|
3064
|
-
get: function () {
|
|
3065
|
-
return ConnectionNodeIdFactory;
|
|
3066
|
-
}
|
|
3067
|
-
});
|
|
3068
|
-
Object.defineProperty(exports, 'CredentialResolverFactory', {
|
|
3069
|
-
enumerable: true,
|
|
3070
|
-
get: function () {
|
|
3071
|
-
return CredentialResolverFactory;
|
|
3072
|
-
}
|
|
3073
|
-
});
|
|
3074
|
-
Object.defineProperty(exports, 'ENGINE_EXECUTION_LIMITS_DEFAULTS', {
|
|
3075
|
-
enumerable: true,
|
|
3076
|
-
get: function () {
|
|
3077
|
-
return ENGINE_EXECUTION_LIMITS_DEFAULTS;
|
|
3078
|
-
}
|
|
3079
|
-
});
|
|
3080
|
-
Object.defineProperty(exports, 'Engine', {
|
|
3081
|
-
enumerable: true,
|
|
3082
|
-
get: function () {
|
|
3083
|
-
return Engine;
|
|
3084
|
-
}
|
|
3085
|
-
});
|
|
3086
|
-
Object.defineProperty(exports, 'EngineExecutionLimitsPolicy', {
|
|
3087
|
-
enumerable: true,
|
|
3088
|
-
get: function () {
|
|
3089
|
-
return EngineExecutionLimitsPolicy;
|
|
3090
|
-
}
|
|
3091
|
-
});
|
|
3092
|
-
Object.defineProperty(exports, 'EngineFactory', {
|
|
3093
|
-
enumerable: true,
|
|
3094
|
-
get: function () {
|
|
3095
|
-
return EngineFactory;
|
|
3096
|
-
}
|
|
3097
|
-
});
|
|
3098
|
-
Object.defineProperty(exports, 'MissingRuntimeNodeToken', {
|
|
3099
|
-
enumerable: true,
|
|
3100
|
-
get: function () {
|
|
3101
|
-
return MissingRuntimeNodeToken;
|
|
3102
|
-
}
|
|
3103
|
-
});
|
|
3104
|
-
Object.defineProperty(exports, 'MissingRuntimeTriggerToken', {
|
|
3105
|
-
enumerable: true,
|
|
3106
|
-
get: function () {
|
|
3107
|
-
return MissingRuntimeTriggerToken;
|
|
3108
|
-
}
|
|
3109
|
-
});
|
|
3110
|
-
Object.defineProperty(exports, 'NodeEventPublisher', {
|
|
3111
|
-
enumerable: true,
|
|
3112
|
-
get: function () {
|
|
3113
|
-
return NodeEventPublisher;
|
|
3114
|
-
}
|
|
3115
|
-
});
|
|
3116
|
-
Object.defineProperty(exports, 'RunPolicySnapshotFactory', {
|
|
3117
|
-
enumerable: true,
|
|
3118
|
-
get: function () {
|
|
3119
|
-
return RunPolicySnapshotFactory;
|
|
3120
|
-
}
|
|
3121
|
-
});
|
|
3122
|
-
Object.defineProperty(exports, 'RunTerminalPersistenceCoordinator', {
|
|
3123
|
-
enumerable: true,
|
|
3124
|
-
get: function () {
|
|
3125
|
-
return RunTerminalPersistenceCoordinator;
|
|
3126
|
-
}
|
|
3127
|
-
});
|
|
3128
|
-
Object.defineProperty(exports, 'WorkflowExecutableNodeClassifier', {
|
|
3129
|
-
enumerable: true,
|
|
3130
|
-
get: function () {
|
|
3131
|
-
return WorkflowExecutableNodeClassifier;
|
|
3132
|
-
}
|
|
3133
|
-
});
|
|
3134
|
-
Object.defineProperty(exports, 'WorkflowPolicyErrorServices', {
|
|
3135
|
-
enumerable: true,
|
|
3136
|
-
get: function () {
|
|
3137
|
-
return WorkflowPolicyErrorServices;
|
|
3138
|
-
}
|
|
3139
|
-
});
|
|
3140
|
-
Object.defineProperty(exports, 'WorkflowStoragePolicyEvaluator', {
|
|
3141
|
-
enumerable: true,
|
|
3142
|
-
get: function () {
|
|
3143
|
-
return WorkflowStoragePolicyEvaluator;
|
|
3144
|
-
}
|
|
3145
|
-
});
|
|
3146
|
-
Object.defineProperty(exports, 'createWorkflowExecutableNodeClassifier', {
|
|
3147
|
-
enumerable: true,
|
|
3148
|
-
get: function () {
|
|
3149
|
-
return createWorkflowExecutableNodeClassifier;
|
|
3150
|
-
}
|
|
3151
|
-
});
|
|
3152
|
-
//# sourceMappingURL=EngineFactory-CBnntY3J.cjs.map
|