@codemation/core 0.3.0 → 0.5.0
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/CHANGELOG.md +23 -0
- package/dist/{EngineRuntimeRegistration.types-Bjeo7Sfq.d.ts → EngineRuntimeRegistration.types-BtTZolK0.d.ts} +2 -2
- package/dist/{EngineWorkflowRunnerService-Dd4yD31l.d.cts → EngineWorkflowRunnerService-Ddl0fekp.d.cts} +2 -2
- package/dist/{InMemoryRunDataFactory-OUzDmAHt.d.cts → InMemoryRunDataFactory-i-u2yngD.d.cts} +11 -3
- package/dist/{RunIntentService-Bkg4oYrM.d.cts → RunIntentService-Cjx-glgz.d.cts} +232 -237
- package/dist/{RunIntentService-BAKikN8h.d.ts → RunIntentService-Dkr4YwN8.d.ts} +313 -259
- package/dist/bootstrap/index.cjs +2 -2
- package/dist/bootstrap/index.d.cts +19 -7
- package/dist/bootstrap/index.d.ts +3 -3
- package/dist/bootstrap/index.js +2 -2
- package/dist/{bootstrap-DwS5S7s9.cjs → bootstrap-DHH2uo-W.cjs} +4 -2
- package/dist/bootstrap-DHH2uo-W.cjs.map +1 -0
- package/dist/{bootstrap-BD6CobHl.js → bootstrap-DbUlOl11.js} +4 -2
- package/dist/bootstrap-DbUlOl11.js.map +1 -0
- package/dist/{index-uCm9l0nw.d.ts → index-B2v4wtys.d.ts} +62 -34
- package/dist/index.cjs +22 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +108 -42
- package/dist/index.d.ts +3 -3
- package/dist/index.js +13 -16
- package/dist/index.js.map +1 -1
- package/dist/{runtime-Cy-3FTI_.js → runtime-BdH94eBR.js} +502 -123
- package/dist/runtime-BdH94eBR.js.map +1 -0
- package/dist/{runtime-ZJUpWmPH.cjs → runtime-feFn8OmG.cjs} +561 -122
- package/dist/runtime-feFn8OmG.cjs.map +1 -0
- package/dist/testing.cjs +40 -36
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +17 -26
- package/dist/testing.d.ts +17 -26
- package/dist/testing.js +40 -36
- package/dist/testing.js.map +1 -1
- package/dist/{workflowActivationPolicy-BzyzXLa_.cjs → workflowActivationPolicy-6V3OJD3N.cjs} +65 -19
- package/dist/workflowActivationPolicy-6V3OJD3N.cjs.map +1 -0
- package/dist/{workflowActivationPolicy-B8HzTk3o.js → workflowActivationPolicy-Td9HTOuD.js} +65 -19
- package/dist/workflowActivationPolicy-Td9HTOuD.js.map +1 -0
- package/package.json +2 -1
- package/src/ai/AgentConfigInspectorFactory.ts +4 -0
- package/src/ai/AgentMessageConfigNormalizerFactory.ts +7 -0
- package/src/ai/AgentToolFactory.ts +2 -2
- package/src/ai/AiHost.ts +11 -10
- package/src/ai/NodeBackedToolConfig.ts +1 -1
- package/src/authoring/defineNode.types.ts +48 -72
- package/src/authoring/index.ts +1 -1
- package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +8 -0
- package/src/contracts/credentialTypes.ts +9 -0
- package/src/contracts/emitPorts.ts +27 -0
- package/src/contracts/index.ts +3 -0
- package/src/contracts/itemMeta.ts +11 -0
- package/src/contracts/itemValue.ts +147 -0
- package/src/contracts/runtimeTypes.ts +39 -22
- package/src/contracts/workflowTypes.ts +26 -56
- package/src/execution/FanInMergeByOriginMerger.ts +67 -0
- package/src/execution/ItemValueResolver.ts +27 -0
- package/src/execution/NodeActivationRequestComposer.ts +25 -0
- package/src/execution/NodeActivationRequestInputPreparer.ts +57 -25
- package/src/execution/NodeExecutor.ts +199 -30
- package/src/execution/NodeOutputNormalizer.ts +90 -0
- package/src/execution/index.ts +2 -0
- package/src/index.ts +2 -0
- package/src/orchestration/NodeExecutionRequestHandlerService.ts +39 -18
- package/src/orchestration/RunContinuationService.ts +11 -17
- package/src/planning/CurrentStateFrontierPlanner.ts +20 -20
- package/src/planning/RunQueuePlanner.ts +56 -19
- package/src/planning/WorkflowTopologyPlanner.ts +57 -33
- package/src/testing/ItemHarnessNode.ts +4 -10
- package/src/testing/ItemHarnessNodeConfig.ts +7 -16
- package/src/testing/RegistrarEngineTestKitFactory.ts +2 -0
- package/src/testing/SubWorkflowRunnerTestNode.ts +28 -43
- package/src/testing/SwitchHarnessNode.ts +54 -0
- package/src/types/index.ts +3 -0
- package/src/workflow/dsl/ChainCursorResolver.ts +68 -23
- package/src/workflow/dsl/WorkflowBuilder.ts +3 -5
- package/src/workflow/dsl/workflowBuilderTypes.ts +5 -8
- package/src/workflowSnapshots/MissingRuntimeNode.ts +4 -4
- package/src/workflowSnapshots/MissingRuntimeNodeConfig.ts +2 -2
- package/src/workflowSnapshots/WorkflowSnapshotCodec.ts +16 -7
- package/dist/bootstrap-BD6CobHl.js.map +0 -1
- package/dist/bootstrap-DwS5S7s9.cjs.map +0 -1
- package/dist/runtime-Cy-3FTI_.js.map +0 -1
- package/dist/runtime-ZJUpWmPH.cjs.map +0 -1
- package/dist/workflowActivationPolicy-B8HzTk3o.js.map +0 -1
- package/dist/workflowActivationPolicy-BzyzXLa_.cjs.map +0 -1
|
@@ -164,6 +164,74 @@ function chatModel(options = {}) {
|
|
|
164
164
|
return InjectableRuntimeDecoratorComposer.compose("chatModel", options, require("url").pathToFileURL(__filename).href);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/contracts/itemValue.ts
|
|
169
|
+
const ITEM_VALUE_BRAND = Symbol.for("codemation.itemValue");
|
|
170
|
+
function itemValue(fn) {
|
|
171
|
+
return {
|
|
172
|
+
[ITEM_VALUE_BRAND]: true,
|
|
173
|
+
fn
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function isItemValue(value) {
|
|
177
|
+
if (typeof value !== "object" || value === null) return false;
|
|
178
|
+
const v = value;
|
|
179
|
+
if (v[ITEM_VALUE_BRAND] === true) return true;
|
|
180
|
+
const keys = Object.keys(v);
|
|
181
|
+
if (keys.length === 1 && keys[0] === "fn" && typeof v.fn === "function") return true;
|
|
182
|
+
for (const sym of Object.getOwnPropertySymbols(v)) if (sym.description === "codemation.itemValue" && v[sym] === true) return true;
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
function containsItemValueInUnknown(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
186
|
+
if (isItemValue(value)) return true;
|
|
187
|
+
if (value === null || typeof value !== "object") return false;
|
|
188
|
+
if (seen.has(value)) return false;
|
|
189
|
+
seen.add(value);
|
|
190
|
+
if (Array.isArray(value)) return value.some((entry) => containsItemValueInUnknown(entry, seen));
|
|
191
|
+
for (const entry of Object.values(value)) if (containsItemValueInUnknown(entry, seen)) return true;
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Deep-resolves {@link itemValue} leaves. Returns a new graph (does not mutate the original config object).
|
|
196
|
+
*/
|
|
197
|
+
async function resolveItemValuesInUnknown(value, args, seen = /* @__PURE__ */ new WeakSet()) {
|
|
198
|
+
if (isItemValue(value)) return await Promise.resolve(value.fn(args));
|
|
199
|
+
if (value === null || typeof value !== "object") return value;
|
|
200
|
+
if (seen.has(value)) return value;
|
|
201
|
+
seen.add(value);
|
|
202
|
+
if (Array.isArray(value)) {
|
|
203
|
+
const out$1 = [];
|
|
204
|
+
for (let i = 0; i < value.length; i++) out$1.push(await resolveItemValuesInUnknown(value[i], args, seen));
|
|
205
|
+
return out$1;
|
|
206
|
+
}
|
|
207
|
+
const rec = value;
|
|
208
|
+
const entries = Object.entries(rec);
|
|
209
|
+
const proto = Object.getPrototypeOf(value);
|
|
210
|
+
if (proto !== Object.prototype && proto !== null && entries.length === 0) return value;
|
|
211
|
+
const out = Object.create(proto);
|
|
212
|
+
for (const [k, v] of entries) out[k] = await resolveItemValuesInUnknown(v, args, seen);
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Clones runnable config (best-effort) so per-item {@link itemValue} resolution never mutates shared instances.
|
|
217
|
+
*/
|
|
218
|
+
async function resolveItemValuesForExecution(config, nodeCtx, item, itemIndex, items) {
|
|
219
|
+
const ivArgs = {
|
|
220
|
+
item,
|
|
221
|
+
itemIndex,
|
|
222
|
+
items,
|
|
223
|
+
ctx: {
|
|
224
|
+
runId: nodeCtx.runId,
|
|
225
|
+
workflowId: nodeCtx.workflowId,
|
|
226
|
+
nodeId: nodeCtx.nodeId,
|
|
227
|
+
activationId: nodeCtx.activationId,
|
|
228
|
+
data: nodeCtx.data
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
if (!containsItemValueInUnknown(config)) return;
|
|
232
|
+
return await resolveItemValuesInUnknown(config, ivArgs);
|
|
233
|
+
}
|
|
234
|
+
|
|
167
235
|
//#endregion
|
|
168
236
|
//#region src/workflow/definition/ConnectionNodeIdFactory.ts
|
|
169
237
|
/**
|
|
@@ -591,6 +659,64 @@ var ActivationEnqueueService = class {
|
|
|
591
659
|
}
|
|
592
660
|
};
|
|
593
661
|
|
|
662
|
+
//#endregion
|
|
663
|
+
//#region src/contracts/itemMeta.ts
|
|
664
|
+
/**
|
|
665
|
+
* Reads `meta._cm.originIndex` when present (used for fan-in merge-by-origin and Merge routing).
|
|
666
|
+
*/
|
|
667
|
+
function getOriginIndexFromItem(item) {
|
|
668
|
+
const v = (item.meta?._cm)?.originIndex;
|
|
669
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
//#endregion
|
|
673
|
+
//#region src/execution/FanInMergeByOriginMerger.ts
|
|
674
|
+
/**
|
|
675
|
+
* Default fan-in: combine multi-port {@link NodeInputsByPort} into one {@link Items} batch for per-item nodes.
|
|
676
|
+
*
|
|
677
|
+
* This is used when a single-input per-item node has multiple inbound edges (for example, branch reconverge
|
|
678
|
+
* after an `If` / `Switch`). The default behavior is **append / union** (preserving item payloads) with a
|
|
679
|
+
* deterministic order:
|
|
680
|
+
*
|
|
681
|
+
* - When router origin metadata exists (`meta._cm.originIndex`), items are sorted by origin index so the
|
|
682
|
+
* downstream batch preserves original ordering across branches.
|
|
683
|
+
* - Otherwise, items are appended by port-key order, preserving each port's local order.
|
|
684
|
+
*/
|
|
685
|
+
var FanInMergeByOriginMerger = class {
|
|
686
|
+
merge(inputsByPort) {
|
|
687
|
+
const portKeys = Object.keys(inputsByPort).sort();
|
|
688
|
+
if (portKeys.length === 0) return [];
|
|
689
|
+
if (portKeys.length === 1) return [...inputsByPort[portKeys[0]] ?? []];
|
|
690
|
+
const entries = [];
|
|
691
|
+
let anyOrigin = false;
|
|
692
|
+
for (let p = 0; p < portKeys.length; p++) {
|
|
693
|
+
const portKey = portKeys[p];
|
|
694
|
+
const items = inputsByPort[portKey] ?? [];
|
|
695
|
+
for (let i = 0; i < items.length; i++) {
|
|
696
|
+
const item = items[i];
|
|
697
|
+
const originIndex = getOriginIndexFromItem(item);
|
|
698
|
+
if (originIndex !== void 0) anyOrigin = true;
|
|
699
|
+
entries.push({
|
|
700
|
+
portKey,
|
|
701
|
+
portIndex: i,
|
|
702
|
+
item,
|
|
703
|
+
originIndex
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
if (!anyOrigin) return entries.map((e) => e.item);
|
|
708
|
+
const missingOriginRank = Number.MAX_SAFE_INTEGER;
|
|
709
|
+
return entries.slice().sort((a, b) => {
|
|
710
|
+
const ao = a.originIndex ?? missingOriginRank;
|
|
711
|
+
const bo = b.originIndex ?? missingOriginRank;
|
|
712
|
+
if (ao !== bo) return ao - bo;
|
|
713
|
+
const pk = a.portKey.localeCompare(b.portKey);
|
|
714
|
+
if (pk !== 0) return pk;
|
|
715
|
+
return a.portIndex - b.portIndex;
|
|
716
|
+
}).map((e) => e.item);
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
|
|
594
720
|
//#endregion
|
|
595
721
|
//#region src/execution/NodeInputContractError.ts
|
|
596
722
|
var NodeInputContractError = class extends Error {
|
|
@@ -606,45 +732,58 @@ var NodeInputContractError = class extends Error {
|
|
|
606
732
|
//#endregion
|
|
607
733
|
//#region src/execution/NodeActivationRequestInputPreparer.ts
|
|
608
734
|
/**
|
|
609
|
-
*
|
|
735
|
+
* Validates per-item inputs for {@link RunnableNode} before enqueue persistence (Zod on `item.json`).
|
|
736
|
+
* Does not rewrite `item.json` (wire stays as emitted upstream; engine passes parsed input via `execute` args).
|
|
737
|
+
* Converts multi-input activations into a single-input batch when the node is per-item only (engine fan-in).
|
|
610
738
|
*/
|
|
611
739
|
var NodeActivationRequestInputPreparer = class {
|
|
740
|
+
fanInMerger = new FanInMergeByOriginMerger();
|
|
612
741
|
constructor(workflowNodeInstanceFactory) {
|
|
613
742
|
this.workflowNodeInstanceFactory = workflowNodeInstanceFactory;
|
|
614
743
|
}
|
|
615
744
|
async prepare(request) {
|
|
616
|
-
if (request.kind
|
|
745
|
+
if (request.kind === "multi") return await this.prepareMulti(request);
|
|
746
|
+
return await this.prepareSingle(request);
|
|
747
|
+
}
|
|
748
|
+
async prepareMulti(request) {
|
|
617
749
|
const nodeInstance = this.workflowNodeInstanceFactory.createByType(request.ctx.config.type);
|
|
618
|
-
if (!this.
|
|
750
|
+
if (!this.hasRunnableExecute(nodeInstance) || this.hasExecuteMulti(nodeInstance) || this.isTriggerNode(nodeInstance)) return request;
|
|
751
|
+
const merged = this.fanInMerger.merge(request.inputsByPort);
|
|
752
|
+
const single = {
|
|
753
|
+
...request,
|
|
754
|
+
kind: "single",
|
|
755
|
+
input: merged
|
|
756
|
+
};
|
|
757
|
+
return await this.prepareSingle(single);
|
|
758
|
+
}
|
|
759
|
+
async prepareSingle(request) {
|
|
760
|
+
const nodeInstance = this.workflowNodeInstanceFactory.createByType(request.ctx.config.type);
|
|
761
|
+
if (!this.hasRunnableExecute(nodeInstance) || this.isTriggerNode(nodeInstance)) return request;
|
|
619
762
|
const inputSchema = this.resolveInputSchema(nodeInstance, request.ctx.config);
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
const item = request.input[i];
|
|
763
|
+
const inputBatch = request.input ?? [];
|
|
764
|
+
for (let i = 0; i < inputBatch.length; i++) {
|
|
765
|
+
const item = inputBatch[i];
|
|
624
766
|
try {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
itemIndex: i,
|
|
628
|
-
items: request.input,
|
|
629
|
-
ctx: request.ctx
|
|
630
|
-
})) : item.json;
|
|
631
|
-
const parsed = inputSchema.parse(mappedRaw);
|
|
632
|
-
mappedItems.push({
|
|
633
|
-
...item,
|
|
634
|
-
json: parsed
|
|
635
|
-
});
|
|
767
|
+
if (Array.isArray(item.json)) throw new Error("Item JSON must not be a top-level array");
|
|
768
|
+
inputSchema.parse(item.json);
|
|
636
769
|
} catch (cause) {
|
|
637
770
|
const message = this.formatContractFailure(cause);
|
|
638
771
|
throw new NodeInputContractError(`Node ${request.nodeId} activation ${request.activationId}: input contract failed: ${message}`, request.nodeId, request.activationId, cause);
|
|
639
772
|
}
|
|
640
773
|
}
|
|
641
|
-
return {
|
|
774
|
+
return request.input === void 0 ? {
|
|
642
775
|
...request,
|
|
643
|
-
input:
|
|
644
|
-
};
|
|
776
|
+
input: inputBatch
|
|
777
|
+
} : request;
|
|
778
|
+
}
|
|
779
|
+
isTriggerNode(nodeInstance) {
|
|
780
|
+
return typeof nodeInstance === "object" && nodeInstance !== null && nodeInstance.kind === "trigger";
|
|
781
|
+
}
|
|
782
|
+
hasRunnableExecute(nodeInstance) {
|
|
783
|
+
return typeof nodeInstance === "object" && nodeInstance !== null && nodeInstance.kind === "node" && typeof nodeInstance.execute === "function";
|
|
645
784
|
}
|
|
646
|
-
|
|
647
|
-
return typeof nodeInstance
|
|
785
|
+
hasExecuteMulti(nodeInstance) {
|
|
786
|
+
return typeof nodeInstance.executeMulti === "function";
|
|
648
787
|
}
|
|
649
788
|
resolveInputSchema(nodeInstance, config) {
|
|
650
789
|
const fromInstance = nodeInstance.inputSchema;
|
|
@@ -801,6 +940,87 @@ var InProcessRetryRunner = class InProcessRetryRunner {
|
|
|
801
940
|
}
|
|
802
941
|
};
|
|
803
942
|
|
|
943
|
+
//#endregion
|
|
944
|
+
//#region src/execution/ItemValueResolver.ts
|
|
945
|
+
/**
|
|
946
|
+
* Resolves {@link import("../contracts/itemValue").ItemValue} leaves on runnable config before {@link RunnableNode.execute}.
|
|
947
|
+
*/
|
|
948
|
+
var ItemValueResolver = class {
|
|
949
|
+
async resolveConfigForItem(ctx, item, itemIndex, items) {
|
|
950
|
+
if (!ctx) throw new Error("ItemValueResolver.resolveConfigForItem: ctx is required");
|
|
951
|
+
const resolvedConfig = await resolveItemValuesForExecution(ctx.config, ctx, item, itemIndex, items);
|
|
952
|
+
const merged = resolvedConfig !== void 0 && resolvedConfig !== null ? resolvedConfig : ctx.config;
|
|
953
|
+
if (merged === void 0 || merged === null) return ctx;
|
|
954
|
+
return {
|
|
955
|
+
...ctx,
|
|
956
|
+
config: merged
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
//#endregion
|
|
962
|
+
//#region src/contracts/emitPorts.ts
|
|
963
|
+
const EMIT_PORTS_BRAND = Symbol.for("codemation.emitPorts");
|
|
964
|
+
function emitPorts(ports) {
|
|
965
|
+
return {
|
|
966
|
+
[EMIT_PORTS_BRAND]: true,
|
|
967
|
+
ports
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
function isPortsEmission(value) {
|
|
971
|
+
return typeof value === "object" && value !== null && EMIT_PORTS_BRAND in value && value[EMIT_PORTS_BRAND] === true;
|
|
972
|
+
}
|
|
973
|
+
function isUnbrandedPortsEmissionShape(value) {
|
|
974
|
+
return typeof value === "object" && value !== null && "ports" in value && !isPortsEmission(value);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
//#endregion
|
|
978
|
+
//#region src/execution/NodeOutputNormalizer.ts
|
|
979
|
+
var NodeOutputNormalizer = class {
|
|
980
|
+
normalizeExecuteResult(args) {
|
|
981
|
+
const { baseItem, raw, carry } = args;
|
|
982
|
+
if (isPortsEmission(raw)) return this.emitPortsToOutputs(baseItem, raw, carry);
|
|
983
|
+
if (isUnbrandedPortsEmissionShape(raw)) throw new Error("execute() returned an unbranded `{ ports: ... }` object. Use emitPorts(...) for multi-port runnable outputs.");
|
|
984
|
+
if (Array.isArray(raw)) return this.arrayFanOutToMain(baseItem, raw, carry);
|
|
985
|
+
if (this.isItemLike(raw)) return { main: [this.applyLineage(baseItem, raw, carry)] };
|
|
986
|
+
return { main: [this.applyLineage(baseItem, { json: raw }, carry)] };
|
|
987
|
+
}
|
|
988
|
+
arrayFanOutToMain(baseItem, raw, carry) {
|
|
989
|
+
for (const el of raw) if (Array.isArray(el)) throw new Error("execute() fan-out arrays must contain only non-array JSON elements (nested arrays belong inside objects).");
|
|
990
|
+
return { main: raw.map((json) => this.applyLineage(baseItem, { json }, carry)) };
|
|
991
|
+
}
|
|
992
|
+
emitPortsToOutputs(baseItem, emission, carry) {
|
|
993
|
+
const out = {};
|
|
994
|
+
for (const [port, payload] of Object.entries(emission.ports)) {
|
|
995
|
+
if (payload === void 0) continue;
|
|
996
|
+
out[port] = this.normalizePortPayload(baseItem, payload, carry);
|
|
997
|
+
}
|
|
998
|
+
return out;
|
|
999
|
+
}
|
|
1000
|
+
normalizePortPayload(baseItem, payload, carry) {
|
|
1001
|
+
if (payload.length === 0) return [];
|
|
1002
|
+
const el0 = payload[0];
|
|
1003
|
+
if (this.isItemLike(el0)) return payload.map((it) => this.applyLineage(baseItem, it, carry));
|
|
1004
|
+
return payload.map((json) => this.applyLineage(baseItem, { json }, carry));
|
|
1005
|
+
}
|
|
1006
|
+
isItemLike(value) {
|
|
1007
|
+
return typeof value === "object" && value !== null && "json" in value;
|
|
1008
|
+
}
|
|
1009
|
+
applyLineage(baseItem, next, carry) {
|
|
1010
|
+
if (carry === "carryThrough") return {
|
|
1011
|
+
...baseItem,
|
|
1012
|
+
...next,
|
|
1013
|
+
json: next.json
|
|
1014
|
+
};
|
|
1015
|
+
return {
|
|
1016
|
+
json: next.json,
|
|
1017
|
+
...next.binary ? { binary: next.binary } : {},
|
|
1018
|
+
...next.meta ? { meta: next.meta } : {},
|
|
1019
|
+
...next.paired ? { paired: next.paired } : {}
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
};
|
|
1023
|
+
|
|
804
1024
|
//#endregion
|
|
805
1025
|
//#region src/execution/InProcessRetryRunnerFactory.ts
|
|
806
1026
|
var InProcessRetryRunnerFactory = class {
|
|
@@ -840,6 +1060,21 @@ var NodeActivationRequestComposer = class {
|
|
|
840
1060
|
ctx
|
|
841
1061
|
};
|
|
842
1062
|
}
|
|
1063
|
+
createMultiFromDefinitionWithActivation(args) {
|
|
1064
|
+
const ctx = this.createNodeExecutionContext(args, args.definition, args.activationId);
|
|
1065
|
+
return {
|
|
1066
|
+
kind: "multi",
|
|
1067
|
+
runId: args.runId,
|
|
1068
|
+
activationId: args.activationId,
|
|
1069
|
+
workflowId: args.workflowId,
|
|
1070
|
+
nodeId: args.definition.id,
|
|
1071
|
+
parent: args.parent,
|
|
1072
|
+
executionOptions: args.executionOptions,
|
|
1073
|
+
batchId: args.batchId,
|
|
1074
|
+
inputsByPort: args.inputsByPort,
|
|
1075
|
+
ctx
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
843
1078
|
createFromPlannedActivation(args) {
|
|
844
1079
|
const activationId = this.activationIdFactory.makeActivationId();
|
|
845
1080
|
const ctx = this.createNodeExecutionContext(args, args.nodeDefinition, activationId);
|
|
@@ -887,49 +1122,152 @@ var NodeActivationRequestComposer = class {
|
|
|
887
1122
|
//#endregion
|
|
888
1123
|
//#region src/execution/NodeExecutor.ts
|
|
889
1124
|
var NodeExecutor = class {
|
|
890
|
-
|
|
1125
|
+
fanInMerger = new FanInMergeByOriginMerger();
|
|
1126
|
+
outputNormalizer = new NodeOutputNormalizer();
|
|
1127
|
+
itemValueResolver;
|
|
1128
|
+
constructor(nodeInstanceFactory, retryRunner, itemValueResolver) {
|
|
891
1129
|
this.nodeInstanceFactory = nodeInstanceFactory;
|
|
892
1130
|
this.retryRunner = retryRunner;
|
|
1131
|
+
this.itemValueResolver = itemValueResolver ?? new ItemValueResolver();
|
|
893
1132
|
}
|
|
894
1133
|
async execute(request) {
|
|
895
1134
|
const policy = request.ctx.config.retryPolicy;
|
|
896
1135
|
return await this.retryRunner.run(policy, async () => {
|
|
897
1136
|
const nodeInstance = this.nodeInstanceFactory.createByType(request.ctx.config.type);
|
|
898
|
-
if (request.kind === "multi") return await this.
|
|
1137
|
+
if (request.kind === "multi") return await this.executeMultiInputActivation(request, nodeInstance);
|
|
899
1138
|
return await this.executeSingleInputNode(request, nodeInstance);
|
|
900
1139
|
});
|
|
901
1140
|
}
|
|
902
|
-
async
|
|
1141
|
+
async executeMultiInputActivation(request, node$1) {
|
|
903
1142
|
const multiInputNode = node$1;
|
|
904
|
-
if (typeof multiInputNode.executeMulti
|
|
905
|
-
|
|
1143
|
+
if (typeof multiInputNode.executeMulti === "function") {
|
|
1144
|
+
const raw = await multiInputNode.executeMulti(request.inputsByPort, request.ctx);
|
|
1145
|
+
this.assertNoPortEnvelopeBypass(request.nodeId, raw, "executeMulti()");
|
|
1146
|
+
return raw;
|
|
1147
|
+
}
|
|
1148
|
+
if (this.isRunnableNode(node$1)) {
|
|
1149
|
+
const merged = this.fanInMerger.merge(request.inputsByPort);
|
|
1150
|
+
const single = {
|
|
1151
|
+
...request,
|
|
1152
|
+
kind: "single",
|
|
1153
|
+
input: merged
|
|
1154
|
+
};
|
|
1155
|
+
return await this.executeRunnableActivation(single, node$1);
|
|
1156
|
+
}
|
|
1157
|
+
throw new Error(`Node ${request.nodeId} does not support executeMulti or RunnableNode.execute but received multi-input activation`);
|
|
906
1158
|
}
|
|
907
1159
|
async executeSingleInputNode(request, node$1) {
|
|
908
|
-
if (this.
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1160
|
+
if (this.isTriggerNode(node$1)) {
|
|
1161
|
+
const raw = await node$1.execute(request.input, request.ctx);
|
|
1162
|
+
this.assertNoPortEnvelopeBypass(request.nodeId, raw, "trigger execute()");
|
|
1163
|
+
return raw;
|
|
1164
|
+
}
|
|
1165
|
+
if (this.isRunnableNode(node$1)) return await this.executeRunnableActivation(request, node$1);
|
|
1166
|
+
if (this.hasExecuteMulti(node$1)) return await this.executeMultiInputActivation(this.asMultiFromSingleActivation(request), node$1);
|
|
1167
|
+
throw new Error(`Node ${request.nodeId} does not support trigger or RunnableNode execution`);
|
|
912
1168
|
}
|
|
913
|
-
|
|
914
|
-
return typeof node$1 === "object" && node$1 !== null &&
|
|
1169
|
+
isTriggerNode(node$1) {
|
|
1170
|
+
return typeof node$1 === "object" && node$1 !== null && node$1.kind === "trigger";
|
|
915
1171
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1172
|
+
isRunnableNode(node$1) {
|
|
1173
|
+
return typeof node$1 === "object" && node$1 !== null && node$1.kind === "node" && typeof node$1.execute === "function";
|
|
1174
|
+
}
|
|
1175
|
+
hasExecuteMulti(node$1) {
|
|
1176
|
+
return typeof node$1?.executeMulti === "function";
|
|
1177
|
+
}
|
|
1178
|
+
asMultiFromSingleActivation(request) {
|
|
1179
|
+
return {
|
|
1180
|
+
kind: "multi",
|
|
1181
|
+
runId: request.runId,
|
|
1182
|
+
activationId: request.activationId,
|
|
1183
|
+
workflowId: request.workflowId,
|
|
1184
|
+
nodeId: request.nodeId,
|
|
1185
|
+
parent: request.parent,
|
|
1186
|
+
executionOptions: request.executionOptions,
|
|
1187
|
+
batchId: request.batchId,
|
|
1188
|
+
ctx: request.ctx,
|
|
1189
|
+
inputsByPort: { in: request.input ?? [] }
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
async executeRunnableActivation(request, node$1) {
|
|
1193
|
+
const runnableConfig = request.ctx.config;
|
|
1194
|
+
const carry = this.resolveLineageCarry(node$1, runnableConfig);
|
|
1195
|
+
const inputSchema = this.resolveInputSchema(node$1, runnableConfig);
|
|
1196
|
+
const inputBatch = request.input ?? [];
|
|
1197
|
+
if (inputBatch.length === 0 && runnableConfig.emptyBatchExecution === "runOnce") {
|
|
1198
|
+
const syntheticItem = { json: {} };
|
|
1199
|
+
const parsed = inputSchema.parse(syntheticItem.json);
|
|
1200
|
+
const runnableCtx = request.ctx;
|
|
1201
|
+
const resolvedCtx = await this.itemValueResolver.resolveConfigForItem(runnableCtx, syntheticItem, 0, inputBatch);
|
|
1202
|
+
const args = {
|
|
1203
|
+
input: parsed,
|
|
1204
|
+
item: syntheticItem,
|
|
1205
|
+
itemIndex: 0,
|
|
1206
|
+
items: inputBatch,
|
|
1207
|
+
ctx: this.pickExecutionContext(runnableCtx, resolvedCtx)
|
|
1208
|
+
};
|
|
1209
|
+
const raw = await Promise.resolve(node$1.execute(args));
|
|
1210
|
+
return this.outputNormalizer.normalizeExecuteResult({
|
|
1211
|
+
baseItem: syntheticItem,
|
|
1212
|
+
raw,
|
|
1213
|
+
carry
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
const byPort = {};
|
|
1217
|
+
for (let i = 0; i < inputBatch.length; i++) {
|
|
1218
|
+
const item = inputBatch[i];
|
|
1219
|
+
this.assertItemJsonNotTopLevelArray(request.nodeId, item);
|
|
1220
|
+
const parsed = inputSchema.parse(item.json);
|
|
1221
|
+
const runnableCtx = request.ctx;
|
|
1222
|
+
const resolvedCtx = await this.itemValueResolver.resolveConfigForItem(runnableCtx, item, i, inputBatch);
|
|
1223
|
+
const ctx = this.pickExecutionContext(runnableCtx, resolvedCtx);
|
|
1224
|
+
const args = {
|
|
1225
|
+
input: parsed,
|
|
922
1226
|
item,
|
|
923
1227
|
itemIndex: i,
|
|
924
|
-
items:
|
|
925
|
-
ctx
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1228
|
+
items: inputBatch,
|
|
1229
|
+
ctx
|
|
1230
|
+
};
|
|
1231
|
+
const raw = await Promise.resolve(node$1.execute(args));
|
|
1232
|
+
const normalized = this.outputNormalizer.normalizeExecuteResult({
|
|
1233
|
+
baseItem: item,
|
|
1234
|
+
raw,
|
|
1235
|
+
carry
|
|
930
1236
|
});
|
|
1237
|
+
for (const [port, batch] of Object.entries(normalized)) {
|
|
1238
|
+
if (!batch || batch.length === 0) continue;
|
|
1239
|
+
const list = byPort[port] ?? [];
|
|
1240
|
+
list.push(...batch);
|
|
1241
|
+
byPort[port] = list;
|
|
1242
|
+
}
|
|
931
1243
|
}
|
|
932
|
-
return
|
|
1244
|
+
return byPort;
|
|
1245
|
+
}
|
|
1246
|
+
/** Use resolver ctx only when {@link NodeExecutionContext.config} is non-nullish. */
|
|
1247
|
+
pickExecutionContext(runnableCtx, resolvedCtx) {
|
|
1248
|
+
if (resolvedCtx != null && resolvedCtx.config != null) return resolvedCtx;
|
|
1249
|
+
return runnableCtx;
|
|
1250
|
+
}
|
|
1251
|
+
resolveInputSchema(nodeInstance, config) {
|
|
1252
|
+
const fromInstance = nodeInstance.inputSchema;
|
|
1253
|
+
if (fromInstance && typeof fromInstance.parse === "function") return fromInstance;
|
|
1254
|
+
const fromConfig = config.inputSchema;
|
|
1255
|
+
if (fromConfig && typeof fromConfig.parse === "function") return fromConfig;
|
|
1256
|
+
return zod.z.unknown();
|
|
1257
|
+
}
|
|
1258
|
+
assertItemJsonNotTopLevelArray(nodeId, item) {
|
|
1259
|
+
if (Array.isArray(item.json)) throw new Error(`Node ${nodeId}: item.json must not be a top-level JSON array`);
|
|
1260
|
+
}
|
|
1261
|
+
assertNoPortEnvelopeBypass(nodeId, value, methodName) {
|
|
1262
|
+
if (isPortsEmission(value)) throw new Error(`Node ${nodeId}: ${methodName} must return NodeOutputs, not emitPorts(...).`);
|
|
1263
|
+
if (isUnbrandedPortsEmissionShape(value)) throw new Error(`Node ${nodeId}: ${methodName} returned an unbranded \`{ ports: ... }\` object. Return NodeOutputs instead.`);
|
|
1264
|
+
}
|
|
1265
|
+
resolveLineageCarry(node$1, config) {
|
|
1266
|
+
if (config.lineageCarry) return config.lineageCarry;
|
|
1267
|
+
const base = config;
|
|
1268
|
+
const declared = base.declaredOutputPorts;
|
|
1269
|
+
if ((declared && declared.length > 0 ? [...new Set([...declared, ...base.nodeErrorHandler ? ["error"] : []])] : base.nodeErrorHandler ? ["main", "error"] : ["main"]).length > 1) return "carryThrough";
|
|
1270
|
+
return "emitOnly";
|
|
933
1271
|
}
|
|
934
1272
|
};
|
|
935
1273
|
|
|
@@ -1007,8 +1345,8 @@ var MissingRuntimeFallbacks = class {
|
|
|
1007
1345
|
var MissingRuntimeNode = class {
|
|
1008
1346
|
kind = "node";
|
|
1009
1347
|
outputPorts = ["main"];
|
|
1010
|
-
|
|
1011
|
-
return
|
|
1348
|
+
execute(args) {
|
|
1349
|
+
return args.item;
|
|
1012
1350
|
}
|
|
1013
1351
|
};
|
|
1014
1352
|
|
|
@@ -1197,6 +1535,7 @@ var WorkflowSnapshotCodec = class {
|
|
|
1197
1535
|
}
|
|
1198
1536
|
restoreNonSerializableProperties(liveRecord, hydrated) {
|
|
1199
1537
|
for (const [key, value] of Object.entries(liveRecord)) if (typeof value === "function" || typeof value === "symbol") hydrated[key] = value;
|
|
1538
|
+
for (const sym of Object.getOwnPropertySymbols(liveRecord)) hydrated[sym] = liveRecord[sym];
|
|
1200
1539
|
}
|
|
1201
1540
|
restoreTypeProperty(record) {
|
|
1202
1541
|
const tokenId = typeof record.tokenId === "string" ? record.tokenId : void 0;
|
|
@@ -1216,7 +1555,10 @@ var WorkflowSnapshotCodec = class {
|
|
|
1216
1555
|
}
|
|
1217
1556
|
asRecord(value) {
|
|
1218
1557
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1219
|
-
|
|
1558
|
+
const record = value;
|
|
1559
|
+
const out = { ...record };
|
|
1560
|
+
for (const sym of Object.getOwnPropertySymbols(value)) out[sym] = record[sym];
|
|
1561
|
+
return out;
|
|
1220
1562
|
}
|
|
1221
1563
|
};
|
|
1222
1564
|
|
|
@@ -1593,19 +1935,6 @@ var WorkflowTopology = class WorkflowTopology {
|
|
|
1593
1935
|
const classifier = WorkflowExecutableNodeClassifierFactory.create(wf);
|
|
1594
1936
|
const defs = /* @__PURE__ */ new Map();
|
|
1595
1937
|
for (const n of wf.nodes) if (classifier.isExecutableNodeId(n.id)) defs.set(n.id, n);
|
|
1596
|
-
const outgoing = /* @__PURE__ */ new Map();
|
|
1597
|
-
for (const e of wf.edges) {
|
|
1598
|
-
if (!classifier.isExecutableNodeId(e.from.nodeId) || !classifier.isExecutableNodeId(e.to.nodeId)) continue;
|
|
1599
|
-
const list = outgoing.get(e.from.nodeId) ?? [];
|
|
1600
|
-
list.push({
|
|
1601
|
-
output: e.from.output,
|
|
1602
|
-
to: {
|
|
1603
|
-
nodeId: e.to.nodeId,
|
|
1604
|
-
input: e.to.input
|
|
1605
|
-
}
|
|
1606
|
-
});
|
|
1607
|
-
outgoing.set(e.from.nodeId, list);
|
|
1608
|
-
}
|
|
1609
1938
|
const incomingByNode = /* @__PURE__ */ new Map();
|
|
1610
1939
|
for (const e of wf.edges) {
|
|
1611
1940
|
if (!classifier.isExecutableNodeId(e.from.nodeId) || !classifier.isExecutableNodeId(e.to.nodeId)) continue;
|
|
@@ -1615,21 +1944,51 @@ var WorkflowTopology = class WorkflowTopology {
|
|
|
1615
1944
|
nodeId: e.from.nodeId,
|
|
1616
1945
|
output: e.from.output
|
|
1617
1946
|
},
|
|
1618
|
-
input: e.to.input
|
|
1947
|
+
input: e.to.input,
|
|
1948
|
+
collectKey: e.to.input
|
|
1619
1949
|
});
|
|
1620
1950
|
incomingByNode.set(e.to.nodeId, list);
|
|
1621
1951
|
}
|
|
1622
|
-
const
|
|
1623
|
-
for (const [toNodeId,
|
|
1952
|
+
const duplicateInputCounts = /* @__PURE__ */ new Map();
|
|
1953
|
+
for (const [toNodeId, edges] of incomingByNode.entries()) {
|
|
1624
1954
|
const counts = /* @__PURE__ */ new Map();
|
|
1625
|
-
for (const edge of
|
|
1626
|
-
|
|
1955
|
+
for (const edge of edges) counts.set(edge.input, (counts.get(edge.input) ?? 0) + 1);
|
|
1956
|
+
duplicateInputCounts.set(toNodeId, counts);
|
|
1957
|
+
}
|
|
1958
|
+
for (const [toNodeId, edges] of incomingByNode.entries()) {
|
|
1959
|
+
const counts = duplicateInputCounts.get(toNodeId) ?? /* @__PURE__ */ new Map();
|
|
1960
|
+
for (let i = 0; i < edges.length; i++) {
|
|
1961
|
+
const edge = edges[i];
|
|
1962
|
+
const collectKey = (counts.get(edge.input) ?? 0) > 1 ? `${edge.from.nodeId}:${edge.from.output}` : edge.input;
|
|
1963
|
+
edges[i] = {
|
|
1964
|
+
...edge,
|
|
1965
|
+
collectKey
|
|
1966
|
+
};
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
1970
|
+
for (const e of wf.edges) {
|
|
1971
|
+
if (!classifier.isExecutableNodeId(e.from.nodeId) || !classifier.isExecutableNodeId(e.to.nodeId)) continue;
|
|
1972
|
+
const collectKey = ((duplicateInputCounts.get(e.to.nodeId) ?? /* @__PURE__ */ new Map()).get(e.to.input) ?? 0) > 1 ? `${e.from.nodeId}:${e.from.output}` : e.to.input;
|
|
1973
|
+
const list = outgoing.get(e.from.nodeId) ?? [];
|
|
1974
|
+
list.push({
|
|
1975
|
+
output: e.from.output,
|
|
1976
|
+
to: {
|
|
1977
|
+
nodeId: e.to.nodeId,
|
|
1978
|
+
input: e.to.input,
|
|
1979
|
+
collectKey
|
|
1980
|
+
}
|
|
1981
|
+
});
|
|
1982
|
+
outgoing.set(e.from.nodeId, list);
|
|
1983
|
+
}
|
|
1984
|
+
const expected = /* @__PURE__ */ new Map();
|
|
1985
|
+
for (const [toNodeId, edges] of incomingByNode.entries()) {
|
|
1627
1986
|
const order = [];
|
|
1628
1987
|
const seen = /* @__PURE__ */ new Set();
|
|
1629
|
-
for (const edge of
|
|
1630
|
-
if (seen.has(edge.
|
|
1631
|
-
seen.add(edge.
|
|
1632
|
-
order.push(edge.
|
|
1988
|
+
for (const edge of edges) {
|
|
1989
|
+
if (seen.has(edge.collectKey)) continue;
|
|
1990
|
+
seen.add(edge.collectKey);
|
|
1991
|
+
order.push(edge.collectKey);
|
|
1633
1992
|
}
|
|
1634
1993
|
expected.set(toNodeId, order);
|
|
1635
1994
|
}
|
|
@@ -2135,6 +2494,11 @@ var RunContinuationService = class {
|
|
|
2135
2494
|
batchId
|
|
2136
2495
|
});
|
|
2137
2496
|
const next = planner.nextActivation(queue);
|
|
2497
|
+
const finishedAt = completedSnapshot.finishedAt ?? completedSnapshot.updatedAt;
|
|
2498
|
+
const mergedSnapshots = {
|
|
2499
|
+
...args.state.nodeSnapshotsByNodeId ?? {},
|
|
2500
|
+
[args.args.nodeId]: completedSnapshot
|
|
2501
|
+
};
|
|
2138
2502
|
if (!next) {
|
|
2139
2503
|
const lastNodeId = WorkflowExecutableNodeClassifierFactory.create(args.workflow).lastExecutableNodeIdInDefinitionOrder(args.workflow);
|
|
2140
2504
|
const outputs = data.getOutputItems(lastNodeId, "main");
|
|
@@ -2144,11 +2508,8 @@ var RunContinuationService = class {
|
|
|
2144
2508
|
status: "completed",
|
|
2145
2509
|
queue: [],
|
|
2146
2510
|
outputsByNode: data.dump(),
|
|
2147
|
-
nodeSnapshotsByNodeId:
|
|
2148
|
-
|
|
2149
|
-
[args.args.nodeId]: completedSnapshot
|
|
2150
|
-
},
|
|
2151
|
-
finishedAtIso: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
|
|
2511
|
+
nodeSnapshotsByNodeId: mergedSnapshots,
|
|
2512
|
+
finishedAtIso: finishedAt
|
|
2152
2513
|
});
|
|
2153
2514
|
await this.workflowExecutionRepository.save(completedState);
|
|
2154
2515
|
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
@@ -2183,11 +2544,8 @@ var RunContinuationService = class {
|
|
|
2183
2544
|
status: "failed",
|
|
2184
2545
|
queue: queue.map((q) => ({ ...q })),
|
|
2185
2546
|
outputsByNode: data.dump(),
|
|
2186
|
-
nodeSnapshotsByNodeId:
|
|
2187
|
-
|
|
2188
|
-
[args.args.nodeId]: completedSnapshot
|
|
2189
|
-
},
|
|
2190
|
-
finishedAtIso: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
|
|
2547
|
+
nodeSnapshotsByNodeId: mergedSnapshots,
|
|
2548
|
+
finishedAtIso: finishedAt
|
|
2191
2549
|
});
|
|
2192
2550
|
await this.workflowExecutionRepository.save(failedState);
|
|
2193
2551
|
await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
|
|
@@ -2238,10 +2596,6 @@ var RunContinuationService = class {
|
|
|
2238
2596
|
executionOptions: args.state.executionOptions,
|
|
2239
2597
|
nodeDefinition: nextDefinition
|
|
2240
2598
|
});
|
|
2241
|
-
const mergedSnapshots = {
|
|
2242
|
-
...args.state.nodeSnapshotsByNodeId ?? {},
|
|
2243
|
-
[args.args.nodeId]: completedSnapshot
|
|
2244
|
-
};
|
|
2245
2599
|
try {
|
|
2246
2600
|
const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
|
|
2247
2601
|
runId: args.state.runId,
|
|
@@ -2272,7 +2626,6 @@ var RunContinuationService = class {
|
|
|
2272
2626
|
return result;
|
|
2273
2627
|
} catch (cause) {
|
|
2274
2628
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
2275
|
-
const finishedAt = completedSnapshot.finishedAt ?? completedSnapshot.updatedAt;
|
|
2276
2629
|
const result = await this.terminateRunAfterActivationEnqueueRejected({
|
|
2277
2630
|
wf: args.workflow,
|
|
2278
2631
|
state: args.state,
|
|
@@ -2560,7 +2913,7 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
|
|
|
2560
2913
|
const frontierNodeIds = [];
|
|
2561
2914
|
for (const nodeId of this.topology.defsById.keys()) {
|
|
2562
2915
|
if (!requiredNodeIds.has(nodeId) || this.isNodeSatisfied(currentState, nodeId)) continue;
|
|
2563
|
-
if ((this.topology.incomingByNode.get(nodeId) ?? []).every((edge) => this.isEdgeSatisfied(currentState, nodeId, edge.
|
|
2916
|
+
if ((this.topology.incomingByNode.get(nodeId) ?? []).every((edge) => this.isEdgeSatisfied(currentState, nodeId, edge.collectKey))) frontierNodeIds.push(nodeId);
|
|
2564
2917
|
}
|
|
2565
2918
|
return frontierNodeIds;
|
|
2566
2919
|
}
|
|
@@ -2578,13 +2931,13 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
|
|
|
2578
2931
|
if (requiredNodeIds.has(nodeId)) return;
|
|
2579
2932
|
if (this.isNodeSatisfied(currentState, nodeId) && !this.isNodeSatisfiedByOutputsOnly(currentState, nodeId)) return;
|
|
2580
2933
|
requiredNodeIds.add(nodeId);
|
|
2581
|
-
for (const edge of this.topology.incomingByNode.get(nodeId) ?? []) if (!this.isEdgeSatisfied(currentState, nodeId, edge.
|
|
2934
|
+
for (const edge of this.topology.incomingByNode.get(nodeId) ?? []) if (!this.isEdgeSatisfied(currentState, nodeId, edge.collectKey) || this.isNodeSatisfiedByOutputsOnly(currentState, edge.from.nodeId)) this.collectRequiredNode(requiredNodeIds, currentState, edge.from.nodeId);
|
|
2582
2935
|
}
|
|
2583
2936
|
buildFrontierQueue(nodeId, currentState) {
|
|
2584
2937
|
const incomingEdges = this.topology.incomingByNode.get(nodeId) ?? [];
|
|
2585
2938
|
if (incomingEdges.length === 0) return [];
|
|
2586
2939
|
const expectedInputs = this.topology.expectedInputsByNode.get(nodeId) ?? [];
|
|
2587
|
-
if (
|
|
2940
|
+
if (this.usesCollect(nodeId)) {
|
|
2588
2941
|
const received = {};
|
|
2589
2942
|
for (const input$1 of expectedInputs) received[input$1] = this.resolveInput(currentState, nodeId, input$1);
|
|
2590
2943
|
return [{
|
|
@@ -2598,7 +2951,7 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
|
|
|
2598
2951
|
}];
|
|
2599
2952
|
}
|
|
2600
2953
|
const input = expectedInputs[0] ?? "in";
|
|
2601
|
-
const incomingEdge = incomingEdges.find((edge) => edge.
|
|
2954
|
+
const incomingEdge = incomingEdges.find((edge) => edge.collectKey === input);
|
|
2602
2955
|
return [{
|
|
2603
2956
|
nodeId,
|
|
2604
2957
|
input: this.resolveInput(currentState, nodeId, input),
|
|
@@ -2618,16 +2971,17 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
|
|
|
2618
2971
|
isNodeSatisfiedByOutputsOnly(currentState, nodeId) {
|
|
2619
2972
|
return this.hasOutputs(currentState, nodeId) && !this.hasCompletedSnapshot(currentState, nodeId);
|
|
2620
2973
|
}
|
|
2621
|
-
isEdgeSatisfied(currentState, nodeId,
|
|
2622
|
-
const incomingEdge = (this.topology.incomingByNode.get(nodeId) ?? []).find((edge) => edge.
|
|
2974
|
+
isEdgeSatisfied(currentState, nodeId, collectKey) {
|
|
2975
|
+
const incomingEdge = (this.topology.incomingByNode.get(nodeId) ?? []).find((edge) => edge.collectKey === collectKey);
|
|
2623
2976
|
if (!incomingEdge) return false;
|
|
2624
|
-
|
|
2977
|
+
const fromNodeId = incomingEdge.from.nodeId;
|
|
2978
|
+
if (!this.isNodeSatisfied(currentState, fromNodeId)) return false;
|
|
2625
2979
|
if (this.usesCollect(nodeId)) return true;
|
|
2626
|
-
if (this.resolveOutputItems(currentState,
|
|
2627
|
-
return this.shouldContinueAfterEmptyOutputFromSource(
|
|
2980
|
+
if (this.resolveOutputItems(currentState, fromNodeId, incomingEdge.from.output).length > 0) return true;
|
|
2981
|
+
return this.shouldContinueAfterEmptyOutputFromSource(fromNodeId);
|
|
2628
2982
|
}
|
|
2629
|
-
resolveInput(currentState, nodeId,
|
|
2630
|
-
const incomingEdge = (this.topology.incomingByNode.get(nodeId) ?? []).find((edge) => edge.
|
|
2983
|
+
resolveInput(currentState, nodeId, collectKey) {
|
|
2984
|
+
const incomingEdge = (this.topology.incomingByNode.get(nodeId) ?? []).find((edge) => edge.collectKey === collectKey);
|
|
2631
2985
|
if (!incomingEdge) return [];
|
|
2632
2986
|
return this.resolveOutputItems(currentState, incomingEdge.from.nodeId, incomingEdge.from.output);
|
|
2633
2987
|
}
|
|
@@ -2638,17 +2992,13 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
|
|
|
2638
2992
|
const snapshot = currentState.nodeSnapshotsByNodeId[nodeId];
|
|
2639
2993
|
return snapshot?.status === "completed" || snapshot?.status === "skipped";
|
|
2640
2994
|
}
|
|
2641
|
-
hasOutputPort(currentState, nodeId, output) {
|
|
2642
|
-
const outputs = currentState.outputsByNode[nodeId];
|
|
2643
|
-
if (!outputs) return false;
|
|
2644
|
-
return Object.prototype.hasOwnProperty.call(outputs, output);
|
|
2645
|
-
}
|
|
2646
2995
|
resolveOutputItems(currentState, nodeId, output) {
|
|
2647
2996
|
return currentState.outputsByNode[nodeId]?.[output] ?? [];
|
|
2648
2997
|
}
|
|
2649
2998
|
usesCollect(nodeId) {
|
|
2650
2999
|
const expectedInputs = this.topology.expectedInputsByNode.get(nodeId) ?? [];
|
|
2651
|
-
|
|
3000
|
+
if (expectedInputs.length !== 1 || expectedInputs[0] !== "in") return true;
|
|
3001
|
+
return (this.topology.incomingByNode.get(nodeId) ?? []).length > 1;
|
|
2652
3002
|
}
|
|
2653
3003
|
shouldContinueAfterEmptyOutputFromSource(nodeId) {
|
|
2654
3004
|
const definition = this.topology.defsById.get(nodeId);
|
|
@@ -3540,7 +3890,6 @@ var NodeExecutionRequestHandlerService = class {
|
|
|
3540
3890
|
const resolvedParent = request.parent ?? state.parent;
|
|
3541
3891
|
const data = this.runDataFactory.create(state.outputsByNode);
|
|
3542
3892
|
const limits = this.resolveEngineLimitsFromState(state);
|
|
3543
|
-
const persistedInput = pendingExecution.inputsByPort.in ?? request.input;
|
|
3544
3893
|
const base = this.runExecutionContextFactory.create({
|
|
3545
3894
|
runId: state.runId,
|
|
3546
3895
|
workflowId: state.workflowId,
|
|
@@ -3552,7 +3901,11 @@ var NodeExecutionRequestHandlerService = class {
|
|
|
3552
3901
|
data,
|
|
3553
3902
|
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent)
|
|
3554
3903
|
});
|
|
3555
|
-
const
|
|
3904
|
+
const inputsByPort = pendingExecution.inputsByPort;
|
|
3905
|
+
const portKeys = Object.keys(inputsByPort);
|
|
3906
|
+
const kind = portKeys.length === 1 && portKeys[0] === "in" ? "single" : "multi";
|
|
3907
|
+
const batchId = pendingExecution.batchId ?? "batch_1";
|
|
3908
|
+
const activationRequest = kind === "multi" ? this.nodeActivationRequestComposer.createMultiFromDefinitionWithActivation({
|
|
3556
3909
|
activationId: request.activationId,
|
|
3557
3910
|
runId: request.runId,
|
|
3558
3911
|
workflowId: request.workflowId,
|
|
@@ -3564,8 +3917,22 @@ var NodeExecutionRequestHandlerService = class {
|
|
|
3564
3917
|
id: definition.id,
|
|
3565
3918
|
config: definition.config
|
|
3566
3919
|
},
|
|
3567
|
-
batchId
|
|
3568
|
-
|
|
3920
|
+
batchId,
|
|
3921
|
+
inputsByPort
|
|
3922
|
+
}) : this.nodeActivationRequestComposer.createSingleFromDefinitionWithActivation({
|
|
3923
|
+
activationId: request.activationId,
|
|
3924
|
+
runId: request.runId,
|
|
3925
|
+
workflowId: request.workflowId,
|
|
3926
|
+
parent: resolvedParent,
|
|
3927
|
+
executionOptions: request.executionOptions ?? state.executionOptions,
|
|
3928
|
+
base,
|
|
3929
|
+
data,
|
|
3930
|
+
definition: {
|
|
3931
|
+
id: definition.id,
|
|
3932
|
+
config: definition.config
|
|
3933
|
+
},
|
|
3934
|
+
batchId,
|
|
3935
|
+
input: inputsByPort.in ?? request.input ?? []
|
|
3569
3936
|
});
|
|
3570
3937
|
await this.continuation.markNodeRunning({
|
|
3571
3938
|
runId: activationRequest.runId,
|
|
@@ -3650,7 +4017,7 @@ var RunQueuePlanner = class {
|
|
|
3650
4017
|
continue;
|
|
3651
4018
|
}
|
|
3652
4019
|
const inst = this.nodeInstances.get(toNodeId);
|
|
3653
|
-
if (!this.isMultiInputNode(inst)) throw new Error(`Node ${toNodeId} has ${inputs.length} inbound edges
|
|
4020
|
+
if (!this.isMultiInputNode(inst) && !this.supportsEngineFanInMerge(inst)) throw new Error(`Node ${toNodeId} has ${inputs.length} inbound edges but does not support multi-input execution.`);
|
|
3654
4021
|
}
|
|
3655
4022
|
}
|
|
3656
4023
|
seedFromTrigger(args) {
|
|
@@ -3659,7 +4026,7 @@ var RunQueuePlanner = class {
|
|
|
3659
4026
|
if (e.output !== "main") continue;
|
|
3660
4027
|
this.enqueueEdge(queue, {
|
|
3661
4028
|
batchId: args.batchId,
|
|
3662
|
-
to: e
|
|
4029
|
+
to: this.toEnqueueTarget(e),
|
|
3663
4030
|
from: {
|
|
3664
4031
|
nodeId: args.startNodeId,
|
|
3665
4032
|
output: "main"
|
|
@@ -3674,7 +4041,7 @@ var RunQueuePlanner = class {
|
|
|
3674
4041
|
const outItems = args.outputs[e.output] ?? [];
|
|
3675
4042
|
this.enqueueEdge(queue, {
|
|
3676
4043
|
batchId: args.batchId,
|
|
3677
|
-
to: e
|
|
4044
|
+
to: this.toEnqueueTarget(e),
|
|
3678
4045
|
from: {
|
|
3679
4046
|
nodeId: args.fromNodeId,
|
|
3680
4047
|
output: e.output
|
|
@@ -3756,29 +4123,35 @@ var RunQueuePlanner = class {
|
|
|
3756
4123
|
*/
|
|
3757
4124
|
usesTopologyCollectMerge(toNodeId) {
|
|
3758
4125
|
const expectedInputs = this.topology.expectedInputsByNode.get(toNodeId) ?? [];
|
|
3759
|
-
|
|
4126
|
+
if (expectedInputs.length !== 1 || expectedInputs[0] !== "in") return true;
|
|
4127
|
+
return (this.topology.incomingByNode.get(toNodeId) ?? []).length > 1;
|
|
3760
4128
|
}
|
|
3761
|
-
|
|
4129
|
+
toEnqueueTarget(edge) {
|
|
4130
|
+
return edge.to;
|
|
4131
|
+
}
|
|
4132
|
+
enqueueEdge(queue, args, emptyPathSourceNodeId) {
|
|
3762
4133
|
const target = this.nodeInstances.get(args.to.nodeId);
|
|
3763
4134
|
if (!(this.usesTopologyCollectMerge(args.to.nodeId) || this.isMultiInputNode(target))) {
|
|
3764
4135
|
if (args.items.length === 0) {
|
|
3765
|
-
|
|
4136
|
+
const continueSourceNodeId = emptyPathSourceNodeId ?? args.from.nodeId;
|
|
4137
|
+
if (this.shouldContinueAfterEmptyOutputFromSource(continueSourceNodeId)) {
|
|
3766
4138
|
queue.push({
|
|
3767
4139
|
nodeId: args.to.nodeId,
|
|
3768
4140
|
input: args.items,
|
|
3769
|
-
toInput: args.to.
|
|
4141
|
+
toInput: args.to.collectKey,
|
|
3770
4142
|
batchId: args.batchId,
|
|
3771
4143
|
from: args.from
|
|
3772
4144
|
});
|
|
3773
4145
|
return;
|
|
3774
4146
|
}
|
|
3775
|
-
|
|
4147
|
+
const source = emptyPathSourceNodeId ?? args.from.nodeId;
|
|
4148
|
+
this.propagateEmptyPath(queue, args.to.nodeId, args.batchId, source);
|
|
3776
4149
|
return;
|
|
3777
4150
|
}
|
|
3778
4151
|
queue.push({
|
|
3779
4152
|
nodeId: args.to.nodeId,
|
|
3780
4153
|
input: args.items,
|
|
3781
|
-
toInput: args.to.
|
|
4154
|
+
toInput: args.to.collectKey,
|
|
3782
4155
|
batchId: args.batchId,
|
|
3783
4156
|
from: args.from
|
|
3784
4157
|
});
|
|
@@ -3799,14 +4172,14 @@ var RunQueuePlanner = class {
|
|
|
3799
4172
|
queue.push(collect);
|
|
3800
4173
|
}
|
|
3801
4174
|
const received = collect.collect.received;
|
|
3802
|
-
received[args.to.
|
|
4175
|
+
received[args.to.collectKey] = args.items;
|
|
3803
4176
|
}
|
|
3804
4177
|
shouldContinueAfterEmptyOutputFromSource(fromNodeId) {
|
|
3805
4178
|
const def = this.topology.defsById.get(fromNodeId);
|
|
3806
4179
|
if (!def) return false;
|
|
3807
4180
|
return def.config.continueWhenEmptyOutput === true;
|
|
3808
4181
|
}
|
|
3809
|
-
propagateEmptyPath(queue, nodeId, batchId) {
|
|
4182
|
+
propagateEmptyPath(queue, nodeId, batchId, emptyPathSourceNodeId) {
|
|
3810
4183
|
for (const edge of this.topology.outgoingByNode.get(nodeId) ?? []) this.enqueueEdge(queue, {
|
|
3811
4184
|
batchId,
|
|
3812
4185
|
to: edge.to,
|
|
@@ -3815,11 +4188,17 @@ var RunQueuePlanner = class {
|
|
|
3815
4188
|
output: edge.output
|
|
3816
4189
|
},
|
|
3817
4190
|
items: []
|
|
3818
|
-
});
|
|
4191
|
+
}, emptyPathSourceNodeId);
|
|
3819
4192
|
}
|
|
3820
4193
|
isMultiInputNode(n) {
|
|
3821
4194
|
return typeof n?.executeMulti === "function";
|
|
3822
4195
|
}
|
|
4196
|
+
hasRunnableExecute(n) {
|
|
4197
|
+
return typeof n === "object" && n !== null && n.kind === "node" && typeof n.execute === "function";
|
|
4198
|
+
}
|
|
4199
|
+
supportsEngineFanInMerge(n) {
|
|
4200
|
+
return this.hasRunnableExecute(n) && !this.isMultiInputNode(n);
|
|
4201
|
+
}
|
|
3823
4202
|
describeUnsatisfiedCollect(queueEntry) {
|
|
3824
4203
|
const batchId = queueEntry.batchId ?? "batch_1";
|
|
3825
4204
|
const expectedInputs = queueEntry.collect?.expectedInputs ?? [];
|
|
@@ -3851,7 +4230,7 @@ var RunQueuePlanner = class {
|
|
|
3851
4230
|
}
|
|
3852
4231
|
findSources(nodeId, input) {
|
|
3853
4232
|
const matches = [];
|
|
3854
|
-
for (const [sourceNodeId, edges] of this.topology.outgoingByNode.entries()) for (const edge of edges) if (edge.to.nodeId === nodeId && edge.to.
|
|
4233
|
+
for (const [sourceNodeId, edges] of this.topology.outgoingByNode.entries()) for (const edge of edges) if (edge.to.nodeId === nodeId && edge.to.collectKey === input) matches.push(this.formatNodeLabel(sourceNodeId));
|
|
3855
4234
|
return matches;
|
|
3856
4235
|
}
|
|
3857
4236
|
formatInputList(inputs) {
|
|
@@ -4658,6 +5037,12 @@ Object.defineProperty(exports, 'InlineDrivingScheduler', {
|
|
|
4658
5037
|
return InlineDrivingScheduler;
|
|
4659
5038
|
}
|
|
4660
5039
|
});
|
|
5040
|
+
Object.defineProperty(exports, 'ItemValueResolver', {
|
|
5041
|
+
enumerable: true,
|
|
5042
|
+
get: function () {
|
|
5043
|
+
return ItemValueResolver;
|
|
5044
|
+
}
|
|
5045
|
+
});
|
|
4661
5046
|
Object.defineProperty(exports, 'LocalOnlyScheduler', {
|
|
4662
5047
|
enumerable: true,
|
|
4663
5048
|
get: function () {
|
|
@@ -4700,6 +5085,12 @@ Object.defineProperty(exports, 'NodeInstanceFactoryFactory', {
|
|
|
4700
5085
|
return NodeInstanceFactoryFactory;
|
|
4701
5086
|
}
|
|
4702
5087
|
});
|
|
5088
|
+
Object.defineProperty(exports, 'NodeOutputNormalizer', {
|
|
5089
|
+
enumerable: true,
|
|
5090
|
+
get: function () {
|
|
5091
|
+
return NodeOutputNormalizer;
|
|
5092
|
+
}
|
|
5093
|
+
});
|
|
4703
5094
|
Object.defineProperty(exports, 'PersistedRuntimeTypeMetadataStore', {
|
|
4704
5095
|
enumerable: true,
|
|
4705
5096
|
get: function () {
|
|
@@ -4814,22 +5205,70 @@ Object.defineProperty(exports, 'chatModel', {
|
|
|
4814
5205
|
return chatModel;
|
|
4815
5206
|
}
|
|
4816
5207
|
});
|
|
5208
|
+
Object.defineProperty(exports, 'emitPorts', {
|
|
5209
|
+
enumerable: true,
|
|
5210
|
+
get: function () {
|
|
5211
|
+
return emitPorts;
|
|
5212
|
+
}
|
|
5213
|
+
});
|
|
5214
|
+
Object.defineProperty(exports, 'getOriginIndexFromItem', {
|
|
5215
|
+
enumerable: true,
|
|
5216
|
+
get: function () {
|
|
5217
|
+
return getOriginIndexFromItem;
|
|
5218
|
+
}
|
|
5219
|
+
});
|
|
4817
5220
|
Object.defineProperty(exports, 'getPersistedRuntimeTypeMetadata', {
|
|
4818
5221
|
enumerable: true,
|
|
4819
5222
|
get: function () {
|
|
4820
5223
|
return getPersistedRuntimeTypeMetadata;
|
|
4821
5224
|
}
|
|
4822
5225
|
});
|
|
5226
|
+
Object.defineProperty(exports, 'isItemValue', {
|
|
5227
|
+
enumerable: true,
|
|
5228
|
+
get: function () {
|
|
5229
|
+
return isItemValue;
|
|
5230
|
+
}
|
|
5231
|
+
});
|
|
5232
|
+
Object.defineProperty(exports, 'isPortsEmission', {
|
|
5233
|
+
enumerable: true,
|
|
5234
|
+
get: function () {
|
|
5235
|
+
return isPortsEmission;
|
|
5236
|
+
}
|
|
5237
|
+
});
|
|
5238
|
+
Object.defineProperty(exports, 'isUnbrandedPortsEmissionShape', {
|
|
5239
|
+
enumerable: true,
|
|
5240
|
+
get: function () {
|
|
5241
|
+
return isUnbrandedPortsEmissionShape;
|
|
5242
|
+
}
|
|
5243
|
+
});
|
|
5244
|
+
Object.defineProperty(exports, 'itemValue', {
|
|
5245
|
+
enumerable: true,
|
|
5246
|
+
get: function () {
|
|
5247
|
+
return itemValue;
|
|
5248
|
+
}
|
|
5249
|
+
});
|
|
4823
5250
|
Object.defineProperty(exports, 'node', {
|
|
4824
5251
|
enumerable: true,
|
|
4825
5252
|
get: function () {
|
|
4826
5253
|
return node;
|
|
4827
5254
|
}
|
|
4828
5255
|
});
|
|
5256
|
+
Object.defineProperty(exports, 'resolveItemValuesForExecution', {
|
|
5257
|
+
enumerable: true,
|
|
5258
|
+
get: function () {
|
|
5259
|
+
return resolveItemValuesForExecution;
|
|
5260
|
+
}
|
|
5261
|
+
});
|
|
5262
|
+
Object.defineProperty(exports, 'resolveItemValuesInUnknown', {
|
|
5263
|
+
enumerable: true,
|
|
5264
|
+
get: function () {
|
|
5265
|
+
return resolveItemValuesInUnknown;
|
|
5266
|
+
}
|
|
5267
|
+
});
|
|
4829
5268
|
Object.defineProperty(exports, 'tool', {
|
|
4830
5269
|
enumerable: true,
|
|
4831
5270
|
get: function () {
|
|
4832
5271
|
return tool;
|
|
4833
5272
|
}
|
|
4834
5273
|
});
|
|
4835
|
-
//# sourceMappingURL=runtime-
|
|
5274
|
+
//# sourceMappingURL=runtime-feFn8OmG.cjs.map
|