@codemation/core 0.11.0 → 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 (101) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/CostCatalogContract-DD7fQ4FF.d.cts +19 -0
  3. package/dist/{EngineRuntimeRegistration.types-MPYWsEM0.d.cts → EngineRuntimeRegistration.types-DTV5_7Jw.d.cts} +3 -2
  4. package/dist/{EngineRuntimeRegistration.types-BZ_1XWAJ.d.ts → EngineRuntimeRegistration.types-Dl92Hdoi.d.ts} +2 -2
  5. package/dist/InMemoryRunDataFactory-qMiYjhCK.d.cts +202 -0
  6. package/dist/{InMemoryRunEventBusRegistry-sM4z4n_i.js → InMemoryRunEventBusRegistry-Bwunvt1T.js} +1 -1
  7. package/dist/{InMemoryRunEventBusRegistry-sM4z4n_i.js.map → InMemoryRunEventBusRegistry-Bwunvt1T.js.map} +1 -1
  8. package/dist/{InMemoryRunEventBusRegistry-VM3OWnHo.cjs → InMemoryRunEventBusRegistry-Sa86VxuV.cjs} +1 -1
  9. package/dist/{InMemoryRunEventBusRegistry-VM3OWnHo.cjs.map → InMemoryRunEventBusRegistry-Sa86VxuV.cjs.map} +1 -1
  10. package/dist/ItemsInputNormalizer-BhuxvZh5.js +36 -0
  11. package/dist/ItemsInputNormalizer-BhuxvZh5.js.map +1 -0
  12. package/dist/ItemsInputNormalizer-C09a7iFP.d.ts +321 -0
  13. package/dist/ItemsInputNormalizer-DLaD6rTl.d.cts +407 -0
  14. package/dist/ItemsInputNormalizer-Div-fb6a.cjs +43 -0
  15. package/dist/ItemsInputNormalizer-Div-fb6a.cjs.map +1 -0
  16. package/dist/RunIntentService-BOSGwmqn.d.ts +299 -0
  17. package/dist/RunIntentService-CWMMrAP4.d.cts +220 -0
  18. package/dist/{RunIntentService-MUHJ1bhO.d.cts → agentMcpTypes-DUmniLOY.d.cts} +183 -206
  19. package/dist/bootstrap/index.cjs +4 -2
  20. package/dist/bootstrap/index.d.cts +63 -5
  21. package/dist/bootstrap/index.d.ts +5 -4
  22. package/dist/bootstrap/index.js +4 -2
  23. package/dist/{bootstrap-Dgzsjoj7.js → bootstrap-CKTMMNmL.js} +174 -3
  24. package/dist/bootstrap-CKTMMNmL.js.map +1 -0
  25. package/dist/{bootstrap-dVmpU1ju.cjs → bootstrap-D460dCgS.cjs} +209 -36
  26. package/dist/bootstrap-D460dCgS.cjs.map +1 -0
  27. package/dist/browser.cjs +17 -0
  28. package/dist/browser.d.cts +4 -0
  29. package/dist/browser.d.ts +3 -0
  30. package/dist/browser.js +4 -0
  31. package/dist/contracts-CK0x6w_G.cjs +74 -0
  32. package/dist/contracts-CK0x6w_G.cjs.map +1 -0
  33. package/dist/contracts-DXdfTdpW.js +50 -0
  34. package/dist/contracts-DXdfTdpW.js.map +1 -0
  35. package/dist/contracts.cjs +6 -0
  36. package/dist/contracts.d.cts +5 -0
  37. package/dist/contracts.d.ts +2 -0
  38. package/dist/contracts.js +3 -0
  39. package/dist/di-DdsgWfVy.js +405 -0
  40. package/dist/di-DdsgWfVy.js.map +1 -0
  41. package/dist/di-tO6R7VJV.cjs +524 -0
  42. package/dist/di-tO6R7VJV.cjs.map +1 -0
  43. package/dist/executionPersistenceContracts-DenJJK2T.d.cts +275 -0
  44. package/dist/{index-Bes88mxT.d.ts → index-BZDhEQ6W.d.ts} +278 -415
  45. package/dist/{RunIntentService-BrEq6Jm6.d.ts → index-CSKKuK60.d.ts} +441 -286
  46. package/dist/index.cjs +97 -250
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +395 -803
  49. package/dist/index.d.ts +5 -3
  50. package/dist/index.js +58 -224
  51. package/dist/index.js.map +1 -1
  52. package/dist/params-DqRvku2h.d.cts +44 -0
  53. package/dist/{runtime-Duf3ClPw.js → runtime-BPZgnZ9G.js} +591 -382
  54. package/dist/runtime-BPZgnZ9G.js.map +1 -0
  55. package/dist/{runtime-vH0EeZzH.cjs → runtime-CyW9c9XM.cjs} +651 -500
  56. package/dist/runtime-CyW9c9XM.cjs.map +1 -0
  57. package/dist/testing.cjs +23 -21
  58. package/dist/testing.cjs.map +1 -1
  59. package/dist/testing.d.cts +3 -2
  60. package/dist/testing.d.ts +3 -2
  61. package/dist/testing.js +5 -3
  62. package/dist/testing.js.map +1 -1
  63. package/package.json +9 -5
  64. package/src/ai/AgentConnectionNodeCollector.ts +1 -1
  65. package/src/authoring/defineHumanApprovalNode.types.ts +379 -0
  66. package/src/authoring/index.ts +6 -0
  67. package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +29 -0
  68. package/src/contracts/CodemationTelemetryAttributeNames.ts +10 -0
  69. package/src/contracts/credentialTypes.ts +10 -0
  70. package/src/contracts/hitlSeamTypes.ts +34 -0
  71. package/src/contracts/humanTaskStoreTypes.ts +48 -0
  72. package/src/contracts/inboxChannelTypes.ts +58 -0
  73. package/src/contracts/index.ts +3 -0
  74. package/src/contracts/runTypes.ts +61 -3
  75. package/src/contracts/runtimeTypes.ts +112 -0
  76. package/src/credentials/CredentialMaterialProvider.types.ts +61 -0
  77. package/src/credentials/ManagedCredentialMaterialWriteError.ts +14 -0
  78. package/src/credentials/ManagedMaterialFetchError.ts +16 -0
  79. package/src/execution/ActivationEnqueueService.ts +16 -0
  80. package/src/execution/DefaultExecutionContextFactory.ts +11 -0
  81. package/src/execution/NodeExecutionSnapshotFactory.ts +7 -1
  82. package/src/execution/NodeExecutor.ts +60 -1
  83. package/src/execution/NodeExecutorFactory.ts +12 -2
  84. package/src/execution/NodeSuspensionHandler.ts +220 -0
  85. package/src/execution/PersistedRunStateTerminalBuilder.ts +5 -2
  86. package/src/execution/RunStateSemantics.ts +5 -0
  87. package/src/execution/RunSuspendedError.ts +21 -0
  88. package/src/index.ts +40 -0
  89. package/src/orchestration/Engine.ts +12 -2
  90. package/src/orchestration/EngineWaiters.ts +1 -1
  91. package/src/orchestration/NodeExecutionRequestHandlerService.ts +25 -2
  92. package/src/orchestration/RunContinuationService.ts +226 -2
  93. package/src/orchestration/TestSuiteOrchestrator.ts +5 -4
  94. package/src/runtime/RunIntentService.ts +3 -0
  95. package/src/workflow/dsl/ChainCursorResolver.ts +36 -0
  96. package/tsdown.config.ts +1 -1
  97. package/dist/InMemoryRunDataFactory-hmkh0lzR.d.cts +0 -138
  98. package/dist/bootstrap-Dgzsjoj7.js.map +0 -1
  99. package/dist/bootstrap-dVmpU1ju.cjs.map +0 -1
  100. package/dist/runtime-Duf3ClPw.js.map +0 -1
  101. package/dist/runtime-vH0EeZzH.cjs.map +0 -1
