@codemation/core 0.8.1 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/CHANGELOG.md +386 -0
  2. package/dist/{EngineRuntimeRegistration.types-BP6tsaNP.d.ts → EngineRuntimeRegistration.types-D1fyApMI.d.ts} +2 -2
  3. package/dist/{EngineWorkflowRunnerService-DzOCa1BW.d.cts → EngineRuntimeRegistration.types-pB3FnzqR.d.cts} +17 -17
  4. package/dist/{InMemoryRunDataFactory-1iz7_SnO.d.cts → InMemoryRunDataFactory-Xw7v4-sj.d.cts} +31 -29
  5. package/dist/InMemoryRunEventBusRegistry-VM3OWnHo.cjs +47 -0
  6. package/dist/InMemoryRunEventBusRegistry-VM3OWnHo.cjs.map +1 -0
  7. package/dist/InMemoryRunEventBusRegistry-sM4z4n_i.js +41 -0
  8. package/dist/InMemoryRunEventBusRegistry-sM4z4n_i.js.map +1 -0
  9. package/dist/{RunIntentService-BqhmdoA1.d.ts → RunIntentService-BE9CAkbf.d.ts} +966 -471
  10. package/dist/{RunIntentService-S-1lW-gS.d.cts → RunIntentService-siBSjaaY.d.cts} +859 -493
  11. package/dist/bootstrap/index.cjs +5 -2
  12. package/dist/bootstrap/index.d.cts +212 -135
  13. package/dist/bootstrap/index.d.ts +4 -4
  14. package/dist/bootstrap/index.js +3 -3
  15. package/dist/{bootstrap-Bx1u4cbS.cjs → bootstrap-Cm5ruQxx.cjs} +253 -2
  16. package/dist/bootstrap-Cm5ruQxx.cjs.map +1 -0
  17. package/dist/{bootstrap-BoknFKnw.js → bootstrap-D3r505ko.js} +236 -3
  18. package/dist/bootstrap-D3r505ko.js.map +1 -0
  19. package/dist/{index-CVs9rVhl.d.ts → index-DeLl1Tne.d.ts} +632 -230
  20. package/dist/index.cjs +323 -176
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +544 -91
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js +299 -166
  25. package/dist/index.js.map +1 -1
  26. package/dist/{runtime-DUW6tIJ1.js → runtime-BGNbRnqs.js} +934 -75
  27. package/dist/runtime-BGNbRnqs.js.map +1 -0
  28. package/dist/{runtime-Dvo2ru5A.cjs → runtime-DKXJwTNv.cjs} +1028 -73
  29. package/dist/runtime-DKXJwTNv.cjs.map +1 -0
  30. package/dist/testing.cjs +4 -4
  31. package/dist/testing.cjs.map +1 -1
  32. package/dist/testing.d.cts +2 -2
  33. package/dist/testing.d.ts +2 -2
  34. package/dist/testing.js +3 -3
  35. package/package.json +7 -2
  36. package/src/ai/AiHost.ts +42 -14
  37. package/src/authoring/DefinedCollectionRegistry.ts +17 -0
  38. package/src/authoring/defineCollection.types.ts +181 -0
  39. package/src/authoring/definePollingTrigger.types.ts +396 -0
  40. package/src/authoring/definePollingTriggerInternals.ts +74 -0
  41. package/src/authoring/index.ts +19 -0
  42. package/src/bootstrap/index.ts +9 -0
  43. package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +8 -0
  44. package/src/browser.ts +1 -0
  45. package/src/contracts/CodemationTelemetryAttributeNames.ts +6 -0
  46. package/src/contracts/NoOpNodeExecutionTelemetry.ts +2 -11
  47. package/src/contracts/NoOpTelemetrySpanScope.ts +46 -10
  48. package/src/contracts/assertionTypes.ts +63 -0
  49. package/src/contracts/baseTypes.ts +12 -0
  50. package/src/contracts/collectionTypes.ts +44 -0
  51. package/src/contracts/credentialTypes.ts +23 -1
  52. package/src/contracts/executionPersistenceContracts.ts +30 -0
  53. package/src/contracts/index.ts +4 -0
  54. package/src/contracts/runTypes.ts +37 -1
  55. package/src/contracts/runtimeTypes.ts +42 -0
  56. package/src/contracts/telemetryTypes.ts +8 -0
  57. package/src/contracts/testTriggerTypes.ts +66 -0
  58. package/src/contracts/workflowTypes.ts +36 -7
  59. package/src/contracts.ts +59 -0
  60. package/src/events/ConnectionInvocationEventPublisher.ts +46 -0
  61. package/src/events/index.ts +1 -0
  62. package/src/events/runEvents.ts +74 -0
  63. package/src/execution/ChildExecutionScopeFactory.ts +55 -0
  64. package/src/execution/DefaultExecutionContextFactory.ts +6 -0
  65. package/src/execution/ExecutionTelemetryCostTrackingDecoratorFactory.ts +18 -0
  66. package/src/execution/NodeExecutor.ts +10 -2
  67. package/src/execution/NodeInstanceFactory.ts +13 -1
  68. package/src/execution/NodeInstantiationError.ts +16 -0
  69. package/src/execution/NodeRunStateWriter.ts +7 -0
  70. package/src/execution/NodeRunStateWriterFactory.ts +7 -0
  71. package/src/execution/WorkflowRunExecutionContextFactory.ts +3 -0
  72. package/src/execution/index.ts +2 -0
  73. package/src/index.ts +8 -0
  74. package/src/orchestration/AbortControllerFactory.ts +9 -0
  75. package/src/orchestration/NodeExecutionRequestHandlerService.ts +1 -0
  76. package/src/orchestration/RunContinuationService.ts +3 -0
  77. package/src/orchestration/RunStartService.ts +122 -3
  78. package/src/orchestration/TestSuiteOrchestrator.ts +350 -0
  79. package/src/orchestration/TestSuiteRunIdFactory.ts +11 -0
  80. package/src/orchestration/TriggerRuntimeService.ts +34 -7
  81. package/src/orchestration/index.ts +9 -0
  82. package/src/runtime/EngineFactory.ts +12 -0
  83. package/src/triggers/polling/PollingTriggerDedupWindow.ts +23 -0
  84. package/src/triggers/polling/PollingTriggerLogger.ts +18 -0
  85. package/src/triggers/polling/PollingTriggerRuntime.ts +122 -0
  86. package/src/triggers/polling/index.ts +5 -0
  87. package/src/types/index.ts +12 -9
  88. package/src/workflow/definition/NodeIterationIdFactory.ts +26 -0
  89. package/src/workflow/dsl/NodeIdSlugifier.ts +18 -0
  90. package/src/workflow/dsl/WorkflowBuilder.ts +71 -3
  91. package/src/workflow/dsl/WorkflowDefinitionError.ts +15 -0
  92. package/src/workflow/index.ts +3 -0
  93. package/dist/InMemoryRunEventBusRegistry-B0_C4OnP.cjs +0 -262
  94. package/dist/InMemoryRunEventBusRegistry-B0_C4OnP.cjs.map +0 -1
  95. package/dist/InMemoryRunEventBusRegistry-C2U83Hmv.js +0 -238
  96. package/dist/InMemoryRunEventBusRegistry-C2U83Hmv.js.map +0 -1
  97. package/dist/bootstrap-BoknFKnw.js.map +0 -1
  98. package/dist/bootstrap-Bx1u4cbS.cjs.map +0 -1
  99. package/dist/runtime-DUW6tIJ1.js.map +0 -1
  100. package/dist/runtime-Dvo2ru5A.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import "reflect-metadata";
2
2
  import { container as container$1, delay, inject, injectAll, injectable, instanceCachingFactory, instancePerContainerCachingFactory, predicateAwareClassFactory, registry, singleton } from "tsyringe";
3
3
  import { ZodError, z } from "zod";
4
- import { createHash } from "node:crypto";
4
+ import { createHash, randomUUID } from "node:crypto";
5
5
  import { ReadableStream } from "node:stream/web";
6
6
 
7
7
  //#region src/di/CoreTokens.ts
@@ -137,6 +137,56 @@ function chatModel(options = {}) {
137
137
  return InjectableRuntimeDecoratorComposer.compose("chatModel", options, import.meta.url);
138
138
  }
139
139
 
140
+ //#endregion
141
+ //#region src/ai/NodeBackedToolConfig.ts
142
+ var NodeBackedToolConfig = class {
143
+ type;
144
+ toolKind = "nodeBacked";
145
+ description;
146
+ presentation;
147
+ inputSchemaValue;
148
+ outputSchemaValue;
149
+ mapInputValue;
150
+ mapOutputValue;
151
+ constructor(name, node$1, options) {
152
+ this.name = name;
153
+ this.node = node$1;
154
+ this.type = node$1.type;
155
+ this.description = options.description;
156
+ this.presentation = options.presentation;
157
+ this.inputSchemaValue = options.inputSchema;
158
+ this.outputSchemaValue = options.outputSchema;
159
+ this.mapInputValue = options.mapInput;
160
+ this.mapOutputValue = options.mapOutput;
161
+ }
162
+ getCredentialRequirements() {
163
+ return this.node.getCredentialRequirements?.() ?? [];
164
+ }
165
+ getInputSchema() {
166
+ return this.inputSchemaValue;
167
+ }
168
+ getOutputSchema() {
169
+ return this.outputSchemaValue;
170
+ }
171
+ toNodeItem(args) {
172
+ const mapped = this.mapInputValue?.(args) ?? args.input;
173
+ if (this.isItem(mapped)) return mapped;
174
+ return { json: mapped };
175
+ }
176
+ toToolOutput(args) {
177
+ const raw = this.mapOutputValue?.(args) ?? this.readDefaultToolOutput(args.outputs);
178
+ return this.outputSchemaValue.parse(raw);
179
+ }
180
+ readDefaultToolOutput(outputs) {
181
+ const firstMainItem = outputs.main?.[0];
182
+ if (!firstMainItem) throw new Error(`Node-backed tool "${this.name}" did not produce a main output item.`);
183
+ return firstMainItem.json;
184
+ }
185
+ isItem(value) {
186
+ return typeof value === "object" && value !== null && "json" in value;
187
+ }
188
+ };
189
+
140
190
  //#endregion
