@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,8 +1,36 @@
1
- import { S as resolveItemExprsForExecution, _ as AgentConnectionNodeCollector, a as injectable, g as NodeIterationIdFactory, h as CredentialUnboundError, w as ConnectionNodeIdFactory, y as AgentConfigInspector } from "./di-0Wop7z1y.js";
1
+ import { C as resolveItemExprsForExecution, T as ConnectionNodeIdFactory, _ as NodeIterationIdFactory, a as injectable, b as AgentConfigInspector, g as CredentialUnboundError, h as SuspensionRequest, v as AgentConnectionNodeCollector } from "./di-DdsgWfVy.js";
2
2
  import { ZodError, z } from "zod";
3
3
  import { ReadableStream } from "node:stream/web";
4
4
  import { createHash } from "node:crypto";
5
5
 
6
+ //#region src/contracts/humanTaskStoreTypes.ts
7
+ const HumanTaskStoreToken = Symbol.for("codemation.core.HumanTaskStore");
8
+
9
+ //#endregion
10
+ //#region src/contracts/hitlSeamTypes.ts
11
+ const HitlResumeTokenSignerToken = Symbol.for("codemation.core.HitlResumeTokenSigner");
12
+ const HitlTimeoutJobSchedulerToken = Symbol.for("codemation.core.HitlTimeoutJobScheduler");
13
+ /**
14
+ * Optional workspace ID injected into NodeSuspensionHandler in managed mode (T7 security fix).
15
+ * Allows the handler to stamp the workspaceId on each HumanTaskRecord so HitlCallbackHandler
16
+ * can assert workspace identity independently of the HMAC middleware.
17
+ * Not registered in non-managed mode; NodeSuspensionHandler defaults to null.
18
+ */
19
+ const HitlWorkspaceIdToken = Symbol.for("codemation.core.HitlWorkspaceId");
20
+
21
+ //#endregion
22
+ //#region src/authoring/DefinedNodeRegistry.ts
23
+ var DefinedNodeRegistry = class {
24
+ static definitions = /* @__PURE__ */ new Map();
25
+ static register(definition) {
26
+ this.definitions.set(definition.key, definition);
27
+ }
28
+ static resolve(key) {
29
+ return this.definitions.get(key);
30
+ }
31
+ };
32
+
33
+ //#endregion
6
34
  //#region src/runtime-types/persistedRuntimeTypeModelRegistry.ts
7
35
  /** Shared metadata key used to attach persisted runtime-type information to decorated classes. */
8
36
  const persistedRuntimeTypeMetadataKey = Symbol.for("codemation.core.persistedRuntimeTypeMetadata");
@@ -111,6 +139,305 @@ function chatModel(options = {}) {
111
139
  return InjectableRuntimeDecoratorComposer.compose("chatModel", options, import.meta.url);
112
140
  }
113
141
 