@@ -1,59 +1,38 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
- key = keys[i];
11
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
- get: ((k) => from[k]).bind(null, key),
13
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
- });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
- value: mod,
20
- enumerable: true
21
- }) : target, mod));
22
-
23
- //#endregion
24
- require("reflect-metadata");
25
- let tsyringe = require("tsyringe");
26
- tsyringe = __toESM(tsyringe);
1
+ const require_di = require('./di-tO6R7VJV.cjs');
27
2
  let zod = require("zod");
28
- zod = __toESM(zod);
3
+ zod = require_di.__toESM(zod);
29
4
  let node_stream_web = require("node:stream/web");
30
- node_stream_web = __toESM(node_stream_web);
5
+ node_stream_web = require_di.__toESM(node_stream_web);
31
6
  let node_crypto = require("node:crypto");
32
- node_crypto = __toESM(node_crypto);
7
+ node_crypto = require_di.__toESM(node_crypto);
8
+ let tsyringe = require("tsyringe");
9
+ tsyringe = require_di.__toESM(tsyringe);
10
+
11
+ //#region src/contracts/humanTaskStoreTypes.ts
12
+ const HumanTaskStoreToken = Symbol.for("codemation.core.HumanTaskStore");
33
13
 
34
- //#region src/di/CoreTokens.ts
35
- const CoreTokens = {
36
- PersistedWorkflowTokenRegistry: Symbol.for("codemation.core.PersistedWorkflowTokenRegistry"),
37
- CredentialSessionService: Symbol.for("codemation.core.CredentialSessionService"),
38
- CredentialTypeRegistry: Symbol.for("codemation.core.CredentialTypeRegistry"),
39
- WorkflowRunnerService: Symbol.for("codemation.core.WorkflowRunnerService"),
40
- LiveWorkflowRepository: Symbol.for("codemation.core.LiveWorkflowRepository"),
41
- WorkflowRepository: Symbol.for("codemation.core.WorkflowRepository"),
42
- NodeResolver: Symbol.for("codemation.core.NodeResolver"),
43
- WorkflowNodeInstanceFactory: Symbol.for("codemation.core.WorkflowNodeInstanceFactory"),
44
- RunIdFactory: Symbol.for("codemation.core.RunIdFactory"),
45
- ActivationIdFactory: Symbol.for("codemation.core.ActivationIdFactory"),
46
- WorkflowExecutionRepository: Symbol.for("codemation.core.WorkflowExecutionRepository"),
47
- TriggerSetupStateRepository: Symbol.for("codemation.core.TriggerSetupStateRepository"),
48
- NodeActivationScheduler: Symbol.for("codemation.core.NodeActivationScheduler"),
49
- RunDataFactory: Symbol.for("codemation.core.RunDataFactory"),
50
- ExecutionContextFactory: Symbol.for("codemation.core.ExecutionContextFactory"),
51
- RunEventBus: Symbol.for("codemation.core.RunEventBus"),
52
- BinaryStorage: Symbol.for("codemation.core.BinaryStorage"),
53
- WebhookBasePath: Symbol.for("codemation.core.WebhookBasePath"),
54
- EngineExecutionLimitsPolicy: Symbol.for("codemation.core.EngineExecutionLimitsPolicy"),
55
- WorkflowActivationPolicy: Symbol.for("codemation.core.WorkflowActivationPolicy"),
56
- AgentMcpIntegration: Symbol.for("codemation.core.AgentMcpIntegration")
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
+ }
57
36
  };
58
37
 
59
38
  //#endregion
@@ -166,287 +145,303 @@ function chatModel(options = {}) {
166
145
  }
167
146
 
168
147
  //#endregion
169
- //#region src/ai/NodeBackedToolConfig.ts
170
- var NodeBackedToolConfig = class {
171
- type;
172
- toolKind = "nodeBacked";
173
- description;
174
- presentation;
175
- inputSchemaValue;
176
- outputSchemaValue;
177
- mapInputValue;
178
- mapOutputValue;
179
- constructor(name, node$1, options) {
180
- this.name = name;
181
- this.node = node$1;
182
- this.type = node$1.type;
183
- this.description = options.description;
184
- this.presentation = options.presentation;
185
- this.inputSchemaValue = options.inputSchema;
186
- this.outputSchemaValue = options.outputSchema;
187
- this.mapInputValue = options.mapInput;
188
- this.mapOutputValue = options.mapOutput;
189
- }
190
- getCredentialRequirements() {
191
- return this.node.getCredentialRequirements?.() ?? [];
192
- }
193
- getInputSchema() {
194
- return this.inputSchemaValue;
195
- }
196
- getOutputSchema() {
197
- return this.outputSchemaValue;
198
- }
199
- toNodeItem(args) {
200
- const mapped = this.mapInputValue?.(args) ?? args.input;
201
- if (this.isItem(mapped)) return mapped;
202
- return { json: mapped };
203
- }
204
- toToolOutput(args) {
205
- const raw = this.mapOutputValue?.(args) ?? this.readDefaultToolOutput(args.outputs);
206
- return this.outputSchemaValue.parse(raw);
207
- }
208
- readDefaultToolOutput(outputs) {
209
- const firstMainItem = outputs.main?.[0];
210
- if (!firstMainItem) throw new Error(`Node-backed tool "${this.name}" did not produce a main output item.`);
211
- return firstMainItem.json;
212
- }
213
- isItem(value) {
214
- return typeof value === "object" && value !== null && "json" in value;
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());
215
177
  }
216
178
  };
217
-
218
- //#endregion
219
- //#region src/contracts/itemExpr.ts
220
- const ITEM_EXPR_BRAND = Symbol.for("codemation.itemExpr");
221
- function itemExpr(fn) {
222
- return {
223
- [ITEM_EXPR_BRAND]: true,
224
- fn
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
+ }
225
206
  };
