@codemation/core 0.0.19 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/EngineRuntimeRegistration.types-0sgV2XL2.d.ts +42 -0
  3. package/dist/EngineWorkflowRunnerService-Dx7bJsJR.d.cts +73 -0
  4. package/dist/InMemoryRunDataFactory-qIYQEar7.d.cts +94 -0
  5. package/dist/{InMemoryLiveWorkflowRepository-DxoualoC.d.ts → RunIntentService-BCvGdOSY.d.ts} +438 -9
  6. package/dist/{RunIntentService-C1nu_YwM.js → RunIntentService-BFA48UpH.js} +252 -67
  7. package/dist/RunIntentService-BFA48UpH.js.map +1 -0
  8. package/dist/{InMemoryLiveWorkflowRepository-orY1VsWG.d.cts → RunIntentService-CV8izV8t.d.cts} +214 -7
  9. package/dist/{RunIntentService-ZkjpY7MS.cjs → RunIntentService-DcxXf_AM.cjs} +262 -65
  10. package/dist/RunIntentService-DcxXf_AM.cjs.map +1 -0
  11. package/dist/bootstrap/index.cjs +14 -1135
  12. package/dist/bootstrap/index.d.cts +7 -60
  13. package/dist/bootstrap/index.d.ts +4 -40
  14. package/dist/bootstrap/index.js +3 -1122
  15. package/dist/bootstrap-D67Sf2BF.js +1136 -0
  16. package/dist/bootstrap-D67Sf2BF.js.map +1 -0
  17. package/dist/bootstrap-DoQHAEQJ.cjs +1203 -0
  18. package/dist/bootstrap-DoQHAEQJ.cjs.map +1 -0
  19. package/dist/{index-BIewO9-9.d.ts → index-CueSzHsf.d.ts} +37 -260
  20. package/dist/index.cjs +99 -223
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +201 -6
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js +93 -218
  25. package/dist/index.js.map +1 -1
  26. package/dist/testing.cjs +329 -3
  27. package/dist/testing.cjs.map +1 -1
  28. package/dist/testing.d.cts +181 -4
  29. package/dist/testing.d.ts +181 -3
  30. package/dist/testing.js +319 -2
  31. package/dist/testing.js.map +1 -1
  32. package/dist/workflowActivationPolicy-B8HzTk3o.js +201 -0
  33. package/dist/workflowActivationPolicy-B8HzTk3o.js.map +1 -0
  34. package/dist/workflowActivationPolicy-BzyzXLa_.cjs +231 -0
  35. package/dist/workflowActivationPolicy-BzyzXLa_.cjs.map +1 -0
  36. package/package.json +1 -1
  37. package/src/ai/AgentConnectionNodeCollector.ts +99 -0
  38. package/src/ai/AgentToolFactory.ts +38 -2
  39. package/src/ai/AiHost.ts +1 -1
  40. package/src/authoring/defineNode.types.ts +6 -0
  41. package/src/browser.ts +11 -0
  42. package/src/contracts/executionPersistenceContracts.ts +186 -0
  43. package/src/contracts/index.ts +1 -0
  44. package/src/contracts/runFinishedAtFactory.ts +5 -2
  45. package/src/contracts/runTypes.ts +10 -0
  46. package/src/contracts/runtimeTypes.ts +6 -2
  47. package/src/contracts/workflowTypes.ts +3 -2
  48. package/src/events/EventPublishingWorkflowExecutionRepository.ts +5 -0
  49. package/src/execution/ActivationEnqueueService.ts +8 -8
  50. package/src/execution/PersistedRunStateTerminalBuilder.ts +3 -0
  51. package/src/index.ts +6 -0
  52. package/src/orchestration/NodeExecutionRequestHandlerService.ts +11 -6
  53. package/src/orchestration/RunContinuationService.ts +94 -24
  54. package/src/runStorage/InMemoryWorkflowExecutionRepository.ts +14 -1
  55. package/src/scheduler/DefaultDrivingScheduler.ts +21 -11
  56. package/src/scheduler/InlineDrivingScheduler.ts +17 -21
  57. package/src/testing/CapturingScheduler.ts +15 -0
  58. package/src/testing/EngineTestKitRunIdFactory.ts +24 -0
  59. package/src/testing/InMemoryTriggerSetupStateRepository.ts +21 -0
  60. package/src/testing/PrefixedSequentialIdGenerator.ts +17 -0
  61. package/src/testing/RegistrarEngineTestKit.types.ts +76 -0
  62. package/src/testing/RegistrarEngineTestKitFactory.ts +154 -0
  63. package/src/testing/SubWorkflowRunnerTestNode.ts +83 -0
  64. package/src/testing/WorkflowTestHarnessManualTrigger.ts +39 -0
  65. package/src/testing/WorkflowTestKit.types.ts +9 -0
  66. package/src/testing/WorkflowTestKitBuilder.ts +77 -0
  67. package/src/testing/WorkflowTestKitNodeRegistrationContextFactory.ts +17 -0
  68. package/src/testing/WorkflowTestKitRunNodeWorkflowFactory.ts +26 -0
  69. package/src/testing.ts +19 -0
  70. package/src/types/index.ts +1 -0
  71. package/src/workflow/definition/ConnectionNodeIdFactory.ts +28 -0
  72. package/dist/InMemoryLiveWorkflowRepository-BTzHpQ6e.cjs +0 -151
  73. package/dist/InMemoryLiveWorkflowRepository-BTzHpQ6e.cjs.map +0 -1
  74. package/dist/InMemoryLiveWorkflowRepository-BoLNnVLg.js +0 -139
  75. package/dist/InMemoryLiveWorkflowRepository-BoLNnVLg.js.map +0 -1
  76. package/dist/RunIntentService-C1nu_YwM.js.map +0 -1
  77. package/dist/RunIntentService-DjbxzBBP.d.cts +0 -288
  78. package/dist/RunIntentService-ZkjpY7MS.cjs.map +0 -1
  79. package/dist/WorkflowSnapshotCodec-DSEzKyt3.d.cts +0 -22
  80. package/dist/bootstrap/index.cjs.map +0 -1
  81. package/dist/bootstrap/index.js.map +0 -1