142
+ //#endregion
143
+ //#region src/authoring/defineNode.types.ts
144
+ const definedNodeCredentialRequirementFactory = {
145
+ create(bindings) {
146
+ if (!bindings) return [];
147
+ return Object.entries(bindings).map(([slotKey, binding]) => {
148
+ if (typeof binding === "string" || this.isCredentialType(binding)) return {
149
+ slotKey,
150
+ label: this.humanize(slotKey),
151
+ acceptedTypes: [this.resolveTypeId(binding)]
152
+ };
153
+ const types = Array.isArray(binding.type) ? binding.type : [binding.type];
154
+ return {
155
+ slotKey,
156
+ label: binding.label ?? this.humanize(slotKey),
157
+ acceptedTypes: types.map((entry) => this.resolveTypeId(entry)),
158
+ optional: binding.optional,
159
+ helpText: binding.helpText,
160
+ helpUrl: binding.helpUrl
161
+ };
162
+ });
163
+ },
164
+ isCredentialType(value) {
165
+ return Boolean(value) && typeof value === "object" && "definition" in value && typeof value.definition?.typeId === "string";
166
+ },
167
+ resolveTypeId(type) {
168
+ return typeof type === "string" ? type : type.definition.typeId;
169
+ },
170
+ humanize(key) {
171
+ return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_.]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (character) => character.toUpperCase());
172
+ }
173
+ };
174
+ const definedNodeCredentialAccessorFactory = { create(bindings, ctx) {
175
+ if (!bindings) return {};
176
+ const entries = Object.keys(bindings).map((slotKey) => [slotKey, () => ctx.getCredential(slotKey)]);
177
+ return Object.fromEntries(entries);
178
+ } };
179
+ function defineNode(options) {
180
+ const credentialRequirements = definedNodeCredentialRequirementFactory.create(options.credentials);
181
+ const DefinedNodeRuntime = class {
182
+ kind = "node";
183
+ outputPorts = ["main"];
184
+ inputSchema = options.inputSchema;
185
+ async execute(args) {
186
+ const ctx = args.ctx;
187
+ const context = {
188
+ config: ctx.config.config,
189
+ credentials: definedNodeCredentialAccessorFactory.create(options.credentials, ctx),
190
+ execution: ctx
191
+ };
192
+ const payload = {
193
+ input: args.input,
194
+ item: args.item,
195
+ itemIndex: args.itemIndex,
196
+ items: args.items,
197
+ ctx
198
+ };
199
+ return await options.execute(payload, context);
200
+ }
201
+ };
202
+ node({ name: options.key })(DefinedNodeRuntime);
203
+ const DefinedRunnableNodeConfig = class {
204
+ kind = "node";
205
+ type = DefinedNodeRuntime;
206
+ icon = options.icon;
207
+ inputSchema = options.inputSchema;
208
+ keepBinaries = options.keepBinaries ?? false;
209
+ constructor(name, config, id) {
210
+ this.name = name;
211
+ this.id = id;
212
+ this.config = config;
213
+ }
214
+ config;
215
+ getCredentialRequirements() {
216
+ return credentialRequirements;
217
+ }
218
+ inspectorSummary() {
219
+ return options.inspectorSummary?.({ config: this.config });
220
+ }
221
+ };
222
+ const definition = {
223
+ kind: "defined-node",
224
+ key: options.key,
225
+ title: options.title,
226
+ description: options.description,
227
+ create(config, name = options.title, id) {
228
+ return new DefinedRunnableNodeConfig(name, config, id);
229
+ },
230
+ register(context) {
231
+ context.registerNode(DefinedNodeRuntime);
232
+ }
233
+ };
234
+ DefinedNodeRegistry.register(definition);
235
+ return definition;
236
+ }
237
+ function defineBatchNode(options) {
238
+ const credentialRequirements = definedNodeCredentialRequirementFactory.create(options.credentials);
239
+ const DefinedNodeRuntime = class {
240
+ kind = "node";
241
+ outputPorts = ["main"];
242
+ async execute(args) {
243
+ if (args.itemIndex !== args.items.length - 1) return [];
244
+ const ctx = args.ctx;
245
+ const context = {
246
+ config: ctx.config.config,
247
+ credentials: definedNodeCredentialAccessorFactory.create(options.credentials, ctx),
248
+ execution: ctx
249
+ };
250
+ return [...await options.run(args.items.map((item) => item.json), context)];
251
+ }
252
+ };
253
+ node({ name: options.key })(DefinedNodeRuntime);
254
+ const DefinedRunnableNodeConfig = class {
255
+ kind = "node";
256
+ type = DefinedNodeRuntime;
257
+ icon = options.icon;
258
+ constructor(name, config, id) {
259
+ this.name = name;
260
+ this.id = id;
261
+ this.config = config;
262
+ }
263
+ config;
264
+ getCredentialRequirements() {
265
+ return credentialRequirements;
266
+ }
267
+ inspectorSummary() {
268
+ return options.inspectorSummary?.({ config: this.config });
269
+ }
270
+ };
271
+ const definition = {
272
+ kind: "defined-node",
273
+ key: options.key,
274
+ title: options.title,
275
+ description: options.description,
276
+ create(config, name = options.title, id) {
277
+ return new DefinedRunnableNodeConfig(name, config, id);
278
+ },
279
+ register(context) {
280
+ context.registerNode(DefinedNodeRuntime);
281
+ }
282
+ };
283
+ DefinedNodeRegistry.register(definition);
284
+ return definition;
285
+ }
286
+
287
+ //#endregion
288
+ //#region src/authoring/defineHumanApprovalNode.types.ts
289
+ /**
290
+ * Returns `true` when `node` was created by {@link defineHumanApprovalNode}.
291
+ * Uses the `humanApprovalToolBehavior` typed field as the discriminant.
292
+ */
293
+ function isHumanApprovalNode(node$1) {
294
+ return typeof node$1 === "object" && node$1 !== null && "humanApprovalToolBehavior" in node$1 && typeof node$1.humanApprovalToolBehavior === "object";
295
+ }
296
+ /**
297
+ * Authoring helper that compiles a HITL approval channel down to a regular
298
+ * {@link defineNode}-backed node with `SuspensionRequest` semantics.
299
+ *
300
+ * **Fast-forward decision semantics:**
301
+ * - On the first `execute` call (no `ctx.resumeContext`): throws a `SuspensionRequest`
302
+ * that calls the author's `deliver`. The engine persists the suspension and continues.
303
+ * - On resume (`ctx.resumeContext` set): calls `onDecision`/`onTimeout` as appropriate,
304
+ * merges a `decision` key into `item.json`, and returns an item with the original
305
+ * `binary` map passed by reference (no copy).
306
+ *
307
+ * **Output shape per item:**
308
+ * ```ts
309
+ * // Input: { json: { invoiceId: 42 }, binary?: {...} }
310
+ * // Output: { json: { invoiceId: 42, decision: { status: "approved", actor, decidedAt } }, binary: <unchanged> }
311
+ * ```
312
+ * If `item.json` already has a `decision` key it is **overwritten**. Namespace as
313
+ * needed if your schema reserves that key for another purpose.
314
+ *
315
+ * **Predicate persistence:**
316
+ * The `approvedPredicate` function is NOT serialized to the suspension record (except
317
+ * as an audit-only string via `toString()`). On resume, the workflow definition is
318
+ * reloaded from code at process start and the predicate closure is rebuilt naturally.
319
+ * If a deploy ships a changed predicate between suspend and resume, the *new* predicate
320
+ * runs — document this in your runbook when the predicate carries business logic that
321
+ * may change across deploys.
322
+ *
323
+ * @example
324
+ * ```ts
325
+ * export const slackApprovalNode = defineHumanApprovalNode({
326
+ * key: "my-plugin.slackApproval",
327
+ * title: "Slack Approval",
328
+ * channel: "slack",
329
+ * configSchema: z.object({ channel: z.string(), message: z.string() }),
330
+ * decisionSchema: z.object({ approved: z.boolean(), note: z.string().optional() }),
331
+ *
332
+ * async deliver({ task, config, item }, ctx) {
333
+ * const ts = await postSlackMessage(config.channel, `Approve? <${task.resumeUrl}>`);
334
+ * return { channel: config.channel, ts };
335
+ * },
336
+ *
337
+ * async onDecision({ decision, actor, delivery }, ctx) {
338
+ * await updateSlackMessage(delivery.channel, delivery.ts, decision.approved ? "✅" : "❌");
339
+ * },
340
+ * });
341
+ * ```
342
+ */
343
+ function defineHumanApprovalNode(opts) {
344
+ const resolvedPredicate = resolveApprovedPredicate(opts.decisionSchema, opts.approvedPredicate);
345
+ const timeout = opts.defaultTimeout ?? "24h";
346
+ const onTimeout = opts.defaultOnTimeout ?? "halt";
347
+ const inner = defineNode({
348
+ key: opts.key,
349
+ title: opts.title,
350
+ description: opts.description,
351
+ icon: opts.icon,
352
+ configSchema: opts.configSchema,
353
+ inputSchema: opts.inputSchema,
354
+ credentials: opts.credentials,
355
+ inspectorSummary: opts.inspectorSummary ? ({ config }) => opts.inspectorSummary(config) : void 0,
356
+ async execute(args, { config, execution: ctx }) {
357
+ if (!ctx.resumeContext) {
358
+ const subject = buildSubject(opts.title, args.item, ctx);
359
+ throw new SuspensionRequest({
360
+ decisionSchema: opts.decisionSchema,
361
+ timeout,
362
+ onTimeout,
363
+ subject,
364
+ metadata: {
365
+ channel: opts.channel,
366
+ nodeKey: opts.key,
367
+ approvedPredicateSource: opts.approvedPredicate?.toString() ?? null
368
+ },
369
+ deliver: (handle) => opts.deliver({
370
+ task: handle,
371
+ config,
372
+ input: args.input,
373
+ item: args.item
374
+ }, ctx)
375
+ });
376
+ }
377
+ return await handleResume(args.item, ctx.resumeContext, opts.decisionSchema, resolvedPredicate, opts.onDecision, opts.onTimeout, ctx);
378
+ }
379
+ });
380
+ return Object.assign(inner, { humanApprovalToolBehavior: { onRejected: "return" } });
381
+ }
382
+ function resolveApprovedPredicate(schema, predicate) {
383
+ if (predicate) return predicate;
384
+ const shape = schema.shape;
385
+ if (shape && typeof shape === "object" && "approved" in shape) return (d) => d.approved === true;
386
+ 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.");
387
+ }
388
+ function buildSubject(title, item, ctx) {
389
+ return {
390
+ title,
391
+ summary: "",
392
+ attributes: {
393
+ workflowId: ctx.workflowId,
394
+ nodeId: ctx.nodeId,
395
+ item: item.json
396
+ }
397
+ };
398
+ }
399
+ function mergeDecision(item, decision) {
400
+ return {
401
+ json: {
402
+ ...item.json,
403
+ decision
404
+ },
405
+ binary: item.binary,
406
+ meta: item.meta
407
+ };
408
+ }
409
+ async function handleResume(item, resumeContext, decisionSchema, resolvedPredicate, onDecision, onTimeoutCb, ctx) {
410
+ const { decision: dec, delivery, task } = resumeContext;
411
+ if (dec.kind === "timed_out" || dec.kind === "auto_accepted") {
412
+ const policy = dec.kind === "auto_accepted" ? "auto-accept" : "halt";
413
+ await onTimeoutCb?.({
414
+ task,
415
+ delivery,
416
+ item,
417
+ policy
418
+ }, ctx);
419
+ return mergeDecision(item, {
420
+ status: dec.kind === "auto_accepted" ? "auto-accepted" : "timed-out",
421
+ decidedAt: dec.at
422
+ });
423
+ }
424
+ const parsed = decisionSchema.parse(dec.value);
425
+ await onDecision?.({
426
+ decision: parsed,
427
+ actor: dec.actor,
428
+ task,
429
+ delivery,
430
+ item
431
+ }, ctx);
432
+ return mergeDecision(item, {
433
+ status: resolvedPredicate(parsed) ? "approved" : "rejected",
434
+ actor: dec.actor,
435
+ decidedAt: dec.decidedAt,
436
+ note: parsed.note,
437
+ payload: parsed
438
+ });
439
+ }
440
+
114
441
  //#endregion