226
- }
227
- function isItemExpr(value) {
228
- if (typeof value !== "object" || value === null) return false;
229
- const v = value;
230
- if (v[ITEM_EXPR_BRAND] === true) return true;
231
- const keys = Object.keys(v);
232
- if (keys.length === 1 && keys[0] === "fn" && typeof v.fn === "function") return true;
233
- for (const sym of Object.getOwnPropertySymbols(v)) if (sym.description === "codemation.itemExpr" && v[sym] === true) return true;
234
- return false;
235
- }
236
- function containsItemExprInUnknown(value, seen = /* @__PURE__ */ new WeakSet()) {
237
- if (isItemExpr(value)) return true;
238
- if (value === null || typeof value !== "object") return false;
239
- if (seen.has(value)) return false;
240
- seen.add(value);
241
- if (Array.isArray(value)) return value.some((entry) => containsItemExprInUnknown(entry, seen));
242
- for (const entry of Object.values(value)) if (containsItemExprInUnknown(entry, seen)) return true;
243
- return false;
244
- }
245
- /**
246
- * Deep-resolves {@link itemExpr} leaves. Returns a new graph (does not mutate the original config object).
247
- */
248
- async function resolveItemExprsInUnknown(value, args, seen = /* @__PURE__ */ new WeakSet()) {
249
- if (isItemExpr(value)) return await Promise.resolve(value.fn(args));
250
- if (value === null || typeof value !== "object") return value;
251
- if (seen.has(value)) return value;
252
- seen.add(value);
253
- if (Array.isArray(value)) {
254
- const out$1 = [];
255
- for (let i = 0; i < value.length; i++) out$1.push(await resolveItemExprsInUnknown(value[i], args, seen));
256
- return out$1;
257
- }
258
- const rec = value;
259
- const entries = Object.entries(rec);
260
- const proto = Object.getPrototypeOf(value);
261
- if (proto !== Object.prototype && proto !== null && entries.length === 0) return value;
262
- const out = Object.create(proto);
263
- for (const [k, v] of entries) out[k] = await resolveItemExprsInUnknown(v, args, seen);
264
- return out;
265
- }
266
- /**
267
- * Clones runnable config (best-effort) so per-item {@link itemExpr} resolution never mutates shared instances.
268
- */
269
- async function resolveItemExprsForExecution(config, nodeCtx, item, itemIndex, items) {
270
- const exprArgs = {
271
- item,
272
- itemIndex,
273
- items,
274
- ctx: {
275
- runId: nodeCtx.runId,
276
- workflowId: nodeCtx.workflowId,
277
- nodeId: nodeCtx.nodeId,
278
- activationId: nodeCtx.activationId,
279
- data: nodeCtx.data
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 });
280
225
  }
281
226
  };
282
- if (!containsItemExprInUnknown(config)) return;
283
- return await resolveItemExprsInUnknown(config, exprArgs);
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;
284
241
  }
285
-
286
- //#endregion
287
- //#region src/ai/AgentConfigInspectorFactory.ts
288
- var AgentConfigInspector = class {
289
- static isAgentNodeConfig(config) {
290
- if (!config) return false;
291
- const candidate = config;
292
- return !!candidate.chatModel && this.hasCompatibleMessageConfiguration(candidate);
293
- }
294
- static hasCompatibleMessageConfiguration(candidate) {
295
- const messages = candidate.messages;
296
- if (messages === void 0 || messages === null) return false;
297
- if (Array.isArray(messages)) return messages.length > 0;
298
- if (typeof messages === "object") {
299
- if (isItemExpr(messages)) return true;
300
- const o = messages;
301
- return Array.isArray(o.prompt) && o.prompt.length > 0 || typeof o.buildMessages === "function";
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)];
302
256
  }
303
- return false;
304
- }
305
- };
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
+ }
306
291
 
307
292
  //#endregion
308
- //#region src/workflow/definition/ConnectionNodeIdFactory.ts
293
+ //#region src/authoring/defineHumanApprovalNode.types.ts
309
294
  /**
310
- * Deterministic ids for workflow connection-owned child nodes (LLM slot, tools, etc.).
311
- * These are stable across loads.
295
+ * Returns `true` when `node` was created by {@link defineHumanApprovalNode}.
296
+ * Uses the `humanApprovalToolBehavior` typed field as the discriminant.
312
297
  */
313
- var ConnectionNodeIdFactory = class {
314
- static connectionSegment = "__conn__";
315
- static languageModelConnectionNodeId(parentNodeId) {
316
- return `${parentNodeId}${this.connectionSegment}llm`;
317
- }
318
- static toolConnectionNodeId(parentNodeId, toolName) {
319
- const normalized = this.normalizeToolName(toolName);
320
- return `${parentNodeId}${this.connectionSegment}tool${this.connectionSegment}${normalized}`;
321
- }
322
- static mcpConnectionNodeId(parentNodeId, serverId) {
323
- return `${parentNodeId}${this.connectionSegment}mcp${this.connectionSegment}${serverId}`;
324
- }
325
- static isMcpConnectionNodeId(nodeId) {
326
- return nodeId.includes(`${this.connectionSegment}mcp${this.connectionSegment}`);
327
- }
328
- static parseMcpConnectionNodeId(nodeId) {
329
- if (!this.isMcpConnectionNodeId(nodeId)) return;
330
- const marker = `${this.connectionSegment}mcp${this.connectionSegment}`;
331
- const idx = nodeId.lastIndexOf(marker);
332
- if (idx < 0) return;
333
- const parentNodeId = nodeId.slice(0, idx);
334
- const serverId = nodeId.slice(idx + marker.length);
335
- if (!parentNodeId || !serverId) return;
336
- return {
337
- parentNodeId,
338
- serverId
339
- };
340
- }
341
- static isLanguageModelConnectionNodeId(nodeId) {
342
- return nodeId.endsWith(`${this.connectionSegment}llm`);
343
- }
344
- static isToolConnectionNodeId(nodeId) {
345
- return nodeId.includes(`${this.connectionSegment}tool${this.connectionSegment}`);
346
- }
347
- static parseLanguageModelConnectionNodeId(nodeId) {
348
- if (!this.isLanguageModelConnectionNodeId(nodeId)) return;
349
- const suffix = `${this.connectionSegment}llm`;
350
- const parentNodeId = nodeId.slice(0, -suffix.length);
351
- return parentNodeId ? { parentNodeId } : void 0;
352
- }
353
- static parseToolConnectionNodeId(nodeId) {
354
- if (!this.isToolConnectionNodeId(nodeId)) return;
355
- const marker = `${this.connectionSegment}tool${this.connectionSegment}`;
356
- const idx = nodeId.lastIndexOf(marker);
357
- if (idx < 0) return;
358
- const parentNodeId = nodeId.slice(0, idx);
359
- const normalizedToolName = nodeId.slice(idx + marker.length);
360
- if (!parentNodeId || !normalizedToolName) return;
361
- return {
362
- parentNodeId,
363
- normalizedToolName
364
- };
365
- }
366
- /** True when `nodeId` is a connection-owned child of `parentNodeId` (LLM or tool slot). */
367
- static isConnectionOwnedDescendantOf(parentNodeId, nodeId) {
368
- return nodeId.startsWith(`${parentNodeId}${this.connectionSegment}`);
369
- }
370
- /** Normalizes a tool display name to a stable id segment. */
371
- static normalizeToolName(toolName) {
372
- return toolName.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "tool";
373
- }
374
- };
375
-
376
- //#endregion
377
- //#region src/ai/AgentConnectionNodeCollector.ts
378
- const AgentConnectionNodeCollector = new class {
379
- collect(parentNodeId, agentConfig, mcpServerResolver) {
380
- const collected = [];
381
- this.collectInto(parentNodeId, agentConfig, collected, mcpServerResolver);
382
- return collected;
383
- }
384
- collectInto(parentNodeId, agentConfig, collected, mcpServerResolver) {
385
- collected.push({
386
- nodeId: ConnectionNodeIdFactory.languageModelConnectionNodeId(parentNodeId),
387
- parentNodeId,
388
- connectionName: "llm",
389
- role: "languageModel",
390
- name: agentConfig.chatModel.presentation?.label ?? agentConfig.chatModel.name,
391
- typeName: agentConfig.chatModel.name,
392
- icon: agentConfig.chatModel.presentation?.icon,
393
- credentialSource: agentConfig.chatModel
394
- });
395
- for (const tool$1 of agentConfig.tools ?? []) {
396
- const toolNodeId = ConnectionNodeIdFactory.toolConnectionNodeId(parentNodeId, tool$1.name);
397
- const isNestedAgent = this.isNodeBackedAgentTool(tool$1);
398
- collected.push({
399
- nodeId: toolNodeId,
400
- parentNodeId,
401
- connectionName: "tools",
402
- role: isNestedAgent ? "nestedAgent" : "tool",
403
- name: tool$1.presentation?.label ?? tool$1.name,
404
- typeName: tool$1.name,
405
- icon: tool$1.presentation?.icon,
406
- credentialSource: tool$1
407
- });
408
- this.collectNestedAgentTools(toolNodeId, tool$1, collected, mcpServerResolver);
409
- }
410
- if (mcpServerResolver) {
411
- const mcpServers = agentConfig.mcpServers;
412
- for (const serverId of mcpServers ?? []) {
413
- const decl = mcpServerResolver(serverId);
414
- if (!decl) continue;
415
- const acceptedTypes = decl.acceptedCredentialTypes ?? [];
416
- collected.push({
417
- nodeId: ConnectionNodeIdFactory.mcpConnectionNodeId(parentNodeId, serverId),
418
- parentNodeId,
419
- connectionName: "tools",
420
- role: "tool",
421
- name: decl.displayName,
422
- typeName: serverId,
423
- icon: "lucide:plug",
424
- credentialSource: { getCredentialRequirements: () => [{
425
- slotKey: "credential",
426
- label: decl.displayName,
427
- acceptedTypes
428
- }] }
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)
429
380
  });
430
381
  }
382
+ return await handleResume(args.item, ctx.resumeContext, opts.decisionSchema, resolvedPredicate, opts.onDecision, opts.onTimeout, ctx);
431
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
+ });
432
428
  }
