@codemation/core 0.11.1 → 0.12.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 (89) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{CostCatalogContract-DZgcUBE4.d.cts → CostCatalogContract-DD7fQ4FF.d.cts} +2 -2
  3. package/dist/{EngineRuntimeRegistration.types-Cggm5GVY.d.cts → EngineRuntimeRegistration.types-DTV5_7Jw.d.cts} +3 -3
  4. package/dist/{EngineRuntimeRegistration.types-BQbS9_gs.d.ts → EngineRuntimeRegistration.types-Dl92Hdoi.d.ts} +2 -2
  5. package/dist/InMemoryRunDataFactory-qMiYjhCK.d.cts +202 -0
  6. package/dist/{ItemsInputNormalizer-D-MH8MBs.js → ItemsInputNormalizer-BhuxvZh5.js} +2 -2
  7. package/dist/{ItemsInputNormalizer-D-MH8MBs.js.map → ItemsInputNormalizer-BhuxvZh5.js.map} +1 -1
  8. package/dist/{ItemsInputNormalizer-_Mfcd3YU.d.ts → ItemsInputNormalizer-C09a7iFP.d.ts} +2 -2
  9. package/dist/{ItemsInputNormalizer-C_dpn76M.d.cts → ItemsInputNormalizer-DLaD6rTl.d.cts} +3 -3
  10. package/dist/{ItemsInputNormalizer-CwdOhSAK.cjs → ItemsInputNormalizer-Div-fb6a.cjs} +2 -2
  11. package/dist/{ItemsInputNormalizer-CwdOhSAK.cjs.map → ItemsInputNormalizer-Div-fb6a.cjs.map} +1 -1
  12. package/dist/{RunIntentService-BVur7x9n.d.ts → RunIntentService-BOSGwmqn.d.ts} +18 -4
  13. package/dist/{RunIntentService-CEF-sFfI.d.cts → RunIntentService-CWMMrAP4.d.cts} +18 -4
  14. package/dist/{agentMcpTypes-ZiNbNsEi.d.cts → agentMcpTypes-DUmniLOY.d.cts} +183 -4
  15. package/dist/bootstrap/index.cjs +3 -3
  16. package/dist/bootstrap/index.d.cts +63 -7
  17. package/dist/bootstrap/index.d.ts +5 -5
  18. package/dist/bootstrap/index.js +3 -3
  19. package/dist/{bootstrap-D_Yyi0wL.js → bootstrap-CKTMMNmL.js} +173 -4
  20. package/dist/bootstrap-CKTMMNmL.js.map +1 -0
  21. package/dist/{bootstrap-BxuTFTLB.cjs → bootstrap-D460dCgS.cjs} +175 -4
  22. package/dist/bootstrap-D460dCgS.cjs.map +1 -0
  23. package/dist/browser.cjs +3 -2
  24. package/dist/browser.d.cts +4 -4
  25. package/dist/browser.d.ts +3 -3
  26. package/dist/browser.js +3 -3
  27. package/dist/contracts.d.cts +5 -5
  28. package/dist/contracts.d.ts +2 -2
  29. package/dist/{di-0Wop7z1y.js → di-DdsgWfVy.js} +31 -2
  30. package/dist/di-DdsgWfVy.js.map +1 -0
  31. package/dist/{di-BlEKdoZS.cjs → di-tO6R7VJV.cjs} +36 -1
  32. package/dist/di-tO6R7VJV.cjs.map +1 -0
  33. package/dist/{executionPersistenceContracts-BgZMRsTa.d.cts → executionPersistenceContracts-DenJJK2T.d.cts} +2 -2
  34. package/dist/{index-62Ba9f7D.d.ts → index-BZDhEQ6W.d.ts} +277 -101
  35. package/dist/{index-zWGtEhrf.d.ts → index-CSKKuK60.d.ts} +441 -5
  36. package/dist/index.cjs +71 -161
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +395 -97
  39. package/dist/index.d.ts +5 -5
  40. package/dist/index.js +56 -159
  41. package/dist/index.js.map +1 -1
  42. package/dist/{params-B5SENSzZ.d.cts → params-DqRvku2h.d.cts} +2 -2
  43. package/dist/{runtime-cxmUkk0l.js → runtime-BPZgnZ9G.js} +611 -16
  44. package/dist/runtime-BPZgnZ9G.js.map +1 -0
  45. package/dist/{runtime-DBzq5YBi.cjs → runtime-CyW9c9XM.cjs} +670 -15
  46. package/dist/runtime-CyW9c9XM.cjs.map +1 -0
  47. package/dist/testing.cjs +3 -3
  48. package/dist/testing.d.cts +3 -3
  49. package/dist/testing.d.ts +3 -3
  50. package/dist/testing.js +3 -3
  51. package/package.json +1 -1
  52. package/src/authoring/defineHumanApprovalNode.types.ts +379 -0
  53. package/src/authoring/index.ts +6 -0
  54. package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +29 -0
  55. package/src/contracts/CodemationTelemetryAttributeNames.ts +10 -0
  56. package/src/contracts/credentialTypes.ts +10 -0
  57. package/src/contracts/hitlSeamTypes.ts +34 -0
  58. package/src/contracts/humanTaskStoreTypes.ts +48 -0
  59. package/src/contracts/inboxChannelTypes.ts +58 -0
  60. package/src/contracts/index.ts +3 -0
  61. package/src/contracts/runTypes.ts +61 -3
  62. package/src/contracts/runtimeTypes.ts +112 -0
  63. package/src/credentials/CredentialMaterialProvider.types.ts +61 -0
  64. package/src/credentials/ManagedCredentialMaterialWriteError.ts +14 -0
  65. package/src/credentials/ManagedMaterialFetchError.ts +16 -0
  66. package/src/execution/ActivationEnqueueService.ts +16 -0
  67. package/src/execution/DefaultExecutionContextFactory.ts +11 -0
  68. package/src/execution/NodeExecutionSnapshotFactory.ts +7 -1
  69. package/src/execution/NodeExecutor.ts +60 -1
  70. package/src/execution/NodeExecutorFactory.ts +12 -2
  71. package/src/execution/NodeSuspensionHandler.ts +220 -0
  72. package/src/execution/PersistedRunStateTerminalBuilder.ts +5 -2
  73. package/src/execution/RunStateSemantics.ts +5 -0
  74. package/src/execution/RunSuspendedError.ts +21 -0
  75. package/src/index.ts +40 -0
  76. package/src/orchestration/Engine.ts +12 -2
  77. package/src/orchestration/EngineWaiters.ts +1 -1
  78. package/src/orchestration/NodeExecutionRequestHandlerService.ts +25 -2
  79. package/src/orchestration/RunContinuationService.ts +226 -2
  80. package/src/orchestration/TestSuiteOrchestrator.ts +5 -4
  81. package/src/runtime/RunIntentService.ts +3 -0
  82. package/src/workflow/dsl/ChainCursorResolver.ts +36 -0
  83. package/dist/InMemoryRunDataFactory-C7YItvHG.d.cts +0 -123
  84. package/dist/bootstrap-BxuTFTLB.cjs.map +0 -1
  85. package/dist/bootstrap-D_Yyi0wL.js.map +0 -1
  86. package/dist/di-0Wop7z1y.js.map +0 -1
  87. package/dist/di-BlEKdoZS.cjs.map +0 -1
  88. package/dist/runtime-DBzq5YBi.cjs.map +0 -1
  89. package/dist/runtime-cxmUkk0l.js.map +0 -1