115
442
  //#region src/workflow/dsl/WhenBuilder.ts
116
443
  var WhenBuilder = class WhenBuilder {
@@ -237,6 +564,25 @@ var ChainCursor = class ChainCursor {
237
564
  }
238
565
  return new ChainCursor(this.wf, nextEndpoints);
239
566
  }
567
+ /**
568
+ * Chainable shorthand for `.then(node.create(config, metadata?.name, metadata?.nodeId))`.
569
+ *
570
+ * Signals to readers that this step suspends the run and waits for a human decision.
571
+ * Throws at workflow-build time if `node` was not created via `defineHumanApprovalNode`.
572
+ *
573
+ * @example
574
+ * ```ts
575
+ * workflow
576
+ * .trigger(...)
577
+ * .humanApproval(inboxApproval, { title: "Approve?", body: "...", priority: "normal" })
578
+ * .then(nextStep.create(...))
579
+ * .build();
580
+ * ```
581
+ */
582
+ humanApproval(node$1, config, metadata) {
583
+ if (!isHumanApprovalNode(node$1)) throw new Error(`.humanApproval() requires a node created via defineHumanApprovalNode (got '${node$1.key ?? String(node$1)}').`);
584
+ return this.then(node$1.create(config, metadata?.name, metadata?.nodeId));
585
+ }
240
586
  build() {
241
587
  return this.wf.build();
242
588
  }
@@ -703,7 +1049,7 @@ var NodeExecutionSnapshotFactory = class {
703
1049
  nodeId: args.nodeId,
704
1050
  activationId: args.activationId,
705
1051
  parent: args.parent,
706
- status: "completed",
1052
+ status: args.hitlStatus ?? "completed",
707
1053
  queuedAt: args.previous?.queuedAt,
708
1054
  startedAt,
709
1055
  finishedAt: args.finishedAt,
@@ -830,7 +1176,9 @@ var ActivationEnqueueService = class {
830
1176
  nodeSnapshotsByNodeId: {
831
1177
  ...args.previousNodeSnapshotsByNodeId,
832
1178
  [args.request.nodeId]: queuedSnapshot
833
- }
1179
+ },
1180
+ ...args.suspension !== void 0 ? { suspension: args.suspension } : {},
1181
+ ...args.pendingResume !== void 0 ? { pendingResume: args.pendingResume } : {}
834
1182
  });
835
1183
  await this.dispatchPreparedActivation(preparedDispatch);