433
- collectNestedAgentTools(toolNodeId, tool$1, collected, mcpServerResolver) {
434
- if (!this.isNodeBackedAgentTool(tool$1)) return;
435
- const innerAgent = tool$1 instanceof NodeBackedToolConfig ? tool$1.node : tool$1.node;
436
- this.collectInto(toolNodeId, innerAgent, collected, mcpServerResolver);
437
- }
438
- /**
439
- * After JSON round-trip (persisted snapshots), tools are plain objects — `instanceof NodeBackedToolConfig` fails.
440
- * Detect node-backed tools structurally via {@link NodeBackedToolConfig#toolKind}.
441
- */
442
- isNodeBackedAgentTool(tool$1) {
443
- if (tool$1 instanceof NodeBackedToolConfig) return AgentConfigInspector.isAgentNodeConfig(tool$1.node);
444
- if (!tool$1 || typeof tool$1 !== "object") return false;
445
- const t = tool$1;
446
- if (t.toolKind !== "nodeBacked") return false;
447
- return AgentConfigInspector.isAgentNodeConfig(t.node);
448
- }
449
- }();
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
+ }
450
445
 
451
446
  //#endregion
452
447
  //#region src/workflow/dsl/WhenBuilder.ts
@@ -574,6 +569,25 @@ var ChainCursor = class ChainCursor {
574
569
  }
575
570
  return new ChainCursor(this.wf, nextEndpoints);
576
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
+ }
577
591
  build() {
578
592
  return this.wf.build();
579
593
  }
@@ -685,7 +699,7 @@ var WorkflowBuilder = class {
685
699
  tokenName,
686
700
  label: node$1.name ?? ""
687
701
  });