141
191
  //#region src/contracts/itemExpr.ts
142
192
  const ITEM_EXPR_BRAND = Symbol.for("codemation.itemExpr");
@@ -205,6 +255,27 @@ async function resolveItemExprsForExecution(config, nodeCtx, item, itemIndex, it
205
255
  return await resolveItemExprsInUnknown(config, exprArgs);
206
256
  }
207
257
 
258
+ //#endregion
259
+ //#region src/ai/AgentConfigInspectorFactory.ts
260
+ var AgentConfigInspector = class {
261
+ static isAgentNodeConfig(config) {
262
+ if (!config) return false;
263
+ const candidate = config;
264
+ return !!candidate.chatModel && this.hasCompatibleMessageConfiguration(candidate);
265
+ }
266
+ static hasCompatibleMessageConfiguration(candidate) {
267
+ const messages = candidate.messages;
268
+ if (messages === void 0 || messages === null) return false;
269
+ if (Array.isArray(messages)) return messages.length > 0;
270
+ if (typeof messages === "object") {
271
+ if (isItemExpr(messages)) return true;
272
+ const o = messages;
273
+ return Array.isArray(o.prompt) && o.prompt.length > 0 || typeof o.buildMessages === "function";
274
+ }
275
+ return false;
276
+ }
277
+ };
278
+
208
279
  //#endregion
209
280
  //#region src/workflow/definition/ConnectionNodeIdFactory.ts
210
281
  /**
@@ -255,6 +326,369 @@ var ConnectionNodeIdFactory = class {
255
326
  }
256
327
  };
257
328
 
329
+ //#endregion
330
+ //#region src/ai/AgentConnectionNodeCollector.ts
331
+ const AgentConnectionNodeCollector = new class {
332
+ collect(parentNodeId, agentConfig) {
333
+ const collected = [];
334
+ this.collectInto(parentNodeId, agentConfig, collected);
335
+ return collected;
336
+ }
337
+ collectInto(parentNodeId, agentConfig, collected) {
338
+ collected.push({
339
+ nodeId: ConnectionNodeIdFactory.languageModelConnectionNodeId(parentNodeId),
340
+ parentNodeId,
341
+ connectionName: "llm",
342
+ role: "languageModel",
343
+ name: agentConfig.chatModel.presentation?.label ?? agentConfig.chatModel.name,
344
+ typeName: agentConfig.chatModel.name,
345
+ icon: agentConfig.chatModel.presentation?.icon,
346
+ credentialSource: agentConfig.chatModel
347
+ });
348
+ for (const tool$1 of agentConfig.tools ?? []) {
349
+ const toolNodeId = ConnectionNodeIdFactory.toolConnectionNodeId(parentNodeId, tool$1.name);
350
+ const isNestedAgent = this.isNodeBackedAgentTool(tool$1);
351
+ collected.push({
352
+ nodeId: toolNodeId,
353
+ parentNodeId,
354
+ connectionName: "tools",
355
+ role: isNestedAgent ? "nestedAgent" : "tool",
356
+ name: tool$1.presentation?.label ?? tool$1.name,
357
+ typeName: tool$1.name,
358
+ icon: tool$1.presentation?.icon,
359
+ credentialSource: tool$1
360
+ });
361
+ this.collectNestedAgentTools(toolNodeId, tool$1, collected);
362
+ }
363
+ }
364
+ collectNestedAgentTools(toolNodeId, tool$1, collected) {
365
+ if (!this.isNodeBackedAgentTool(tool$1)) return;
366
+ const innerAgent = tool$1 instanceof NodeBackedToolConfig ? tool$1.node : tool$1.node;
367
+ this.collectInto(toolNodeId, innerAgent, collected);
368
+ }
369
+ /**
370
+ * After JSON round-trip (persisted snapshots), tools are plain objects — `instanceof NodeBackedToolConfig` fails.
371
+ * Detect node-backed tools structurally via {@link NodeBackedToolConfig#toolKind}.
372
+ */
373
+ isNodeBackedAgentTool(tool$1) {
374
+ if (tool$1 instanceof NodeBackedToolConfig) return AgentConfigInspector.isAgentNodeConfig(tool$1.node);
375
+ if (!tool$1 || typeof tool$1 !== "object") return false;
376
+ const t = tool$1;
377
+ if (t.toolKind !== "nodeBacked") return false;
378
+ return AgentConfigInspector.isAgentNodeConfig(t.node);
379
+ }
380
+ }();
381
+
382
+ //#endregion
383
+ //#region src/workflow/dsl/WhenBuilder.ts
384
+ var WhenBuilder = class WhenBuilder {
385
+ constructor(wf, from, branchPort) {
386
+ this.wf = wf;
387
+ this.from = from;
388
+ this.branchPort = branchPort;
389
+ }
390
+ addBranch(steps) {
391
+ const created = [];
392
+ let prev = null;
393
+ for (const cfg of steps) {
394
+ const ref = this.wf.add(cfg);
395
+ created.push(ref);
396
+ if (!prev) this.wf.connect(this.from, ref, this.branchPort, "in");
397
+ else this.wf.connect(prev, ref, "main", "in");
398
+ prev = ref;
399
+ }
400
+ for (const cfg of steps) {
401
+ const maybe = cfg;
402
+ if (!Array.isArray(maybe.upstreamRefs) || maybe.upstreamRefs.length === 0) continue;
403
+ maybe.upstreamRefs = maybe.upstreamRefs.map((r) => {
404
+ if (typeof r !== "string") return r;
405
+ const nodeId = created[parseInt(r.slice(1), 10)]?.id;
406
+ return nodeId ? { nodeId } : { nodeId: r };
407
+ });
408
+ }
409
+ return this;
410
+ }
411
+ when = (branch, steps, ...more) => {
412
+ const list = Array.isArray(steps) ? steps : [steps, ...more];
413
+ const port = branch ? "true" : "false";
414
+ const b = new WhenBuilder(this.wf, this.from, port);
415
+ b.addBranch(list);
416
+ return b;
417
+ };
418
+ build() {
419
+ return this.wf.build();
420
+ }
421
+ };
422
+
423
+ //#endregion
424
+ //#region src/workflow/dsl/ChainCursorResolver.ts
425
+ var ChainCursor = class ChainCursor {
426
+ constructor(wf, endpoints) {
427
+ this.wf = wf;
428
+ this.endpoints = endpoints;
429
+ }
430
+ then(config) {
431
+ const next = this.wf.add(config);
432
+ const inputPortHint = this.resolveSharedInputPortHint();
433
+ for (const e of this.endpoints) this.wf.connect(e.node, next, e.output);
434
+ return new ChainCursor(this.wf, [{
435
+ node: next,
436
+ output: "main",
437
+ ...inputPortHint ? { inputPortHint } : {}
438
+ }]);
439
+ }
440
+ thenIntoInputHints(config) {
441
+ const next = this.wf.add(config);
442
+ for (const e of this.endpoints) this.wf.connect(e.node, next, e.output, e.inputPortHint ?? "in");
443
+ return new ChainCursor(this.wf, [{
444
+ node: next,
445
+ output: "main"
446
+ }]);
447
+ }
448
+ when = ((arg1, steps, ...more) => {
449
+ if (this.endpoints.length !== 1) throw new Error("ChainCursor.when(...) is only supported from a single cursor endpoint");
450
+ const cursor = this.endpoints[0].node;
451
+ if (typeof arg1 === "boolean") {
452
+ const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;
453
+ const port = arg1 ? "true" : "false";
454
+ const b = new WhenBuilder(this.wf, cursor, port);
455
+ b.addBranch(list);
456
+ return b;
457
+ }
458
+ const branches = arg1;
459
+ const wfAny = this.wf;
460
+ const buildBranch = (port, branchSteps) => {
461
+ const list = branchSteps ?? [];
462
+ let prev = null;
463
+ for (const cfg of list) {
464
+ const ref = wfAny.add(cfg);
465
+ if (!prev) wfAny.connect(cursor, ref, port, "in");
466
+ else wfAny.connect(prev, ref, "main", "in");
467
+ prev = ref;
468
+ }
469
+ if (!prev) return {
470
+ end: cursor,
471
+ endOutput: port,
472
+ inputPortHint: port
473
+ };
474
+ return {
475
+ end: prev,
476
+ endOutput: "main",
477
+ inputPortHint: port
478
+ };
479
+ };
480
+ const t = buildBranch("true", branches.true);
481
+ const f = buildBranch("false", branches.false);
482
+ return new ChainCursor(this.wf, [{
483
+ node: t.end,
484
+ output: t.endOutput,
485
+ inputPortHint: t.inputPortHint
486
+ }, {
487
+ node: f.end,
488
+ output: f.endOutput,
489
+ inputPortHint: f.inputPortHint
490
+ }]);
491
+ });
492
+ route(branches) {
493
+ if (this.endpoints.length !== 1) throw new Error("ChainCursor.route(...) is only supported from a single cursor endpoint");
494
+ const cursor = this.endpoints[0];
495
+ const nextEndpoints = [];
496
+ for (const [port, branchFactory] of Object.entries(branches)) {
497
+ if (!branchFactory) continue;
498
+ const builtBranch = branchFactory(new ChainCursor(this.wf, [{
499
+ node: cursor.node,
500
+ output: port,
501
+ inputPortHint: port
502
+ }]));
503
+ if (!builtBranch) continue;
504
+ nextEndpoints.push(...builtBranch.endpoints);
505
+ }
506
+ return new ChainCursor(this.wf, nextEndpoints);
507
+ }
508
+ build() {
509
+ return this.wf.build();
510
+ }
511
+ resolveSharedInputPortHint() {
512
+ const first = this.endpoints[0]?.inputPortHint;
513
+ if (!first) return;
514
+ return this.endpoints.every((endpoint) => endpoint.inputPortHint === first) ? first : void 0;
515
+ }
516
+ };
517
+
518
+ //#endregion
519
+ //#region src/workflow/dsl/NodeIdSlugifier.ts
520
+ /**
521
+ * Converts a human-readable node label into a stable, URL-safe identifier segment.
522
+ *
523
+ * Rules:
524
+ * - Lowercase the entire string.
525
+ * - Replace every run of characters outside `[a-z0-9]` with a single `-`.
526
+ * - Strip any leading or trailing `-` characters.
527
+ * - Return `""` for blank/empty input.
528
+ */
529
+ const NodeIdSlugifier = { slugify(label) {
530
+ if (!label) return "";
531
+ return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
532
+ } };
533
+
534
+ //#endregion
535
+ //#region src/workflow/dsl/WorkflowDefinitionError.ts
536
+ /**
537
+ * Thrown by {@link WorkflowBuilder.build} when the workflow definition is structurally invalid.
538
+ *
539
+ * Common causes:
540
+ * - A node has an empty effective id (label is blank and no explicit `id` was given).
541
+ * - Two or more nodes share the same effective id (label slugs collide or explicit ids clash).
542
+ *
543
+ * Fix: provide an explicit `id:` on the offending node configs.
544
+ */
545
+ var WorkflowDefinitionError = class extends Error {
546
+ constructor(message) {
547
+ super(message);
548
+ this.name = "WorkflowDefinitionError";
549
+ }
550
+ };
551
+
552
+ //#endregion
553
+ //#region src/workflow/dsl/WorkflowBuilder.ts
554
+ var WorkflowBuilder = class {
555
+ nodes = [];
556
+ edges = [];
557
+ constructor(meta, options) {
558
+ this.meta = meta;
559
+ this.options = options;
560
+ }
561
+ add(config) {
562
+ const id = config.id ?? NodeIdSlugifier.slugify(config.name ?? "");
563
+ this.nodes.push({
564
+ id,
565
+ kind: config.kind,
566
+ type: config.type,
567
+ name: config.name,
568
+ config
569
+ });
570
+ return {
571
+ id,
572
+ kind: config.kind,
573
+ name: config.name
574
+ };
575
+ }
576
+ connect(from, to, fromOutput = "main", toInput = "in") {
577
+ this.edges.push({
578
+ from: {
579
+ nodeId: from.id,
580
+ output: fromOutput
581
+ },
582
+ to: {
583
+ nodeId: to.id,
584
+ input: toInput
585
+ }
586
+ });
587
+ }
588
+ trigger(config) {
589
+ const ref = this.add(config);
590
+ return new ChainCursor(this, [{
591
+ node: ref,
592
+ output: "main"
593
+ }]);
594
+ }
595
+ start(config) {
596
+ const ref = this.add(config);
597
+ return new ChainCursor(this, [{
598
+ node: ref,
599
+ output: "main"
600
+ }]);
601
+ }
602
+ build() {
603
+ this.validateNodeIds();
604
+ return {
605
+ ...this.meta,
606
+ nodes: this.nodes,
607
+ edges: this.edges
608
+ };
609
+ }
610
+ validateNodeIds() {
611
+ const entries = [];
612
+ for (const node$1 of this.nodes) {
613
+ const tokenName = typeof node$1.type === "function" ? node$1.type.name : String(node$1.type);
614
+ entries.push({
615
+ nodeId: node$1.id,
616
+ tokenName,
617
+ label: node$1.name ?? ""
618
+ });
619
+ if (AgentConfigInspector.isAgentNodeConfig(node$1.config)) for (const child of AgentConnectionNodeCollector.collect(node$1.id, node$1.config)) entries.push({
620
+ nodeId: child.nodeId,
621
+ tokenName: child.typeName,
622
+ label: child.name
623
+ });
624
+ }
625
+ const emptyIds = [];
626
+ const seenIds = /* @__PURE__ */ new Map();
627
+ const duplicateIds = [];
628
+ for (const entry of entries) {
629
+ if (!entry.nodeId) {
630
+ emptyIds.push(entry);
631
+ continue;
632
+ }
633
+ const existing = seenIds.get(entry.nodeId);
634
+ if (existing) {
635
+ if (!duplicateIds.includes(existing)) duplicateIds.push(existing);
636
+ duplicateIds.push(entry);
637
+ } else seenIds.set(entry.nodeId, entry);
638
+ }
639
+ if (emptyIds.length === 0 && duplicateIds.length === 0) return;
640
+ const lines = ["WorkflowBuilder.build() found invalid node ids:"];
641
+ if (emptyIds.length > 0) {
642
+ lines.push(" Empty ids (label is blank and no explicit id was given):");
643
+ for (const e of emptyIds) lines.push(` - type "${e.tokenName}" label "${e.label}"`);
644
+ }
645
+ if (duplicateIds.length > 0) {
646
+ lines.push(" Duplicate ids:");
647
+ for (const e of duplicateIds) lines.push(` - id "${e.nodeId}" type "${e.tokenName}" label "${e.label}"`);
648
+ }
649
+ lines.push(" Fix: set an explicit `id:` on each offending node config.");
650
+ throw new WorkflowDefinitionError(lines.join("\n"));
651
+ }
652
+ };
653
+
654
+ //#endregion
655
+ //#region src/workflow/definition/ConnectionInvocationIdFactory.ts
656
+ /**
657
+ * Unique ids for persisted connection invocation history rows (LLM/tool calls under an owning node).
658
+ */
659
+ var ConnectionInvocationIdFactory = class {
660
+ static create() {
661
+ return `cinv_${randomUUID()}`;
662
+ }
663
+ /** Deterministic id for tests when a stable sequence is needed. */
664
+ static createForTest(runId, connectionNodeId, sequence) {
665
+ return `cinv_${runId}_${connectionNodeId}_${sequence}`;
666
+ }
667
+ };
668
+
669
+ //#endregion
670
+ //#region src/workflow/definition/NodeIterationIdFactory.ts
671
+ /**
672
+ * Unique ids for one per-item iteration of a runnable node's execute loop.
673
+ *
674
+ * Activations are per-batch (one scheduled execution of a node, possibly with N items).
675
+ * Iterations refine that to one identifier per item-index inside the batch loop, so per-item
676
+ * connection invocations and telemetry can be grouped without time-window heuristics.
677
+ */
678
+ var NodeIterationIdFactory = class {
679
+ static create() {
680
+ return `iter_${randomUUID()}`;
681
+ }
682
+ /** Deterministic id for tests when a stable sequence is needed. */
683
+ static createForTest(seed, sequence) {
684
+ return `iter_${seed}_${sequence}`;
685
+ }
686
+ /** Deterministic id derived from a connection node id (for sub-agent / tool-call scopes). */
687
+ static createForConnection(connectionNodeId, sequence) {
688
+ return `iter_${connectionNodeId}_${sequence}`;
689
+ }
690
+ };
691
+
258
692
  //#endregion
