flowcraft 2.1.1 → 2.3.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.
Files changed (162) hide show
  1. package/README.md +41 -35
  2. package/dist/analysis.d.ts +5 -2
  3. package/dist/analysis.js +1 -1
  4. package/dist/{chunk-HN72TZY5.js → chunk-233SESC2.js} +34 -23
  5. package/dist/chunk-233SESC2.js.map +1 -0
  6. package/dist/chunk-33NO4PUJ.js +74 -0
  7. package/dist/chunk-33NO4PUJ.js.map +1 -0
  8. package/dist/chunk-5KKSQWSC.js +90 -0
  9. package/dist/chunk-5KKSQWSC.js.map +1 -0
  10. package/dist/{chunk-O3XD45IL.js → chunk-6INWPSZT.js} +44 -17
  11. package/dist/chunk-6INWPSZT.js.map +1 -0
  12. package/dist/chunk-BC4G7OM6.js +42 -0
  13. package/dist/chunk-BC4G7OM6.js.map +1 -0
  14. package/dist/chunk-BCRWXTWX.js +21 -0
  15. package/dist/chunk-BCRWXTWX.js.map +1 -0
  16. package/dist/chunk-C4HYIJI3.js +279 -0
  17. package/dist/chunk-C4HYIJI3.js.map +1 -0
  18. package/dist/chunk-CD3Q4N6V.js +13 -0
  19. package/dist/chunk-CD3Q4N6V.js.map +1 -0
  20. package/dist/chunk-CD4FUZOJ.js +114 -0
  21. package/dist/chunk-CD4FUZOJ.js.map +1 -0
  22. package/dist/chunk-CY755I7I.js +25 -0
  23. package/dist/chunk-CY755I7I.js.map +1 -0
  24. package/dist/chunk-DL7KVYZF.js +39 -0
  25. package/dist/chunk-DL7KVYZF.js.map +1 -0
  26. package/dist/{chunk-UETC63DP.js → chunk-EUJWJWFA.js} +24 -4
  27. package/dist/chunk-EUJWJWFA.js.map +1 -0
  28. package/dist/chunk-FRKO3WX4.js +32 -0
  29. package/dist/chunk-FRKO3WX4.js.map +1 -0
  30. package/dist/chunk-G53CSLBF.js +54 -0
  31. package/dist/chunk-G53CSLBF.js.map +1 -0
  32. package/dist/chunk-G5BGBPFP.js +172 -0
  33. package/dist/chunk-G5BGBPFP.js.map +1 -0
  34. package/dist/chunk-HAZ26F3P.js +98 -0
  35. package/dist/chunk-HAZ26F3P.js.map +1 -0
  36. package/dist/chunk-IB2BISIC.js +446 -0
  37. package/dist/chunk-IB2BISIC.js.map +1 -0
  38. package/dist/{chunk-U5V5O5MN.js → chunk-LNK7LZER.js} +5 -3
  39. package/dist/chunk-LNK7LZER.js.map +1 -0
  40. package/dist/chunk-MCGK3FXQ.js +143 -0
  41. package/dist/chunk-MCGK3FXQ.js.map +1 -0
  42. package/dist/chunk-MUYLRTSR.js +82 -0
  43. package/dist/chunk-MUYLRTSR.js.map +1 -0
  44. package/dist/chunk-NVJ3ZO3P.js +3 -0
  45. package/dist/{chunk-HMR2GEGE.js.map → chunk-NVJ3ZO3P.js.map} +1 -1
  46. package/dist/chunk-NVLZFLYM.js +3 -0
  47. package/dist/chunk-NVLZFLYM.js.map +1 -0
  48. package/dist/chunk-ONH7PIJZ.js +300 -0
  49. package/dist/chunk-ONH7PIJZ.js.map +1 -0
  50. package/dist/chunk-QNYXQKFW.js +25 -0
  51. package/dist/chunk-QNYXQKFW.js.map +1 -0
  52. package/dist/{chunk-KWQHFT7E.js → chunk-R3HQXIEL.js} +6 -6
  53. package/dist/chunk-R3HQXIEL.js.map +1 -0
  54. package/dist/chunk-RM677CNU.js +52 -0
  55. package/dist/chunk-RM677CNU.js.map +1 -0
  56. package/dist/chunk-WWGFIYKW.js +47 -0
  57. package/dist/chunk-WWGFIYKW.js.map +1 -0
  58. package/dist/chunk-XNRIM27H.js +76 -0
  59. package/dist/chunk-XNRIM27H.js.map +1 -0
  60. package/dist/container-factory.d.ts +17 -0
  61. package/dist/container-factory.js +13 -0
  62. package/dist/container-factory.js.map +1 -0
  63. package/dist/container.d.ts +23 -0
  64. package/dist/container.js +3 -0
  65. package/dist/container.js.map +1 -0
  66. package/dist/context.d.ts +3 -1
  67. package/dist/context.js +1 -1
  68. package/dist/errors.d.ts +18 -17
  69. package/dist/errors.js +1 -1
  70. package/dist/evaluator.d.ts +3 -1
  71. package/dist/flow.d.ts +29 -8
  72. package/dist/flow.js +2 -2
  73. package/dist/index.d.ts +7 -7
  74. package/dist/index.js +27 -15
  75. package/dist/linter.d.ts +5 -3
  76. package/dist/linter.js +2 -2
  77. package/dist/logger.d.ts +3 -1
  78. package/dist/node.d.ts +3 -1
  79. package/dist/node.js +1 -1
  80. package/dist/nodes/batch-gather.d.ts +9 -0
  81. package/dist/nodes/batch-gather.js +4 -0
  82. package/dist/nodes/batch-gather.js.map +1 -0
  83. package/dist/nodes/batch-scatter.d.ts +9 -0
  84. package/dist/nodes/batch-scatter.js +4 -0
  85. package/dist/nodes/batch-scatter.js.map +1 -0
  86. package/dist/nodes/subflow.d.ts +9 -0
  87. package/dist/nodes/subflow.js +10 -0
  88. package/dist/nodes/subflow.js.map +1 -0
  89. package/dist/nodes/wait.d.ts +9 -0
  90. package/dist/nodes/wait.js +4 -0
  91. package/dist/nodes/wait.js.map +1 -0
  92. package/dist/runtime/adapter.d.ts +6 -5
  93. package/dist/runtime/adapter.js +20 -10
  94. package/dist/runtime/builtin-keys.d.ts +38 -0
  95. package/dist/runtime/builtin-keys.js +10 -0
  96. package/dist/runtime/builtin-keys.js.map +1 -0
  97. package/dist/runtime/execution-context.d.ts +3 -0
  98. package/dist/runtime/execution-context.js +6 -0
  99. package/dist/runtime/execution-context.js.map +1 -0
  100. package/dist/runtime/executors.d.ts +3 -26
  101. package/dist/runtime/executors.js +2 -2
  102. package/dist/runtime/index.d.ts +5 -6
  103. package/dist/runtime/index.js +22 -11
  104. package/dist/runtime/node-executor-factory.d.ts +12 -0
  105. package/dist/runtime/node-executor-factory.js +6 -0
  106. package/dist/runtime/node-executor-factory.js.map +1 -0
  107. package/dist/runtime/orchestrator.d.ts +9 -0
  108. package/dist/runtime/orchestrator.js +8 -0
  109. package/dist/runtime/orchestrator.js.map +1 -0
  110. package/dist/runtime/orchestrators/step-by-step.d.ts +16 -0
  111. package/dist/runtime/orchestrators/step-by-step.js +5 -0
  112. package/dist/runtime/orchestrators/step-by-step.js.map +1 -0
  113. package/dist/runtime/orchestrators/utils.d.ts +35 -0
  114. package/dist/runtime/orchestrators/utils.js +4 -0
  115. package/dist/runtime/orchestrators/utils.js.map +1 -0
  116. package/dist/runtime/runtime.d.ts +3 -35
  117. package/dist/runtime/runtime.js +19 -9
  118. package/dist/runtime/state.d.ts +3 -21
  119. package/dist/runtime/state.js +3 -2
  120. package/dist/runtime/traverser.d.ts +3 -26
  121. package/dist/runtime/traverser.js +2 -3
  122. package/dist/runtime/types.d.ts +3 -16
  123. package/dist/runtime/types.js +1 -1
  124. package/dist/runtime/workflow-logic-handler.d.ts +17 -0
  125. package/dist/runtime/workflow-logic-handler.js +5 -0
  126. package/dist/runtime/workflow-logic-handler.js.map +1 -0
  127. package/dist/sanitizer.d.ts +3 -1
  128. package/dist/serializer.d.ts +3 -1
  129. package/dist/testing/event-logger.d.ts +63 -0
  130. package/dist/testing/event-logger.js +3 -0
  131. package/dist/testing/event-logger.js.map +1 -0
  132. package/dist/testing/index.d.ts +6 -0
  133. package/dist/testing/index.js +31 -0
  134. package/dist/testing/index.js.map +1 -0
  135. package/dist/testing/run-with-trace.d.ts +38 -0
  136. package/dist/testing/run-with-trace.js +29 -0
  137. package/dist/testing/run-with-trace.js.map +1 -0
  138. package/dist/testing/stepper.d.ts +79 -0
  139. package/dist/testing/stepper.js +11 -0
  140. package/dist/testing/stepper.js.map +1 -0
  141. package/dist/types-ezHUBdpL.d.ts +564 -0
  142. package/dist/types.d.ts +3 -1
  143. package/package.json +6 -2
  144. package/dist/chunk-3XVVR2SR.js +0 -417
  145. package/dist/chunk-3XVVR2SR.js.map +0 -1
  146. package/dist/chunk-4A627Q6L.js +0 -147
  147. package/dist/chunk-4A627Q6L.js.map +0 -1
  148. package/dist/chunk-5ZXV3R5D.js +0 -28
  149. package/dist/chunk-5ZXV3R5D.js.map +0 -1
  150. package/dist/chunk-CSZ6EOWG.js +0 -61
  151. package/dist/chunk-CSZ6EOWG.js.map +0 -1
  152. package/dist/chunk-HMR2GEGE.js +0 -3
  153. package/dist/chunk-HN72TZY5.js.map +0 -1
  154. package/dist/chunk-KWQHFT7E.js.map +0 -1
  155. package/dist/chunk-M2FRTT2K.js +0 -144
  156. package/dist/chunk-M2FRTT2K.js.map +0 -1
  157. package/dist/chunk-NBIRTKZ7.js +0 -192
  158. package/dist/chunk-NBIRTKZ7.js.map +0 -1
  159. package/dist/chunk-O3XD45IL.js.map +0 -1
  160. package/dist/chunk-U5V5O5MN.js.map +0 -1
  161. package/dist/chunk-UETC63DP.js.map +0 -1
  162. package/dist/types-CQCe_nBM.d.ts +0 -214