688
- if (AgentConfigInspector.isAgentNodeConfig(node$1.config)) for (const child of AgentConnectionNodeCollector.collect(node$1.id, node$1.config)) entries.push({
702
+ if (require_di.AgentConfigInspector.isAgentNodeConfig(node$1.config)) for (const child of require_di.AgentConnectionNodeCollector.collect(node$1.id, node$1.config)) entries.push({
689
703
  nodeId: child.nodeId,
690
704
  tokenName: child.typeName,
691
705
  label: child.name
@@ -738,33 +752,6 @@ var ConnectionInvocationIdFactory = class {
738
752
  }
739
753
  };
740
754
 
741
- //#endregion
742
- //#region src/workflow/definition/NodeIterationIdFactory.ts
743
- /**
744
- * Unique ids for one per-item iteration of a runnable node's execute loop.
745
- *
746
- * Activations are per-batch (one scheduled execution of a node, possibly with N items).
747
- * Iterations refine that to one identifier per item-index inside the batch loop, so per-item
748
- * connection invocations and telemetry can be grouped without time-window heuristics.
749
- *
750
- * Uses Web Crypto's `randomUUID` (Node 19+ and all modern browsers) so this module is safe
751
- * to include in the browser entry. Importing `node:crypto` here previously leaked into the
752
- * canvas client bundle through `browser.ts` and OOM'd consumers' Turbopack builds.
753
- */
754
- var NodeIterationIdFactory = class {
755
- static create() {
756
- return `iter_${globalThis.crypto.randomUUID()}`;
757
- }
758
- /** Deterministic id for tests when a stable sequence is needed. */
759
- static createForTest(seed, sequence) {
760
- return `iter_${seed}_${sequence}`;
761
- }
762
- /** Deterministic id derived from a connection node id (for sub-agent / tool-call scopes). */
763
- static createForConnection(connectionNodeId, sequence) {
764
- return `iter_${connectionNodeId}_${sequence}`;
765
- }
766
- };
767
-
768
755
  //#endregion
769
756
  //#region src/workflow/definition/WorkflowExecutableNodeClassifier.ts
770
757
  /**
@@ -1067,7 +1054,7 @@ var NodeExecutionSnapshotFactory = class {
1067
1054
  nodeId: args.nodeId,
1068
1055
  activationId: args.activationId,
1069
1056
  parent: args.parent,
1070
- status: "completed",
1057
+ status: args.hitlStatus ?? "completed",
1071
1058
  queuedAt: args.previous?.queuedAt,
1072
1059
  startedAt,
1073
1060
  finishedAt: args.finishedAt,
@@ -1194,7 +1181,9 @@ var ActivationEnqueueService = class {
1194
1181
  nodeSnapshotsByNodeId: {
1195
1182
  ...args.previousNodeSnapshotsByNodeId,
1196
1183
  [args.request.nodeId]: queuedSnapshot
1197
- }
1184
+ },
1185
+ ...args.suspension !== void 0 ? { suspension: args.suspension } : {},
1186
+ ...args.pendingResume !== void 0 ? { pendingResume: args.pendingResume } : {}
1198
1187
  });
1199
1188
  await this.dispatchPreparedActivation(preparedDispatch);
1200
1189
  return {
@@ -1446,20 +1435,6 @@ var DefaultAsyncSleeper = class {
1446
1435
  }
1447
1436
  };
1448
1437
 
1449
- //#endregion
1450
- //#region src/contracts/NoOpAgentMcpIntegration.ts
1451
- /**
1452
- * No-op implementation of AgentMcpIntegration.
1453
- * Registered by the core engine runtime as a fallback when the host does not
1454
- * supply a real implementation (e.g. in unit tests or headless engine setups).
1455
- * Always returns an empty tool map so the agent runs with node-backed tools only.
1456
- */
1457
- var NoOpAgentMcpIntegration = class {
1458
- async prepareMcpTools() {
1459
- return /* @__PURE__ */ new Map();
1460
- }
1461
- };
1462
-
1463
1438
  //#endregion
1464
1439
  //#region src/contracts/emitPorts.ts
1465
1440
  const EMIT_PORTS_BRAND = Symbol.for("codemation.emitPorts");
@@ -1522,21 +1497,6 @@ var ExpRetryPolicy = class {
1522
1497
  }
1523
1498
  };
1524
1499
 
1525
- //#endregion
1526
- //#region src/contracts/credentialTypes.ts
1527
- var CredentialUnboundError = class CredentialUnboundError extends Error {
1528
- constructor(bindingKey, acceptedTypes = []) {
1529
- super(CredentialUnboundError.createMessage(bindingKey, acceptedTypes));
1530
- this.bindingKey = bindingKey;
1531
- this.acceptedTypes = acceptedTypes;
1532
- this.name = "CredentialUnboundError";
1533
- }
1534
- static createMessage(bindingKey, acceptedTypes) {
1535
- const acceptedTypesSuffix = acceptedTypes.length > 0 ? ` Accepted credential types: ${acceptedTypes.join(", ")}.` : "";
1536
- return `Credential slot "${bindingKey.slotKey}" is not bound for workflow ${bindingKey.workflowId} node ${bindingKey.nodeId}.${acceptedTypesSuffix}`;
1537
- }
1538
- };
1539
-
1540
1500
  //#endregion
1541
1501
  //#region src/contracts/CostTrackingTelemetryContract.ts
1542
1502
  const CostTrackingTelemetryMetricNames = {
@@ -1658,19 +1618,6 @@ var NoOpExecutionTelemetryFactory = class {
1658
1618
  }
1659
1619
  };
1660
1620
 
1661
- //#endregion
1662
- //#region src/contracts/runFinishedAtFactory.ts
1663
- /** Derives workflow end time from persisted run root or node snapshots for run listings. */
1664
- var RunFinishedAtFactory = class {
1665
- static resolveIso(state) {
1666
- if (state.finishedAt && state.status !== "running" && state.status !== "pending") return state.finishedAt;
1667
- if (state.status === "running" || state.status === "pending") return;
1668
- let max;
1669
- for (const snap of Object.values(state.nodeSnapshotsByNodeId)) if (snap?.finishedAt && (!max || snap.finishedAt > max)) max = snap.finishedAt;
1670
- return max;
1671
- }
1672
- };
1673
-
1674
1621
  //#endregion
1675
1622
  //#region src/contracts/workflowActivationPolicy.ts
1676
1623
  /** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */
@@ -1703,6 +1650,16 @@ var CodemationTelemetryAttributeNames = class {
1703
1650
  static mcpServerId = "mcp.server_id";
1704
1651
  /** MCP tool name on spans created for callTool invocations. */
1705
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";
1706
1663
  };
1707
1664
 
1708
1665
  //#endregion
@@ -1728,13 +1685,6 @@ var CodemationTelemetryMetricNames = class {
1728
1685
  static gmailAttachmentBytes = "codemation.gmail.attachment_bytes";
1729
1686
  };
1730
1687
 
1731
- //#endregion
1732
- //#region src/contracts/workflowTypes.ts
1733
- function nodeRef(nodeId) {
1734
- return nodeId;
1735
- }
1736
- const branchRef = (index) => `$${index}`;
1737
-
1738
1688
  //#endregion
1739
1689
  //#region src/execution/ExecutionTelemetryCostTrackingDecoratorFactory.ts
1740
1690
  var ExecutionTelemetryCostTrackingDecoratorFactory = class {
@@ -1808,12 +1758,13 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
1808
1758
  //#region src/execution/DefaultExecutionContextFactory.ts
1809
1759
  var DefaultExecutionContextFactory = class {
1810
1760
  telemetryDecoratorFactory = new ExecutionTelemetryCostTrackingDecoratorFactory();
1811
- 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) {
1812
1762
  this.binaryStorage = binaryStorage;
1813
1763
  this.telemetryFactory = telemetryFactory;
1814
1764
  this.costTrackingFactory = costTrackingFactory;
1815
1765
  this.currentDate = currentDate;
1816
1766
  this.collections = collections;
1767
+ this.nodeResolver = nodeResolver;
1817
1768
  }
1818
1769
  create(args) {
1819
1770
  const baseTelemetry = args.telemetry ?? this.telemetryFactory.create({
@@ -1840,7 +1791,11 @@ var DefaultExecutionContextFactory = class {
1840
1791
  binary: new DefaultExecutionBinaryService(this.binaryStorage, args.workflowId, args.runId, this.currentDate),
1841
1792
  getCredential: args.getCredential,
1842
1793
  testContext: args.testContext,
1843
- 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
+ }
1844
1799
  };
1845
1800
  }
1846
1801
  };
@@ -2016,7 +1971,7 @@ var InProcessRetryRunner = class InProcessRetryRunner {
2016
1971
  var ItemExprResolver = class {
2017
1972
  async resolveConfigForItem(ctx, item, itemIndex, items) {
2018
1973
  if (!ctx) throw new Error("ItemExprResolver.resolveConfigForItem: ctx is required");
2019
- const resolvedConfig = await resolveItemExprsForExecution(ctx.config, ctx, item, itemIndex, items);
1974
+ const resolvedConfig = await require_di.resolveItemExprsForExecution(ctx.config, ctx, item, itemIndex, items);
2020
1975
  const merged = resolvedConfig !== void 0 && resolvedConfig !== null ? resolvedConfig : ctx.config;
2021
1976
  if (merged === void 0 || merged === null) return ctx;
2022
1977
  return {
@@ -2182,6 +2137,27 @@ var NodeActivationRequestComposer = class {
2182
2137
  }
2183
2138
  };
2184
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
+
2185
2161
  //#endregion
2186
2162
  //#region src/execution/NodeExecutor.ts
2187
2163
  var NodeExecutor = class {
@@ -2189,9 +2165,11 @@ var NodeExecutor = class {
2189
2165
  outputNormalizer = new NodeOutputNormalizer();
2190
2166
  itemExprResolver;
2191
2167
  outputBehaviorResolver;
2192
- constructor(nodeInstanceFactory, retryRunner, itemExprResolver, outputBehaviorResolver) {
2168
+ constructor(nodeInstanceFactory, retryRunner, itemExprResolver, outputBehaviorResolver, suspensionHandler, loadRunState) {
2193
2169
  this.nodeInstanceFactory = nodeInstanceFactory;
2194
2170
  this.retryRunner = retryRunner;
2171
+ this.suspensionHandler = suspensionHandler;
2172
+ this.loadRunState = loadRunState;
2195
2173
  this.itemExprResolver = itemExprResolver ?? new ItemExprResolver();
2196
2174
  this.outputBehaviorResolver = outputBehaviorResolver ?? new RunnableOutputBehaviorResolver();
2197
2175
  }
@@ -2212,8 +2190,8 @@ var NodeExecutor = class {
2212
2190
  }
2213
2191
  }
2214
2192
  isCredentialError(e) {
2215
- if (e instanceof CredentialUnboundError) return true;
2216
- return (e instanceof Error ? e.cause : void 0) instanceof CredentialUnboundError;
2193
+ if (e instanceof require_di.CredentialUnboundError) return true;
2194
+ return (e instanceof Error ? e.cause : void 0) instanceof require_di.CredentialUnboundError;
2217
2195
  }
2218
2196
  async executeMultiInputActivation(request, node$1) {
2219
2197
  const multiInputNode = node$1;
@@ -2291,6 +2269,7 @@ var NodeExecutor = class {
2291
2269
  });
2292
2270
  }
2293
2271
  const byPort = {};
2272
+ let hasSuspension = false;
2294
2273
  for (let i = 0; i < inputBatch.length; i++) {
2295
2274
  const item = inputBatch[i];
2296
2275
  this.assertItemJsonNotTopLevelArray(request.nodeId, item);
@@ -2299,7 +2278,7 @@ var NodeExecutor = class {
2299
2278
  const resolvedCtx = await this.itemExprResolver.resolveConfigForItem(runnableCtx, item, i, inputBatch);
2300
2279
  const iterationCtx = {
2301
2280
  ...this.pickExecutionContext(runnableCtx, resolvedCtx),
2302
- iterationId: NodeIterationIdFactory.create(),
2281
+ iterationId: require_di.NodeIterationIdFactory.create(),
2303
2282
  itemIndex: i
2304
2283
  };
2305
2284
  const args = {
@@ -2309,7 +2288,28 @@ var NodeExecutor = class {
2309
2288
  items: inputBatch,
2310
2289
  ctx: iterationCtx
2311
2290
  };
2312
- 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
+ }
2313
2313
  const normalized = this.outputNormalizer.normalizeExecuteResult({
2314
2314
  baseItem: item,
2315
2315
  raw,
@@ -2322,6 +2322,7 @@ var NodeExecutor = class {
2322
2322
  byPort[port] = list;
2323
2323
  }
2324
2324
  }
2325
+ if (hasSuspension) throw new RunSuspendedError(request.runId, "unknown");
2325
2326
  return byPort;
2326
2327
  }
2327
2328
  /** Use resolver ctx only when {@link NodeExecutionContext.config} is non-nullish. */
@@ -2348,8 +2349,8 @@ var NodeExecutor = class {
2348
2349
  //#endregion
2349
2350
  //#region src/execution/NodeExecutorFactory.ts
2350
2351
  var NodeExecutorFactory = class {
2351
- create(workflowNodeInstanceFactory, retryRunner, outputBehaviorResolver) {
2352
- 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);
2353
2354
  }
2354
2355
  };
2355
2356
 
@@ -2942,6 +2943,7 @@ var PersistedRunStateTerminalBuilder = class {
2942
2943
  ...args.state,
2943
2944
  engineCounters: args.engineCounters,
2944
2945
  status: args.status,
2946
+ reason: args.reason,
2945
2947
  pending: void 0,
2946
2948
  queue: args.queue,
2947
2949
  outputsByNode: args.outputsByNode,
@@ -3224,6 +3226,7 @@ var RunContinuationService = class {
3224
3226
  });
3225
3227
  data.setOutputs(args.nodeId, args.outputs);
3226
3228
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3229
+ const hitlResolution = this.resolveHitlStatus(args.outputs);
3227
3230
  const completedSnapshot = this.semantics.createFinishedSnapshot({
3228
3231
  workflow: wf,
3229
3232
  previous: state.nodeSnapshotsByNodeId?.[args.nodeId],
@@ -3234,8 +3237,41 @@ var RunContinuationService = class {
3234
3237
  parent: state.parent,
3235
3238
  finishedAt: completedAt,
3236
3239
  inputsByPort: pendingExecution.inputsByPort,
3237
- outputs: args.outputs
3240
+ outputs: args.outputs,
3241
+ hitlStatus: hitlResolution?.nodeStatus
3238
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
+ }
3239
3275
  const completedActivations = (state.engineCounters?.completedNodeActivations ?? 0) + 1;
3240
3276
  const engineCounters = { completedNodeActivations: completedActivations };
3241
3277
  const maxNodeActivations = state.executionOptions?.maxNodeActivations ?? this.executionLimitsPolicy.createRootExecutionOptions().maxNodeActivations;
@@ -3536,13 +3572,114 @@ var RunContinuationService = class {
3536
3572
  status: "failed",
3537
3573
  error: { message: "Run failed" }
3538
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
+ };
3539
3582
  const result = await this.waiters.waitForCompletion(runId);
3540
- 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}`);
3541
3584
  return result;
3542
3585
  }
3543
3586
  async waitForWebhookResponse(runId) {
3544
3587
  return await this.waiters.waitForWebhookResponse(runId);
3545
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
+ }
3546
3683
  async resumeFromWebhookControl(args) {
3547
3684
  const data = this.runDataFactory.create(args.state.outputsByNode);
3548
3685
  const { topology, planner } = this.planningFactory.create(args.workflow);
@@ -3929,6 +4066,34 @@ var RunContinuationService = class {
3929
4066
  this.waiters.resolveRunCompletion(result);
3930
4067
  return result;
3931
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
+ }
3932
4097
  formatNodeLabel(args) {
3933
4098
  const tokenName = typeof args.definition?.type === "function" ? args.definition.type.name : "Node";
3934
4099
  return args.definition?.name ? `"${args.definition.name}" (${tokenName}:${args.nodeId})` : `${tokenName}:${args.nodeId}`;
@@ -4201,7 +4366,7 @@ var CurrentStateFrontierPlanner = class CurrentStateFrontierPlanner {
4201
4366
  isRuntimeDescendant(nodeId, descendantNodeIds) {
4202
4367
  for (const descendantNodeId of descendantNodeIds) {
4203
4368
  if (nodeId === descendantNodeId) return false;
4204
- if (ConnectionNodeIdFactory.isConnectionOwnedDescendantOf(descendantNodeId, nodeId)) return true;
4369
+ if (require_di.ConnectionNodeIdFactory.isConnectionOwnedDescendantOf(descendantNodeId, nodeId)) return true;
4205
4370
  }
4206
4371
  return false;
4207
4372
  }
@@ -5281,13 +5446,19 @@ var NodeExecutionRequestHandlerService = class {
5281
5446
  const portKeys = Object.keys(inputsByPort);
5282
5447
  const kind = portKeys.length === 1 && portKeys[0] === "in" ? "single" : "multi";
5283
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;
5284
5455
  const activationRequest = kind === "multi" ? this.nodeActivationRequestComposer.createMultiFromDefinitionWithActivation({
5285
5456
  activationId: request.activationId,
5286
5457
  runId: request.runId,
5287
5458
  workflowId: request.workflowId,
5288
5459
  parent: resolvedParent,
5289
5460
  executionOptions: request.executionOptions ?? state.executionOptions,
5290
- base,
5461
+ base: baseWithResume,
5291
5462
  data,
5292
5463
  definition: {
5293
5464
  id: definition.id,
@@ -5301,7 +5472,7 @@ var NodeExecutionRequestHandlerService = class {
5301
5472
  workflowId: request.workflowId,
5302
5473
  parent: resolvedParent,
5303
5474
  executionOptions: request.executionOptions ?? state.executionOptions,
5304
- base,
5475
+ base: baseWithResume,
5305
5476
  data,
5306
5477
  definition: {
5307
5478
  id: definition.id,
@@ -5310,6 +5481,13 @@ var NodeExecutionRequestHandlerService = class {
5310
5481
  batchId,
5311
5482
  input: inputsByPort.in ?? request.input ?? []
5312
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
+ }
5313
5491
  await this.continuation.markNodeRunning({
5314
5492
  runId: activationRequest.runId,
5315
5493
  activationId: activationRequest.activationId,
@@ -5320,6 +5498,7 @@ var NodeExecutionRequestHandlerService = class {
5320
5498
  try {
5321
5499
  outputs = await this.nodeExecutor.execute(activationRequest);
5322
5500
  } catch (error) {
5501
+ if (error instanceof RunSuspendedError) return;
5323
5502
  await this.resumeAfterExecutionError(activationRequest, this.asError(error));
5324
5503
  return;
5325
5504
  }
@@ -5880,7 +6059,7 @@ var EngineWaiters = class {
5880
6059
  });
5881
6060
  }
5882
6061
  resolveRunCompletion(result) {
5883
- if (result.status !== "completed" && result.status !== "failed") return;
6062
+ if (result.status !== "completed" && result.status !== "failed" && result.status !== "halted") return;
5884
6063
  const list = this.completionWaiters.get(result.runId);
5885
6064
  if (!list || list.length === 0) return;
5886
6065
  this.completionWaiters.delete(result.runId);
@@ -5974,6 +6153,13 @@ var Engine = class {
5974
6153
  async waitForWebhookResponse(runId) {
5975
6154
  return await this.deps.runContinuationService.waitForWebhookResponse(runId);
5976
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
+ }
5977
6163
  async handleNodeExecutionRequest(request) {
5978
6164
  await this.deps.nodeExecutionRequestHandler.handleNodeExecutionRequest(request);
5979
6165
  }
@@ -6181,6 +6367,7 @@ var RunIntentService = class {
6181
6367
  };
6182
6368
  return await Promise.race([this.engine.waitForWebhookResponse(scheduled.runId), this.engine.waitForCompletion(scheduled.runId).then((completed) => {
6183
6369
  if (completed.status === "failed") throw new Error(completed.error.message);
6370
+ if (completed.status === "halted") throw new Error(`Run halted: ${completed.reason}`);
6184
6371
  return {
6185
6372
  runId: completed.runId,
6186
6373
  workflowId: completed.workflowId,
@@ -6305,18 +6492,6 @@ var WorkflowRepositoryWebhookTriggerMatcherFactory = class {
6305
6492
  };
6306
6493
 
6307
6494
  //#endregion
6308
- Object.defineProperty(exports, 'AgentConfigInspector', {
6309
- enumerable: true,
6310
- get: function () {
6311
- return AgentConfigInspector;
6312
- }
6313
- });
6314
- Object.defineProperty(exports, 'AgentConnectionNodeCollector', {
6315
- enumerable: true,
6316
- get: function () {
6317
- return AgentConnectionNodeCollector;
6318
- }
6319
- });
6320
6495
  Object.defineProperty(exports, 'AllWorkflowsActiveWorkflowActivationPolicy', {
6321
6496
  enumerable: true,
6322
6497
  get: function () {
@@ -6371,18 +6546,6 @@ Object.defineProperty(exports, 'ConnectionInvocationIdFactory', {
6371
6546
  return ConnectionInvocationIdFactory;
6372
6547
  }
6373
6548
  });
6374
- Object.defineProperty(exports, 'ConnectionNodeIdFactory', {
6375
- enumerable: true,
6376
- get: function () {
6377
- return ConnectionNodeIdFactory;
6378
- }
6379
- });
6380
- Object.defineProperty(exports, 'CoreTokens', {
6381
- enumerable: true,
6382
- get: function () {
6383
- return CoreTokens;
6384
- }
6385
- });
6386
6549
  Object.defineProperty(exports, 'CostTrackingTelemetryAttributeNames', {
6387
6550
  enumerable: true,
6388
6551
  get: function () {
@@ -6401,12 +6564,6 @@ Object.defineProperty(exports, 'CredentialResolverFactory', {
6401
6564
  return CredentialResolverFactory;
6402
6565
  }
6403
6566
  });
6404
- Object.defineProperty(exports, 'CredentialUnboundError', {
6405
- enumerable: true,
6406
- get: function () {
6407
- return CredentialUnboundError;
6408
- }
6409
- });
6410
6567
  Object.defineProperty(exports, 'DefaultAsyncSleeper', {
6411
6568
  enumerable: true,
6412
6569
  get: function () {
@@ -6437,6 +6594,12 @@ Object.defineProperty(exports, 'DefaultWorkflowGraphFactory', {
6437
6594
  return DefaultWorkflowGraphFactory;
6438
6595
  }
6439
6596
  });
6597
+ Object.defineProperty(exports, 'DefinedNodeRegistry', {
6598
+ enumerable: true,
6599
+ get: function () {
6600
+ return DefinedNodeRegistry;
6601
+ }
6602
+ });
6440
6603
  Object.defineProperty(exports, 'ENGINE_EXECUTION_LIMITS_DEFAULTS', {
6441
6604
  enumerable: true,
6442
6605
  get: function () {
@@ -6491,6 +6654,30 @@ Object.defineProperty(exports, 'HintOnlyOffloadPolicy', {
6491
6654
  return HintOnlyOffloadPolicy;
6492
6655
  }
6493
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
+ });
6494
6681
  Object.defineProperty(exports, 'InMemoryBinaryStorage', {
6495
6682
  enumerable: true,
6496
6683
  get: function () {
@@ -6551,12 +6738,6 @@ Object.defineProperty(exports, 'MissingRuntimeTriggerToken', {
6551
6738
  return MissingRuntimeTriggerToken;
6552
6739
  }
6553
6740
  });
6554
- Object.defineProperty(exports, 'NoOpAgentMcpIntegration', {
6555
- enumerable: true,
6556
- get: function () {
6557
- return NoOpAgentMcpIntegration;
6558
- }
6559
- });
6560
6741
  Object.defineProperty(exports, 'NoOpCostTrackingTelemetry', {
6561
6742
  enumerable: true,
6562
6743
  get: function () {
@@ -6611,12 +6792,6 @@ Object.defineProperty(exports, 'NoRetryPolicy', {
6611
6792
  return NoRetryPolicy;
6612
6793
  }
6613
6794
  });
6614
- Object.defineProperty(exports, 'NodeBackedToolConfig', {
6615
- enumerable: true,
6616
- get: function () {
6617
- return NodeBackedToolConfig;
6618
- }
6619
- });
6620
6795
  Object.defineProperty(exports, 'NodeEventPublisher', {
6621
6796
  enumerable: true,
6622
6797
  get: function () {
@@ -6653,12 +6828,6 @@ Object.defineProperty(exports, 'NodeInstanceFactoryFactory', {
6653
6828
  return NodeInstanceFactoryFactory;
6654
6829
  }
6655
6830
  });
6656
- Object.defineProperty(exports, 'NodeIterationIdFactory', {
6657
- enumerable: true,
6658
- get: function () {
6659
- return NodeIterationIdFactory;
6660
- }
6661
- });
6662
6831
  Object.defineProperty(exports, 'NodeOutputNormalizer', {
6663
6832
  enumerable: true,
6664
6833
  get: function () {
@@ -6701,12 +6870,6 @@ Object.defineProperty(exports, 'RetryPolicy', {
6701
6870
  return RetryPolicy;
6702
6871
  }
6703
6872
  });
6704
- Object.defineProperty(exports, 'RunFinishedAtFactory', {
6705
- enumerable: true,
6706
- get: function () {
6707
- return RunFinishedAtFactory;
6708
- }
6709
- });
6710
6873
  Object.defineProperty(exports, 'RunIntentService', {
6711
6874
  enumerable: true,
6712
6875
  get: function () {
@@ -6725,6 +6888,12 @@ Object.defineProperty(exports, 'RunPolicySnapshotFactory', {
6725
6888
  return RunPolicySnapshotFactory;
6726
6889
  }
6727
6890
  });
6891
+ Object.defineProperty(exports, 'RunSuspendedError', {
6892
+ enumerable: true,
6893
+ get: function () {
6894
+ return RunSuspendedError;
6895
+ }
6896
+ });
6728
6897
  Object.defineProperty(exports, 'RunTerminalPersistenceCoordinator', {
6729
6898
  enumerable: true,
6730
6899
  get: function () {
@@ -6815,22 +6984,28 @@ Object.defineProperty(exports, 'WorkflowStoragePolicyEvaluator', {
6815
6984
  return WorkflowStoragePolicyEvaluator;
6816
6985
  }
6817
6986
  });
6818
- Object.defineProperty(exports, '__toESM', {
6987
+ Object.defineProperty(exports, 'chatModel', {
6819
6988
  enumerable: true,
6820
6989
  get: function () {
6821
- return __toESM;
6990
+ return chatModel;
6822
6991
  }
6823
6992
  });
6824
- Object.defineProperty(exports, 'branchRef', {
6993
+ Object.defineProperty(exports, 'defineBatchNode', {
6825
6994
  enumerable: true,
6826
6995
  get: function () {
6827
- return branchRef;
6996
+ return defineBatchNode;
6828
6997
  }
6829
6998
  });
6830
- Object.defineProperty(exports, 'chatModel', {
6999
+ Object.defineProperty(exports, 'defineHumanApprovalNode', {
6831
7000
  enumerable: true,
6832
7001
  get: function () {
6833
- return chatModel;
7002
+ return defineHumanApprovalNode;
7003
+ }
7004
+ });
7005
+ Object.defineProperty(exports, 'defineNode', {
7006
+ enumerable: true,
7007
+ get: function () {
7008
+ return defineNode;
6834
7009
  }
6835
7010
  });
6836
7011
  Object.defineProperty(exports, 'emitPorts', {
@@ -6851,10 +7026,10 @@ Object.defineProperty(exports, 'getPersistedRuntimeTypeMetadata', {
6851
7026
  return getPersistedRuntimeTypeMetadata;
6852
7027
  }
6853
7028
  });
6854
- Object.defineProperty(exports, 'isItemExpr', {
7029
+ Object.defineProperty(exports, 'isHumanApprovalNode', {
6855
7030
  enumerable: true,
6856
7031
  get: function () {
6857
- return isItemExpr;
7032
+ return isHumanApprovalNode;
6858
7033
  }
6859
7034
  });
6860
7035
  Object.defineProperty(exports, 'isPortsEmission', {
@@ -6869,40 +7044,16 @@ Object.defineProperty(exports, 'isUnbrandedPortsEmissionShape', {
6869
7044
  return isUnbrandedPortsEmissionShape;
6870
7045
  }
6871
7046
  });
6872
- Object.defineProperty(exports, 'itemExpr', {
6873
- enumerable: true,
6874
- get: function () {
6875
- return itemExpr;
6876
- }
6877
- });
6878
7047
  Object.defineProperty(exports, 'node', {
6879
7048
  enumerable: true,
6880
7049
  get: function () {
6881
7050
  return node;
6882
7051
  }
6883
7052
  });
6884
- Object.defineProperty(exports, 'nodeRef', {
6885
- enumerable: true,
6886
- get: function () {
6887
- return nodeRef;
6888
- }
6889
- });
6890
- Object.defineProperty(exports, 'resolveItemExprsForExecution', {
6891
- enumerable: true,
6892
- get: function () {
6893
- return resolveItemExprsForExecution;
6894
- }
6895
- });
6896
- Object.defineProperty(exports, 'resolveItemExprsInUnknown', {
6897
- enumerable: true,
6898
- get: function () {
6899
- return resolveItemExprsInUnknown;
6900
- }
6901
- });
6902
7053
  Object.defineProperty(exports, 'tool', {
6903
7054
  enumerable: true,
6904
7055
  get: function () {
6905
7056
  return tool;
6906
7057
  }
6907
7058
  });
6908
- //# sourceMappingURL=runtime-vH0EeZzH.cjs.map
7059
+ //# sourceMappingURL=runtime-CyW9c9XM.cjs.map