259
693
  //#region src/workflow/definition/WorkflowExecutableNodeClassifier.ts
260
694
  /**
@@ -315,6 +749,69 @@ var WorkflowExecutableNodeClassifierFactory = class {
315
749
  }
316
750
  };
317
751
 
752
+ //#endregion
753
+ //#region src/workflow/graph/ExecutableGraph.ts
754
+ var ExecutableGraph = class {
755
+ outgoingByNodeAndPort = /* @__PURE__ */ new Map();
756
+ constructor(def) {
757
+ for (const e of def.edges) {
758
+ const byPort = this.outgoingByNodeAndPort.get(e.from.nodeId) ?? /* @__PURE__ */ new Map();
759
+ const next = byPort.get(e.from.output) ?? [];
760
+ next.push({
761
+ nodeId: e.to.nodeId,
762
+ input: e.to.input
763
+ });
764
+ byPort.set(e.from.output, next);
765
+ this.outgoingByNodeAndPort.set(e.from.nodeId, byPort);
766
+ }
767
+ }
768
+ next(nodeId, output$1) {
769
+ return this.outgoingByNodeAndPort.get(nodeId)?.get(output$1) ?? [];
770
+ }
771
+ };
772
+
773
+ //#endregion
774
+ //#region src/workflow/graph/DefaultWorkflowGraphFactory.ts
775
+ var DefaultWorkflowGraphFactory = class {
776
+ create(def) {
777
+ return new ExecutableGraph(def);
778
+ }
779
+ };
780
+
781
+ //#endregion
782
+ //#region src/events/ConnectionInvocationEventPublisher.ts
783
+ /**
784
+ * Publishes per-invocation lifecycle records onto the run {@link RunEventBus}.
785
+ *
786
+ * Surgical, per-invocation events let the UI update the right-side inspector
787
+ * timeline as each LLM round / tool call transitions through `running` → `completed`
788
+ * (or `failed`) without depending on a coarse `runSaved` poll.
789
+ */
790
+ var ConnectionInvocationEventPublisher = class {
791
+ constructor(eventBus, parent) {
792
+ this.eventBus = eventBus;
793
+ this.parent = parent;
794
+ }
795
+ async publish(record) {
796
+ if (!this.eventBus) return;
797
+ const kind = this.kindFor(record);
798
+ if (!kind) return;
799
+ await this.eventBus.publish({
800
+ kind,
801
+ runId: record.runId,
802
+ workflowId: record.workflowId,
803
+ parent: this.parent,
804
+ at: record.updatedAt,
805
+ record
806
+ });
807
+ }
808
+ kindFor(record) {
809
+ if (record.status === "running" || record.status === "queued") return "connectionInvocationStarted";
810
+ if (record.status === "completed") return "connectionInvocationCompleted";
811
+ if (record.status === "failed") return "connectionInvocationFailed";
812
+ }
813
+ };
814
+
318
815
  //#endregion
319
816
  //#region src/events/NodeEventPublisher.ts
320
817
  /** Publishes node lifecycle snapshots onto the run {@link RunEventBus}. */
@@ -633,6 +1130,48 @@ var ActivationEnqueueService = class {
633
1130
  }
634
1131
  };
635
1132
 