@@ -1,4 +1,4 @@
1
- const require_di = require('./di-BlEKdoZS.cjs');
1
+ const require_di = require('./di-tO6R7VJV.cjs');
2
2
  let zod = require("zod");
3
3
  zod = require_di.__toESM(zod);
4
4
  let node_stream_web = require("node:stream/web");
@@ -8,6 +8,34 @@ node_crypto = require_di.__toESM(node_crypto);
8
8
  let tsyringe = require("tsyringe");
9
9
  tsyringe = require_di.__toESM(tsyringe);
10
10
 
11
+ //#region src/contracts/humanTaskStoreTypes.ts
12
+ const HumanTaskStoreToken = Symbol.for("codemation.core.HumanTaskStore");
13
+
14
+ //#endregion
15
+ //#region src/contracts/hitlSeamTypes.ts
16
+ const HitlResumeTokenSignerToken = Symbol.for("codemation.core.HitlResumeTokenSigner");
17
+ const HitlTimeoutJobSchedulerToken = Symbol.for("codemation.core.HitlTimeoutJobScheduler");
18
+ /**
19
+ * Optional workspace ID injected into NodeSuspensionHandler in managed mode (T7 security fix).
20
+ * Allows the handler to stamp the workspaceId on each HumanTaskRecord so HitlCallbackHandler
21
+ * can assert workspace identity independently of the HMAC middleware.
22
+ * Not registered in non-managed mode; NodeSuspensionHandler defaults to null.
23
+ */
24
+ const HitlWorkspaceIdToken = Symbol.for("codemation.core.HitlWorkspaceId");
25
+
26
+ //#endregion
27
+ //#region src/authoring/DefinedNodeRegistry.ts
28
+ var DefinedNodeRegistry = class {
29
+ static definitions = /* @__PURE__ */ new Map();
30
+ static register(definition) {
31
+ this.definitions.set(definition.key, definition);
32
+ }
33
+ static resolve(key) {
34
+ return this.definitions.get(key);
35
+ }
36
+ };
37
+
38
+ //#endregion
11
39
  //#region src/runtime-types/persistedRuntimeTypeModelRegistry.ts
12
40
  /** Shared metadata key used to attach persisted runtime-type information to decorated classes. */
13
41
  const persistedRuntimeTypeMetadataKey = Symbol.for("codemation.core.persistedRuntimeTypeMetadata");
@@ -116,6 +144,305 @@ function chatModel(options = {}) {
116
144
  return InjectableRuntimeDecoratorComposer.compose("chatModel", options, require("url").pathToFileURL(__filename).href);
117
145
  }
118
146
 