836
1184
  return {
@@ -1297,6 +1645,16 @@ var CodemationTelemetryAttributeNames = class {
1297
1645
  static mcpServerId = "mcp.server_id";
1298
1646
  /** MCP tool name on spans created for callTool invocations. */
1299
1647
  static mcpToolName = "mcp.tool_name";
1648
+ /** Terminal node-execution status (e.g. `"hitl-approved"`, `"hitl-rejected"`) on HITL outcome spans. */
1649
+ static nodeExecutionStatus = "codemation.node.execution_status";
1650
+ /** Populated on run-halted spans; discriminates the halt reason (e.g. `"hitl-rejected"`). */
1651
+ static runHaltReason = "codemation.run.halt_reason";
1652
+ /** Human task ID on `hitl.task.*` span events. */
1653
+ static hitlTaskId = "codemation.hitl.task_id";
1654
+ /** HITL channel name (e.g. `"inbox"`, `"control-plane-inbox"`) on `hitl.task.*` span events. */
1655
+ static hitlChannel = "codemation.hitl.channel";
1656
+ /** Decision outcome (e.g. `"approved"`, `"rejected"`) on `hitl.task.decided` span events. */
1657
+ static hitlDecisionStatus = "codemation.hitl.decision_status";
1300
1658
  };
1301
1659
 
1302
1660
  //#endregion
@@ -1395,12 +1753,13 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
1395
1753
  //#region src/execution/DefaultExecutionContextFactory.ts
1396
1754
  var DefaultExecutionContextFactory = class {
1397
1755
  telemetryDecoratorFactory = new ExecutionTelemetryCostTrackingDecoratorFactory();
1398
- constructor(binaryStorage = new UnavailableBinaryStorage(), telemetryFactory = new NoOpExecutionTelemetryFactory(), costTrackingFactory = new NoOpCostTrackingTelemetryFactory(), currentDate = () => /* @__PURE__ */ new Date(), collections) {
1756
+ constructor(binaryStorage = new UnavailableBinaryStorage(), telemetryFactory = new NoOpExecutionTelemetryFactory(), costTrackingFactory = new NoOpCostTrackingTelemetryFactory(), currentDate = () => /* @__PURE__ */ new Date(), collections, nodeResolver) {
1399
1757
  this.binaryStorage = binaryStorage;
1400
1758
  this.telemetryFactory = telemetryFactory;
1401
1759
  this.costTrackingFactory = costTrackingFactory;
1402
1760
  this.currentDate = currentDate;
1403
1761
  this.collections = collections;
1762
+ this.nodeResolver = nodeResolver;
1404
1763
  }
1405
1764
  create(args) {
1406
1765
  const baseTelemetry = args.telemetry ?? this.telemetryFactory.create({
@@ -1427,7 +1786,11 @@ var DefaultExecutionContextFactory = class {
1427
1786
  binary: new DefaultExecutionBinaryService(this.binaryStorage, args.workflowId, args.runId, this.currentDate),
1428
1787
  getCredential: args.getCredential,
1429
1788
  testContext: args.testContext,
1430
- collections: this.collections
1789
+ collections: this.collections,
1790
+ resolve: (token) => {
1791
+ if (!this.nodeResolver) throw new Error("ExecutionContext.resolve() is not available: no NodeResolver was provided to DefaultExecutionContextFactory.");
1792
+ return this.nodeResolver.resolve(token);
1793
+ }
1431
1794
  };
1432
1795
  }
1433
1796
  };
@@ -1769,6 +2132,27 @@ var NodeActivationRequestComposer = class {
1769
2132
  }
1770
2133
  };
1771
2134
 
2135
+ //#endregion
2136
+ //#region src/execution/RunSuspendedError.ts
2137
+ /**
2138
+ * Internal sentinel thrown by {@link NodeSuspensionHandler} after persisting a suspension
2139
+ * entry. `NodeExecutionRequestHandlerService` catches this specifically and returns cleanly —
2140
+ * no continuation call, preventing `resumeFromNodeResult` / `resumeFromNodeError` from
2141
+ * overwriting the `"suspended"` run status.
2142
+ *
2143
+ * The `Error` suffix satisfies the ESLint `no-manual-di-new` allowlist. This is NOT a
2144
+ * user-facing error — it is an engine-internal control-flow primitive and should NOT be
2145
+ * exported from the public barrel.
2146
+ */
2147
+ var RunSuspendedError = class extends Error {
2148
+ constructor(runId, taskId) {
2149
+ super(`RunSuspendedError: run ${runId} suspended on task ${taskId}`);
2150
+ this.runId = runId;
2151
+ this.taskId = taskId;
2152
+ this.name = "RunSuspendedError";
2153
+ }
2154
+ };
2155
+
1772
2156
  //#endregion
1773
2157
  //#region src/execution/NodeExecutor.ts
1774
2158
  var NodeExecutor = class {
@@ -1776,9 +2160,11 @@ var NodeExecutor = class {
1776
2160
  outputNormalizer = new NodeOutputNormalizer();
1777
2161
  itemExprResolver;
1778
2162
  outputBehaviorResolver;
1779
- constructor(nodeInstanceFactory, retryRunner, itemExprResolver, outputBehaviorResolver) {
2163
+ constructor(nodeInstanceFactory, retryRunner, itemExprResolver, outputBehaviorResolver, suspensionHandler, loadRunState) {
1780
2164
  this.nodeInstanceFactory = nodeInstanceFactory;
1781
2165
  this.retryRunner = retryRunner;
2166
+ this.suspensionHandler = suspensionHandler;
2167
+ this.loadRunState = loadRunState;
1782
2168
  this.itemExprResolver = itemExprResolver ?? new ItemExprResolver();
1783
2169
  this.outputBehaviorResolver = outputBehaviorResolver ?? new RunnableOutputBehaviorResolver();
1784
2170
  }
@@ -1878,6 +2264,7 @@ var NodeExecutor = class {
1878
2264
  });
1879
2265
  }
1880
2266
  const byPort = {};
2267
+ let hasSuspension = false;
1881
2268
  for (let i = 0; i < inputBatch.length; i++) {
1882
2269
  const item = inputBatch[i];
1883
2270
  this.assertItemJsonNotTopLevelArray(request.nodeId, item);
@@ -1896,7 +2283,28 @@ var NodeExecutor = class {
1896
2283
  items: inputBatch,
1897
2284
  ctx: iterationCtx
1898
2285
  };
1899
- const raw = await Promise.resolve(node$1.execute(args));
2286
+ let raw;
2287
+ try {
2288
+ raw = await Promise.resolve(node$1.execute(args));
2289
+ } catch (e) {
2290
+ if (e instanceof SuspensionRequest || e instanceof Error && e.name === "SuspensionRequest" && typeof e.request === "object") {
2291
+ if (!this.suspensionHandler || !this.loadRunState) throw new Error(`Node ${request.nodeId} threw SuspensionRequest but this NodeExecutor has no suspensionHandler configured.`, { cause: e });
2292
+ const state = await this.loadRunState(request.runId);
2293
+ if (!state) throw new Error(`NodeExecutor: run state not found for runId ${request.runId} during suspension`, { cause: e });
2294
+ await this.suspensionHandler.handle({
2295
+ runId: request.runId,
2296
+ nodeId: request.nodeId,
2297
+ activationId: request.activationId,
2298
+ itemIndex: i,
2299
+ suspensionRequest: e,
2300
+ state,
2301
+ telemetry: iterationCtx.telemetry
2302
+ });
2303
+ hasSuspension = true;
2304
+ continue;
2305
+ }
2306
+ throw e;
2307
+ }
1900
2308
  const normalized = this.outputNormalizer.normalizeExecuteResult({
1901
2309
  baseItem: item,
1902
2310
  raw,
@@ -1909,6 +2317,7 @@ var NodeExecutor = class {
1909
2317
  byPort[port] = list;
1910
2318
  }
1911
2319
  }
2320
+ if (hasSuspension) throw new RunSuspendedError(request.runId, "unknown");
1912
2321
  return byPort;
1913
2322
  }
1914
2323
  /** Use resolver ctx only when {@link NodeExecutionContext.config} is non-nullish. */
@@ -1935,8 +2344,8 @@ var NodeExecutor = class {
1935
2344
  //#endregion
1936
2345
  //#region src/execution/NodeExecutorFactory.ts
1937
2346
  var NodeExecutorFactory = class {
1938
- create(workflowNodeInstanceFactory, retryRunner, outputBehaviorResolver) {
1939
- return new NodeExecutor(workflowNodeInstanceFactory, retryRunner, void 0, outputBehaviorResolver);
2347
+ create(workflowNodeInstanceFactory, retryRunner, outputBehaviorResolver, suspensionHandler, loadRunState) {
2348
+ return new NodeExecutor(workflowNodeInstanceFactory, retryRunner, void 0, outputBehaviorResolver, suspensionHandler, loadRunState);
1940
2349
  }
1941
2350
  };
1942
2351
 
@@ -2529,6 +2938,7 @@ var PersistedRunStateTerminalBuilder = class {
2529
2938
  ...args.state,
2530
2939
  engineCounters: args.engineCounters,
2531
2940
  status: args.status,
2941
+ reason: args.reason,
2532
2942
  pending: void 0,
2533
2943
  queue: args.queue,
2534
2944
  outputsByNode: args.outputsByNode,
@@ -2811,6 +3221,7 @@ var RunContinuationService = class {
2811
3221
  });
2812
3222
  data.setOutputs(args.nodeId, args.outputs);
2813
3223
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3224
+ const hitlResolution = this.resolveHitlStatus(args.outputs);
2814
3225
  const completedSnapshot = this.semantics.createFinishedSnapshot({
2815
3226
  workflow: wf,
2816
3227
  previous: state.nodeSnapshotsByNodeId?.[args.nodeId],
@@ -2821,8 +3232,41 @@ var RunContinuationService = class {
2821
3232
  parent: state.parent,
2822
3233
  finishedAt: completedAt,
2823
3234
  inputsByPort: pendingExecution.inputsByPort,
2824
- outputs: args.outputs
3235
+ outputs: args.outputs,
3236
+ hitlStatus: hitlResolution?.nodeStatus
2825
3237
  });
3238
+ if (hitlResolution?.halt) {
3239
+ const haltedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
3240
+ state,
3241
+ engineCounters: state.engineCounters ?? { completedNodeActivations: 0 },
3242
+ status: "halted",
3243
+ reason: hitlResolution.reason,
3244
+ queue: [],
3245
+ outputsByNode: data.dump(),
3246
+ nodeSnapshotsByNodeId: {
3247
+ ...state.nodeSnapshotsByNodeId ?? {},
3248
+ [args.nodeId]: completedSnapshot
3249
+ },
3250
+ finishedAtIso: completedAt
3251
+ });
3252
+ await this.workflowExecutionRepository.save(haltedState);
3253
+ await this.nodeEventPublisher.publish("nodeCompleted", completedSnapshot);
3254
+ await this.terminalPersistence.maybeDeleteAfterTerminalState({
3255
+ workflow: wf,
3256
+ state: haltedState,
3257
+ finalStatus: "failed",
3258
+ finishedAt: completedAt
3259
+ });
3260
+ const result = {
3261
+ runId: state.runId,
3262
+ workflowId: state.workflowId,
3263
+ startedAt: state.startedAt,
3264
+ status: "halted",
3265
+ reason: hitlResolution.reason
3266
+ };
3267
+ this.waiters.resolveRunCompletion(result);
3268
+ return result;
3269
+ }
2826
3270
  const completedActivations = (state.engineCounters?.completedNodeActivations ?? 0) + 1;
2827
3271
  const engineCounters = { completedNodeActivations: completedActivations };
2828
3272
  const maxNodeActivations = state.executionOptions?.maxNodeActivations ?? this.executionLimitsPolicy.createRootExecutionOptions().maxNodeActivations;
@@ -3123,13 +3567,114 @@ var RunContinuationService = class {
3123
3567
  status: "failed",
3124
3568
  error: { message: "Run failed" }
3125
3569
  };
3570
+ if (existing?.status === "halted") return {
3571
+ runId: existing.runId,
3572
+ workflowId: existing.workflowId,
3573
+ startedAt: existing.startedAt,
3574
+ status: "halted",
3575
+ reason: existing.reason ?? "hitl-rejected"
3576
+ };
3126
3577
  const result = await this.waiters.waitForCompletion(runId);
3127
- if (result.status !== "completed" && result.status !== "failed") throw new Error(`Unexpected run completion status: ${result.status}`);
3578
+ if (result.status !== "completed" && result.status !== "failed" && result.status !== "halted") throw new Error(`Unexpected run completion status: ${result.status}`);
3128
3579
  return result;
3129
3580
  }
3130
3581
  async waitForWebhookResponse(runId) {
3131
3582
  return await this.waiters.waitForWebhookResponse(runId);
3132
3583
  }
3584
+ /**
3585
+ * Re-activate a previously suspended run item with a human decision.
3586
+ *
3587
+ * Called by the HITL resume endpoint. This method:
3588
+ * 1. Loads `PersistedRunState` and locates the suspension entry by `taskId`.
3589
+ * 2. Removes the entry from the `suspension` array; if empty, run stays `"suspended"` until
3590
+ * enqueue flips it to `"pending"`.
3591
+ * 3. Writes `pendingResume` onto the state so `NodeExecutionRequestHandlerService` can
3592
+ * splice `resumeContext` into the node's execution context.
3593
+ * 4. Reconstructs the original input from `outputsByNode` of the upstream node and
3594
+ * enqueues a new activation via `activationEnqueueService`.
3595
+ *
3596
+ * @throws if the run is not found, not suspended, or the `taskId` is unknown.
3597
+ */
3598
+ async resumeRun(args) {
3599
+ const state = await this.workflowExecutionRepository.load(args.runId);
3600
+ if (!state) throw new Error(`Unknown runId: ${args.runId}`);
3601
+ if (state.status !== "suspended") throw new Error(`Run ${args.runId} is not suspended (status: ${state.status})`);
3602
+ const suspensionEntry = (state.suspension ?? []).find((s) => s.taskId === args.taskId);
3603
+ if (!suspensionEntry) throw new Error(`No suspension entry with taskId "${args.taskId}" found on run ${args.runId}`);
3604
+ const wf = this.resolvePersistedWorkflow(state);
3605
+ if (!wf) throw new Error(`Unknown workflowId: ${state.workflowId}`);
3606
+ const { topology, planner } = this.planningFactory.create(wf);
3607
+ const def = topology.defsById.get(suspensionEntry.nodeId);
3608
+ if (!def || def.kind !== "node") throw new Error(`Node ${suspensionEntry.nodeId} is not a runnable node`);
3609
+ const data = this.runDataFactory.create(state.outputsByNode);
3610
+ const limits = this.resolveEngineLimitsFromState(state);
3611
+ const base = this.runExecutionContextFactory.create({
3612
+ runId: state.runId,
3613
+ workflowId: state.workflowId,
3614
+ nodeId: suspensionEntry.nodeId,
3615
+ parent: state.parent,
3616
+ policySnapshot: state.policySnapshot,
3617
+ subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
3618
+ engineMaxNodeActivations: limits.engineMaxNodeActivations,
3619
+ engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
3620
+ data,
3621
+ nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent),
3622
+ testContext: state.executionOptions?.testContext
3623
+ });
3624
+ const parentEdges = wf.edges.filter((e) => e.to.nodeId === suspensionEntry.nodeId);
3625
+ const parentNodeId = parentEdges[0]?.from.nodeId;
3626
+ const parentOutputPort = parentEdges[0]?.from.output ?? "main";
3627
+ const allParentItems = parentNodeId ? data.getOutputItems(parentNodeId, parentOutputPort) ?? [] : [];
3628
+ const resumeInput = allParentItems.length > suspensionEntry.itemIndex ? [allParentItems[suspensionEntry.itemIndex]] : allParentItems;
3629
+ const newActivationId = this.activationIdFactory.makeActivationId();
3630
+ const pendingResume = {
3631
+ activationId: newActivationId,
3632
+ nodeId: suspensionEntry.nodeId,
3633
+ resumeContext: args.resumeContext
3634
+ };
3635
+ const remainingSuspensions = (state.suspension ?? []).filter((s) => s.taskId !== args.taskId);
3636
+ const baseWithResume = {
3637
+ ...base,
3638
+ resumeContext: args.resumeContext
3639
+ };
3640
+ const batchId = `resume_${newActivationId}`;
3641
+ const request = this.nodeActivationRequestComposer.createSingleFromDefinitionWithActivation({
3642
+ activationId: newActivationId,
3643
+ runId: state.runId,
3644
+ workflowId: state.workflowId,
3645
+ parent: state.parent,
3646
+ executionOptions: state.executionOptions,
3647
+ base: baseWithResume,
3648
+ data,
3649
+ definition: {
3650
+ id: suspensionEntry.nodeId,
3651
+ config: def.config
3652
+ },
3653
+ batchId,
3654
+ input: resumeInput
3655
+ });
3656
+ const { result, queuedSnapshot } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
3657
+ runId: state.runId,
3658
+ workflowId: state.workflowId,
3659
+ startedAt: state.startedAt,
3660
+ parent: state.parent,
3661
+ executionOptions: state.executionOptions,
3662
+ control: state.control,
3663
+ workflowSnapshot: state.workflowSnapshot,
3664
+ mutableState: state.mutableState,
3665
+ policySnapshot: state.policySnapshot,
3666
+ pendingQueue: [],
3667
+ request,
3668
+ previousNodeSnapshotsByNodeId: state.nodeSnapshotsByNodeId ?? {},
3669
+ planner,
3670
+ engineCounters: state.engineCounters,
3671
+ connectionInvocations: state.connectionInvocations ?? [],
3672
+ suspension: remainingSuspensions.length > 0 ? remainingSuspensions : void 0,
3673
+ pendingResume
3674
+ });
3675
+ await this.nodeEventPublisher.publish("nodeQueued", queuedSnapshot);
3676
+ return result;
3677
+ }
3133
3678
  async resumeFromWebhookControl(args) {
3134
3679
  const data = this.runDataFactory.create(args.state.outputsByNode);
3135
3680
  const { topology, planner } = this.planningFactory.create(args.workflow);
@@ -3516,6 +4061,34 @@ var RunContinuationService = class {
3516
4061
  this.waiters.resolveRunCompletion(result);
3517
4062
  return result;
3518
4063
  }
4064
+ /**
4065
+ * Inspects node outputs for a `decision.status` written by `defineHumanApprovalNode`.
4066
+ * Returns the first-class HITL node status and halt classification, or `undefined`
4067
+ * when the node is not a HITL approval node.
4068
+ */
4069
+ resolveHitlStatus(outputs) {
4070
+ const firstItem = outputs?.main?.[0];
4071
+ 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;
4072
+ if (!decisionStatus) return void 0;
4073
+ if (decisionStatus === "approved") return {
4074
+ nodeStatus: "hitl-approved",
4075
+ halt: false
4076
+ };
4077
+ if (decisionStatus === "auto-accepted") return {
4078
+ nodeStatus: "hitl-auto-accepted",
4079
+ halt: false
4080
+ };
4081
+ if (decisionStatus === "rejected") return {
4082
+ nodeStatus: "hitl-rejected",
4083
+ halt: true,
4084
+ reason: "hitl-rejected"
4085
+ };
4086
+ if (decisionStatus === "timed-out") return {
4087
+ nodeStatus: "hitl-timeout",
4088
+ halt: true,
4089
+ reason: "hitl-timeout"
4090
+ };
4091
+ }
3519
4092
  formatNodeLabel(args) {
3520
4093
  const tokenName = typeof args.definition?.type === "function" ? args.definition.type.name : "Node";
3521
4094
  return args.definition?.name ? `"${args.definition.name}" (${tokenName}:${args.nodeId})` : `${tokenName}:${args.nodeId}`;
@@ -4868,13 +5441,19 @@ var NodeExecutionRequestHandlerService = class {
4868
5441
  const portKeys = Object.keys(inputsByPort);
4869
5442
  const kind = portKeys.length === 1 && portKeys[0] === "in" ? "single" : "multi";
4870
5443
  const batchId = pendingExecution.batchId ?? "batch_1";
5444
+ const pendingResume = state.pendingResume;
5445
+ const resumeContext = pendingResume?.activationId === request.activationId && pendingResume?.nodeId === request.nodeId ? pendingResume.resumeContext : void 0;
5446
+ const baseWithResume = resumeContext != null ? {
5447
+ ...base,
5448
+ resumeContext
5449
+ } : base;
4871
5450
  const activationRequest = kind === "multi" ? this.nodeActivationRequestComposer.createMultiFromDefinitionWithActivation({
4872
5451
  activationId: request.activationId,
4873
5452
  runId: request.runId,
4874
5453
  workflowId: request.workflowId,
4875
5454
  parent: resolvedParent,
4876
5455
  executionOptions: request.executionOptions ?? state.executionOptions,
4877
- base,
5456
+ base: baseWithResume,
4878
5457
  data,
4879
5458
  definition: {
4880
5459
  id: definition.id,
@@ -4888,7 +5467,7 @@ var NodeExecutionRequestHandlerService = class {
4888
5467
  workflowId: request.workflowId,
4889
5468
  parent: resolvedParent,
4890
5469
  executionOptions: request.executionOptions ?? state.executionOptions,
4891
- base,
5470
+ base: baseWithResume,
4892
5471
  data,
4893
5472
  definition: {
4894
5473
  id: definition.id,
@@ -4897,6 +5476,13 @@ var NodeExecutionRequestHandlerService = class {
4897
5476
  batchId,
4898
5477
  input: inputsByPort.in ?? request.input ?? []
4899
5478
  });
5479
+ if (resumeContext != null) {
5480
+ const clearedState = await this.workflowExecutionRepository.load(request.runId);
5481
+ if (clearedState?.pendingResume?.activationId === request.activationId) await this.workflowExecutionRepository.save({
5482
+ ...clearedState,
5483
+ pendingResume: void 0
5484
+ });
5485
+ }
4900
5486
  await this.continuation.markNodeRunning({
4901
5487
  runId: activationRequest.runId,
4902
5488
  activationId: activationRequest.activationId,
@@ -4907,6 +5493,7 @@ var NodeExecutionRequestHandlerService = class {
4907
5493
  try {
4908
5494
  outputs = await this.nodeExecutor.execute(activationRequest);
4909
5495
  } catch (error) {
5496
+ if (error instanceof RunSuspendedError) return;
4910
5497
  await this.resumeAfterExecutionError(activationRequest, this.asError(error));
4911
5498
  return;
4912
5499
  }
@@ -5467,7 +6054,7 @@ var EngineWaiters = class {
5467
6054
  });
5468
6055
  }
5469
6056
  resolveRunCompletion(result) {
5470
- if (result.status !== "completed" && result.status !== "failed") return;
6057
+ if (result.status !== "completed" && result.status !== "failed" && result.status !== "halted") return;
5471
6058
  const list = this.completionWaiters.get(result.runId);
5472
6059
  if (!list || list.length === 0) return;
5473
6060
  this.completionWaiters.delete(result.runId);
@@ -5561,6 +6148,13 @@ var Engine = class {
5561
6148
  async waitForWebhookResponse(runId) {
5562
6149
  return await this.deps.runContinuationService.waitForWebhookResponse(runId);
5563
6150
  }
6151
+ /**
6152
+ * Re-activate a suspended run item with a human decision (HITL).
6153
+ * The HTTP resume endpoint calls this; this method exposes the engine primitive.
6154
+ */
6155
+ async resumeRun(args) {
6156
+ return await this.deps.runContinuationService.resumeRun(args);
6157
+ }
5564
6158
  async handleNodeExecutionRequest(request) {
5565
6159
  await this.deps.nodeExecutionRequestHandler.handleNodeExecutionRequest(request);
5566
6160
  }
@@ -5768,6 +6362,7 @@ var RunIntentService = class {
5768
6362
  };
5769
6363
  return await Promise.race([this.engine.waitForWebhookResponse(scheduled.runId), this.engine.waitForCompletion(scheduled.runId).then((completed) => {
5770
6364
  if (completed.status === "failed") throw new Error(completed.error.message);
6365
+ if (completed.status === "halted") throw new Error(`Run halted: ${completed.reason}`);
5771
6366
  return {
5772
6367
  runId: completed.runId,
5773
6368
  workflowId: completed.workflowId,
@@ -5892,5 +6487,5 @@ var WorkflowRepositoryWebhookTriggerMatcherFactory = class {
5892
6487
  };
5893
6488
 
5894
6489
  //#endregion
5895
- export { CostTrackingTelemetryMetricNames as $, PersistedWorkflowTokenRegistry as A, PersistedRuntimeTypeNameResolver as At, DefaultExecutionContextFactory as B, DefaultDrivingScheduler as C, chatModel as Ct, NodeInstanceFactoryFactory as D, InjectableRuntimeDecoratorComposer as Dt, StaticCostCatalog as E, tool as Et, RunnableOutputBehaviorResolver as F, NoOpExecutionTelemetryFactory as G, GenAiTelemetryAttributeNames as H, NodeOutputNormalizer as I, NoOpTelemetrySpanScope as J, NoOpExecutionTelemetry as K, ItemExprResolver as L, NodeExecutorFactory as M, NodeExecutor as N, NodeInstanceFactory as O, PersistedRuntimeTypeMetadataStore as Ot, InProcessRetryRunnerFactory as P, CostTrackingTelemetryAttributeNames as Q, InProcessRetryRunner as R, HintOnlyOffloadPolicy as S, WhenBuilder as St, RunPolicySnapshotFactory as T, node as Tt, CodemationTelemetryAttributeNames as U, CodemationTelemetryMetricNames as V, AllWorkflowsActiveWorkflowActivationPolicy as W, NoOpCostTrackingTelemetryFactory as X, NoOpTelemetryArtifactReference as Y, NoOpCostTrackingTelemetry as Z, RunTerminalPersistenceCoordinator as _, ConnectionInvocationIdFactory as _t, InMemoryLiveWorkflowRepository as a, isUnbrandedPortsEmissionShape as at, LocalOnlyScheduler as b, NodeIdSlugifier as bt, EngineFactory as c, getOriginIndexFromItem as ct, PollingTriggerRuntime as d, UnavailableBinaryStorage as dt, ExpRetryPolicy as et, PollingTriggerDedupWindow as f, NodeEventPublisher as ft, WorkflowPolicyErrorServices as g, WorkflowExecutableNodeClassifier as gt, WorkflowStoragePolicyEvaluator as h, WorkflowExecutableNodeClassifierFactory as ht, RunIntentService as i, isPortsEmission as it, MissingRuntimeTriggerToken as j, WorkflowSnapshotCodec as k, StackTraceCallSitePathResolver as kt, Engine as l, ChildExecutionScopeFactory as lt, InMemoryBinaryStorage as m, DefaultWorkflowGraphFactory as mt, WorkflowRepositoryWebhookTriggerMatcher as n, NoRetryPolicy as nt, EngineWorkflowRunnerServiceFactory as o, DefaultAsyncSleeper as ot, InMemoryRunDataFactory as p, ConnectionInvocationEventPublisher as pt, NoOpNodeExecutionTelemetry as q, RunIntentServiceFactory as r, emitPorts as rt, EngineWorkflowRunnerService as s, CredentialResolverFactory as st, WorkflowRepositoryWebhookTriggerMatcherFactory as t, RetryPolicy as tt, NoOpPollingTriggerLogger as u, DefaultExecutionBinaryService as ut, ENGINE_EXECUTION_LIMITS_DEFAULTS as v, WorkflowBuilder as vt, ConfigDrivenOffloadPolicy as w, getPersistedRuntimeTypeMetadata as wt, InlineDrivingScheduler as x, ChainCursor as xt, EngineExecutionLimitsPolicy as y, WorkflowDefinitionError as yt, CatalogBackedCostTrackingTelemetryFactory as z };
5896
- //# sourceMappingURL=runtime-cxmUkk0l.js.map
6490
+ export { CostTrackingTelemetryAttributeNames as $, PersistedWorkflowTokenRegistry as A, node as At, CatalogBackedCostTrackingTelemetryFactory as B, HumanTaskStoreToken as Bt, DefaultDrivingScheduler as C, WhenBuilder as Ct, NodeInstanceFactoryFactory as D, defineNode as Dt, StaticCostCatalog as E, defineBatchNode as Et, InProcessRetryRunnerFactory as F, PersistedRuntimeTypeNameResolver as Ft, AllWorkflowsActiveWorkflowActivationPolicy as G, CodemationTelemetryMetricNames as H, RunnableOutputBehaviorResolver as I, DefinedNodeRegistry as It, NoOpNodeExecutionTelemetry as J, NoOpExecutionTelemetryFactory as K, NodeOutputNormalizer as L, HitlResumeTokenSignerToken as Lt, NodeExecutorFactory as M, InjectableRuntimeDecoratorComposer as Mt, NodeExecutor as N, PersistedRuntimeTypeMetadataStore as Nt, NodeInstanceFactory as O, chatModel as Ot, RunSuspendedError as P, StackTraceCallSitePathResolver as Pt, NoOpCostTrackingTelemetry as Q, ItemExprResolver as R, HitlTimeoutJobSchedulerToken as Rt, HintOnlyOffloadPolicy as S, ChainCursor as St, RunPolicySnapshotFactory as T, isHumanApprovalNode as Tt, GenAiTelemetryAttributeNames as U, DefaultExecutionContextFactory as V, CodemationTelemetryAttributeNames as W, NoOpTelemetryArtifactReference as X, NoOpTelemetrySpanScope as Y, NoOpCostTrackingTelemetryFactory as Z, RunTerminalPersistenceCoordinator as _, WorkflowExecutableNodeClassifier as _t, InMemoryLiveWorkflowRepository as a, isPortsEmission as at, LocalOnlyScheduler as b, WorkflowDefinitionError as bt, EngineFactory as c, CredentialResolverFactory as ct, PollingTriggerRuntime as d, DefaultExecutionBinaryService as dt, CostTrackingTelemetryMetricNames as et, PollingTriggerDedupWindow as f, UnavailableBinaryStorage as ft, WorkflowPolicyErrorServices as g, WorkflowExecutableNodeClassifierFactory as gt, WorkflowStoragePolicyEvaluator as h, DefaultWorkflowGraphFactory as ht, RunIntentService as i, emitPorts as it, MissingRuntimeTriggerToken as j, tool as jt, WorkflowSnapshotCodec as k, getPersistedRuntimeTypeMetadata as kt, Engine as l, getOriginIndexFromItem as lt, InMemoryBinaryStorage as m, ConnectionInvocationEventPublisher as mt, WorkflowRepositoryWebhookTriggerMatcher as n, RetryPolicy as nt, EngineWorkflowRunnerServiceFactory as o, isUnbrandedPortsEmissionShape as ot, InMemoryRunDataFactory as p, NodeEventPublisher as pt, NoOpExecutionTelemetry as q, RunIntentServiceFactory as r, NoRetryPolicy as rt, EngineWorkflowRunnerService as s, DefaultAsyncSleeper as st, WorkflowRepositoryWebhookTriggerMatcherFactory as t, ExpRetryPolicy as tt, NoOpPollingTriggerLogger as u, ChildExecutionScopeFactory as ut, ENGINE_EXECUTION_LIMITS_DEFAULTS as v, ConnectionInvocationIdFactory as vt, ConfigDrivenOffloadPolicy as w, defineHumanApprovalNode as wt, InlineDrivingScheduler as x, NodeIdSlugifier as xt, EngineExecutionLimitsPolicy as y, WorkflowBuilder as yt, InProcessRetryRunner as z, HitlWorkspaceIdToken as zt };
6491
+ //# sourceMappingURL=runtime-BPZgnZ9G.js.map