@@ -1,7 +1,7 @@
1
- import { analyzeBlueprint } from './chunk-HN72TZY5.js';
1
+ import { analyzeBlueprint } from './chunk-233SESC2.js';
2
2
 
3
3
  // src/linter.ts
4
- function lintBlueprint(blueprint, registry) {
4
+ function lintBlueprint(blueprint, registry, blueprints) {
5
5
  const issues = [];
6
6
  const nodeIds = new Set(blueprint.nodes.map((n) => n.id));
7
7
  const registryKeys = registry instanceof Map ? new Set(registry.keys()) : new Set(Object.keys(registry));
@@ -14,6 +14,26 @@ function lintBlueprint(blueprint, registry) {
14
14
  });
15
15
  }
16
16
  }
17
+ for (const node of blueprint.nodes) {
18
+ if (node.uses.startsWith("batch-") && node.params?.workerUsesKey) {
19
+ if (!registryKeys.has(node.params.workerUsesKey)) {
20
+ issues.push({
21
+ code: "INVALID_BATCH_WORKER_KEY",
22
+ message: `Batch node '${node.id}' references workerUsesKey '${node.params.workerUsesKey}' which is not found in the registry.`,
23
+ nodeId: node.id
24
+ });
25
+ }
26
+ }
27
+ if (node.uses === "subflow" && node.params?.blueprintId) {
28
+ if (!blueprints || !blueprints[node.params.blueprintId]) {
29
+ issues.push({
30
+ code: "INVALID_SUBFLOW_BLUEPRINT_ID",
31
+ message: `Subflow node '${node.id}' references blueprintId '${node.params.blueprintId}' which is not found in the blueprints registry.`,
32
+ nodeId: node.id
33
+ });
34
+ }
35
+ }
36
+ }
17
37
  for (const edge of blueprint.edges || []) {
18
38
  if (!nodeIds.has(edge.source)) {
19
39
  issues.push({
@@ -61,5 +81,5 @@ function lintBlueprint(blueprint, registry) {
61
81
  }
62
82
 
63
83
  export { lintBlueprint };
64
- //# sourceMappingURL=chunk-UETC63DP.js.map
65
- //# sourceMappingURL=chunk-UETC63DP.js.map
84
+ //# sourceMappingURL=chunk-EUJWJWFA.js.map
85
+ //# sourceMappingURL=chunk-EUJWJWFA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/linter.ts"],"names":["e"],"mappings":"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","file":"chunk-EUJWJWFA.js","sourcesContent":["import { analyzeBlueprint } from './analysis'\nimport type { NodeClass, NodeFunction, WorkflowBlueprint } from './types'\n\nexport type LinterIssueCode =\n\t| 'INVALID_EDGE_SOURCE'\n\t| 'INVALID_EDGE_TARGET'\n\t| 'MISSING_NODE_IMPLEMENTATION'\n\t| 'ORPHAN_NODE'\n\t| 'INVALID_BATCH_WORKER_KEY'\n\t| 'INVALID_SUBFLOW_BLUEPRINT_ID'\n\nexport interface LinterIssue {\n\tcode: LinterIssueCode\n\tmessage: string\n\tnodeId?: string\n\trelatedId?: string\n}\n\nexport interface LinterResult {\n\tisValid: boolean\n\tissues: LinterIssue[]\n}\n\n/**\n * Statically analyzes a workflow blueprint against a registry of implementations\n * to find common errors before runtime.\n *\n * @param blueprint The WorkflowBlueprint to analyze.\n * @param registry A map of node implementations (functions or classes) to check against.\n * @returns A LinterResult object containing any issues found.\n */\nexport function lintBlueprint(\n\tblueprint: WorkflowBlueprint,\n\tregistry: Map<string, NodeFunction | NodeClass> | Record<string, NodeFunction | NodeClass>,\n\tblueprints?: Record<string, WorkflowBlueprint>,\n): LinterResult {\n\tconst issues: LinterIssue[] = []\n\tconst nodeIds = new Set(blueprint.nodes.map((n) => n.id))\n\tconst registryKeys = registry instanceof Map ? new Set(registry.keys()) : new Set(Object.keys(registry))\n\n\t// check for missing node implementations\n\tfor (const node of blueprint.nodes) {\n\t\tif (!node.uses.startsWith('batch-') && !node.uses.startsWith('loop-') && !registryKeys.has(node.uses)) {\n\t\t\tissues.push({\n\t\t\t\tcode: 'MISSING_NODE_IMPLEMENTATION',\n\t\t\t\tmessage: `Node implementation key '${node.uses}' is not found in the provided registry.`,\n\t\t\t\tnodeId: node.id,\n\t\t\t})\n\t\t}\n\t}\n\n\t// check for dynamic node validation\n\tfor (const node of blueprint.nodes) {\n\t\tif (node.uses.startsWith('batch-') && node.params?.workerUsesKey) {\n\t\t\tif (!registryKeys.has(node.params.workerUsesKey)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tcode: 'INVALID_BATCH_WORKER_KEY',\n\t\t\t\t\tmessage: `Batch node '${node.id}' references workerUsesKey '${node.params.workerUsesKey}' which is not found in the registry.`,\n\t\t\t\t\tnodeId: node.id,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\tif (node.uses === 'subflow' && node.params?.blueprintId) {\n\t\t\tif (!blueprints || !blueprints[node.params.blueprintId]) {\n\t\t\t\tissues.push({\n\t\t\t\t\tcode: 'INVALID_SUBFLOW_BLUEPRINT_ID',\n\t\t\t\t\tmessage: `Subflow node '${node.id}' references blueprintId '${node.params.blueprintId}' which is not found in the blueprints registry.`,\n\t\t\t\t\tnodeId: node.id,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\t// check for graph integrity (edges must point to valid nodes)\n\tfor (const edge of blueprint.edges || []) {\n\t\tif (!nodeIds.has(edge.source)) {\n\t\t\tissues.push({\n\t\t\t\tcode: 'INVALID_EDGE_SOURCE',\n\t\t\t\tmessage: `Edge source '${edge.source}' does not correspond to a valid node ID.`,\n\t\t\t\trelatedId: edge.target,\n\t\t\t})\n\t\t}\n\t\tif (!nodeIds.has(edge.target)) {\n\t\t\tissues.push({\n\t\t\t\tcode: 'INVALID_EDGE_TARGET',\n\t\t\t\tmessage: `Edge target '${edge.target}' does not correspond to a valid node ID.`,\n\t\t\t\trelatedId: edge.source,\n\t\t\t})\n\t\t}\n\t}\n\n\t// check for orphan nodes (not connected to the main graph)\n\tif (blueprint.nodes.length > 1) {\n\t\tconst analysis = analyzeBlueprint(blueprint)\n\t\tconst connectedNodes = new Set<string>()\n\t\tconst nodesToVisit = [...analysis.startNodeIds]\n\t\tconst visited = new Set<string>()\n\n\t\twhile (nodesToVisit.length > 0) {\n\t\t\tconst currentId = nodesToVisit.pop()\n\t\t\tif (!currentId || visited.has(currentId)) continue\n\n\t\t\tvisited.add(currentId)\n\t\t\tconnectedNodes.add(currentId)\n\n\t\t\tfor (const e of blueprint.edges.filter((e) => e.source === currentId)) {\n\t\t\t\tnodesToVisit.push(e.target)\n\t\t\t}\n\t\t}\n\n\t\tfor (const nodeId of nodeIds) {\n\t\t\tif (!connectedNodes.has(nodeId)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tcode: 'ORPHAN_NODE',\n\t\t\t\t\tmessage: `Node '${nodeId}' is not reachable from any start node.`,\n\t\t\t\t\tnodeId,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tisValid: issues.length === 0,\n\t\tissues,\n\t}\n}\n"]}
@@ -0,0 +1,32 @@
1
+ import { WorkflowState } from './chunk-CD4FUZOJ.js';
2
+
3
+ // src/runtime/execution-context.ts
4
+ var ExecutionContext = class _ExecutionContext {
5
+ constructor(blueprint, state, nodeRegistry, executionId, runtime, services, signal, concurrency) {
6
+ this.blueprint = blueprint;
7
+ this.state = state;
8
+ this.nodeRegistry = nodeRegistry;
9
+ this.executionId = executionId;
10
+ this.runtime = runtime;
11
+ this.services = services;
12
+ this.signal = signal;
13
+ this.concurrency = concurrency;
14
+ }
15
+ createForSubflow(subBlueprint, initialSubState) {
16
+ const subState = new WorkflowState(initialSubState);
17
+ return new _ExecutionContext(
18
+ subBlueprint,
19
+ subState,
20
+ this.nodeRegistry,
21
+ this.executionId,
22
+ this.runtime,
23
+ this.services,
24
+ this.signal,
25
+ this.concurrency
26
+ );
27
+ }
28
+ };
29
+
30
+ export { ExecutionContext };
31
+ //# sourceMappingURL=chunk-FRKO3WX4.js.map
32
+ //# sourceMappingURL=chunk-FRKO3WX4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/execution-context.ts"],"names":[],"mappings":";;;AAkBO,IAAM,gBAAA,GAAN,MAAM,iBAAA,CAAkG;AAAA,EAC9G,WAAA,CACiB,WACA,KAAA,EACA,YAAA,EACA,aACA,OAAA,EACA,QAAA,EAQA,QACA,WAAA,EACf;AAfe,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACA,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAQA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AAAA,EACd;AAAA,EAEI,gBAAA,CACN,cACA,eAAA,EAC4C;AAC5C,IAAA,MAAM,QAAA,GAAW,IAAI,aAAA,CAAwB,eAAe,CAAA;AAC5D,IAAA,OAAO,IAAI,iBAAA;AAAA,MACV,YAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA,CAAK,YAAA;AAAA,MACL,IAAA,CAAK,WAAA;AAAA,MACL,IAAA,CAAK,OAAA;AAAA,MACL,IAAA,CAAK,QAAA;AAAA,MACL,IAAA,CAAK,MAAA;AAAA,MACL,IAAA,CAAK;AAAA,KACN;AAAA,EACD;AACD","file":"chunk-FRKO3WX4.js","sourcesContent":["import type {\n\tIEvaluator,\n\tIEventBus,\n\tILogger,\n\tISerializer,\n\tMiddleware,\n\tNodeClass,\n\tNodeFunction,\n\tRuntimeDependencies,\n\tWorkflowBlueprint,\n} from '../types'\nimport type { FlowRuntime } from './runtime'\nimport { WorkflowState } from './state'\n\n/**\n * A container for all state and dependencies of a single workflow execution.\n * This object is created once per `run` and passed through the execution stack.\n */\nexport class ExecutionContext<TContext extends Record<string, any>, TDependencies extends RuntimeDependencies> {\n\tconstructor(\n\t\tpublic readonly blueprint: WorkflowBlueprint,\n\t\tpublic readonly state: WorkflowState<TContext>,\n\t\tpublic readonly nodeRegistry: Map<string, NodeFunction | NodeClass>,\n\t\tpublic readonly executionId: string,\n\t\tpublic readonly runtime: FlowRuntime<TContext, TDependencies>, // A reference back to the runtime for orchestrating subflows\n\t\tpublic readonly services: {\n\t\t\tlogger: ILogger\n\t\t\teventBus: IEventBus\n\t\t\tserializer: ISerializer\n\t\t\tevaluator: IEvaluator\n\t\t\tmiddleware: Middleware[]\n\t\t\tdependencies: TDependencies\n\t\t},\n\t\tpublic readonly signal?: AbortSignal,\n\t\tpublic readonly concurrency?: number,\n\t) {}\n\n\tpublic createForSubflow(\n\t\tsubBlueprint: WorkflowBlueprint,\n\t\tinitialSubState: Partial<TContext>,\n\t): ExecutionContext<TContext, TDependencies> {\n\t\tconst subState = new WorkflowState<TContext>(initialSubState)\n\t\treturn new ExecutionContext(\n\t\t\tsubBlueprint,\n\t\t\tsubState,\n\t\t\tthis.nodeRegistry,\n\t\t\tthis.executionId,\n\t\t\tthis.runtime,\n\t\t\tthis.services,\n\t\t\tthis.signal,\n\t\t\tthis.concurrency,\n\t\t)\n\t}\n}\n"]}
@@ -0,0 +1,54 @@
1
+ import { executeBatch, processResults } from './chunk-HAZ26F3P.js';
2
+ import { FlowcraftError } from './chunk-BCRWXTWX.js';
3
+
4
+ // src/runtime/orchestrators/step-by-step.ts
5
+ var StepByStepOrchestrator = class {
6
+ async run(context, traverser) {
7
+ try {
8
+ context.signal?.throwIfAborted();
9
+ } catch (error) {
10
+ if (error instanceof DOMException && error.name === "AbortError") {
11
+ throw new FlowcraftError("Workflow cancelled", { isFatal: false });
12
+ }
13
+ throw error;
14
+ }
15
+ if (!traverser.hasMoreWork()) {
16
+ const isTraversalComplete2 = !traverser.hasMoreWork();
17
+ const status2 = context.state.getStatus(isTraversalComplete2);
18
+ const result2 = await context.state.toResult(context.services.serializer);
19
+ result2.status = status2;
20
+ return result2;
21
+ }
22
+ const allReadyNodes = traverser.getReadyNodes();
23
+ const nodesToExecute = context.concurrency ? allReadyNodes.slice(0, context.concurrency) : allReadyNodes;
24
+ const nodesToSkip = context.concurrency ? allReadyNodes.slice(context.concurrency) : [];
25
+ const settledResults = await executeBatch(
26
+ nodesToExecute,
27
+ traverser.getDynamicBlueprint(),
28
+ context.state,
29
+ (nodeId) => context.runtime.getExecutorForNode(nodeId, context),
30
+ context.runtime,
31
+ context.concurrency
32
+ );
33
+ await processResults(
34
+ settledResults,
35
+ traverser,
36
+ context.state,
37
+ context.runtime,
38
+ context.blueprint,
39
+ context.executionId
40
+ );
41
+ for (const { nodeId } of nodesToSkip) {
42
+ traverser.addToFrontier(nodeId);
43
+ }
44
+ const isTraversalComplete = !traverser.hasMoreWork();
45
+ const status = context.state.getStatus(isTraversalComplete);
46
+ const result = await context.state.toResult(context.services.serializer);
47
+ result.status = status;
48
+ return result;
49
+ }
50
+ };
51
+
52
+ export { StepByStepOrchestrator };
53
+ //# sourceMappingURL=chunk-G53CSLBF.js.map
54
+ //# sourceMappingURL=chunk-G53CSLBF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/orchestrators/step-by-step.ts"],"names":["isTraversalComplete","status","result"],"mappings":";;;;AAeO,IAAM,yBAAN,MAAsD;AAAA,EAC5D,MAAa,GAAA,CAAI,OAAA,EAAqC,SAAA,EAAyD;AAC9G,IAAA,IAAI;AACH,MAAA,OAAA,CAAQ,QAAQ,cAAA,EAAe;AAAA,IAChC,SAAS,KAAA,EAAO;AACf,MAAA,IAAI,KAAA,YAAiB,YAAA,IAAgB,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc;AACjE,QAAA,MAAM,IAAI,cAAA,CAAe,oBAAA,EAAsB,EAAE,OAAA,EAAS,OAAO,CAAA;AAAA,MAClE;AACA,MAAA,MAAM,KAAA;AAAA,IACP;AAEA,IAAA,IAAI,CAAC,SAAA,CAAU,WAAA,EAAY,EAAG;AAC7B,MAAA,MAAMA,oBAAAA,GAAsB,CAAC,SAAA,CAAU,WAAA,EAAY;AACnD,MAAA,MAAMC,OAAAA,GAAS,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAUD,oBAAmB,CAAA;AAC1D,MAAA,MAAME,UAAS,MAAM,OAAA,CAAQ,MAAM,QAAA,CAAS,OAAA,CAAQ,SAAS,UAAU,CAAA;AACvE,MAAAA,QAAO,MAAA,GAASD,OAAAA;AAChB,MAAA,OAAOC,OAAAA;AAAA,IACR;AAEA,IAAA,MAAM,aAAA,GAAgB,UAAU,aAAA,EAAc;AAC9C,IAAA,MAAM,cAAA,GAAiB,QAAQ,WAAA,GAAc,aAAA,CAAc,MAAM,CAAA,EAAG,OAAA,CAAQ,WAAW,CAAA,GAAI,aAAA;AAC3F,IAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,GAAc,aAAA,CAAc,MAAM,OAAA,CAAQ,WAAW,IAAI,EAAC;AAEtF,IAAA,MAAM,iBAAiB,MAAM,YAAA;AAAA,MAC5B,cAAA;AAAA,MACA,UAAU,mBAAA,EAAoB;AAAA,MAC9B,OAAA,CAAQ,KAAA;AAAA,MACR,CAAC,MAAA,KAAmB,OAAA,CAAQ,OAAA,CAAQ,kBAAA,CAAmB,QAAQ,OAAO,CAAA;AAAA,MACtE,OAAA,CAAQ,OAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACT;AAEA,IAAA,MAAM,cAAA;AAAA,MACL,cAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA,CAAQ,KAAA;AAAA,MACR,OAAA,CAAQ,OAAA;AAAA,MACR,OAAA,CAAQ,SAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACT;AAEA,IAAA,KAAA,MAAW,EAAE,MAAA,EAAO,IAAK,WAAA,EAAa;AACrC,MAAA,SAAA,CAAU,cAAc,MAAM,CAAA;AAAA,IAC/B;AAEA,IAAA,MAAM,mBAAA,GAAsB,CAAC,SAAA,CAAU,WAAA,EAAY;AACnD,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAU,mBAAmB,CAAA;AAC1D,IAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,MAAM,QAAA,CAAS,OAAA,CAAQ,SAAS,UAAU,CAAA;AACvE,IAAA,MAAA,CAAO,MAAA,GAAS,MAAA;AAChB,IAAA,OAAO,MAAA;AAAA,EACR;AACD","file":"chunk-G53CSLBF.js","sourcesContent":["import { FlowcraftError } from '../../errors'\n\nimport type { WorkflowResult } from '../../types'\nimport type { ExecutionContext } from '../execution-context'\nimport type { GraphTraverser } from '../traverser'\nimport type { IOrchestrator } from '../types'\nimport { executeBatch, processResults } from './utils'\n\n/**\n * An orchestrator that executes only one \"tick\" or \"turn\" of the workflow.\n * It processes a single batch of ready nodes from the frontier and then returns,\n * allowing the caller to inspect the intermediate state before proceeding.\n *\n * Useful for debugging, testing, or building interactive tools.\n */\nexport class StepByStepOrchestrator implements IOrchestrator {\n\tpublic async run(context: ExecutionContext<any, any>, traverser: GraphTraverser): Promise<WorkflowResult<any>> {\n\t\ttry {\n\t\t\tcontext.signal?.throwIfAborted()\n\t\t} catch (error) {\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow new FlowcraftError('Workflow cancelled', { isFatal: false })\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\n\t\tif (!traverser.hasMoreWork()) {\n\t\t\tconst isTraversalComplete = !traverser.hasMoreWork()\n\t\t\tconst status = context.state.getStatus(isTraversalComplete)\n\t\t\tconst result = await context.state.toResult(context.services.serializer)\n\t\t\tresult.status = status\n\t\t\treturn result\n\t\t}\n\n\t\tconst allReadyNodes = traverser.getReadyNodes()\n\t\tconst nodesToExecute = context.concurrency ? allReadyNodes.slice(0, context.concurrency) : allReadyNodes\n\t\tconst nodesToSkip = context.concurrency ? allReadyNodes.slice(context.concurrency) : []\n\n\t\tconst settledResults = await executeBatch(\n\t\t\tnodesToExecute,\n\t\t\ttraverser.getDynamicBlueprint(),\n\t\t\tcontext.state,\n\t\t\t(nodeId: string) => context.runtime.getExecutorForNode(nodeId, context),\n\t\t\tcontext.runtime,\n\t\t\tcontext.concurrency,\n\t\t)\n\n\t\tawait processResults(\n\t\t\tsettledResults,\n\t\t\ttraverser,\n\t\t\tcontext.state,\n\t\t\tcontext.runtime,\n\t\t\tcontext.blueprint,\n\t\t\tcontext.executionId,\n\t\t)\n\n\t\tfor (const { nodeId } of nodesToSkip) {\n\t\t\ttraverser.addToFrontier(nodeId)\n\t\t}\n\n\t\tconst isTraversalComplete = !traverser.hasMoreWork()\n\t\tconst status = context.state.getStatus(isTraversalComplete)\n\t\tconst result = await context.state.toResult(context.services.serializer)\n\t\tresult.status = status\n\t\treturn result\n\t}\n}\n"]}
@@ -0,0 +1,172 @@
1
+ import { analyzeBlueprint } from './chunk-233SESC2.js';
2
+
3
+ // src/runtime/traverser.ts
4
+ var GraphTraverser = class _GraphTraverser {
5
+ frontier = /* @__PURE__ */ new Set();
6
+ allPredecessors;
7
+ dynamicBlueprint;
8
+ completedNodes = /* @__PURE__ */ new Set();
9
+ constructor(blueprint, isStrictMode = false) {
10
+ this.dynamicBlueprint = structuredClone(blueprint);
11
+ this.allPredecessors = /* @__PURE__ */ new Map();
12
+ for (const node of this.dynamicBlueprint.nodes) {
13
+ this.allPredecessors.set(node.id, /* @__PURE__ */ new Set());
14
+ }
15
+ for (const edge of this.dynamicBlueprint.edges) {
16
+ this.allPredecessors.get(edge.target)?.add(edge.source);
17
+ }
18
+ const analysis = analyzeBlueprint(blueprint);
19
+ this.frontier = new Set(analysis.startNodeIds.filter((id) => !this.isFallbackNode(id)));
20
+ if (this.frontier.size === 0 && analysis.cycles.length > 0 && !isStrictMode) {
21
+ const uniqueStartNodes = /* @__PURE__ */ new Set();
22
+ const cycleEntryPoints = new Set(blueprint.metadata?.cycleEntryPoints || []);
23
+ for (const cycle of analysis.cycles) {
24
+ if (cycle.length > 0) {
25
+ const entryPoint = cycle.find((node) => cycleEntryPoints.has(node));
26
+ uniqueStartNodes.add(entryPoint || cycle[0]);
27
+ }
28
+ }
29
+ this.frontier = new Set(uniqueStartNodes);
30
+ }
31
+ }
32
+ /**
33
+ * Clears all nodes from the execution frontier.
34
+ */
35
+ clearFrontier() {
36
+ this.frontier.clear();
37
+ }
38
+ /**
39
+ * Creates and initializes a GraphTraverser from a saved workflow state.
40
+ * This is the correct way to prepare a traverser for a `resume` operation.
41
+ * @param blueprint The workflow blueprint.
42
+ * @param state The workflow state being resumed.
43
+ * @returns A configured GraphTraverser instance.
44
+ */
45
+ static fromState(blueprint, state) {
46
+ const traverser = new _GraphTraverser(blueprint);
47
+ traverser.clearFrontier();
48
+ const completedNodes = state.getCompletedNodes();
49
+ traverser.completedNodes = new Set(completedNodes);
50
+ for (const node of traverser.dynamicBlueprint.nodes) {
51
+ if (traverser.completedNodes.has(node.id)) continue;
52
+ const requiredPredecessors = traverser.allPredecessors.get(node.id);
53
+ const joinStrategy = traverser.getEffectiveJoinStrategy(node.id);
54
+ if (!requiredPredecessors || requiredPredecessors.size === 0) {
55
+ traverser.frontier.add(node.id);
56
+ continue;
57
+ }
58
+ const completedPredecessors = [...requiredPredecessors].filter((p) => traverser.completedNodes.has(p));
59
+ const isReady = joinStrategy === "any" ? completedPredecessors.length > 0 : completedPredecessors.length === requiredPredecessors.size;
60
+ if (isReady) traverser.frontier.add(node.id);
61
+ }
62
+ return traverser;
63
+ }
64
+ isFallbackNode(nodeId) {
65
+ return this.dynamicBlueprint.nodes.some((n) => n.config?.fallback === nodeId);
66
+ }
67
+ getEffectiveJoinStrategy(nodeId) {
68
+ const node = this.dynamicBlueprint.nodes.find((n) => n.id === nodeId);
69
+ const baseJoinStrategy = node?.config?.joinStrategy || "all";
70
+ if (node?.uses === "loop-controller") {
71
+ return "any";
72
+ }
73
+ const predecessors = this.allPredecessors.get(nodeId);
74
+ if (predecessors) {
75
+ for (const predecessorId of predecessors) {
76
+ const predecessorNode = this.dynamicBlueprint.nodes.find((n) => n.id === predecessorId);
77
+ if (predecessorNode?.uses === "loop-controller") {
78
+ return "any";
79
+ }
80
+ }
81
+ }
82
+ return baseJoinStrategy;
83
+ }
84
+ getReadyNodes() {
85
+ const readyNodes = [];
86
+ for (const nodeId of this.frontier) {
87
+ const nodeDef = this.dynamicBlueprint.nodes.find((n) => n.id === nodeId);
88
+ if (nodeDef) {
89
+ readyNodes.push({ nodeId, nodeDef });
90
+ }
91
+ }
92
+ this.frontier.clear();
93
+ return readyNodes;
94
+ }
95
+ hasMoreWork() {
96
+ return this.frontier.size > 0;
97
+ }
98
+ markNodeCompleted(nodeId, result, nextNodes) {
99
+ this.completedNodes.add(nodeId);
100
+ if (result.dynamicNodes && result.dynamicNodes.length > 0) {
101
+ const gatherNodeId = result.output?.gatherNodeId;
102
+ for (const dynamicNode of result.dynamicNodes) {
103
+ this.dynamicBlueprint.nodes.push(dynamicNode);
104
+ this.allPredecessors.set(dynamicNode.id, /* @__PURE__ */ new Set([nodeId]));
105
+ if (gatherNodeId) {
106
+ this.allPredecessors.get(gatherNodeId)?.add(dynamicNode.id);
107
+ }
108
+ this.frontier.add(dynamicNode.id);
109
+ }
110
+ }
111
+ for (const node of nextNodes) {
112
+ const joinStrategy = this.getEffectiveJoinStrategy(node.id);
113
+ if (joinStrategy !== "any" && this.completedNodes.has(node.id)) continue;
114
+ const requiredPredecessors = this.allPredecessors.get(node.id);
115
+ if (!requiredPredecessors) continue;
116
+ const isReady = joinStrategy === "any" ? requiredPredecessors.has(nodeId) : [...requiredPredecessors].every((p) => this.completedNodes.has(p));
117
+ if (isReady) {
118
+ this.frontier.add(node.id);
119
+ }
120
+ }
121
+ if (nextNodes.length === 0) {
122
+ for (const [potentialNextId, predecessors] of this.allPredecessors) {
123
+ if (predecessors.has(nodeId) && !this.completedNodes.has(potentialNextId)) {
124
+ const joinStrategy = this.getEffectiveJoinStrategy(potentialNextId);
125
+ const isReady = joinStrategy === "any" ? predecessors.has(nodeId) : [...predecessors].every((p) => this.completedNodes.has(p));
126
+ if (isReady) {
127
+ this.frontier.add(potentialNextId);
128
+ }
129
+ }
130
+ }
131
+ }
132
+ }
133
+ getAllNodeIds() {
134
+ return new Set(this.dynamicBlueprint.nodes.map((n) => n.id));
135
+ }
136
+ getFallbackNodeIds() {
137
+ const fallbackNodeIds = /* @__PURE__ */ new Set();
138
+ for (const node of this.dynamicBlueprint.nodes) {
139
+ if (node.config?.fallback) fallbackNodeIds.add(node.config.fallback);
140
+ }
141
+ return fallbackNodeIds;
142
+ }
143
+ getCompletedNodes() {
144
+ return new Set(this.completedNodes);
145
+ }
146
+ getDynamicBlueprint() {
147
+ return this.dynamicBlueprint;
148
+ }
149
+ getAllPredecessors() {
150
+ return this.allPredecessors;
151
+ }
152
+ addDynamicNode(_nodeId, dynamicNode, predecessorId, gatherNodeId) {
153
+ this.dynamicBlueprint.nodes.push(dynamicNode);
154
+ this.allPredecessors.set(dynamicNode.id, /* @__PURE__ */ new Set([predecessorId]));
155
+ if (gatherNodeId) {
156
+ this.allPredecessors.get(gatherNodeId)?.add(dynamicNode.id);
157
+ }
158
+ this.frontier.add(dynamicNode.id);
159
+ }
160
+ /**
161
+ * Manually adds a node ID back to the execution frontier.
162
+ * Used by orchestrators that need fine-grained control over steps.
163
+ * @param nodeId The ID of the node to add to the frontier.
164
+ */
165
+ addToFrontier(nodeId) {
166
+ this.frontier.add(nodeId);
167
+ }
168
+ };
169
+
170
+ export { GraphTraverser };
171
+ //# sourceMappingURL=chunk-G5BGBPFP.js.map
172
+ //# sourceMappingURL=chunk-G5BGBPFP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/traverser.ts"],"names":[],"mappings":"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","file":"chunk-G5BGBPFP.js","sourcesContent":["import { analyzeBlueprint } from '../analysis'\nimport type { NodeDefinition, NodeResult, WorkflowBlueprint } from '../types'\nimport type { WorkflowState } from './state'\n\nexport interface ReadyNode {\n\tnodeId: string\n\tnodeDef: NodeDefinition\n}\n\nexport class GraphTraverser {\n\tprivate frontier = new Set<string>()\n\tprivate allPredecessors: Map<string, Set<string>>\n\tprivate dynamicBlueprint: WorkflowBlueprint\n\tprivate completedNodes = new Set<string>()\n\n\tconstructor(blueprint: WorkflowBlueprint, isStrictMode: boolean = false) {\n\t\tthis.dynamicBlueprint = structuredClone(blueprint) as WorkflowBlueprint\n\t\tthis.allPredecessors = new Map<string, Set<string>>()\n\t\tfor (const node of this.dynamicBlueprint.nodes) {\n\t\t\tthis.allPredecessors.set(node.id, new Set())\n\t\t}\n\t\tfor (const edge of this.dynamicBlueprint.edges) {\n\t\t\tthis.allPredecessors.get(edge.target)?.add(edge.source)\n\t\t}\n\t\tconst analysis = analyzeBlueprint(blueprint)\n\t\tthis.frontier = new Set(analysis.startNodeIds.filter((id) => !this.isFallbackNode(id)))\n\t\tif (this.frontier.size === 0 && analysis.cycles.length > 0 && !isStrictMode) {\n\t\t\tconst uniqueStartNodes = new Set<string>()\n\t\t\tconst cycleEntryPoints = new Set(blueprint.metadata?.cycleEntryPoints || [])\n\t\t\tfor (const cycle of analysis.cycles) {\n\t\t\t\tif (cycle.length > 0) {\n\t\t\t\t\tconst entryPoint = cycle.find((node) => cycleEntryPoints.has(node))\n\t\t\t\t\tuniqueStartNodes.add(entryPoint || cycle[0])\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.frontier = new Set(uniqueStartNodes)\n\t\t}\n\t}\n\n\t/**\n\t * Clears all nodes from the execution frontier.\n\t */\n\tpublic clearFrontier(): void {\n\t\tthis.frontier.clear()\n\t}\n\n\t/**\n\t * Creates and initializes a GraphTraverser from a saved workflow state.\n\t * This is the correct way to prepare a traverser for a `resume` operation.\n\t * @param blueprint The workflow blueprint.\n\t * @param state The workflow state being resumed.\n\t * @returns A configured GraphTraverser instance.\n\t */\n\tpublic static fromState(blueprint: WorkflowBlueprint, state: WorkflowState<any>): GraphTraverser {\n\t\tconst traverser = new GraphTraverser(blueprint)\n\n\t\t// clear auto-populated frontier from constructor\n\t\ttraverser.clearFrontier()\n\n\t\t// re-hydrate the set of completed nodes\n\t\tconst completedNodes = state.getCompletedNodes()\n\t\ttraverser.completedNodes = new Set(completedNodes)\n\n\t\tfor (const node of traverser.dynamicBlueprint.nodes) {\n\t\t\tif (traverser.completedNodes.has(node.id)) continue\n\n\t\t\tconst requiredPredecessors = traverser.allPredecessors.get(node.id)\n\t\t\tconst joinStrategy = traverser.getEffectiveJoinStrategy(node.id)\n\n\t\t\t// if no predecessors and not completed, it's a start node and should be in the frontier\n\t\t\tif (!requiredPredecessors || requiredPredecessors.size === 0) {\n\t\t\t\ttraverser.frontier.add(node.id)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst completedPredecessors = [...requiredPredecessors].filter((p) => traverser.completedNodes.has(p))\n\t\t\tconst isReady =\n\t\t\t\tjoinStrategy === 'any'\n\t\t\t\t\t? completedPredecessors.length > 0\n\t\t\t\t\t: completedPredecessors.length === requiredPredecessors.size\n\n\t\t\tif (isReady) traverser.frontier.add(node.id)\n\t\t}\n\n\t\treturn traverser\n\t}\n\n\tprivate isFallbackNode(nodeId: string): boolean {\n\t\treturn this.dynamicBlueprint.nodes.some((n) => n.config?.fallback === nodeId)\n\t}\n\n\tprivate getEffectiveJoinStrategy(nodeId: string): 'any' | 'all' {\n\t\tconst node = this.dynamicBlueprint.nodes.find((n) => n.id === nodeId)\n\t\tconst baseJoinStrategy = node?.config?.joinStrategy || 'all'\n\n\t\tif (node?.uses === 'loop-controller') {\n\t\t\treturn 'any'\n\t\t}\n\n\t\tconst predecessors = this.allPredecessors.get(nodeId)\n\t\tif (predecessors) {\n\t\t\tfor (const predecessorId of predecessors) {\n\t\t\t\tconst predecessorNode = this.dynamicBlueprint.nodes.find((n) => n.id === predecessorId)\n\t\t\t\tif (predecessorNode?.uses === 'loop-controller') {\n\t\t\t\t\treturn 'any'\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn baseJoinStrategy\n\t}\n\n\tgetReadyNodes(): ReadyNode[] {\n\t\tconst readyNodes: ReadyNode[] = []\n\t\tfor (const nodeId of this.frontier) {\n\t\t\tconst nodeDef = this.dynamicBlueprint.nodes.find((n) => n.id === nodeId)\n\t\t\tif (nodeDef) {\n\t\t\t\treadyNodes.push({ nodeId, nodeDef })\n\t\t\t}\n\t\t}\n\t\tthis.frontier.clear()\n\t\treturn readyNodes\n\t}\n\n\thasMoreWork(): boolean {\n\t\treturn this.frontier.size > 0\n\t}\n\n\tmarkNodeCompleted(nodeId: string, result: NodeResult<any, any>, nextNodes: NodeDefinition[]): void {\n\t\tthis.completedNodes.add(nodeId)\n\n\t\tif (result.dynamicNodes && result.dynamicNodes.length > 0) {\n\t\t\tconst gatherNodeId = result.output?.gatherNodeId\n\t\t\tfor (const dynamicNode of result.dynamicNodes) {\n\t\t\t\tthis.dynamicBlueprint.nodes.push(dynamicNode)\n\t\t\t\tthis.allPredecessors.set(dynamicNode.id, new Set([nodeId]))\n\t\t\t\tif (gatherNodeId) {\n\t\t\t\t\tthis.allPredecessors.get(gatherNodeId)?.add(dynamicNode.id)\n\t\t\t\t}\n\t\t\t\tthis.frontier.add(dynamicNode.id)\n\t\t\t}\n\t\t}\n\n\t\tfor (const node of nextNodes) {\n\t\t\tconst joinStrategy = this.getEffectiveJoinStrategy(node.id)\n\t\t\tif (joinStrategy !== 'any' && this.completedNodes.has(node.id)) continue\n\n\t\t\tconst requiredPredecessors = this.allPredecessors.get(node.id)\n\t\t\tif (!requiredPredecessors) continue\n\n\t\t\tconst isReady =\n\t\t\t\tjoinStrategy === 'any'\n\t\t\t\t\t? requiredPredecessors.has(nodeId)\n\t\t\t\t\t: [...requiredPredecessors].every((p) => this.completedNodes.has(p))\n\n\t\t\tif (isReady) {\n\t\t\t\tthis.frontier.add(node.id)\n\t\t\t}\n\t\t}\n\n\t\tif (nextNodes.length === 0) {\n\t\t\tfor (const [potentialNextId, predecessors] of this.allPredecessors) {\n\t\t\t\tif (predecessors.has(nodeId) && !this.completedNodes.has(potentialNextId)) {\n\t\t\t\t\tconst joinStrategy = this.getEffectiveJoinStrategy(potentialNextId)\n\t\t\t\t\tconst isReady =\n\t\t\t\t\t\tjoinStrategy === 'any'\n\t\t\t\t\t\t\t? predecessors.has(nodeId)\n\t\t\t\t\t\t\t: [...predecessors].every((p) => this.completedNodes.has(p))\n\t\t\t\t\tif (isReady) {\n\t\t\t\t\t\tthis.frontier.add(potentialNextId)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tgetAllNodeIds(): Set<string> {\n\t\treturn new Set(this.dynamicBlueprint.nodes.map((n) => n.id))\n\t}\n\n\tgetFallbackNodeIds(): Set<string> {\n\t\tconst fallbackNodeIds = new Set<string>()\n\t\tfor (const node of this.dynamicBlueprint.nodes) {\n\t\t\tif (node.config?.fallback) fallbackNodeIds.add(node.config.fallback)\n\t\t}\n\t\treturn fallbackNodeIds\n\t}\n\n\tgetCompletedNodes(): Set<string> {\n\t\treturn new Set(this.completedNodes)\n\t}\n\n\tgetDynamicBlueprint(): WorkflowBlueprint {\n\t\treturn this.dynamicBlueprint\n\t}\n\n\tgetAllPredecessors(): Map<string, Set<string>> {\n\t\treturn this.allPredecessors\n\t}\n\n\taddDynamicNode(_nodeId: string, dynamicNode: NodeDefinition, predecessorId: string, gatherNodeId?: string): void {\n\t\tthis.dynamicBlueprint.nodes.push(dynamicNode)\n\t\tthis.allPredecessors.set(dynamicNode.id, new Set([predecessorId]))\n\t\tif (gatherNodeId) {\n\t\t\tthis.allPredecessors.get(gatherNodeId)?.add(dynamicNode.id)\n\t\t}\n\t\tthis.frontier.add(dynamicNode.id)\n\t}\n\n\t/**\n\t * Manually adds a node ID back to the execution frontier.\n\t * Used by orchestrators that need fine-grained control over steps.\n\t * @param nodeId The ID of the node to add to the frontier.\n\t */\n\tpublic addToFrontier(nodeId: string): void {\n\t\tthis.frontier.add(nodeId)\n\t}\n}\n"]}
@@ -0,0 +1,98 @@
1
+ import { FlowcraftError } from './chunk-BCRWXTWX.js';
2
+
3
+ // src/runtime/orchestrators/utils.ts
4
+ async function executeBatch(readyNodes, blueprint, state, executorFactory, runtime, maxConcurrency) {
5
+ const concurrency = maxConcurrency || readyNodes.length;
6
+ const results = [];
7
+ for (let i = 0; i < readyNodes.length; i += concurrency) {
8
+ const batch = readyNodes.slice(i, i + concurrency);
9
+ const batchPromises = batch.map(async ({ nodeId }) => {
10
+ try {
11
+ const executor = executorFactory(nodeId);
12
+ if (!executor) throw new Error(`No executor for node ${nodeId}`);
13
+ const executionResult = await executor.execute(
14
+ await runtime.resolveNodeInput(nodeId, blueprint, state.getContext())
15
+ );
16
+ results.push({
17
+ status: "fulfilled",
18
+ value: { nodeId, executionResult }
19
+ });
20
+ } catch (error) {
21
+ results.push({
22
+ status: "rejected",
23
+ reason: { nodeId, error }
24
+ });
25
+ }
26
+ });
27
+ await Promise.all(batchPromises);
28
+ }
29
+ return results;
30
+ }
31
+ async function processResults(settledResults, traverser, state, runtime, _blueprint, executionId) {
32
+ for (const promiseResult of settledResults) {
33
+ if (promiseResult.status === "rejected") {
34
+ const { nodeId: nodeId2, error } = promiseResult.reason;
35
+ if (error instanceof FlowcraftError && error.message.includes("cancelled")) {
36
+ throw error;
37
+ }
38
+ state.addError(nodeId2, error);
39
+ continue;
40
+ }
41
+ const { nodeId, executionResult } = promiseResult.value;
42
+ if (executionResult.status === "success") {
43
+ const result = executionResult.result;
44
+ state.addCompletedNode(nodeId, result.output);
45
+ if (result._fallbackExecuted) {
46
+ state.markFallbackExecuted();
47
+ }
48
+ if (result.dynamicNodes && result.dynamicNodes.length > 0) {
49
+ const gatherNodeId = result.output?.gatherNodeId;
50
+ for (const dynamicNode of result.dynamicNodes) {
51
+ traverser.addDynamicNode(dynamicNode.id, dynamicNode, nodeId, gatherNodeId);
52
+ }
53
+ }
54
+ const matched = await runtime.determineNextNodes(
55
+ traverser.getDynamicBlueprint(),
56
+ nodeId,
57
+ result,
58
+ state.getContext(),
59
+ executionId
60
+ );
61
+ const loopControllerMatch = matched.find(
62
+ (m) => m.node.uses === "loop-controller"
63
+ );
64
+ const finalMatched = loopControllerMatch ? [loopControllerMatch] : matched;
65
+ for (const { node, edge } of finalMatched) {
66
+ await runtime.applyEdgeTransform(edge, result, node, state.getContext(), traverser.getAllPredecessors());
67
+ }
68
+ traverser.markNodeCompleted(
69
+ nodeId,
70
+ result,
71
+ finalMatched.map((m) => m.node)
72
+ );
73
+ } else if (executionResult.status === "failed_with_fallback") {
74
+ const { fallbackNodeId, error } = executionResult;
75
+ const blueprint = traverser.getDynamicBlueprint();
76
+ const fallbackNodeDef = blueprint.nodes.find((n) => n.id === fallbackNodeId);
77
+ if (!fallbackNodeDef) {
78
+ const notFoundError = new FlowcraftError(`Fallback node '${fallbackNodeId}' not found in blueprint.`, {
79
+ nodeId,
80
+ cause: error
81
+ });
82
+ state.addError(nodeId, notFoundError);
83
+ } else {
84
+ state.addCompletedNode(nodeId, null);
85
+ state.markFallbackExecuted();
86
+ traverser.markNodeCompleted(nodeId, { action: "fallback", output: null, _fallbackExecuted: true }, [
87
+ fallbackNodeDef
88
+ ]);
89
+ }
90
+ } else {
91
+ state.addError(nodeId, executionResult.error);
92
+ }
93
+ }
94
+ }
95
+
96
+ export { executeBatch, processResults };
97
+ //# sourceMappingURL=chunk-HAZ26F3P.js.map
98
+ //# sourceMappingURL=chunk-HAZ26F3P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/orchestrators/utils.ts"],"names":["nodeId"],"mappings":"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","file":"chunk-HAZ26F3P.js","sourcesContent":["import { FlowcraftError } from '../../errors'\nimport type { NodeDefinition, WorkflowBlueprint } from '../../types'\nimport type { NodeExecutionResult } from '../executors'\nimport type { WorkflowState } from '../state'\nimport type { GraphTraverser } from '../traverser'\n\nexport async function executeBatch(\n\treadyNodes: Array<{ nodeId: string; nodeDef: any }>,\n\tblueprint: WorkflowBlueprint,\n\tstate: WorkflowState<any>,\n\texecutorFactory: (nodeId: string) => any,\n\truntime: any,\n\tmaxConcurrency?: number,\n): Promise<\n\tArray<\n\t\t| { status: 'fulfilled'; value: { nodeId: string; executionResult: NodeExecutionResult } }\n\t\t| { status: 'rejected'; reason: { nodeId: string; error: unknown } }\n\t>\n> {\n\tconst concurrency = maxConcurrency || readyNodes.length\n\tconst results: Array<\n\t\t| { status: 'fulfilled'; value: { nodeId: string; executionResult: NodeExecutionResult } }\n\t\t| { status: 'rejected'; reason: { nodeId: string; error: unknown } }\n\t> = []\n\n\tfor (let i = 0; i < readyNodes.length; i += concurrency) {\n\t\tconst batch = readyNodes.slice(i, i + concurrency)\n\t\tconst batchPromises = batch.map(async ({ nodeId }) => {\n\t\t\ttry {\n\t\t\t\tconst executor = executorFactory(nodeId)\n\t\t\t\tif (!executor) throw new Error(`No executor for node ${nodeId}`)\n\t\t\t\tconst executionResult = await executor.execute(\n\t\t\t\t\tawait runtime.resolveNodeInput(nodeId, blueprint, state.getContext()),\n\t\t\t\t)\n\t\t\t\tresults.push({\n\t\t\t\t\tstatus: 'fulfilled' as const,\n\t\t\t\t\tvalue: { nodeId, executionResult },\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\tresults.push({\n\t\t\t\t\tstatus: 'rejected' as const,\n\t\t\t\t\treason: { nodeId, error },\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\n\t\tawait Promise.all(batchPromises)\n\t}\n\n\treturn results\n}\n\nexport async function processResults(\n\tsettledResults: Array<\n\t\t| { status: 'fulfilled'; value: { nodeId: string; executionResult: NodeExecutionResult } }\n\t\t| { status: 'rejected'; reason: { nodeId: string; error: unknown } }\n\t>,\n\ttraverser: GraphTraverser,\n\tstate: WorkflowState<any>,\n\truntime: any,\n\t_blueprint: WorkflowBlueprint,\n\texecutionId?: string,\n): Promise<void> {\n\tfor (const promiseResult of settledResults) {\n\t\tif (promiseResult.status === 'rejected') {\n\t\t\tconst { nodeId, error } = promiseResult.reason\n\t\t\tif (error instanceof FlowcraftError && error.message.includes('cancelled')) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tstate.addError(nodeId, error as Error)\n\t\t\tcontinue\n\t\t}\n\n\t\tconst { nodeId, executionResult } = promiseResult.value\n\n\t\tif (executionResult.status === 'success') {\n\t\t\tconst result = executionResult.result\n\t\t\tstate.addCompletedNode(nodeId, result.output)\n\t\t\tif (result._fallbackExecuted) {\n\t\t\t\tstate.markFallbackExecuted()\n\t\t\t}\n\n\t\t\tif (result.dynamicNodes && result.dynamicNodes.length > 0) {\n\t\t\t\tconst gatherNodeId = result.output?.gatherNodeId\n\t\t\t\tfor (const dynamicNode of result.dynamicNodes) {\n\t\t\t\t\ttraverser.addDynamicNode(dynamicNode.id, dynamicNode, nodeId, gatherNodeId)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst matched = await runtime.determineNextNodes(\n\t\t\t\ttraverser.getDynamicBlueprint(),\n\t\t\t\tnodeId,\n\t\t\t\tresult,\n\t\t\t\tstate.getContext(),\n\t\t\t\texecutionId,\n\t\t\t)\n\n\t\t\tconst loopControllerMatch = matched.find(\n\t\t\t\t(m: { node: NodeDefinition; edge: any }) => m.node.uses === 'loop-controller',\n\t\t\t)\n\t\t\tconst finalMatched = loopControllerMatch ? [loopControllerMatch] : matched\n\n\t\t\tfor (const { node, edge } of finalMatched) {\n\t\t\t\tawait runtime.applyEdgeTransform(edge, result, node, state.getContext(), traverser.getAllPredecessors())\n\t\t\t}\n\n\t\t\ttraverser.markNodeCompleted(\n\t\t\t\tnodeId,\n\t\t\t\tresult,\n\t\t\t\tfinalMatched.map((m: { node: NodeDefinition; edge: any }) => m.node),\n\t\t\t)\n\t\t} else if (executionResult.status === 'failed_with_fallback') {\n\t\t\tconst { fallbackNodeId, error } = executionResult\n\t\t\tconst blueprint = traverser.getDynamicBlueprint()\n\t\t\tconst fallbackNodeDef = blueprint.nodes.find((n) => n.id === fallbackNodeId)\n\n\t\t\tif (!fallbackNodeDef) {\n\t\t\t\tconst notFoundError = new FlowcraftError(`Fallback node '${fallbackNodeId}' not found in blueprint.`, {\n\t\t\t\t\tnodeId,\n\t\t\t\t\tcause: error,\n\t\t\t\t})\n\t\t\t\tstate.addError(nodeId, notFoundError)\n\t\t\t} else {\n\t\t\t\tstate.addCompletedNode(nodeId, null)\n\t\t\t\tstate.markFallbackExecuted()\n\n\t\t\t\ttraverser.markNodeCompleted(nodeId, { action: 'fallback', output: null, _fallbackExecuted: true }, [\n\t\t\t\t\tfallbackNodeDef,\n\t\t\t\t])\n\t\t\t}\n\t\t} else {\n\t\t\tstate.addError(nodeId, executionResult.error)\n\t\t}\n\t}\n}\n"]}