147
+ //#endregion
148
+ //#region src/authoring/defineNode.types.ts
149
+ const definedNodeCredentialRequirementFactory = {
150
+ create(bindings) {
151
+ if (!bindings) return [];
152
+ return Object.entries(bindings).map(([slotKey, binding]) => {
153
+ if (typeof binding === "string" || this.isCredentialType(binding)) return {
154
+ slotKey,
155
+ label: this.humanize(slotKey),
156
+ acceptedTypes: [this.resolveTypeId(binding)]
157
+ };
158
+ const types = Array.isArray(binding.type) ? binding.type : [binding.type];
159
+ return {
160
+ slotKey,
161
+ label: binding.label ?? this.humanize(slotKey),
162
+ acceptedTypes: types.map((entry) => this.resolveTypeId(entry)),
163
+ optional: binding.optional,
164
+ helpText: binding.helpText,
165
+ helpUrl: binding.helpUrl
166
+ };
167
+ });
168
+ },
169
+ isCredentialType(value) {
170
+ return Boolean(value) && typeof value === "object" && "definition" in value && typeof value.definition?.typeId === "string";
171
+ },
172
+ resolveTypeId(type) {
173
+ return typeof type === "string" ? type : type.definition.typeId;
174
+ },
175
+ humanize(key) {
176
+ return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_.]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (character) => character.toUpperCase());
177
+ }
178
+ };
179
+ const definedNodeCredentialAccessorFactory = { create(bindings, ctx) {
180
+ if (!bindings) return {};
181
+ const entries = Object.keys(bindings).map((slotKey) => [slotKey, () => ctx.getCredential(slotKey)]);
182
+ return Object.fromEntries(entries);
183
+ } };
184
+ function defineNode(options) {
185
+ const credentialRequirements = definedNodeCredentialRequirementFactory.create(options.credentials);
186
+ const DefinedNodeRuntime = class {
187
+ kind = "node";
188
+ outputPorts = ["main"];
189
+ inputSchema = options.inputSchema;
190
+ async execute(args) {
191
+ const ctx = args.ctx;
192
+ const context = {
193
+ config: ctx.config.config,
194
+ credentials: definedNodeCredentialAccessorFactory.create(options.credentials, ctx),
195
+ execution: ctx
196
+ };
197
+ const payload = {
198
+ input: args.input,
199
+ item: args.item,
200
+ itemIndex: args.itemIndex,
201
+ items: args.items,
202
+ ctx
203
+ };
204
+ return await options.execute(payload, context);
205
+ }
206
+ };
207
+ node({ name: options.key })(DefinedNodeRuntime);
208
+ const DefinedRunnableNodeConfig = class {
209
+ kind = "node";
210
+ type = DefinedNodeRuntime;
211
+ icon = options.icon;
212
+ inputSchema = options.inputSchema;
213
+ keepBinaries = options.keepBinaries ?? false;
214
+ constructor(name, config, id) {
215
+ this.name = name;
216
+ this.id = id;
217
+ this.config = config;
218
+ }
219
+ config;
220
+ getCredentialRequirements() {
221
+ return credentialRequirements;
222
+ }
223
+ inspectorSummary() {
224
+ return options.inspectorSummary?.({ config: this.config });
225
+ }
226
+ };
227
+ const definition = {
228
+ kind: "defined-node",
229
+ key: options.key,
230
+ title: options.title,
231
+ description: options.description,
232
+ create(config, name = options.title, id) {
233
+ return new DefinedRunnableNodeConfig(name, config, id);
234
+ },
235
+ register(context) {
236
+ context.registerNode(DefinedNodeRuntime);
237
+ }
238
+ };
239
+ DefinedNodeRegistry.register(definition);
240
+ return definition;
241
+ }
242
+ function defineBatchNode(options) {
243
+ const credentialRequirements = definedNodeCredentialRequirementFactory.create(options.credentials);
244
+ const DefinedNodeRuntime = class {
245
+ kind = "node";
246
+ outputPorts = ["main"];
247
+ async execute(args) {
248
+ if (args.itemIndex !== args.items.length - 1) return [];
249
+ const ctx = args.ctx;
250
+ const context = {
251
+ config: ctx.config.config,
252
+ credentials: definedNodeCredentialAccessorFactory.create(options.credentials, ctx),
253
+ execution: ctx
254
+ };
255
+ return [...await options.run(args.items.map((item) => item.json), context)];
256
+ }
257
+ };
258
+ node({ name: options.key })(DefinedNodeRuntime);
259
+ const DefinedRunnableNodeConfig = class {
260
+ kind = "node";
261
+ type = DefinedNodeRuntime;
262
+ icon = options.icon;
263
+ constructor(name, config, id) {
264
+ this.name = name;
265
+ this.id = id;
266
+ this.config = config;
267
+ }
268
+ config;
269
+ getCredentialRequirements() {
270
+ return credentialRequirements;
271
+ }
272
+ inspectorSummary() {
273
+ return options.inspectorSummary?.({ config: this.config });
274
+ }
275
+ };
276
+ const definition = {
277
+ kind: "defined-node",
278
+ key: options.key,
279
+ title: options.title,
280
+ description: options.description,
281
+ create(config, name = options.title, id) {
282
+ return new DefinedRunnableNodeConfig(name, config, id);
283
+ },
284
+ register(context) {
285
+ context.registerNode(DefinedNodeRuntime);
286
+ }
287
+ };
288
+ DefinedNodeRegistry.register(definition);
289
+ return definition;
290
+ }
291
+
292
+ //#endregion
293
+ //#region src/authoring/defineHumanApprovalNode.types.ts
294
+ /**
295
+ * Returns `true` when `node` was created by {@link defineHumanApprovalNode}.
296
+ * Uses the `humanApprovalToolBehavior` typed field as the discriminant.
297
+ */
298
+ function isHumanApprovalNode(node$1) {
299
+ return typeof node$1 === "object" && node$1 !== null && "humanApprovalToolBehavior" in node$1 && typeof node$1.humanApprovalToolBehavior === "object";
300
+ }
301
+ /**
302
+ * Authoring helper that compiles a HITL approval channel down to a regular
303
+ * {@link defineNode}-backed node with `SuspensionRequest` semantics.
304
+ *
305
+ * **Fast-forward decision semantics:**
306
+ * - On the first `execute` call (no `ctx.resumeContext`): throws a `SuspensionRequest`
307
+ * that calls the author's `deliver`. The engine persists the suspension and continues.
308
+ * - On resume (`ctx.resumeContext` set): calls `onDecision`/`onTimeout` as appropriate,
309
+ * merges a `decision` key into `item.json`, and returns an item with the original
310
+ * `binary` map passed by reference (no copy).
311
+ *
312
+ * **Output shape per item:**
313
+ * ```ts
314
+ * // Input: { json: { invoiceId: 42 }, binary?: {...} }
315
+ * // Output: { json: { invoiceId: 42, decision: { status: "approved", actor, decidedAt } }, binary: <unchanged> }
316
+ * ```
317
+ * If `item.json` already has a `decision` key it is **overwritten**. Namespace as
318
+ * needed if your schema reserves that key for another purpose.
319
+ *
320
+ * **Predicate persistence:**
321
+ * The `approvedPredicate` function is NOT serialized to the suspension record (except
322
+ * as an audit-only string via `toString()`). On resume, the workflow definition is
323
+ * reloaded from code at process start and the predicate closure is rebuilt naturally.
324
+ * If a deploy ships a changed predicate between suspend and resume, the *new* predicate
325
+ * runs — document this in your runbook when the predicate carries business logic that
326
+ * may change across deploys.
327
+ *
328
+ * @example
329
+ * ```ts
330
+ * export const slackApprovalNode = defineHumanApprovalNode({
331
+ * key: "my-plugin.slackApproval",
332
+ * title: "Slack Approval",
333
+ * channel: "slack",
334
+ * configSchema: z.object({ channel: z.string(), message: z.string() }),
335
+ * decisionSchema: z.object({ approved: z.boolean(), note: z.string().optional() }),
336
+ *
337
+ * async deliver({ task, config, item }, ctx) {
338
+ * const ts = await postSlackMessage(config.channel, `Approve? <${task.resumeUrl}>`);
339
+ * return { channel: config.channel, ts };
340
+ * },
341
+ *
342
+ * async onDecision({ decision, actor, delivery }, ctx) {
343
+ * await updateSlackMessage(delivery.channel, delivery.ts, decision.approved ? "✅" : "❌");
344
+ * },
345
+ * });
346
+ * ```
347
+ */
348
+ function defineHumanApprovalNode(opts) {
349
+ const resolvedPredicate = resolveApprovedPredicate(opts.decisionSchema, opts.approvedPredicate);
350
+ const timeout = opts.defaultTimeout ?? "24h";
351
+ const onTimeout = opts.defaultOnTimeout ?? "halt";
352
+ const inner = defineNode({
353
+ key: opts.key,
354
+ title: opts.title,
355
+ description: opts.description,
356
+ icon: opts.icon,
357
+ configSchema: opts.configSchema,
358
+ inputSchema: opts.inputSchema,
359
+ credentials: opts.credentials,
360
+ inspectorSummary: opts.inspectorSummary ? ({ config }) => opts.inspectorSummary(config) : void 0,
361
+ async execute(args, { config, execution: ctx }) {
362
+ if (!ctx.resumeContext) {
363
+ const subject = buildSubject(opts.title, args.item, ctx);
364
+ throw new require_di.SuspensionRequest({
365
+ decisionSchema: opts.decisionSchema,
366
+ timeout,
367
+ onTimeout,
368
+ subject,
369
+ metadata: {
370
+ channel: opts.channel,
371
+ nodeKey: opts.key,
372
+ approvedPredicateSource: opts.approvedPredicate?.toString() ?? null
373
+ },
374
+ deliver: (handle) => opts.deliver({
375
+ task: handle,
376
+ config,
377
+ input: args.input,
378
+ item: args.item
379
+ }, ctx)
380
+ });
381
+ }
382
+ return await handleResume(args.item, ctx.resumeContext, opts.decisionSchema, resolvedPredicate, opts.onDecision, opts.onTimeout, ctx);
383
+ }
384
+ });
385
+ return Object.assign(inner, { humanApprovalToolBehavior: { onRejected: "return" } });
386
+ }
387
+ function resolveApprovedPredicate(schema, predicate) {
388
+ if (predicate) return predicate;
389
+ const shape = schema.shape;
390
+ if (shape && typeof shape === "object" && "approved" in shape) return (d) => d.approved === true;
391
+ throw new Error("defineHumanApprovalNode: decisionSchema has no \"approved\" field and no approvedPredicate was provided. Either add { approved: z.boolean() } to the decision schema or supply approvedPredicate explicitly.");
392
+ }
393
+ function buildSubject(title, item, ctx) {
394
+ return {
395
+ title,
396
+ summary: "",
397
+ attributes: {
398
+ workflowId: ctx.workflowId,
399
+ nodeId: ctx.nodeId,
400
+ item: item.json
401
+ }
402
+ };
403
+ }
404
+ function mergeDecision(item, decision) {
405
+ return {
406
+ json: {
407
+ ...item.json,
408
+ decision
409
+ },
410
+ binary: item.binary,
411
+ meta: item.meta
412
+ };
413
+ }
414
+ async function handleResume(item, resumeContext, decisionSchema, resolvedPredicate, onDecision, onTimeoutCb, ctx) {
415
+ const { decision: dec, delivery, task } = resumeContext;
416
+ if (dec.kind === "timed_out" || dec.kind === "auto_accepted") {
417
+ const policy = dec.kind === "auto_accepted" ? "auto-accept" : "halt";
418
+ await onTimeoutCb?.({
419
+ task,
420
+ delivery,
421
+ item,
422
+ policy
423
+ }, ctx);
424
+ return mergeDecision(item, {
425
+ status: dec.kind === "auto_accepted" ? "auto-accepted" : "timed-out",
426
+ decidedAt: dec.at
427
+ });
428
+ }
429
+ const parsed = decisionSchema.parse(dec.value);
430
+ await onDecision?.({
431
+ decision: parsed,
432
+ actor: dec.actor,
433
+ task,
434
+ delivery,
435
+ item
436
+ }, ctx);
437
+ return mergeDecision(item, {
438
+ status: resolvedPredicate(parsed) ? "approved" : "rejected",
439
+ actor: dec.actor,
440
+ decidedAt: dec.decidedAt,
441
+ note: parsed.note,
442
+ payload: parsed
443
+ });
444
+ }
445
+
119
446
  //#endregion