@@ -183,6 +183,25 @@ var ConnectionNodeIdFactory = class {
183
183
  static isToolConnectionNodeId(nodeId) {
184
184
  return nodeId.includes(`${this.connectionSegment}tool${this.connectionSegment}`);
185
185
  }
186
+ static parseLanguageModelConnectionNodeId(nodeId) {
187
+ if (!this.isLanguageModelConnectionNodeId(nodeId)) return;
188
+ const suffix = `${this.connectionSegment}llm`;
189
+ const parentNodeId = nodeId.slice(0, -suffix.length);
190
+ return parentNodeId ? { parentNodeId } : void 0;
191
+ }
192
+ static parseToolConnectionNodeId(nodeId) {
193
+ if (!this.isToolConnectionNodeId(nodeId)) return;
194
+ const marker = `${this.connectionSegment}tool${this.connectionSegment}`;
195
+ const idx = nodeId.lastIndexOf(marker);
196
+ if (idx < 0) return;
197
+ const parentNodeId = nodeId.slice(0, idx);
198
+ const normalizedToolName = nodeId.slice(idx + marker.length);
199
+ if (!parentNodeId || !normalizedToolName) return;
200
+ return {
201
+ parentNodeId,
202
+ normalizedToolName
203
+ };
204
+ }
186
205
  /** True when `nodeId` is a connection-owned child of `parentNodeId` (LLM or tool slot). */
187
206
  static isConnectionOwnedDescendantOf(parentNodeId, nodeId) {
188
207
  return nodeId.startsWith(`${parentNodeId}${this.connectionSegment}`);
@@ -505,7 +524,7 @@ var ActivationEnqueueService = class {
505
524
  return result;
506
525
  }
507
526
  async enqueueActivationWithSnapshot(args) {
508
- const receipt = await this.activationScheduler.enqueue(args.request);
527
+ const preparedDispatch = await this.activationScheduler.prepareDispatch(args.request);
509
528
  const inputsByPort = NodeInputsByPortFactory.fromRequest(args.request);
510
529
  const itemsIn = args.request.kind === "multi" ? args.planner.sumItemsByPort(args.request.inputsByPort) : args.request.input.length;
511
530
  const enqueuedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -516,8 +535,8 @@ var ActivationEnqueueService = class {
516
535
  nodeId: args.request.nodeId,
517
536
  itemsIn,
518
537
  inputsByPort,
519
- receiptId: receipt.receiptId,
520
- queue: receipt.queue,
538
+ receiptId: preparedDispatch.receipt.receiptId,
539
+ queue: preparedDispatch.receipt.queue,
521
540
  batchId: args.request.batchId,
522
541
  enqueuedAt
523
542
  };
@@ -551,7 +570,7 @@ var ActivationEnqueueService = class {
551
570
  [args.request.nodeId]: queuedSnapshot
552
571
  }
553
572
  });
554
- this.notifyPendingStatePersisted(args.runId);
573
+ await this.dispatchPreparedActivation(preparedDispatch);
555
574
  return {
556
575
  result: {
557
576
  runId: args.runId,
@@ -563,8 +582,8 @@ var ActivationEnqueueService = class {
563
582
  queuedSnapshot
564
583
  };
565
584
  }
566
- notifyPendingStatePersisted(runId) {
567
- this.activationScheduler.notifyPendingStatePersisted?.(runId);
585
+ async dispatchPreparedActivation(preparedDispatch) {
586
+ await preparedDispatch.dispatch();
568
587
  }
569
588
  };
570
589
 
@@ -985,6 +1004,127 @@ var PersistedWorkflowTokenRegistry = class {
985
1004
  }
986
1005
  };
987
1006
 
1007
+ //#endregion
1008
+ //#region src/workflowSnapshots/WorkflowSnapshotCodec.ts
1009
+ var WorkflowSnapshotCodec = class {
1010
+ constructor(tokenRegistry) {
1011
+ this.tokenRegistry = tokenRegistry;
1012
+ }
1013
+ create(workflow) {
1014
+ return {
1015
+ id: workflow.id,
1016
+ name: workflow.name,
1017
+ workflowErrorHandlerConfigured: workflow.workflowErrorHandler !== void 0,
1018
+ ...workflow.connections !== void 0 && workflow.connections.length > 0 ? { connections: workflow.connections } : {},
1019
+ nodes: workflow.nodes.map((node$1) => ({
1020
+ id: node$1.id,
1021
+ kind: node$1.kind,
1022
+ name: node$1.name,
1023
+ nodeTokenId: this.resolveTokenId(node$1.type),
1024
+ configTokenId: this.resolveTokenId(node$1.config.type),
1025
+ tokenName: this.resolveTokenName(node$1.type),
1026
+ configTokenName: this.resolveTokenName(node$1.config.type),
1027
+ config: this.serializeConfig(node$1.config)
1028
+ })),
1029
+ edges: workflow.edges.map((edge) => ({
1030
+ from: {
1031
+ nodeId: edge.from.nodeId,
1032
+ output: edge.from.output
1033
+ },
1034
+ to: {
1035
+ nodeId: edge.to.nodeId,
1036
+ input: edge.to.input
1037
+ }
1038
+ }))
1039
+ };
1040
+ }
1041
+ hydrate(snapshotNode, liveConfig) {
1042
+ const hydrated = this.mergeValue(liveConfig, snapshotNode.config);
1043
+ const configToken = this.tokenRegistry.resolve(snapshotNode.configTokenId);
1044
+ Object.assign(hydrated, {
1045
+ type: configToken ?? liveConfig.type,
1046
+ kind: snapshotNode.kind
1047
+ });
1048
+ if (snapshotNode.name && !("name" in hydrated && hydrated.name)) Object.assign(hydrated, { name: snapshotNode.name });
1049
+ return hydrated;
1050
+ }
1051
+ serializeConfig(config) {
1052
+ try {
1053
+ const cloned = JSON.parse(JSON.stringify(config));
1054
+ this.injectTokenIds(cloned, config);
1055
+ return cloned;
1056
+ } catch {
1057
+ const fallback = {
1058
+ kind: config.kind,
1059
+ name: config.name,
1060
+ id: config.id,
1061
+ icon: config.icon,
1062
+ execution: config.execution
1063
+ };
1064
+ this.injectTokenIds(fallback, config);
1065
+ return fallback;
1066
+ }
1067
+ }
1068
+ injectTokenIds(target, source) {
1069
+ const type = this.asTypeToken(source.type);
1070
+ if (type) target.tokenId = this.tokenRegistry.getTokenId(type) ?? this.resolveTokenName(type) ?? "unknown";
1071
+ for (const [key, value] of Object.entries(source)) {
1072
+ if (key === "type" || value == null) continue;
1073
+ if (Array.isArray(value)) {
1074
+ const targetArray = target[key];
1075
+ if (Array.isArray(targetArray)) value.forEach((item, index) => {
1076
+ if (item && typeof item === "object" && targetArray[index] && typeof targetArray[index] === "object") this.injectTokenIds(targetArray[index], item);
1077
+ });
1078
+ continue;
1079
+ }
1080
+ if (typeof value === "object") {
1081
+ const targetValue = target[key];
1082
+ if (targetValue && typeof targetValue === "object") this.injectTokenIds(targetValue, value);
1083
+ }
1084
+ }
1085
+ }
1086
+ mergeValue(liveValue, snapshotValue) {
1087
+ const liveRecord = this.asRecord(liveValue);
1088
+ const snapshotRecord = this.asRecord(snapshotValue);
1089
+ const hydrated = Object.create(liveValue && typeof liveValue === "object" ? Object.getPrototypeOf(liveValue) ?? Object.prototype : Object.prototype);
1090
+ for (const [key, value] of Object.entries(snapshotRecord)) hydrated[key] = this.mergeNestedValue(liveRecord[key], value);
1091
+ this.restoreNonSerializableProperties(liveRecord, hydrated);
1092
+ this.restoreTypeProperty(hydrated);
1093
+ return hydrated;
1094
+ }
1095
+ mergeNestedValue(liveValue, snapshotValue) {
1096
+ if (Array.isArray(snapshotValue)) {
1097
+ const liveArray = Array.isArray(liveValue) ? liveValue : [];
1098
+ return snapshotValue.map((entry, index) => this.mergeNestedValue(liveArray[index], entry));
1099
+ }
1100
+ if (snapshotValue && typeof snapshotValue === "object") return this.mergeValue(liveValue, snapshotValue);
1101
+ return snapshotValue;
1102
+ }
1103
+ restoreNonSerializableProperties(liveRecord, hydrated) {
1104
+ for (const [key, value] of Object.entries(liveRecord)) if (typeof value === "function" || typeof value === "symbol") hydrated[key] = value;
1105
+ }
1106
+ restoreTypeProperty(record) {
1107
+ const tokenId = typeof record.tokenId === "string" ? record.tokenId : void 0;
1108
+ if (!tokenId) return;
1109
+ const type = this.tokenRegistry.resolve(tokenId);
1110
+ if (type) record.type = type;
1111
+ }
1112
+ resolveTokenId(token) {
1113
+ return this.tokenRegistry.getTokenId(token) ?? this.resolveTokenName(token) ?? "unknown";
1114
+ }
1115
+ resolveTokenName(token) {
1116
+ if (typeof token === "function" && token.name) return token.name;
1117
+ if (typeof token === "string") return token;
1118
+ }
1119
+ asTypeToken(value) {
1120
+ if (typeof value === "function" || typeof value === "string" || typeof value === "symbol") return value;
1121
+ }
1122
+ asRecord(value) {
1123
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
1124
+ return { ...value };
1125
+ }
1126
+ };
1127
+
988
1128
  //#endregion
989
1129
  //#region src/workflowSnapshots/WorkflowSnapshotResolver.ts
990
1130
  var WorkflowSnapshotResolver = class {
@@ -1234,7 +1374,8 @@ var PersistedRunStateTerminalBuilder = class {
1234
1374
  pending: void 0,
1235
1375
  queue: args.queue,
1236
1376
  outputsByNode: args.outputsByNode,
1237
- nodeSnapshotsByNodeId: args.nodeSnapshotsByNodeId
1377
+ nodeSnapshotsByNodeId: args.nodeSnapshotsByNodeId,
1378
+ finishedAt: args.finishedAtIso ?? args.state.finishedAt
1238
1379
  };
1239
1380
  }
1240
1381
  };