1133
+ //#endregion
1134
+ //#region src/execution/ChildExecutionScopeFactory.ts
1135
+ /**
1136
+ * Builds a re-rooted child execution context for sub-agent (and other deeply-nested) invocations.
1137
+ *
1138
+ * At the orchestrator's `agent.tool.call` boundary the inner runtime needs a ctx whose:
1139
+ * - `nodeId` is the tool's connection node id (so inner LLM/tool connection ids derive correctly),
1140
+ * - `activationId` is fresh (so its connection-invocation rows are uniquely identifiable),
1141
+ * - `telemetry` parents children under the tool-call span (not the orchestrator's node span),
1142
+ * - `binary` is scoped to the new (nodeId, activationId),
1143
+ * - `parentInvocationId` points back to the tool-call invocation for downstream lineage.
1144
+ *
1145
+ * Registered via factory in {@link EngineRuntimeRegistrar} so constructors stay free of parameter
1146
+ * decorators (Next/SWC and coverage tooling cannot parse them on in-repo sources).
1147
+ */
1148
+ var ChildExecutionScopeFactory = class {
1149
+ constructor(activationIdFactory) {
1150
+ this.activationIdFactory = activationIdFactory;
1151
+ }
1152
+ forSubAgent(args) {
1153
+ const childActivationId = this.activationIdFactory.makeActivationId();
1154
+ const childTelemetry = args.parentSpan.asNodeTelemetry({
1155
+ nodeId: args.childNodeId,
1156
+ activationId: childActivationId
1157
+ });
1158
+ const childBinary = args.parentCtx.binary.forNode({
1159
+ nodeId: args.childNodeId,
1160
+ activationId: childActivationId
1161
+ });
1162
+ return {
1163
+ ...args.parentCtx,
1164
+ nodeId: args.childNodeId,
1165
+ activationId: childActivationId,
1166
+ config: args.childConfig,
1167
+ telemetry: childTelemetry,
1168
+ binary: childBinary,
1169
+ parentInvocationId: args.parentInvocationId,
1170
+ iterationId: void 0
1171
+ };
1172
+ }
1173
+ };
1174
+
636
1175
  //#endregion
637
1176
  //#region src/contracts/itemMeta.ts
638
1177
  /**
@@ -773,6 +1312,20 @@ var NodeActivationRequestInputPreparer = class {
773
1312
  }
774
1313
  };
775
1314
 
1315
+ //#endregion
1316
+ //#region src/execution/NodeInstantiationError.ts
1317
+ var NodeInstantiationError = class extends Error {
1318
+ name = "NodeInstantiationError";
1319
+ originalError;
1320
+ constructor(nodeId, nodeType, originalError) {
1321
+ super(`Failed to instantiate node "${nodeId}" (type ${nodeType}): ${originalError.message}`);
1322
+ this.nodeId = nodeId;
1323
+ this.nodeType = nodeType;
1324
+ this.originalError = originalError;
1325
+ this.stack = originalError.stack;
1326
+ }
1327
+ };
1328
+
776
1329
  //#endregion
777
1330
  //#region src/execution/CredentialResolverFactory.ts
778
1331
  var CredentialResolverFactory = class {
@@ -933,31 +1486,54 @@ var NoOpTelemetryArtifactReference = class {
933
1486
 
934
1487
  //#endregion
935
1488
  //#region src/contracts/NoOpTelemetrySpanScope.ts
1489
+ /**
1490
+ * Standalone no-op {@link NodeExecutionTelemetry} value used as the return for `asNodeTelemetry`.
1491
+ *
1492
+ * Defined here (instead of in `NoOpNodeExecutionTelemetry.ts`) so that {@link NoOpTelemetrySpanScope}
1493
+ * can return it without importing the other module — both no-ops share this leaf.
1494
+ */
1495
+ const noOpNodeExecutionTelemetry = {
1496
+ traceId: "00000000000000000000000000000000",
1497
+ spanId: "0000000000000000",
1498
+ addSpanEvent(_) {},
1499
+ recordMetric(_) {},
1500
+ attachArtifact(_) {
1501
+ return NoOpTelemetryArtifactReference.value;
1502
+ },
1503
+ end(_ = {}) {},
1504
+ asNodeTelemetry(_) {
1505
+ return noOpNodeExecutionTelemetry;
1506
+ },
1507
+ forNode(_) {
1508
+ return noOpNodeExecutionTelemetry;
1509
+ },
1510
+ startChildSpan(_) {
1511
+ return noOpTelemetrySpanScope;
1512
+ }
1513
+ };
1514
+ const noOpTelemetrySpanScope = {
1515
+ traceId: "00000000000000000000000000000000",
1516
+ spanId: "0000000000000000",
1517
+ addSpanEvent(_) {},
1518
+ recordMetric(_) {},
1519
+ attachArtifact(_) {
1520
+ return NoOpTelemetryArtifactReference.value;
1521
+ },
1522
+ end(_ = {}) {},
1523
+ asNodeTelemetry(_) {
1524
+ return noOpNodeExecutionTelemetry;
1525
+ }
1526
+ };
936
1527
  var NoOpTelemetrySpanScope = class {
937
- static value = {
938
- traceId: "00000000000000000000000000000000",
939
- spanId: "0000000000000000",
940
- addSpanEvent(_) {},
941
- recordMetric(_) {},
942
- attachArtifact(_) {
943
- return NoOpTelemetryArtifactReference.value;
944
- },
945
- end(_ = {}) {}
946
- };
1528
+ static value = noOpTelemetrySpanScope;
1529
+ /** Internal: the shared no-op {@link NodeExecutionTelemetry} that {@link NoOpNodeExecutionTelemetry} re-exposes. */
1530
+ static nodeExecutionTelemetryValue = noOpNodeExecutionTelemetry;
947
1531
  };
948
1532
 
949
1533
  //#endregion
950
1534
  //#region src/contracts/NoOpNodeExecutionTelemetry.ts
951
- var NoOpNodeExecutionTelemetry = class NoOpNodeExecutionTelemetry {
952
- static value = {
953
- ...NoOpTelemetrySpanScope.value,
954
- forNode(_) {
955
- return NoOpNodeExecutionTelemetry.value;
956
- },
957
- startChildSpan(_) {
958
- return NoOpTelemetrySpanScope.value;
959
- }
960
- };
1535
+ var NoOpNodeExecutionTelemetry = class {
1536
+ static value = NoOpTelemetrySpanScope.nodeExecutionTelemetryValue;
961
1537
  };
962
1538
 
963
1539
  //#endregion
@@ -985,6 +1561,28 @@ var NoOpExecutionTelemetryFactory = class {
985
1561
  }
986
1562
  };
987
1563
 
1564
+ //#endregion
1565
+ //#region src/contracts/runFinishedAtFactory.ts
1566
+ /** Derives workflow end time from persisted run root or node snapshots for run listings. */
1567
+ var RunFinishedAtFactory = class {
1568
+ static resolveIso(state) {
1569
+ if (state.finishedAt && state.status !== "running" && state.status !== "pending") return state.finishedAt;
1570
+ if (state.status === "running" || state.status === "pending") return;
1571
+ let max;
1572
+ for (const snap of Object.values(state.nodeSnapshotsByNodeId)) if (snap?.finishedAt && (!max || snap.finishedAt > max)) max = snap.finishedAt;
1573
+ return max;
1574
+ }
1575
+ };
1576
+
1577
+ //#endregion
1578
+ //#region src/contracts/workflowActivationPolicy.ts
1579
+ /** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */
1580
+ var AllWorkflowsActiveWorkflowActivationPolicy = class {
1581
+ isActive(_workflowId) {
1582
+ return true;
1583
+ }
1584
+ };
1585
+
988
1586
  //#endregion
989
1587
  //#region src/contracts/CodemationTelemetryAttributeNames.ts
990
1588
  var CodemationTelemetryAttributeNames = class {
@@ -998,6 +1596,12 @@ var CodemationTelemetryAttributeNames = class {
998
1596
  static connectionInvocationId = "codemation.connection.invocation_id";
999
1597
  static toolName = "codemation.tool.name";
1000
1598
  static traceParentRunId = "codemation.parent.run.id";
1599
+ /** Per-item iteration that emitted this span/metric. Set on spans recorded inside a runnable per-item loop. */
1600
+ static iterationId = "codemation.iteration.id";
1601
+ /** Item index (0-based) of the iteration. */
1602
+ static iterationIndex = "codemation.iteration.index";
1603
+ /** Set when this span/metric was recorded under a sub-agent triggered by an outer LLM/tool call. */
1604
+ static parentInvocationId = "codemation.parent.invocation_id";
1001
1605
  };
1002
1606
 
1003
1607
  //#endregion
@@ -1023,19 +1627,6 @@ var CodemationTelemetryMetricNames = class {
1023
1627
  static gmailAttachmentBytes = "codemation.gmail.attachment_bytes";
1024
1628
  };
1025
1629
 
1026
- //#endregion
1027
- //#region src/contracts/runFinishedAtFactory.ts
1028
- /** Derives workflow end time from persisted run root or node snapshots for run listings. */
1029
- var RunFinishedAtFactory = class {
1030
- static resolveIso(state) {
1031
- if (state.finishedAt && state.status !== "running" && state.status !== "pending") return state.finishedAt;
1032
- if (state.status === "running" || state.status === "pending") return;
1033
- let max;
1034
- for (const snap of Object.values(state.nodeSnapshotsByNodeId)) if (snap?.finishedAt && (!max || snap.finishedAt > max)) max = snap.finishedAt;
1035
- return max;
1036
- }
1037
- };
1038
-
1039
1630
  //#endregion
1040
1631
  //#region src/contracts/workflowTypes.ts
1041
1632
  function nodeRef(nodeId) {
@@ -1043,15 +1634,6 @@ function nodeRef(nodeId) {
1043
1634
  }
1044
1635
  const branchRef = (index) => `$${index}`;
1045
1636
 
1046
- //#endregion
1047
- //#region src/contracts/workflowActivationPolicy.ts
1048
- /** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */
1049
- var AllWorkflowsActiveWorkflowActivationPolicy = class {
1050
- isActive(_workflowId) {
1051
- return true;
1052
- }
1053
- };
1054
-
1055
1637
  //#endregion
1056
1638
  //#region src/execution/ExecutionTelemetryCostTrackingDecoratorFactory.ts
1057
1639
  var ExecutionTelemetryCostTrackingDecoratorFactory = class {
@@ -1091,6 +1673,13 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
1091
1673
  telemetry: nodeTelemetry,
1092
1674
  costTracking: args.costTracking.forScope(nodeTelemetry)
1093
1675
  });
1676
+ },
1677
+ asNodeTelemetry: (rescope) => {
1678
+ const nodeTelemetry = args.telemetry.asNodeTelemetry(rescope);
1679
+ return this.decorateNodeExecutionTelemetry({
1680
+ telemetry: nodeTelemetry,
1681
+ costTracking: args.costTracking.forScope(nodeTelemetry)
1682
+ });
1094
1683
  }