120
447
  //#region src/workflow/dsl/WhenBuilder.ts
121
448
  var WhenBuilder = class WhenBuilder {
@@ -242,6 +569,25 @@ var ChainCursor = class ChainCursor {
242
569
  }
243
570
  return new ChainCursor(this.wf, nextEndpoints);
244
571
  }
572
+ /**
573
+ * Chainable shorthand for `.then(node.create(config, metadata?.name, metadata?.nodeId))`.
574
+ *
575
+ * Signals to readers that this step suspends the run and waits for a human decision.
576
+ * Throws at workflow-build time if `node` was not created via `defineHumanApprovalNode`.
577
+ *
578
+ * @example
579
+ * ```ts
580
+ * workflow
581
+ * .trigger(...)
582
+ * .humanApproval(inboxApproval, { title: "Approve?", body: "...", priority: "normal" })
583
+ * .then(nextStep.create(...))
584
+ * .build();
585
+ * ```
586
+ */
587
+ humanApproval(node$1, config, metadata) {
588
+ if (!isHumanApprovalNode(node$1)) throw new Error(`.humanApproval() requires a node created via defineHumanApprovalNode (got '${node$1.key ?? String(node$1)}').`);
589
+ return this.then(node$1.create(config, metadata?.name, metadata?.nodeId));
590
+ }
245
591
  build() {
246
592
  return this.wf.build();
247
593
  }
@@ -708,7 +1054,7 @@ var NodeExecutionSnapshotFactory = class {
708
1054
  nodeId: args.nodeId,
709
1055
  activationId: args.activationId,
710
1056
  parent: args.parent,
711
- status: "completed",
1057
+ status: args.hitlStatus ?? "completed",
712
1058
  queuedAt: args.previous?.queuedAt,
713
1059
  startedAt,
714
1060
  finishedAt: args.finishedAt,
@@ -835,7 +1181,9 @@ var ActivationEnqueueService = class {
835
1181
  nodeSnapshotsByNodeId: {
836
1182
  ...args.previousNodeSnapshotsByNodeId,
837
1183
  [args.request.nodeId]: queuedSnapshot
838
- }
1184
+ },
1185
+ ...args.suspension !== void 0 ? { suspension: args.suspension } : {},
1186
+ ...args.pendingResume !== void 0 ? { pendingResume: args.pendingResume } : {}
839
1187
  });
840
1188
  await this.dispatchPreparedActivation(preparedDispatch);