@@ -1424,9 +1565,10 @@ var RunContinuationService = class {
1424
1565
  this.executionLimitsPolicy = executionLimitsPolicy;
1425
1566
  }
1426
1567
  async markNodeRunning(args) {
1427
- const state = await this.workflowExecutionRepository.load(args.runId);
1428
- if (!state?.pending) return;
1429
- if (state.pending.activationId !== args.activationId || state.pending.nodeId !== args.nodeId) return;
1568
+ const [state, schedulingState] = await Promise.all([this.workflowExecutionRepository.load(args.runId), this.workflowExecutionRepository.loadSchedulingState(args.runId)]);
1569
+ const pendingExecution = schedulingState?.pending;
1570
+ if (!state || !pendingExecution) return;
1571
+ if (pendingExecution.activationId !== args.activationId || pendingExecution.nodeId !== args.nodeId) return;
1430
1572
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
1431
1573
  const previous = state.nodeSnapshotsByNodeId?.[args.nodeId];
1432
1574
  const snapshot = NodeExecutionSnapshotFactory.running({
@@ -1449,11 +1591,11 @@ var RunContinuationService = class {
1449
1591
  await this.nodeEventPublisher.publish("nodeStarted", snapshot);
1450
1592
  }
1451
1593
  async resumeFromNodeResult(args) {
1452
- const state = await this.workflowExecutionRepository.load(args.runId);
1594
+ const [state, schedulingState] = await Promise.all([this.workflowExecutionRepository.load(args.runId), this.workflowExecutionRepository.loadSchedulingState(args.runId)]);
1453
1595
  if (!state) throw new Error(`Unknown runId: ${args.runId}`);
1454
- if (state.status !== "pending" || !state.pending) throw new Error(`Run ${args.runId} is not pending`);
1455
- if (state.pending.activationId !== args.activationId) throw new Error(`activationId mismatch for run ${args.runId}`);
1456
- if (state.pending.nodeId !== args.nodeId) throw new Error(`nodeId mismatch for run ${args.runId}`);
1596
+ const pendingExecution = this.requirePendingExecution(args.runId, args.activationId, args.nodeId, state, schedulingState);
1597
+ if (pendingExecution.activationId !== args.activationId) throw new Error(`activationId mismatch for run ${args.runId}`);
1598
+ if (pendingExecution.nodeId !== args.nodeId) throw new Error(`nodeId mismatch for run ${args.runId}`);
1457
1599
  const wf = this.resolvePersistedWorkflow(state);
1458
1600
  if (!wf) throw new Error(`Unknown workflowId: ${state.workflowId}`);
1459
1601
  const { topology, planner } = this.planningFactory.create(wf);
@@ -1481,7 +1623,7 @@ var RunContinuationService = class {
1481
1623
  activationId: args.activationId,
1482
1624
  parent: state.parent,
1483
1625
  finishedAt: completedAt,
1484
- inputsByPort: state.pending.inputsByPort,
1626
+ inputsByPort: pendingExecution.inputsByPort,
1485
1627
  outputs: args.outputs
1486
1628
  });
1487
1629
  const completedActivations = (state.engineCounters?.completedNodeActivations ?? 0) + 1;
@@ -1497,7 +1639,8 @@ var RunContinuationService = class {
1497
1639
  nodeSnapshotsByNodeId: {
1498
1640
  ...state.nodeSnapshotsByNodeId ?? {},
1499
1641
  [args.nodeId]: completedSnapshot
1500
- }
1642
+ },
1643
+ finishedAtIso: completedAt
1501
1644
  });
1502
1645
  await this.workflowExecutionRepository.save(completedState);
1503
1646
  await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
@@ -1517,8 +1660,8 @@ var RunContinuationService = class {
1517
1660
  this.waiters.resolveRunCompletion(result$1);
1518
1661
  return result$1;
1519
1662
  }
1520
- const batchId = state.pending.batchId ?? "batch_1";
1521
- const queue = (state.queue ?? []).map((q) => ({
1663
+ const batchId = pendingExecution.batchId ?? "batch_1";
1664
+ const queue = (schedulingState?.queue ?? []).map((q) => ({
1522
1665
  ...q,
1523
1666
  batchId: q.batchId ?? batchId
1524
1667
  }));
@@ -1563,7 +1706,8 @@ var RunContinuationService = class {
1563
1706
  status: "completed",
1564
1707
  queue: [],
1565
1708
  outputsByNode: data.dump(),
1566
- nodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId
1709
+ nodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId,
1710
+ finishedAtIso: completedAt
1567
1711
  });
1568
1712
  await this.workflowExecutionRepository.save(completedState);
1569
1713
  await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
@@ -1591,7 +1735,8 @@ var RunContinuationService = class {
1591
1735
  status: "failed",
1592
1736
  queue: queue.map((q) => ({ ...q })),
1593
1737
  outputsByNode: data.dump(),
1594
- nodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId
1738
+ nodeSnapshotsByNodeId: nextNodeSnapshotsByNodeId,
1739
+ finishedAtIso: completedAt
1595
1740
  });
1596
1741
  await this.workflowExecutionRepository.save(failedState);
1597
1742
  await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
@@ -1645,17 +1790,19 @@ var RunContinuationService = class {
1645
1790
  return result;
1646
1791
  }
1647
1792
  async resumeFromNodeError(args) {
1648
- const state = await this.workflowExecutionRepository.load(args.runId);
1793
+ const [state, schedulingState] = await Promise.all([this.workflowExecutionRepository.load(args.runId), this.workflowExecutionRepository.loadSchedulingState(args.runId)]);
1649
1794
  if (!state) throw new Error(`Unknown runId: ${args.runId}`);
1650
- if (state.status !== "pending" || !state.pending) throw new Error(`Run ${args.runId} is not pending`);
1651
- if (state.pending.activationId !== args.activationId) throw new Error(`activationId mismatch for run ${args.runId}`);
1652
- if (state.pending.nodeId !== args.nodeId) throw new Error(`nodeId mismatch for run ${args.runId}`);
1795
+ const pendingExecution = this.requirePendingExecution(args.runId, args.activationId, args.nodeId, state, schedulingState);
1796
+ if (pendingExecution.activationId !== args.activationId) throw new Error(`activationId mismatch for run ${args.runId}`);
1797
+ if (pendingExecution.nodeId !== args.nodeId) throw new Error(`nodeId mismatch for run ${args.runId}`);
1653
1798
  const wf = this.resolvePersistedWorkflow(state);
1654
1799
  if (!wf) throw new Error(`Unknown workflowId: ${state.workflowId}`);
1655
1800
  const failedDefinition = WorkflowTopology.fromWorkflow(wf).defsById.get(args.nodeId);
1656
1801
  const webhookControlSignal = state.executionOptions?.webhook && failedDefinition?.kind === "trigger" ? this.asWebhookControlSignal(args.error) : void 0;
1657
1802
  if (webhookControlSignal) return await this.resumeFromWebhookControl({
1658
1803
  state,
1804
+ schedulingState,
1805
+ pendingExecution,
1659
1806
  workflow: wf,
1660
1807
  args,
1661
1808
  signal: webhookControlSignal
@@ -1663,8 +1810,8 @@ var RunContinuationService = class {
1663
1810
  if (failedDefinition && failedDefinition.kind === "node") {
1664
1811
  const nodeHandler = this.policyErrorServices.resolveNodeErrorHandler(failedDefinition.config.nodeErrorHandler);
1665
1812
  if (nodeHandler) try {
1666
- const ctx = this.buildNodeExecutionContextForPending(state, wf, failedDefinition, args.nodeId);
1667
- const inputsByPort = state.pending.inputsByPort;
1813
+ const ctx = this.buildNodeExecutionContextForPending(state, pendingExecution, wf, failedDefinition, args.nodeId);
1814
+ const inputsByPort = pendingExecution.inputsByPort;
1668
1815
  const portKeys = Object.keys(inputsByPort);
1669
1816
  const kind = portKeys.length === 1 && portKeys[0] === "in" ? "single" : "multi";
1670
1817
  const items = inputsByPort.in ?? [];
@@ -1693,19 +1840,20 @@ var RunContinuationService = class {
1693
1840
  activationId: args.activationId,
1694
1841
  parent: state.parent,
1695
1842
  finishedAt,
1696
- inputsByPort: state.pending.inputsByPort,
1843
+ inputsByPort: pendingExecution.inputsByPort,
1697
1844
  error: args.error
1698
1845
  });
1699
1846
  const failedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
1700
1847
  state,
1701
1848
  engineCounters: state.engineCounters ?? { completedNodeActivations: 0 },
1702
1849
  status: "failed",
1703
- queue: (state.queue ?? []).map((q) => ({ ...q })),
1850
+ queue: (schedulingState?.queue ?? []).map((q) => ({ ...q })),
1704
1851
  outputsByNode: state.outputsByNode,
1705
1852
  nodeSnapshotsByNodeId: {
1706
1853
  ...state.nodeSnapshotsByNodeId ?? {},
1707
1854
  [args.nodeId]: failedSnapshot
1708
- }
1855
+ },
1856
+ finishedAtIso: finishedAt
1709
1857
  });
1710
1858
  await this.workflowExecutionRepository.save(failedState);
1711
1859
  await this.nodeEventPublisher.publish("nodeFailed", failedSnapshot);
@@ -1782,7 +1930,7 @@ var RunContinuationService = class {
1782
1930
  activationId: args.args.activationId,
1783
1931
  parent: args.state.parent,
1784
1932
  finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
1785
- inputsByPort: args.state.pending?.inputsByPort ?? NodeInputsByPortFactory.empty(),
1933
+ inputsByPort: args.pendingExecution.inputsByPort,
1786
1934
  outputs: triggerOutputs
1787
1935
  });
1788
1936
  const completedActivations = (args.state.engineCounters?.completedNodeActivations ?? 0) + 1;
@@ -1798,7 +1946,8 @@ var RunContinuationService = class {
1798
1946
  nodeSnapshotsByNodeId: {
1799
1947
  ...args.state.nodeSnapshotsByNodeId ?? {},
1800
1948
  [args.args.nodeId]: completedSnapshot
1801
- }
1949
+ },
1950
+ finishedAtIso: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
1802
1951
  });
1803
1952
  await this.workflowExecutionRepository.save(completedState);
1804
1953
  await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
@@ -1835,7 +1984,8 @@ var RunContinuationService = class {
1835
1984
  nodeSnapshotsByNodeId: {
1836
1985
  ...args.state.nodeSnapshotsByNodeId ?? {},
1837
1986
  [args.args.nodeId]: completedSnapshot
1838
- }
1987
+ },
1988
+ finishedAtIso: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
1839
1989
  });