1095
1684
  };
1096
1685
  }
@@ -1102,7 +1691,14 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
1102
1691
  addSpanEvent: (event) => args.scope.addSpanEvent(event),
1103
1692
  recordMetric: (metric) => args.scope.recordMetric(metric),
1104
1693
  attachArtifact: (artifact) => args.scope.attachArtifact(artifact),
1105
- end: (endArgs) => args.scope.end(endArgs)
1694
+ end: (endArgs) => args.scope.end(endArgs),
1695
+ asNodeTelemetry: (rescope) => {
1696
+ const nodeTelemetry = args.scope.asNodeTelemetry(rescope);
1697
+ return this.decorateNodeExecutionTelemetry({
1698
+ telemetry: nodeTelemetry,
1699
+ costTracking: args.costTracking.forScope(nodeTelemetry)
1700
+ });
1701
+ }
1106
1702
  };
1107
1703
  }
1108
1704
  };
@@ -1111,11 +1707,12 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
1111
1707
  //#region src/execution/DefaultExecutionContextFactory.ts
1112
1708
  var DefaultExecutionContextFactory = class {
1113
1709
  telemetryDecoratorFactory = new ExecutionTelemetryCostTrackingDecoratorFactory();
1114
- constructor(binaryStorage = new UnavailableBinaryStorage(), telemetryFactory = new NoOpExecutionTelemetryFactory(), costTrackingFactory = new NoOpCostTrackingTelemetryFactory(), currentDate = () => /* @__PURE__ */ new Date()) {
1710
+ constructor(binaryStorage = new UnavailableBinaryStorage(), telemetryFactory = new NoOpExecutionTelemetryFactory(), costTrackingFactory = new NoOpCostTrackingTelemetryFactory(), currentDate = () => /* @__PURE__ */ new Date(), collections) {
1115
1711
  this.binaryStorage = binaryStorage;
1116
1712
  this.telemetryFactory = telemetryFactory;
1117
1713
  this.costTrackingFactory = costTrackingFactory;
1118
1714
  this.currentDate = currentDate;
1715
+ this.collections = collections;
1119
1716
  }
1120
1717
  create(args) {
1121
1718
  const baseTelemetry = args.telemetry ?? this.telemetryFactory.create({
@@ -1140,7 +1737,9 @@ var DefaultExecutionContextFactory = class {
1140
1737
  nodeState: args.nodeState,
1141
1738
  telemetry,
1142
1739
  binary: new DefaultExecutionBinaryService(this.binaryStorage, args.workflowId, args.runId, this.currentDate),
1143
- getCredential: args.getCredential
1740
+ getCredential: args.getCredential,
1741
+ testContext: args.testContext,
1742
+ collections: this.collections
1144
1743
  };
1145
1744
  }
1146
1745
  };
@@ -1573,13 +2172,17 @@ var NodeExecutor = class {
1573
2172
  const parsed = inputSchema.parse(item.json);
1574
2173
  const runnableCtx = request.ctx;
1575
2174
  const resolvedCtx = await this.itemExprResolver.resolveConfigForItem(runnableCtx, item, i, inputBatch);
1576
- const ctx = this.pickExecutionContext(runnableCtx, resolvedCtx);
2175
+ const iterationCtx = {
2176
+ ...this.pickExecutionContext(runnableCtx, resolvedCtx),
2177
+ iterationId: NodeIterationIdFactory.create(),
2178
+ itemIndex: i
2179
+ };
1577
2180
  const args = {
1578
2181
  input: parsed,
1579
2182
  item,
1580
2183
  itemIndex: i,
1581
2184
  items: inputBatch,
1582
- ctx
2185
+ ctx: iterationCtx
1583
2186
  };
1584
2187
  const raw = await Promise.resolve(node$1.execute(args));
1585
2188
  const normalized = this.outputNormalizer.normalizeExecuteResult({
@@ -1973,7 +2576,12 @@ var NodeInstanceFactory = class {
1973
2576
  }
1974
2577
  createNodes(workflow) {
1975
2578
  const nodeInstances = /* @__PURE__ */ new Map();
1976
- for (const definition of workflow.nodes) nodeInstances.set(definition.id, this.createNode(definition));
2579
+ for (const definition of workflow.nodes) try {
2580
+ nodeInstances.set(definition.id, this.createNode(definition));
2581
+ } catch (err) {
2582
+ if (err instanceof NodeInstantiationError) throw err;
2583
+ throw new NodeInstantiationError(definition.id, typeof definition.type === "function" ? definition.type.name : String(definition.type), err instanceof Error ? err : new Error(String(err)));
2584
+ }
1977
2585
  return nodeInstances;
1978
2586
  }
1979
2587
  createNode(definition) {
@@ -1998,12 +2606,13 @@ var NodeInstanceFactoryFactory = class {
1998
2606
  //#region src/execution/NodeRunStateWriter.ts
1999
2607
  var NodeRunStateWriter = class {
2000
2608
  chain = Promise.resolve();
2001
- constructor(workflowExecutionRepository, runId, workflowId, parent, publishNodeEvent) {
2609
+ constructor(workflowExecutionRepository, runId, workflowId, parent, publishNodeEvent, publishConnectionInvocationEvent) {
2002
2610
  this.workflowExecutionRepository = workflowExecutionRepository;
2003
2611
  this.runId = runId;
2004
2612
  this.workflowId = workflowId;
2005
2613
  this.parent = parent;
2006
2614
  this.publishNodeEvent = publishNodeEvent;
2615
+ this.publishConnectionInvocationEvent = publishConnectionInvocationEvent;
2007
2616
  }
2008
2617
  markQueued(args) {
2009
2618
  return this.enqueue(async () => {
@@ -2100,12 +2709,16 @@ var NodeRunStateWriter = class {
2100
2709
  queuedAt: args.queuedAt,
2101
2710
  startedAt: args.startedAt,
2102
2711
  finishedAt: args.finishedAt,
2103
- updatedAt
2712
+ updatedAt,
2713
+ iterationId: args.iterationId,
2714
+ itemIndex: args.itemIndex,
2715
+ parentInvocationId: args.parentInvocationId
2104
2716
  };
2105
2717
  await this.workflowExecutionRepository.save({
2106
2718
  ...state,
2107
2719
  connectionInvocations: [...state.connectionInvocations ?? [], record]
2108
2720
  });
2721
+ if (this.publishConnectionInvocationEvent) await this.publishConnectionInvocationEvent(record);
2109
2722
  });
2110
2723
  }
2111
2724
  enqueue(work) {
@@ -2132,13 +2745,17 @@ var NodeRunStateWriter = class {
2132
2745
  //#endregion
2133
2746
  //#region src/execution/NodeRunStateWriterFactory.ts
2134
2747
  var NodeRunStateWriterFactory = class {
2135
- constructor(workflowExecutionRepository, nodeEventPublisher) {
2748
+ constructor(workflowExecutionRepository, nodeEventPublisher, eventBus) {
2136
2749
  this.workflowExecutionRepository = workflowExecutionRepository;
2137
2750
  this.nodeEventPublisher = nodeEventPublisher;
2751
+ this.eventBus = eventBus;
2138
2752
  }
2139
2753
  create(runId, workflowId, parent) {
2754
+ const connectionInvocationEventPublisher = new ConnectionInvocationEventPublisher(this.eventBus, parent);
2140
2755
  return new NodeRunStateWriter(this.workflowExecutionRepository, runId, workflowId, parent, async (kind, snapshot) => {
2141
2756
  await this.nodeEventPublisher.publish(kind, snapshot);
2757
+ }, async (record) => {
2758
+ await connectionInvocationEventPublisher.publish(record);
2142
2759
  });
2143
2760
  }
2144
2761
  };
@@ -2263,7 +2880,8 @@ var WorkflowRunExecutionContextFactory = class {
2263
2880
  engineMaxSubworkflowDepth: args.engineMaxSubworkflowDepth,
2264
2881
  data: args.data,
2265
2882
  nodeState: args.nodeState,
2266
- getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId)
2883
+ getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId),
2884
+ testContext: args.testContext
2267
2885
  });
2268
2886
  }
2269
2887
  };
@@ -2430,7 +3048,8 @@ var RunContinuationService = class {
2430
3048
  engineMaxNodeActivations: limits.engineMaxNodeActivations,
2431
3049
  engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
2432
3050
  data,
2433
- nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent)
3051
+ nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent),
3052
+ testContext: state.executionOptions?.testContext
2434
3053
  });
2435
3054
  data.setOutputs(args.nodeId, args.outputs);
2436
3055
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -2951,7 +3570,8 @@ var RunContinuationService = class {
2951
3570
  engineMaxNodeActivations: webhookLimits.engineMaxNodeActivations,
2952
3571
  engineMaxSubworkflowDepth: webhookLimits.engineMaxSubworkflowDepth,
2953
3572
  data,
2954
- nodeState: this.nodeStatePublisherFactory.create(args.state.runId, args.state.workflowId, args.state.parent)
3573
+ nodeState: this.nodeStatePublisherFactory.create(args.state.runId, args.state.workflowId, args.state.parent),
3574
+ testContext: args.state.executionOptions?.testContext
2955
3575
  });
2956
3576
  const request = this.nodeActivationRequestComposer.createFromPlannedActivation({
2957
3577
  next,
@@ -3042,7 +3662,8 @@ var RunContinuationService = class {
3042
3662
  engineMaxNodeActivations: limits.engineMaxNodeActivations,
3043
3663
  engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
3044
3664
  data,
3045
- nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent)
3665
+ nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent),
3666
+ testContext: state.executionOptions?.testContext
3046
3667
  });
3047
3668
  const activationId = pendingExecution.activationId;
3048
3669
  return {
@@ -3434,7 +4055,7 @@ var RunPolicySnapshotFactory = class {
3434
4055
  //#endregion
3435
4056
  //#region src/orchestration/RunStartService.ts
3436
4057
  var RunStartService = class {
3437
- constructor(runIdFactory, workflowExecutionRepository, runDataFactory, workflowSnapshotFactory, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, workflowPolicyRuntimeDefaults, executionLimitsPolicy) {
4058
+ constructor(runIdFactory, workflowExecutionRepository, runDataFactory, workflowSnapshotFactory, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, workflowPolicyRuntimeDefaults, executionLimitsPolicy, nodeEventPublisher, persistedRunStateTerminalBuilder) {
3438
4059
  this.runIdFactory = runIdFactory;
3439
4060
  this.workflowExecutionRepository = workflowExecutionRepository;
3440
4061
  this.runDataFactory = runDataFactory;
@@ -3448,6 +4069,8 @@ var RunStartService = class {
3448
4069
  this.waiters = waiters;
3449
4070
  this.workflowPolicyRuntimeDefaults = workflowPolicyRuntimeDefaults;
3450
4071
  this.executionLimitsPolicy = executionLimitsPolicy;
4072
+ this.nodeEventPublisher = nodeEventPublisher;
4073
+ this.persistedRunStateTerminalBuilder = persistedRunStateTerminalBuilder;
3451
4074
  }
3452
4075
  async runWorkflow(workflow, startAt, items, parent, executionOptions, persistedStateOverrides) {
3453
4076
  const runId = this.runIdFactory.makeRunId();
@@ -3478,9 +4101,28 @@ var RunStartService = class {
3478
4101
  engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations,
3479
4102
  engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth,
3480
4103
  data,
3481
- nodeState: this.nodeStatePublisherFactory.create(runId, workflow.id, parent)
4104
+ nodeState: this.nodeStatePublisherFactory.create(runId, workflow.id, parent),
4105
+ testContext: mergedExecutionOptions.testContext
3482
4106
  });
3483
- const { topology, planner } = this.planningFactory.create(workflow);
4107
+ let planning;
4108
+ try {
4109
+ planning = this.planningFactory.create(workflow);
4110
+ } catch (err) {
4111
+ if (err instanceof NodeInstantiationError) return await this.failRunDuringPlanning({
4112
+ runId,
4113
+ workflowId: workflow.id,
4114
+ startedAt,
4115
+ parent,
4116
+ executionOptions: mergedExecutionOptions,
4117
+ control: void 0,
4118
+ workflowSnapshot,
4119
+ mutableState,
4120
+ policySnapshot,
4121
+ err
4122
+ });
4123
+ throw err;
4124
+ }
4125
+ const { topology, planner } = planning;
3484
4126
  const startDefinition = topology.defsById.get(startAt);
3485
4127
  if (!startDefinition) throw new Error(`Unknown start nodeId: ${startAt}`);
3486
4128
  const initialNodeSnapshotsByNodeId = {};
@@ -3559,7 +4201,25 @@ var RunStartService = class {
3559
4201
  policySnapshot,
3560
4202
  engineCounters: { completedNodeActivations: 0 }
3561
4203
  });
3562
- const { topology, planner } = this.planningFactory.create(request.workflow);
4204
+ let planningFromState;
4205
+ try {
4206
+ planningFromState = this.planningFactory.create(request.workflow);
4207
+ } catch (err) {
4208
+ if (err instanceof NodeInstantiationError) return await this.failRunDuringPlanning({
4209
+ runId,
4210
+ workflowId: request.workflow.id,
4211
+ startedAt,
4212
+ parent: request.parent,
4213
+ executionOptions: mergedExecutionOptions,
4214
+ control,
4215
+ workflowSnapshot,
4216
+ mutableState,
4217
+ policySnapshot,
4218
+ err
4219
+ });
4220
+ throw err;
4221
+ }
4222
+ const { topology, planner } = planningFromState;
3563
4223
  const plan = CurrentStateFrontierPlanner.createFromTopology(topology).plan({
3564
4224
  currentState: this.createRunCurrentState(request.currentState, mutableState),
3565
4225
  stopCondition: control.stopCondition,
@@ -3577,7 +4237,8 @@ var RunStartService = class {
3577
4237
  engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations,
3578
4238
  engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth,
3579
4239
  data,
3580
- nodeState: this.nodeStatePublisherFactory.create(runId, request.workflow.id, request.parent)
4240
+ nodeState: this.nodeStatePublisherFactory.create(runId, request.workflow.id, request.parent),
4241
+ testContext: mergedExecutionOptions.testContext
3581
4242
  });
3582
4243
  return await this.scheduleInitialPlan({
3583
4244
  runId,
@@ -3599,7 +4260,7 @@ var RunStartService = class {
3599
4260
  return {
3600
4261
  outputsByNode: { ...currentState?.outputsByNode ?? {} },
3601
4262
  nodeSnapshotsByNodeId: { ...currentState?.nodeSnapshotsByNodeId ?? {} },
3602
- connectionInvocations: currentState?.connectionInvocations ? [...currentState.connectionInvocations] : void 0,
4263
+ connectionInvocations: [],
3603
4264
  mutableState: mutableState ?? currentState?.mutableState
3604
4265
  };
3605
4266
  }
@@ -3752,6 +4413,57 @@ var RunStartService = class {
3752
4413
  this.waiters.resolveRunCompletion(result);
3753
4414
  return result;
3754
4415
  }
4416
+ async failRunDuringPlanning(args) {
4417
+ const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
4418
+ const failedSnapshot = NodeExecutionSnapshotFactory.failed({
4419
+ previous: void 0,
4420
+ runId: args.runId,
4421
+ workflowId: args.workflowId,
4422
+ nodeId: args.err.nodeId,
4423
+ activationId: "planning_failure",
4424
+ parent: args.parent,
4425
+ finishedAt,
4426
+ inputsByPort: {},
4427
+ error: args.err
4428
+ });
4429
+ const failedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
4430
+ state: {
4431
+ runId: args.runId,
4432
+ workflowId: args.workflowId,
4433
+ startedAt: args.startedAt,
4434
+ parent: args.parent,
4435
+ executionOptions: args.executionOptions,
4436
+ control: args.control,
4437
+ workflowSnapshot: args.workflowSnapshot,
4438
+ mutableState: args.mutableState,
4439
+ policySnapshot: args.policySnapshot,
4440
+ engineCounters: { completedNodeActivations: 0 },
4441
+ status: "pending",
4442
+ pending: void 0,
4443
+ queue: [],
4444
+ outputsByNode: {},
4445
+ nodeSnapshotsByNodeId: {},
4446
+ connectionInvocations: []
4447
+ },
4448
+ engineCounters: { completedNodeActivations: 0 },
4449
+ status: "failed",
4450
+ queue: [],
4451
+ outputsByNode: {},
4452
+ nodeSnapshotsByNodeId: { [args.err.nodeId]: failedSnapshot },
4453
+ finishedAtIso: finishedAt
4454
+ });
4455
+ await this.workflowExecutionRepository.save(failedState);
4456
+ await this.nodeEventPublisher.publish("nodeFailed", failedSnapshot);
4457
+ const result = {
4458
+ runId: args.runId,
4459
+ workflowId: args.workflowId,
4460
+ startedAt: args.startedAt,
4461
+ status: "failed",
4462
+ error: { message: args.err.message }
4463
+ };
4464
+ this.waiters.resolveRunCompletion(result);
4465
+ return result;
4466
+ }
3755
4467
  };
3756
4468
 
3757
4469
  //#endregion
@@ -4225,6 +4937,128 @@ var InMemoryRunDataFactory = class {
4225
4937
  }
4226
4938
  };
4227
4939
 
4940
+ //#endregion
4941
+ //#region src/triggers/polling/PollingTriggerDedupWindow.ts
4942
+ /**
4943
+ * Merges processed-ID windows for polling triggers, capping the total to avoid unbounded growth.
4944
+ * Plugin code receives an instance of this class via {@link PollingTriggerHandle.dedup}.
4945
+ */
4946
+ var PollingTriggerDedupWindow = class PollingTriggerDedupWindow {
4947
+ static defaultCapN = 2e3;
4948
+ merge(previous, incoming, capN = PollingTriggerDedupWindow.defaultCapN) {
4949
+ const merged = new Set(previous);
4950
+ for (const id of incoming) merged.add(id);
4951
+ const result = [...merged];
4952
+ if (result.length <= capN) return result;
4953
+ return result.slice(result.length - capN);
4954
+ }
4955
+ };
4956
+
4957
+ //#endregion
4958
+ //#region src/triggers/polling/PollingTriggerRuntime.ts
4959
+ /**
4960
+ * Generic polling-trigger runtime. Owns the set-interval loop, overlap guard, and persistence.
4961
+ * Constructed by {@link import("../../runtime/EngineFactory").EngineFactory} and exposed to plugin
4962
+ * authors via {@link import("../../contracts/runtimeTypes").TriggerSetupContext}.polling.
4963
+ */
4964
+ var PollingTriggerRuntime = class {
4965
+ activeTriggers = /* @__PURE__ */ new Set();
4966
+ intervalsByTrigger = /* @__PURE__ */ new Map();
4967
+ busyTriggers = /* @__PURE__ */ new Set();
4968
+ constructor(triggerSetupStateRepository, logger) {
4969
+ this.triggerSetupStateRepository = triggerSetupStateRepository;
4970
+ this.logger = logger;
4971
+ }
4972
+ async start(args) {
4973
+ let first;
4974
+ try {
4975
+ first = await this.runCycle(args, { seedState: args.seedState });
4976
+ } catch (err) {
4977
+ this.logError(`Polling trigger initial cycle failed for ${this.describe(args.trigger)}`, err);
4978
+ }
4979
+ this.ensureLoop(args);
4980
+ return first;
4981
+ }
4982
+ async stop(trigger) {
4983
+ const key = this.toKey(trigger);
4984
+ const interval = this.intervalsByTrigger.get(key);
4985
+ if (interval !== void 0) {
4986
+ clearInterval(interval);
4987
+ this.intervalsByTrigger.delete(key);
4988
+ }
4989
+ this.busyTriggers.delete(key);
4990
+ this.activeTriggers.delete(key);
4991
+ this.logger.debug(`Polling trigger stopped for ${this.describe(trigger)}`);
4992
+ }
4993
+ ensureLoop(args) {
4994
+ const key = this.toKey(args.trigger);
4995
+ if (this.activeTriggers.has(key)) {
4996
+ this.logger.debug(`Polling trigger already active for ${this.describe(args.trigger)}`);
4997
+ return;
4998
+ }
4999
+ this.activeTriggers.add(key);
5000
+ const intervalMs = Math.max(args.intervalMs, 25);
5001
+ const interval = setInterval(() => {
5002
+ this.runCycle(args, { seedState: void 0 }).catch((err) => {
5003
+ this.logError(`Polling trigger cycle failed for ${this.describe(args.trigger)}`, err);
5004
+ });
5005
+ }, intervalMs);
5006
+ this.intervalsByTrigger.set(key, interval);
5007
+ this.logger.info(`Polling trigger started for ${this.describe(args.trigger)} (interval ${intervalMs}ms)`);
5008
+ }
5009
+ async runCycle(args, opts) {
5010
+ const key = this.toKey(args.trigger);
5011
+ if (this.busyTriggers.has(key)) {
5012
+ this.logger.debug(`Polling trigger skipping overlapping tick for ${this.describe(args.trigger)}`);
5013
+ return;
5014
+ }
5015
+ this.busyTriggers.add(key);
5016
+ try {
5017
+ const loaded = await this.triggerSetupStateRepository.load(args.trigger);
5018
+ const previousState = loaded !== void 0 ? loaded.state : opts.seedState;
5019
+ const controller = new AbortController();
5020
+ const { items, nextState } = await args.runCycle({
5021
+ previousState,
5022
+ signal: controller.signal
5023
+ });
5024
+ await this.triggerSetupStateRepository.save({
5025
+ trigger: args.trigger,
5026
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
5027
+ state: nextState
5028
+ });
5029
+ if (items.length > 0) {
5030
+ this.logger.info(`Polling trigger emitting ${items.length} item(s) for ${this.describe(args.trigger)}`);
5031
+ await args.emit(items);
5032
+ }
5033
+ return nextState;
5034
+ } finally {
5035
+ this.busyTriggers.delete(key);
5036
+ }
5037
+ }
5038
+ toKey(trigger) {
5039
+ return `${trigger.workflowId}:${trigger.nodeId}`;
5040
+ }
5041
+ describe(trigger) {
5042
+ return `${trigger.workflowId}.${trigger.nodeId}`;
5043
+ }
5044
+ logError(message, error) {
5045
+ if (error instanceof Error) {
5046
+ this.logger.error(message, error);
5047
+ return;
5048
+ }
5049
+ this.logger.error(`${message}: ${String(error)}`);
5050
+ }
5051
+ };
5052
+
5053
+ //#endregion
5054
+ //#region src/triggers/polling/PollingTriggerLogger.ts
5055
+ var NoOpPollingTriggerLogger = class {
5056
+ info() {}
5057
+ warn() {}
5058
+ error() {}
5059
+ debug() {}
5060
+ };
5061
+
4228
5062
  //#endregion
4229
5063
  //#region src/orchestration/NodeExecutionRequestHandlerService.ts
4230
5064
  var NodeExecutionRequestHandlerService = class {
@@ -4264,7 +5098,8 @@ var NodeExecutionRequestHandlerService = class {
4264
5098
  engineMaxNodeActivations: limits.engineMaxNodeActivations,
4265
5099
  engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
4266
5100
  data,
4267
- nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent)
5101
+ nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent),
5102
+ testContext: state.executionOptions?.testContext
4268
5103
  });
4269
5104
  const inputsByPort = pendingExecution.inputsByPort;
4270
5105
  const portKeys = Object.keys(inputsByPort);
@@ -4654,7 +5489,7 @@ var EngineWorkflowPlanningFactory = class {
4654
5489
  var TriggerRuntimeService = class {
4655
5490
  credentialResolverFactory;
4656
5491
  triggerCleanupHandlesByKey = /* @__PURE__ */ new Map();
4657
- constructor(workflowRepository, workflowActivationPolicy, runIdFactory, runDataFactory, executionContextFactory, credentialResolverFactory, nodeExecutionStatePublisherFactory, nodeResolver, triggerSetupStateRepository, emitHandler, executionLimitsPolicy, diagnostics) {
5492
+ constructor(workflowRepository, workflowActivationPolicy, runIdFactory, runDataFactory, executionContextFactory, credentialResolverFactory, nodeExecutionStatePublisherFactory, nodeResolver, triggerSetupStateRepository, emitHandler, executionLimitsPolicy, diagnostics, pollingTriggerRuntime, pollingTriggerDedupWindow) {
4658
5493
  this.workflowRepository = workflowRepository;
4659
5494
  this.workflowActivationPolicy = workflowActivationPolicy;
4660
5495
  this.runIdFactory = runIdFactory;
@@ -4666,6 +5501,8 @@ var TriggerRuntimeService = class {
4666
5501
  this.emitHandler = emitHandler;
4667
5502
  this.executionLimitsPolicy = executionLimitsPolicy;
4668
5503
  this.diagnostics = diagnostics;
5504
+ this.pollingTriggerRuntime = pollingTriggerRuntime;
5505
+ this.pollingTriggerDedupWindow = pollingTriggerDedupWindow;
4669
5506
  this.credentialResolverFactory = credentialResolverFactory;
4670
5507
  }
4671
5508
  async startTriggers() {
@@ -4721,6 +5558,7 @@ var TriggerRuntimeService = class {
4721
5558
  async startTriggersForWorkflow(wf) {
4722
5559
  for (const def of wf.nodes) {
4723
5560
  if (def.kind !== "trigger") continue;
5561
+ if (def.config.triggerKind === "test") continue;
4724
5562
  const node$1 = this.nodeResolver.resolve(def.type);
4725
5563
  const data = this.runDataFactory.create();
4726
5564
  const triggerRunId = this.runIdFactory.makeRunId();
@@ -4730,6 +5568,9 @@ var TriggerRuntimeService = class {
4730
5568
  };
4731
5569
  await this.stopTrigger(trigger);
4732
5570
  const previousState = await this.triggerSetupStateRepository.load(trigger);
5571
+ const emit = this.emitHandler.emit.bind(this.emitHandler, wf, def.id);
5572
+ const registerCleanup = this.registerTriggerCleanupHandle.bind(this, trigger);
5573
+ const polling = this.buildPollingHandle(trigger, emit);
4733
5574
  let nextState;
4734
5575
  try {
4735
5576
  nextState = await node$1.setup({
@@ -4742,12 +5583,9 @@ var TriggerRuntimeService = class {
4742
5583
  trigger,
4743
5584
  config: def.config,
4744
5585
  previousState: previousState?.state,
4745
- registerCleanup: (cleanup) => {
4746
- this.registerTriggerCleanupHandle(trigger, cleanup);
4747
- },
4748
- emit: async (items) => {
4749
- await this.emitHandler.emit(wf, def.id, items);
4750
- }
5586
+ registerCleanup,
5587
+ emit,
5588
+ polling
4751
5589
  });
4752
5590
  } catch (triggerError) {
4753
5591
  await this.stopTrigger(trigger);
@@ -4766,6 +5604,7 @@ var TriggerRuntimeService = class {
4766
5604
  async stopTriggersForWorkflow(workflow) {
4767
5605
  for (const node$1 of workflow.nodes) {
4768
5606
  if (node$1.kind !== "trigger") continue;
5607
+ if (node$1.config.triggerKind === "test") continue;
4769
5608
  await this.stopTrigger({
4770
5609
  workflowId: workflow.id,
4771
5610
  nodeId: node$1.id
@@ -4806,6 +5645,7 @@ var TriggerRuntimeService = class {
4806
5645
  const out = [];
4807
5646
  for (const def of wf.nodes) {
4808
5647
  if (def.kind !== "trigger") continue;
5648
+ if (def.config.triggerKind === "test") continue;
4809
5649
  out.push(this.describeTriggerNode(def));
4810
5650
  }
4811
5651
  return out;
@@ -4823,6 +5663,22 @@ var TriggerRuntimeService = class {
4823
5663
  if (this.diagnostics) this.diagnostics.warn(message);
4824
5664
  else console.warn(`[engine] ${message}`);
4825
5665
  }
5666
+ buildPollingHandle(trigger, emit) {
5667
+ const runtime = this.pollingTriggerRuntime;
5668
+ return {
5669
+ dedup: this.pollingTriggerDedupWindow,
5670
+ start: async (args) => {
5671
+ this.registerTriggerCleanupHandle(trigger, { stop: async () => {
5672
+ await runtime.stop(trigger);
5673
+ } });
5674
+ return runtime.start({
5675
+ trigger,
5676
+ emit,
5677
+ ...args
5678
+ });
5679
+ }
5680
+ };
5681
+ }
4826
5682
  isTestableTriggerNode(node$1) {
4827
5683
  return typeof node$1.getTestItems === "function";
4828
5684
  }
@@ -4959,7 +5815,7 @@ var EngineFactory = class {
4959
5815
  const waiters = new EngineWaiters();
4960
5816
  const credentialResolverFactory = new CredentialResolverFactory(deps.credentialSessions);
4961
5817
  const nodeEventPublisher = new NodeEventPublisher(deps.eventBus);
4962
- const nodeStatePublisherFactory = new NodeRunStateWriterFactory(deps.workflowExecutionRepository, nodeEventPublisher);
5818
+ const nodeStatePublisherFactory = new NodeRunStateWriterFactory(deps.workflowExecutionRepository, nodeEventPublisher, deps.eventBus);
4963
5819
  const planningFactory = new EngineWorkflowPlanningFactory(deps.workflowNodeInstanceFactory);
4964
5820
  const executionLimitsPolicy = deps.executionLimitsPolicy ?? new EngineExecutionLimitsPolicy();
4965
5821
  const workflowSnapshotCodec = deps.workflowSnapshotCodec ?? new WorkflowSnapshotCodec(deps.tokenRegistry);
@@ -4974,12 +5830,15 @@ var EngineFactory = class {
4974
5830
  const storagePolicyEvaluator = new WorkflowStoragePolicyEvaluator(deps.nodeResolver);
4975
5831
  const terminalPersistence = new RunTerminalPersistenceCoordinator(deps.workflowExecutionRepository, storagePolicyEvaluator);
4976
5832
  const policyErrorServices = new WorkflowPolicyErrorServices(deps.nodeResolver);
4977
- const runStartService = new RunStartService(deps.runIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, workflowSnapshotCodec, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, deps.workflowPolicyRuntimeDefaults, executionLimitsPolicy);
5833
+ const runStartService = new RunStartService(deps.runIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, workflowSnapshotCodec, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, deps.workflowPolicyRuntimeDefaults, executionLimitsPolicy, nodeEventPublisher, persistedRunStateTerminalBuilder);
4978
5834
  const runContinuationService = new RunContinuationService(deps.activationIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, runExecutionContextFactory, workflowSnapshotResolver, planningFactory, nodeStatePublisherFactory, credentialResolverFactory, nodeActivationRequestComposer, persistedRunStateTerminalBuilder, activationEnqueueService, nodeEventPublisher, semantics, waiters, policyErrorServices, terminalPersistence, executionLimitsPolicy);
4979
5835
  const nodeExecutionRequestHandler = new NodeExecutionRequestHandlerService(deps.workflowExecutionRepository, workflowSnapshotResolver, deps.runDataFactory, runExecutionContextFactory, nodeStatePublisherFactory, nodeActivationRequestComposer, deps.nodeExecutor, runContinuationService, executionLimitsPolicy);
5836
+ const pollingTriggerLogger = deps.pollingTriggerLogger ?? new NoOpPollingTriggerLogger();
5837
+ const pollingTriggerDedupWindow = new PollingTriggerDedupWindow();
5838
+ const pollingTriggerRuntime = new PollingTriggerRuntime(deps.triggerSetupStateRepository, pollingTriggerLogger);
4980
5839
  const triggerRuntime = new TriggerRuntimeService(deps.workflowRepository, deps.workflowActivationPolicy, deps.runIdFactory, deps.runDataFactory, deps.executionContextFactory, credentialResolverFactory, nodeStatePublisherFactory, deps.nodeResolver, deps.triggerSetupStateRepository, { emit: async (workflow, triggerNodeId, items) => {
4981
5840
  await runStartService.runWorkflow(workflow, triggerNodeId, items, void 0);
4982
- } }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics);
5841
+ } }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics, pollingTriggerRuntime, pollingTriggerDedupWindow);
4983
5842
  const engine = new Engine({
4984
5843
  liveWorkflowRepository: deps.liveWorkflowRepository,
4985
5844
  tokenRegistry: deps.tokenRegistry,
@@ -5270,5 +6129,5 @@ var WorkflowRepositoryWebhookTriggerMatcherFactory = class {
5270
6129
  };
5271
6130
 
5272
6131
  //#endregion
5273
- export { CostTrackingTelemetryMetricNames as $, NodeExecutor as A, inject as At, nodeRef as B, StaticCostCatalog as C, tool as Ct, PersistedWorkflowTokenRegistry as D, PersistedRuntimeTypeNameResolver as Dt, WorkflowSnapshotCodec as E, StackTraceCallSitePathResolver as Et, InProcessRetryRunner as F, predicateAwareClassFactory as Ft, NoOpExecutionTelemetryFactory as G, CodemationTelemetryMetricNames as H, CatalogBackedCostTrackingTelemetryFactory as I, registry as It, NoOpTelemetrySpanScope as J, NoOpExecutionTelemetry as K, DefaultExecutionContextFactory as L, singleton as Lt, RunnableOutputBehaviorResolver as M, injectable as Mt, NodeOutputNormalizer as N, instanceCachingFactory as Nt, MissingRuntimeTriggerToken as O, container$1 as Ot, ItemExprResolver as P, instancePerContainerCachingFactory as Pt, CostTrackingTelemetryAttributeNames as Q, AllWorkflowsActiveWorkflowActivationPolicy as R, CoreTokens as Rt, RunPolicySnapshotFactory as S, node as St, NodeInstanceFactory as T, PersistedRuntimeTypeMetadataStore as Tt, GenAiTelemetryAttributeNames as U, RunFinishedAtFactory as V, CodemationTelemetryAttributeNames as W, NoOpCostTrackingTelemetryFactory as X, NoOpTelemetryArtifactReference as Y, NoOpCostTrackingTelemetry as Z, LocalOnlyScheduler as _, itemExpr as _t, InMemoryLiveWorkflowRepository as a, isPortsEmission as at, DefaultDrivingScheduler as b, chatModel as bt, EngineFactory as c, CredentialResolverFactory as ct, InMemoryBinaryStorage as d, UnavailableBinaryStorage as dt, CredentialUnboundError as et, WorkflowStoragePolicyEvaluator as f, NodeEventPublisher as ft, EngineExecutionLimitsPolicy as g, isItemExpr as gt, ENGINE_EXECUTION_LIMITS_DEFAULTS as h, ConnectionNodeIdFactory as ht, RunIntentService as i, emitPorts as it, InProcessRetryRunnerFactory as j, injectAll as jt, NodeExecutorFactory as k, delay as kt, Engine as l, getOriginIndexFromItem as lt, RunTerminalPersistenceCoordinator as m, WorkflowExecutableNodeClassifier as mt, WorkflowRepositoryWebhookTriggerMatcher as n, RetryPolicy as nt, EngineWorkflowRunnerServiceFactory as o, isUnbrandedPortsEmissionShape as ot, WorkflowPolicyErrorServices as p, WorkflowExecutableNodeClassifierFactory as pt, NoOpNodeExecutionTelemetry as q, RunIntentServiceFactory as r, NoRetryPolicy as rt, EngineWorkflowRunnerService as s, DefaultAsyncSleeper as st, WorkflowRepositoryWebhookTriggerMatcherFactory as t, ExpRetryPolicy as tt, InMemoryRunDataFactory as u, DefaultExecutionBinaryService as ut, InlineDrivingScheduler as v, resolveItemExprsForExecution as vt, NodeInstanceFactoryFactory as w, InjectableRuntimeDecoratorComposer as wt, ConfigDrivenOffloadPolicy as x, getPersistedRuntimeTypeMetadata as xt, HintOnlyOffloadPolicy as y, resolveItemExprsInUnknown as yt, branchRef as z };
5274
- //# sourceMappingURL=runtime-DUW6tIJ1.js.map
6132
+ export { NoOpCostTrackingTelemetryFactory as $, singleton as $t, PersistedWorkflowTokenRegistry as A, AgentConfigInspector as At, DefaultExecutionContextFactory as B, InjectableRuntimeDecoratorComposer as Bt, DefaultDrivingScheduler as C, WorkflowBuilder as Ct, NodeInstanceFactoryFactory as D, WhenBuilder as Dt, StaticCostCatalog as E, ChainCursor as Et, RunnableOutputBehaviorResolver as F, NodeBackedToolConfig as Ft, CodemationTelemetryAttributeNames as G, delay as Gt, nodeRef as H, StackTraceCallSitePathResolver as Ht, NodeOutputNormalizer as I, chatModel as It, NoOpExecutionTelemetryFactory as J, injectable as Jt, AllWorkflowsActiveWorkflowActivationPolicy as K, inject as Kt, ItemExprResolver as L, getPersistedRuntimeTypeMetadata as Lt, NodeExecutorFactory as M, itemExpr as Mt, NodeExecutor as N, resolveItemExprsForExecution as Nt, NodeInstanceFactory as O, AgentConnectionNodeCollector as Ot, InProcessRetryRunnerFactory as P, resolveItemExprsInUnknown as Pt, NoOpTelemetryArtifactReference as Q, registry as Qt, InProcessRetryRunner as R, node as Rt, HintOnlyOffloadPolicy as S, ConnectionInvocationIdFactory as St, RunPolicySnapshotFactory as T, NodeIdSlugifier as Tt, CodemationTelemetryMetricNames as U, PersistedRuntimeTypeNameResolver as Ut, branchRef as V, PersistedRuntimeTypeMetadataStore as Vt, GenAiTelemetryAttributeNames as W, container$1 as Wt, NoOpNodeExecutionTelemetry as X, instancePerContainerCachingFactory as Xt, NoOpExecutionTelemetry as Y, instanceCachingFactory as Yt, NoOpTelemetrySpanScope as Z, predicateAwareClassFactory as Zt, RunTerminalPersistenceCoordinator as _, ConnectionInvocationEventPublisher as _t, InMemoryLiveWorkflowRepository as a, RetryPolicy as at, LocalOnlyScheduler as b, WorkflowExecutableNodeClassifier as bt, EngineFactory as c, isPortsEmission as ct, PollingTriggerRuntime as d, CredentialResolverFactory as dt, CoreTokens as en, NoOpCostTrackingTelemetry as et, PollingTriggerDedupWindow as f, getOriginIndexFromItem as ft, WorkflowPolicyErrorServices as g, NodeEventPublisher as gt, WorkflowStoragePolicyEvaluator as h, UnavailableBinaryStorage as ht, RunIntentService as i, ExpRetryPolicy as it, MissingRuntimeTriggerToken as j, isItemExpr as jt, WorkflowSnapshotCodec as k, ConnectionNodeIdFactory as kt, Engine as l, isUnbrandedPortsEmissionShape as lt, InMemoryBinaryStorage as m, DefaultExecutionBinaryService as mt, WorkflowRepositoryWebhookTriggerMatcher as n, CostTrackingTelemetryMetricNames as nt, EngineWorkflowRunnerServiceFactory as o, NoRetryPolicy as ot, InMemoryRunDataFactory as p, ChildExecutionScopeFactory as pt, RunFinishedAtFactory as q, injectAll as qt, RunIntentServiceFactory as r, CredentialUnboundError as rt, EngineWorkflowRunnerService as s, emitPorts as st, WorkflowRepositoryWebhookTriggerMatcherFactory as t, CostTrackingTelemetryAttributeNames as tt, NoOpPollingTriggerLogger as u, DefaultAsyncSleeper as ut, ENGINE_EXECUTION_LIMITS_DEFAULTS as v, DefaultWorkflowGraphFactory as vt, ConfigDrivenOffloadPolicy as w, WorkflowDefinitionError as wt, InlineDrivingScheduler as x, NodeIterationIdFactory as xt, EngineExecutionLimitsPolicy as y, WorkflowExecutableNodeClassifierFactory as yt, CatalogBackedCostTrackingTelemetryFactory as z, tool as zt };
6133
+ //# sourceMappingURL=runtime-BGNbRnqs.js.map