841
1189
  return {
@@ -1302,6 +1650,16 @@ var CodemationTelemetryAttributeNames = class {
1302
1650
  static mcpServerId = "mcp.server_id";
1303
1651
  /** MCP tool name on spans created for callTool invocations. */
1304
1652
  static mcpToolName = "mcp.tool_name";
1653
+ /** Terminal node-execution status (e.g. `"hitl-approved"`, `"hitl-rejected"`) on HITL outcome spans. */
1654
+ static nodeExecutionStatus = "codemation.node.execution_status";
1655
+ /** Populated on run-halted spans; discriminates the halt reason (e.g. `"hitl-rejected"`). */
1656
+ static runHaltReason = "codemation.run.halt_reason";
1657
+ /** Human task ID on `hitl.task.*` span events. */
1658
+ static hitlTaskId = "codemation.hitl.task_id";
1659
+ /** HITL channel name (e.g. `"inbox"`, `"control-plane-inbox"`) on `hitl.task.*` span events. */
1660
+ static hitlChannel = "codemation.hitl.channel";
1661
+ /** Decision outcome (e.g. `"approved"`, `"rejected"`) on `hitl.task.decided` span events. */
1662
+ static hitlDecisionStatus = "codemation.hitl.decision_status";
1305
1663
  };
1306
1664
 
1307
1665
  //#endregion
@@ -1400,12 +1758,13 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
1400
1758
  //#region src/execution/DefaultExecutionContextFactory.ts
1401
1759
  var DefaultExecutionContextFactory = class {
1402
1760
  telemetryDecoratorFactory = new ExecutionTelemetryCostTrackingDecoratorFactory();
1403
- constructor(binaryStorage = new UnavailableBinaryStorage(), telemetryFactory = new NoOpExecutionTelemetryFactory(), costTrackingFactory = new NoOpCostTrackingTelemetryFactory(), currentDate = () => /* @__PURE__ */ new Date(), collections) {
1761
+ constructor(binaryStorage = new UnavailableBinaryStorage(), telemetryFactory = new NoOpExecutionTelemetryFactory(), costTrackingFactory = new NoOpCostTrackingTelemetryFactory(), currentDate = () => /* @__PURE__ */ new Date(), collections, nodeResolver) {
1404
1762
  this.binaryStorage = binaryStorage;
1405
1763
  this.telemetryFactory = telemetryFactory;
1406
1764
  this.costTrackingFactory = costTrackingFactory;
1407
1765
  this.currentDate = currentDate;
1408
1766
  this.collections = collections;
1767
+ this.nodeResolver = nodeResolver;
1409
1768
  }
1410
1769
  create(args) {
1411
1770
  const baseTelemetry = args.telemetry ?? this.telemetryFactory.create({
@@ -1432,7 +1791,11 @@ var DefaultExecutionContextFactory = class {
1432
1791
  binary: new DefaultExecutionBinaryService(this.binaryStorage, args.workflowId, args.runId, this.currentDate),
1433
1792
  getCredential: args.getCredential,
1434
1793
  testContext: args.testContext,
1435
- collections: this.collections
1794
+ collections: this.collections,
1795
+ resolve: (token) => {
1796
+ if (!this.nodeResolver) throw new Error("ExecutionContext.resolve() is not available: no NodeResolver was provided to DefaultExecutionContextFactory.");
1797
+ return this.nodeResolver.resolve(token);
1798
+ }
1436
1799
  };
1437
1800
  }
1438
1801
  };
@@ -1774,6 +2137,27 @@ var NodeActivationRequestComposer = class {
1774
2137
  }
1775
2138
  };
1776
2139
 
2140
+ //#endregion
2141
+ //#region src/execution/RunSuspendedError.ts
2142
+ /**
2143
+ * Internal sentinel thrown by {@link NodeSuspensionHandler} after persisting a suspension
2144
+ * entry. `NodeExecutionRequestHandlerService` catches this specifically and returns cleanly —
2145
+ * no continuation call, preventing `resumeFromNodeResult` / `resumeFromNodeError` from
2146
+ * overwriting the `"suspended"` run status.
2147
+ *
2148
+ * The `Error` suffix satisfies the ESLint `no-manual-di-new` allowlist. This is NOT a
2149
+ * user-facing error — it is an engine-internal control-flow primitive and should NOT be
2150
+ * exported from the public barrel.
2151
+ */
2152
+ var RunSuspendedError = class extends Error {
2153
+ constructor(runId, taskId) {
2154
+ super(`RunSuspendedError: run ${runId} suspended on task ${taskId}`);
2155
+ this.runId = runId;
2156
+ this.taskId = taskId;
2157
+ this.name = "RunSuspendedError";
2158
+ }
2159
+ };
2160
+
1777
2161
  //#endregion
1778
2162
  //#region src/execution/NodeExecutor.ts
1779
2163
  var NodeExecutor = class {
@@ -1781,9 +2165,11 @@ var NodeExecutor = class {
1781
2165
  outputNormalizer = new NodeOutputNormalizer();
1782
2166
  itemExprResolver;
1783
2167
  outputBehaviorResolver;
1784
- constructor(nodeInstanceFactory, retryRunner, itemExprResolver, outputBehaviorResolver) {
2168
+ constructor(nodeInstanceFactory, retryRunner, itemExprResolver, outputBehaviorResolver, suspensionHandler, loadRunState) {
1785
2169
  this.nodeInstanceFactory = nodeInstanceFactory;
1786
2170
  this.retryRunner = retryRunner;
2171
+ this.suspensionHandler = suspensionHandler;
2172
+ this.loadRunState = loadRunState;
1787
2173
  this.itemExprResolver = itemExprResolver ?? new ItemExprResolver();
1788
2174
  this.outputBehaviorResolver = outputBehaviorResolver ?? new RunnableOutputBehaviorResolver();
1789
2175
  }
@@ -1883,6 +2269,7 @@ var NodeExecutor = class {
1883
2269
  });
1884
2270
  }
1885
2271
  const byPort = {};
2272
+ let hasSuspension = false;
1886
2273
  for (let i = 0; i < inputBatch.length; i++) {
1887
2274
  const item = inputBatch[i];
1888
2275
  this.assertItemJsonNotTopLevelArray(request.nodeId, item);
@@ -1901,7 +2288,28 @@ var NodeExecutor = class {
1901
2288
  items: inputBatch,
1902
2289
  ctx: iterationCtx
1903
2290
  };
1904
- const raw = await Promise.resolve(node$1.execute(args));
2291
+ let raw;
2292
+ try {
2293
+ raw = await Promise.resolve(node$1.execute(args));
2294
+ } catch (e) {
2295
+ if (e instanceof require_di.SuspensionRequest || e instanceof Error && e.name === "SuspensionRequest" && typeof e.request === "object") {
2296
+ if (!this.suspensionHandler || !this.loadRunState) throw new Error(`Node ${request.nodeId} threw SuspensionRequest but this NodeExecutor has no suspensionHandler configured.`, { cause: e });
2297
+ const state = await this.loadRunState(request.runId);
2298
+ if (!state) throw new Error(`NodeExecutor: run state not found for runId ${request.runId} during suspension`, { cause: e });
2299
+ await this.suspensionHandler.handle({
2300
+ runId: request.runId,
2301
+ nodeId: request.nodeId,
2302
+ activationId: request.activationId,
2303
+ itemIndex: i,
2304
+ suspensionRequest: e,
2305
+ state,
2306
+ telemetry: iterationCtx.telemetry
2307
+ });
2308
+ hasSuspension = true;
2309
+ continue;
2310
+ }
2311
+ throw e;
2312
+ }
1905
2313
  const normalized = this.outputNormalizer.normalizeExecuteResult({
1906
2314
  baseItem: item,
1907
2315
  raw,
@@ -1914,6 +2322,7 @@ var NodeExecutor = class {
1914
2322
  byPort[port] = list;
1915
2323
  }
1916
2324
  }
2325
+ if (hasSuspension) throw new RunSuspendedError(request.runId, "unknown");
1917
2326
  return byPort;
1918
2327
  }
1919
2328
  /** Use resolver ctx only when {@link NodeExecutionContext.config} is non-nullish. */
@@ -1940,8 +2349,8 @@ var NodeExecutor = class {
1940
2349
  //#endregion
1941
2350
  //#region src/execution/NodeExecutorFactory.ts
1942
2351
  var NodeExecutorFactory = class {
1943
- create(workflowNodeInstanceFactory, retryRunner, outputBehaviorResolver) {
1944
- return new NodeExecutor(workflowNodeInstanceFactory, retryRunner, void 0, outputBehaviorResolver);
2352
+ create(workflowNodeInstanceFactory, retryRunner, outputBehaviorResolver, suspensionHandler, loadRunState) {
2353
+ return new NodeExecutor(workflowNodeInstanceFactory, retryRunner, void 0, outputBehaviorResolver, suspensionHandler, loadRunState);
1945
2354
  }
1946
2355
  };
1947
2356
 
@@ -2534,6 +2943,7 @@ var PersistedRunStateTerminalBuilder = class {
2534
2943
  ...args.state,
2535
2944
  engineCounters: args.engineCounters,
2536
2945
  status: args.status,
2946
+ reason: args.reason,
2537
2947
  pending: void 0,
2538
2948
  queue: args.queue,
2539
2949
  outputsByNode: args.outputsByNode,
@@ -2816,6 +3226,7 @@ var RunContinuationService = class {
2816
3226
  });
2817
3227
  data.setOutputs(args.nodeId, args.outputs);
2818
3228
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3229
+ const hitlResolution = this.resolveHitlStatus(args.outputs);
2819
3230
  const completedSnapshot = this.semantics.createFinishedSnapshot({
2820
3231
  workflow: wf,
2821
3232
  previous: state.nodeSnapshotsByNodeId?.[args.nodeId],
@@ -2826,8 +3237,41 @@ var RunContinuationService = class {
2826
3237
  parent: state.parent,
2827
3238
  finishedAt: completedAt,
2828
3239
  inputsByPort: pendingExecution.inputsByPort,
2829
- outputs: args.outputs
3240
+ outputs: args.outputs,
3241
+ hitlStatus: hitlResolution?.nodeStatus
2830
3242
  });
3243
+ if (hitlResolution?.halt) {
3244
+ const haltedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
3245
+ state,
3246
+ engineCounters: state.engineCounters ?? { completedNodeActivations: 0 },
3247
+ status: "halted",
3248
+ reason: hitlResolution.reason,
3249
+ queue: [],
3250
+ outputsByNode: data.dump(),
3251
+ nodeSnapshotsByNodeId: {
3252
+ ...state.nodeSnapshotsByNodeId ?? {},
3253
+ [args.nodeId]: completedSnapshot
3254
+ },
3255
+ finishedAtIso: completedAt
3256
+ });
3257
+ await this.workflowExecutionRepository.save(haltedState);
3258
+ await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
3259
+ await this.terminalPersistence.maybeDeleteAfterTerminalState({
3260
+ workflow: wf,
3261
+ state: haltedState,
3262
+ finalStatus: "failed",
3263
+ finishedAt: completedAt
3264
+ });
3265
+ const result = {
3266
+ runId: state.runId,
3267
+ workflowId: state.workflowId,
3268
+ startedAt: state.startedAt,
3269
+ status: "halted",
3270
+ reason: hitlResolution.reason
3271
+ };
3272
+ this.waiters.resolveRunCompletion(result);
3273
+ return result;
3274
+ }
2831
3275
  const completedActivations = (state.engineCounters?.completedNodeActivations ?? 0) + 1;
2832
3276
  const engineCounters = { completedNodeActivations: completedActivations };
2833
3277
  const maxNodeActivations = state.executionOptions?.maxNodeActivations ?? this.executionLimitsPolicy.createRootExecutionOptions().maxNodeActivations;
@@ -3128,13 +3572,114 @@ var RunContinuationService = class {
3128
3572
  status: "failed",
3129
3573
  error: { message: "Run failed" }
3130
3574
  };
3575
+ if (existing?.status === "halted") return {
3576
+ runId: existing.runId,
3577
+ workflowId: existing.workflowId,
3578
+ startedAt: existing.startedAt,
3579
+ status: "halted",
3580
+ reason: existing.reason ?? "hitl-rejected"
3581
+ };
3131
3582
  const result = await this.waiters.waitForCompletion(runId);
3132
- if (result.status !== "completed" && result.status !== "failed") throw new Error(`Unexpected run completion status: ${result.status}`);
3583
+ if (result.status !== "completed" && result.status !== "failed" && result.status !== "halted") throw new Error(`Unexpected run completion status: ${result.status}`);
3133
3584
  return result;
3134
3585
  }
3135
3586
  async waitForWebhookResponse(runId) {
3136
3587
  return await this.waiters.waitForWebhookResponse(runId);
3137
3588
  }
3589
+ /**
3590
+ * Re-activate a previously suspended run item with a human decision.
3591
+ *
3592
+ * Called by the HITL resume endpoint. This method:
3593
+ * 1. Loads `PersistedRunState` and locates the suspension entry by `taskId`.
3594
+ * 2. Removes the entry from the `suspension` array; if empty, run stays `"suspended"` until
3595
+ * enqueue flips it to `"pending"`.
3596
+ * 3. Writes `pendingResume` onto the state so `NodeExecutionRequestHandlerService` can
3597
+ * splice `resumeContext` into the node's execution context.
3598
+ * 4. Reconstructs the original input from `outputsByNode` of the upstream node and
3599
+ * enqueues a new activation via `activationEnqueueService`.
3600
+ *
3601
+ * @throws if the run is not found, not suspended, or the `taskId` is unknown.
3602
+ */
3603
+ async resumeRun(args) {
3604
+ const state = await this.workflowExecutionRepository.load(args.runId);
3605
+ if (!state) throw new Error(`Unknown runId: ${args.runId}`);
3606
+ if (state.status !== "suspended") throw new Error(`Run ${args.runId} is not suspended (status: ${state.status})`);
3607
+ const suspensionEntry = (state.suspension ?? []).find((s) => s.taskId === args.taskId);
3608
+ if (!suspensionEntry) throw new Error(`No suspension entry with taskId "${args.taskId}" found on run ${args.runId}`);
3609
+ const wf = this.resolvePersistedWorkflow(state);
3610
+ if (!wf) throw new Error(`Unknown workflowId: ${state.workflowId}`);
3611
+ const { topology, planner } = this.planningFactory.create(wf);
3612
+ const def = topology.defsById.get(suspensionEntry.nodeId);
3613
+ if (!def || def.kind !== "node") throw new Error(`Node ${suspensionEntry.nodeId} is not a runnable node`);
3614
+ const data = this.runDataFactory.create(state.outputsByNode);
3615
+ const limits = this.resolveEngineLimitsFromState(state);
3616
+ const base = this.runExecutionContextFactory.create({
3617
+ runId: state.runId,
3618
+ workflowId: state.workflowId,
3619
+ nodeId: suspensionEntry.nodeId,
3620
+ parent: state.parent,
3621
+ policySnapshot: state.policySnapshot,
3622
+ subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
3623
+ engineMaxNodeActivations: limits.engineMaxNodeActivations,
3624
+ engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
3625
+ data,
3626
+ nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent),
3627
+ testContext: state.executionOptions?.testContext
3628
+ });
3629
+ const parentEdges = wf.edges.filter((e) => e.to.nodeId === suspensionEntry.nodeId);
3630
+ const parentNodeId = parentEdges[0]?.from.nodeId;
3631
+ const parentOutputPort = parentEdges[0]?.from.output ?? "main";
3632
+ const allParentItems = parentNodeId ? data.getOutputItems(parentNodeId, parentOutputPort) ?? [] : [];
3633
+ const resumeInput = allParentItems.length > suspensionEntry.itemIndex ? [allParentItems[suspensionEntry.itemIndex]] : allParentItems;
3634
+ const newActivationId = this.activationIdFactory.makeActivationId();
3635
+ const pendingResume = {
3636
+ activationId: newActivationId,
3637
+ nodeId: suspensionEntry.nodeId,
3638
+ resumeContext: args.resumeContext
3639
+ };
3640
+ const remainingSuspensions = (state.suspension ?? []).filter((s) => s.taskId !== args.taskId);
3641
+ const baseWithResume = {
3642
+ ...base,
3643
+ resumeContext: args.resumeContext
3644
+ };
3645
+ const batchId = `resume_${newActivationId}`;
3646
+ const request = this.nodeActivationRequestComposer.createSingleFromDefinitionWithActivation({
3647
+ activationId: newActivationId,
3648
+ runId: state.runId,
3649
+ workflowId: state.workflowId,
3650
+ parent: state.parent,
3651
+ executionOptions: state.executionOptions,
3652
+ base: baseWithResume,
3653
+ data,
3654
+ definition: {
3655
+ id: suspensionEntry.nodeId,
3656
+ config: def.config
3657
+ },
3658
+ batchId,
3659
+ input: resumeInput
3660
+ });
3661
+ const { result, queuedSnapshot } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
3662
+ runId: state.runId,
3663
+ workflowId: state.workflowId,
3664
+ startedAt: state.startedAt,
3665
+ parent: state.parent,
3666
+ executionOptions: state.executionOptions,
3667
+ control: state.control,
3668
+ workflowSnapshot: state.workflowSnapshot,
3669
+ mutableState: state.mutableState,
3670
+ policySnapshot: state.policySnapshot,
3671
+ pendingQueue: [],
3672
+ request,
3673
+ previousNodeSnapshotsByNodeId: state.nodeSnapshotsByNodeId ?? {},
3674
+ planner,
3675
+ engineCounters: state.engineCounters,
3676
+ connectionInvocations: state.connectionInvocations ?? [],
3677
+ suspension: remainingSuspensions.length > 0 ? remainingSuspensions : void 0,
3678
+ pendingResume
3679
+ });
3680
+ await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
3681
+ return result;
3682
+ }
3138
3683
  async resumeFromWebhookControl(args) {
3139
3684
  const data = this.runDataFactory.create(args.state.outputsByNode);
3140
3685
  const { topology, planner } = this.planningFactory.create(args.workflow);
@@ -3521,6 +4066,34 @@ var RunContinuationService = class {
3521
4066
  this.waiters.resolveRunCompletion(result);
3522
4067
  return result;
3523
4068
  }
4069
+ /**
4070
+ * Inspects node outputs for a `decision.status` written by `defineHumanApprovalNode`.
4071
+ * Returns the first-class HITL node status and halt classification, or `undefined`
4072
+ * when the node is not a HITL approval node.
4073
+ */
4074
+ resolveHitlStatus(outputs) {
4075
+ const firstItem = outputs?.main?.[0];
4076
+ const decisionStatus = firstItem && typeof firstItem === "object" && "json" in firstItem && firstItem.json && typeof firstItem.json === "object" && "decision" in firstItem.json && firstItem.json.decision && typeof firstItem.json.decision === "object" && "status" in firstItem.json.decision ? firstItem.json.decision.status : void 0;
4077
+ if (!decisionStatus) return void 0;
4078
+ if (decisionStatus === "approved") return {
4079
+ nodeStatus: "hitl-approved",
4080
+ halt: false
4081
+ };
4082
+ if (decisionStatus === "auto-accepted") return {
4083
+ nodeStatus: "hitl-auto-accepted",
4084
+ halt: false
4085
+ };
4086
+ if (decisionStatus === "rejected") return {
4087
+ nodeStatus: "hitl-rejected",
4088
+ halt: true,
4089
+ reason: "hitl-rejected"
4090
+ };
4091
+ if (decisionStatus === "timed-out") return {
4092
+ nodeStatus: "hitl-timeout",
4093
+ halt: true,
4094
+ reason: "hitl-timeout"
4095
+ };
4096
+ }
3524
4097
  formatNodeLabel(args) {
3525
4098
  const tokenName = typeof args.definition?.type === "function" ? args.definition.type.name : "Node";
3526
4099
  return args.definition?.name ? `"${args.definition.name}" (${tokenName}:${args.nodeId})` : `${tokenName}:${args.nodeId}`;
@@ -4873,13 +5446,19 @@ var NodeExecutionRequestHandlerService = class {
4873
5446
  const portKeys = Object.keys(inputsByPort);
4874
5447
  const kind = portKeys.length === 1 && portKeys[0] === "in" ? "single" : "multi";
4875
5448
  const batchId = pendingExecution.batchId ?? "batch_1";
5449
+ const pendingResume = state.pendingResume;
5450
+ const resumeContext = pendingResume?.activationId === request.activationId && pendingResume?.nodeId === request.nodeId ? pendingResume.resumeContext : void 0;
5451
+ const baseWithResume = resumeContext != null ? {
5452
+ ...base,
5453
+ resumeContext
5454
+ } : base;
4876
5455
  const activationRequest = kind === "multi" ? this.nodeActivationRequestComposer.createMultiFromDefinitionWithActivation({
4877
5456
  activationId: request.activationId,
4878
5457
  runId: request.runId,
4879
5458
  workflowId: request.workflowId,
4880
5459
  parent: resolvedParent,
4881
5460
  executionOptions: request.executionOptions ?? state.executionOptions,
4882
- base,
5461
+ base: baseWithResume,
4883
5462
  data,
4884
5463
  definition: {
4885
5464
  id: definition.id,
@@ -4893,7 +5472,7 @@ var NodeExecutionRequestHandlerService = class {
4893
5472
  workflowId: request.workflowId,
4894
5473
  parent: resolvedParent,
4895
5474
  executionOptions: request.executionOptions ?? state.executionOptions,
4896
- base,
5475
+ base: baseWithResume,
4897
5476
  data,
4898
5477
  definition: {
4899
5478
  id: definition.id,
@@ -4902,6 +5481,13 @@ var NodeExecutionRequestHandlerService = class {
4902
5481
  batchId,
4903
5482
  input: inputsByPort.in ?? request.input ?? []
4904
5483
  });
5484
+ if (resumeContext != null) {
5485
+ const clearedState = await this.workflowExecutionRepository.load(request.runId);
5486
+ if (clearedState?.pendingResume?.activationId === request.activationId) await this.workflowExecutionRepository.save({
5487
+ ...clearedState,
5488
+ pendingResume: void 0
5489
+ });
5490
+ }
4905
5491
  await this.continuation.markNodeRunning({
4906
5492
  runId: activationRequest.runId,
4907
5493
  activationId: activationRequest.activationId,
@@ -4912,6 +5498,7 @@ var NodeExecutionRequestHandlerService = class {
4912
5498
  try {
4913
5499
  outputs = await this.nodeExecutor.execute(activationRequest);
4914
5500
  } catch (error) {
5501
+ if (error instanceof RunSuspendedError) return;
4915
5502
  await this.resumeAfterExecutionError(activationRequest, this.asError(error));
4916
5503
  return;
4917
5504
  }
@@ -5472,7 +6059,7 @@ var EngineWaiters = class {
5472
6059
  });
5473
6060
  }
5474
6061
  resolveRunCompletion(result) {
5475
- if (result.status !== "completed" && result.status !== "failed") return;
6062
+ if (result.status !== "completed" && result.status !== "failed" && result.status !== "halted") return;
5476
6063
  const list = this.completionWaiters.get(result.runId);
5477
6064
  if (!list || list.length === 0) return;
5478
6065
  this.completionWaiters.delete(result.runId);
@@ -5566,6 +6153,13 @@ var Engine = class {
5566
6153
  async waitForWebhookResponse(runId) {
5567
6154
  return await this.deps.runContinuationService.waitForWebhookResponse(runId);
5568
6155
  }
6156
+ /**
6157
+ * Re-activate a suspended run item with a human decision (HITL).
6158
+ * The HTTP resume endpoint calls this; this method exposes the engine primitive.
6159
+ */
6160
+ async resumeRun(args) {
6161
+ return await this.deps.runContinuationService.resumeRun(args);
6162
+ }
5569
6163
  async handleNodeExecutionRequest(request) {
5570
6164
  await this.deps.nodeExecutionRequestHandler.handleNodeExecutionRequest(request);
5571
6165
  }
@@ -5773,6 +6367,7 @@ var RunIntentService = class {
5773
6367
  };
5774
6368
  return await Promise.race([this.engine.waitForWebhookResponse(scheduled.runId), this.engine.waitForCompletion(scheduled.runId).then((completed) => {
5775
6369
  if (completed.status === "failed") throw new Error(completed.error.message);
6370
+ if (completed.status === "halted") throw new Error(`Run halted: ${completed.reason}`);
5776
6371
  return {
5777
6372
  runId: completed.runId,
5778
6373
  workflowId: completed.workflowId,
@@ -5999,6 +6594,12 @@ Object.defineProperty(exports, 'DefaultWorkflowGraphFactory', {
5999
6594
  return DefaultWorkflowGraphFactory;
6000
6595
  }
6001
6596
  });
6597
+ Object.defineProperty(exports, 'DefinedNodeRegistry', {
6598
+ enumerable: true,
6599
+ get: function () {
6600
+ return DefinedNodeRegistry;
6601
+ }
6602
+ });
6002
6603
  Object.defineProperty(exports, 'ENGINE_EXECUTION_LIMITS_DEFAULTS', {
6003
6604
  enumerable: true,
6004
6605
  get: function () {
@@ -6053,6 +6654,30 @@ Object.defineProperty(exports, 'HintOnlyOffloadPolicy', {
6053
6654
  return HintOnlyOffloadPolicy;
6054
6655
  }
6055
6656
  });
6657
+ Object.defineProperty(exports, 'HitlResumeTokenSignerToken', {
6658
+ enumerable: true,
6659
+ get: function () {
6660
+ return HitlResumeTokenSignerToken;
6661
+ }
6662
+ });
6663
+ Object.defineProperty(exports, 'HitlTimeoutJobSchedulerToken', {
6664
+ enumerable: true,
6665
+ get: function () {
6666
+ return HitlTimeoutJobSchedulerToken;
6667
+ }
6668
+ });
6669
+ Object.defineProperty(exports, 'HitlWorkspaceIdToken', {
6670
+ enumerable: true,
6671
+ get: function () {
6672
+ return HitlWorkspaceIdToken;
6673
+ }
6674
+ });
6675
+ Object.defineProperty(exports, 'HumanTaskStoreToken', {
6676
+ enumerable: true,
6677
+ get: function () {
6678
+ return HumanTaskStoreToken;
6679
+ }
6680
+ });
6056
6681
  Object.defineProperty(exports, 'InMemoryBinaryStorage', {
6057
6682
  enumerable: true,
6058
6683
  get: function () {
@@ -6263,6 +6888,12 @@ Object.defineProperty(exports, 'RunPolicySnapshotFactory', {
6263
6888
  return RunPolicySnapshotFactory;
6264
6889
  }
6265
6890
  });
6891
+ Object.defineProperty(exports, 'RunSuspendedError', {
6892
+ enumerable: true,
6893
+ get: function () {
6894
+ return RunSuspendedError;
6895
+ }
6896
+ });
6266
6897
  Object.defineProperty(exports, 'RunTerminalPersistenceCoordinator', {
6267
6898
  enumerable: true,
6268
6899
  get: function () {
@@ -6359,6 +6990,24 @@ Object.defineProperty(exports, 'chatModel', {
6359
6990
  return chatModel;
6360
6991
  }
6361
6992
  });
6993
+ Object.defineProperty(exports, 'defineBatchNode', {
6994
+ enumerable: true,
6995
+ get: function () {
6996
+ return defineBatchNode;
6997
+ }
6998
+ });
6999
+ Object.defineProperty(exports, 'defineHumanApprovalNode', {
7000
+ enumerable: true,
7001
+ get: function () {
7002
+ return defineHumanApprovalNode;
7003
+ }
7004
+ });
7005
+ Object.defineProperty(exports, 'defineNode', {
7006
+ enumerable: true,
7007
+ get: function () {
7008
+ return defineNode;
7009
+ }
7010
+ });
6362
7011
  Object.defineProperty(exports, 'emitPorts', {
6363
7012
  enumerable: true,
6364
7013
  get: function () {
@@ -6377,6 +7026,12 @@ Object.defineProperty(exports, 'getPersistedRuntimeTypeMetadata', {
6377
7026
  return getPersistedRuntimeTypeMetadata;
6378
7027
  }
6379
7028
  });
7029
+ Object.defineProperty(exports, 'isHumanApprovalNode', {
7030
+ enumerable: true,
7031
+ get: function () {
7032
+ return isHumanApprovalNode;
7033
+ }
7034
+ });
6380
7035
  Object.defineProperty(exports, 'isPortsEmission', {
6381
7036
  enumerable: true,
6382
7037
  get: function () {
@@ -6401,4 +7056,4 @@ Object.defineProperty(exports, 'tool', {
6401
7056
  return tool;
6402
7057
  }
6403
7058
  });
6404
- //# sourceMappingURL=runtime-DBzq5YBi.cjs.map
7059
+ //# sourceMappingURL=runtime-CyW9c9XM.cjs.map