1840
1990
  await this.workflowExecutionRepository.save(completedState);
1841
1991
  await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
@@ -1862,8 +2012,8 @@ var RunContinuationService = class {
1862
2012
  this.waiters.resolveRunCompletion(result$1);
1863
2013
  return result$1;
1864
2014
  }
1865
- const batchId = args.state.pending?.batchId ?? "batch_1";
1866
- const queue = (args.state.queue ?? []).map((entry) => ({
2015
+ const batchId = args.pendingExecution.batchId ?? "batch_1";
2016
+ const queue = (args.schedulingState?.queue ?? []).map((entry) => ({
1867
2017
  ...entry,
1868
2018
  batchId: entry.batchId ?? batchId
1869
2019
  }));
@@ -1885,7 +2035,8 @@ var RunContinuationService = class {
1885
2035
  nodeSnapshotsByNodeId: {
1886
2036
  ...args.state.nodeSnapshotsByNodeId ?? {},
1887
2037
  [args.args.nodeId]: completedSnapshot
1888
- }
2038
+ },
2039
+ finishedAtIso: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
1889
2040
  });
1890
2041
  await this.workflowExecutionRepository.save(completedState);
1891
2042
  await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
@@ -1923,7 +2074,8 @@ var RunContinuationService = class {
1923
2074
  nodeSnapshotsByNodeId: {
1924
2075
  ...args.state.nodeSnapshotsByNodeId ?? {},
1925
2076
  [args.args.nodeId]: completedSnapshot
1926
- }
2077
+ },
2078
+ finishedAtIso: completedSnapshot.finishedAt ?? completedSnapshot.updatedAt
1927
2079
  });
1928
2080
  await this.workflowExecutionRepository.save(failedState);
1929
2081
  await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
@@ -2018,7 +2170,7 @@ var RunContinuationService = class {
2018
2170
  workflowSnapshot: state.workflowSnapshot
2019
2171
  });
2020
2172
  }
2021
- buildNodeExecutionContextForPending(state, wf, def, nodeId) {
2173
+ buildNodeExecutionContextForPending(state, pendingExecution, wf, def, nodeId) {
2022
2174
  const data = this.runDataFactory.create(state.outputsByNode);
2023
2175
  const limits = this.resolveEngineLimitsFromState(state);
2024
2176
  const base = this.runExecutionContextFactory.create({
@@ -2032,7 +2184,7 @@ var RunContinuationService = class {
2032
2184
  data,
2033
2185
  nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent)
2034
2186
  });
2035
- const activationId = state.pending.activationId;
2187
+ const activationId = pendingExecution.activationId;
2036
2188
  return {
2037
2189
  ...base,
2038
2190
  data,
@@ -2046,6 +2198,14 @@ var RunContinuationService = class {
2046
2198
  getCredential: this.credentialResolverFactory.create(wf.id, nodeId, def.config)
2047
2199
  };
2048
2200
  }
2201
+ requirePendingExecution(runId, activationId, nodeId, state, schedulingState) {
2202
+ if (state.status !== "pending") throw new Error(`Run ${runId} is not pending`);
2203
+ const pendingExecution = schedulingState?.pending;
2204
+ if (!pendingExecution) throw new Error(`Run ${runId} is not pending`);
2205
+ if (pendingExecution.activationId !== activationId) throw new Error(`activationId mismatch for run ${runId}`);
2206
+ if (pendingExecution.nodeId !== nodeId) throw new Error(`nodeId mismatch for run ${runId}`);
2207
+ return pendingExecution;
2208
+ }
2049
2209
  resolveEngineLimitsFromState(state) {
2050
2210
  const fb = this.executionLimitsPolicy.createRootExecutionOptions();
2051
2211
  return {
@@ -2702,7 +2862,7 @@ var DefaultDrivingScheduler = class {
2702
2862
  setContinuation(continuation) {
2703
2863
  this.inline.setContinuation(continuation);
2704
2864
  }
2705
- async enqueue(request) {
2865
+ async prepareDispatch(request) {
2706
2866
  const selection = await this.selectScheduler(request);
2707
2867
  if (selection.mode === "worker") {
2708
2868
  if (request.kind === "multi") throw new Error(`Multi-input node ${request.nodeId} cannot be scheduled to worker (insert local placement)`);
@@ -2717,15 +2877,17 @@ var DefaultDrivingScheduler = class {
2717
2877
  executionOptions: request.executionOptions
2718
2878
  };
2719
2879
  return {
2720
- receiptId: (await this.workerScheduler.enqueue(workerRequest)).receiptId,
2721
- mode: "worker",
2722
- queue: selection.queue
2880
+ receipt: {
2881
+ receiptId: request.activationId,
2882
+ mode: "worker",
2883
+ queue: selection.queue
2884
+ },
2885
+ dispatch: async () => {
2886
+ await this.workerScheduler.enqueue(workerRequest);
2887
+ }
2723
2888
  };
2724
2889
  }
2725
- return await this.enqueueInline(request);
2726
- }
2727
- notifyPendingStatePersisted(runId) {
2728
- this.inline.notifyPendingStatePersisted(runId);
2890
+ return await this.prepareInlineDispatch(request);
2729
2891
  }
2730
2892
  /**
2731
2893
  * Scheduler precedence is explicit:
@@ -2757,10 +2919,16 @@ var DefaultDrivingScheduler = class {
2757
2919
  hasNodeSchedulingPreference(request) {
2758
2920
  return request.ctx.config.execution?.hint !== void 0 || request.ctx.config.execution?.queue !== void 0;
2759
2921
  }
2760
- async enqueueInline(request) {
2922
+ async prepareInlineDispatch(request) {
2923
+ const prepared = await this.inline.prepareDispatch(request);
2761
2924
  return {
2762
- ...await this.inline.enqueue(request),
2763
- mode: "local"
2925
+ receipt: {
2926
+ ...prepared.receipt,
2927
+ mode: "local"
2928
+ },
2929
+ dispatch: async () => {
2930
+ await prepared.dispatch();
2931
+ }
2764
2932
  };
2765
2933
  }
2766
2934
  };
@@ -2784,29 +2952,29 @@ var InlineDrivingScheduler = class {
2784
2952
  drainingRuns = /* @__PURE__ */ new Set();
2785
2953
  queuesByRunId = /* @__PURE__ */ new Map();
2786
2954
  scheduledRuns = /* @__PURE__ */ new Set();
2787
- seq = 0;
2788
2955
  constructor(nodeExecutor) {
2789
2956
  this.nodeExecutor = nodeExecutor;
2790
2957
  }
2791
2958
  setContinuation(continuation) {
2792
2959
  this.continuation = continuation;
2793
2960
  }
2794
- async enqueue(request) {
2961
+ async prepareDispatch(request) {
2795
2962
  const receipt = {
2796
- receiptId: `inline_${++this.seq}`,
2963
+ receiptId: request.activationId,
2797
2964
  mode: "local"
2798
2965
  };
2799
- const q = this.queuesByRunId.get(request.runId) ?? [];
2800
- q.push({
2801
- request,
2802
- receipt
2803
- });
2804
- this.queuesByRunId.set(request.runId, q);
2805
- return receipt;
2806
- }
2807
- notifyPendingStatePersisted(runId) {
2808
- if ((this.queuesByRunId.get(runId)?.length ?? 0) === 0) return;
2809
- this.scheduleDrain(runId);
2966
+ return {
2967
+ receipt,
2968
+ dispatch: async () => {
2969
+ const queue = this.queuesByRunId.get(request.runId) ?? [];
2970
+ queue.push({
2971
+ request,
2972
+ receipt
2973
+ });
2974
+ this.queuesByRunId.set(request.runId, queue);
2975
+ this.scheduleDrain(request.runId);
2976
+ }
2977
+ };
2810
2978
  }
2811
2979
  async drainRun(runId) {
2812
2980
  if (this.drainingRuns.has(runId)) return;
@@ -3072,9 +3240,10 @@ var InMemoryRunDataFactory = class {
3072
3240
 
3073
3241
  //#endregion
3074
3242
  //#region src/contracts/runFinishedAtFactory.ts
3075
- /** Derives workflow end time from node snapshots for run listings. */
3243
+ /** Derives workflow end time from persisted run root or node snapshots for run listings. */
3076
3244
  var RunFinishedAtFactory = class {
3077
3245
  static resolveIso(state) {
3246
+ if (state.finishedAt && state.status !== "running" && state.status !== "pending") return state.finishedAt;
3078
3247
  if (state.status === "running" || state.status === "pending") return;
3079
3248
  let max;
3080
3249
  for (const snap of Object.values(state.nodeSnapshotsByNodeId)) if (snap?.finishedAt && (!max || snap.finishedAt > max)) max = snap.finishedAt;
@@ -3082,6 +3251,22 @@ var RunFinishedAtFactory = class {
3082
3251
  }
3083
3252
  };
3084
3253
 
3254
+ //#endregion
3255
+ //#region src/runtime/InMemoryLiveWorkflowRepository.ts
3256
+ var InMemoryLiveWorkflowRepository = class {
3257
+ workflowsById = /* @__PURE__ */ new Map();
3258
+ setWorkflows(workflows) {
3259
+ this.workflowsById.clear();
3260
+ for (const workflow of workflows) this.workflowsById.set(workflow.id, workflow);
3261
+ }
3262
+ list() {
3263
+ return [...this.workflowsById.values()];
3264
+ }
3265
+ get(workflowId) {
3266
+ return this.workflowsById.get(workflowId);
3267
+ }
3268
+ };
3269
+
3085
3270
  //#endregion
3086
3271
  //#region src/runtime/RunIntentService.ts
3087
3272
  var RunIntentService = class {
@@ -3288,6 +3473,12 @@ Object.defineProperty(exports, 'InMemoryBinaryStorage', {
3288
3473
  return InMemoryBinaryStorage;
3289
3474
  }
3290
3475
  });
3476
+ Object.defineProperty(exports, 'InMemoryLiveWorkflowRepository', {
3477
+ enumerable: true,
3478
+ get: function () {
3479
+ return InMemoryLiveWorkflowRepository;
3480
+ }
3481
+ });
3291
3482
  Object.defineProperty(exports, 'InMemoryRunDataFactory', {
3292
3483
  enumerable: true,
3293
3484
  get: function () {
@@ -3474,6 +3665,12 @@ Object.defineProperty(exports, 'WorkflowRunExecutionContextFactory', {
3474
3665
  return WorkflowRunExecutionContextFactory;
3475
3666
  }
3476
3667
  });
3668
+ Object.defineProperty(exports, 'WorkflowSnapshotCodec', {
3669
+ enumerable: true,
3670
+ get: function () {
3671
+ return WorkflowSnapshotCodec;
3672
+ }
3673
+ });
3477
3674
  Object.defineProperty(exports, 'WorkflowSnapshotResolver', {
3478
3675
  enumerable: true,
3479
3676
  get: function () {
@@ -3516,4 +3713,4 @@ Object.defineProperty(exports, 'tool', {
3516
3713
  return tool;
3517
3714
  }
3518
3715
  });
3519
- //# sourceMappingURL=RunIntentService-ZkjpY7MS.cjs.map
3716
+ //# sourceMappingURL=RunIntentService-DcxXf_AM.cjs.map