@codemation/core 1.0.1 → 2.0.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 (86) hide show
  1. package/CHANGELOG.md +293 -0
  2. package/dist/{EngineRuntimeRegistration.types-kxQA5NLt.d.ts → EngineRuntimeRegistration.types-D1fyApMI.d.ts} +2 -2
  3. package/dist/{EngineWorkflowRunnerService-Ba2AvBnL.d.cts → EngineRuntimeRegistration.types-pB3FnzqR.d.cts} +17 -17
  4. package/dist/{InMemoryRunDataFactory-Ou4tQUOS.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-dteLjNiT.d.ts → RunIntentService-BE9CAkbf.d.ts} +602 -213
  10. package/dist/{RunIntentService-Dyh_dH0k.d.cts → RunIntentService-siBSjaaY.d.cts} +430 -125
  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-Cko6udwL.cjs → bootstrap-Cm5ruQxx.cjs} +253 -3
  16. package/dist/bootstrap-Cm5ruQxx.cjs.map +1 -0
  17. package/dist/{bootstrap-CL68rqWg.js → bootstrap-D3r505ko.js} +236 -4
  18. package/dist/bootstrap-D3r505ko.js.map +1 -0
  19. package/dist/{index-CyfGTfU1.d.ts → index-DeLl1Tne.d.ts} +574 -242
  20. package/dist/index.cjs +328 -180
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +441 -103
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js +305 -163
  25. package/dist/index.js.map +1 -1
  26. package/dist/{runtime-284ok0cm.js → runtime-BGNbRnqs.js} +764 -75
  27. package/dist/runtime-BGNbRnqs.js.map +1 -0
  28. package/dist/{runtime-B3Og-_St.cjs → runtime-DKXJwTNv.cjs} +841 -80
  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/authoring/DefinedCollectionRegistry.ts +17 -0
  37. package/src/authoring/defineCollection.types.ts +181 -0
  38. package/src/authoring/definePollingTrigger.types.ts +396 -0
  39. package/src/authoring/definePollingTriggerInternals.ts +74 -0
  40. package/src/authoring/index.ts +19 -0
  41. package/src/bootstrap/index.ts +9 -0
  42. package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +5 -1
  43. package/src/contracts/assertionTypes.ts +63 -0
  44. package/src/contracts/baseTypes.ts +12 -0
  45. package/src/contracts/collectionTypes.ts +44 -0
  46. package/src/contracts/credentialTypes.ts +23 -1
  47. package/src/contracts/index.ts +4 -0
  48. package/src/contracts/runTypes.ts +27 -1
  49. package/src/contracts/runtimeTypes.ts +34 -0
  50. package/src/contracts/testTriggerTypes.ts +66 -0
  51. package/src/contracts/workflowTypes.ts +30 -7
  52. package/src/contracts.ts +59 -0
  53. package/src/events/runEvents.ts +49 -0
  54. package/src/execution/ChildExecutionScopeFactory.ts +4 -7
  55. package/src/execution/DefaultExecutionContextFactory.ts +6 -0
  56. package/src/execution/NodeInstanceFactory.ts +13 -1
  57. package/src/execution/NodeInstantiationError.ts +16 -0
  58. package/src/execution/WorkflowRunExecutionContextFactory.ts +3 -0
  59. package/src/execution/index.ts +1 -0
  60. package/src/index.ts +7 -0
  61. package/src/orchestration/AbortControllerFactory.ts +9 -0
  62. package/src/orchestration/NodeExecutionRequestHandlerService.ts +1 -0
  63. package/src/orchestration/RunContinuationService.ts +3 -0
  64. package/src/orchestration/RunStartService.ts +114 -2
  65. package/src/orchestration/TestSuiteOrchestrator.ts +350 -0
  66. package/src/orchestration/TestSuiteRunIdFactory.ts +11 -0
  67. package/src/orchestration/TriggerRuntimeService.ts +34 -7
  68. package/src/orchestration/index.ts +9 -0
  69. package/src/runtime/EngineFactory.ts +11 -0
  70. package/src/triggers/polling/PollingTriggerDedupWindow.ts +23 -0
  71. package/src/triggers/polling/PollingTriggerLogger.ts +18 -0
  72. package/src/triggers/polling/PollingTriggerRuntime.ts +122 -0
  73. package/src/triggers/polling/index.ts +5 -0
  74. package/src/types/index.ts +12 -9
  75. package/src/workflow/dsl/NodeIdSlugifier.ts +18 -0
  76. package/src/workflow/dsl/WorkflowBuilder.ts +71 -3
  77. package/src/workflow/dsl/WorkflowDefinitionError.ts +15 -0
  78. package/src/workflow/index.ts +2 -0
  79. package/dist/InMemoryRunEventBusRegistry-B0_C4OnP.cjs +0 -262
  80. package/dist/InMemoryRunEventBusRegistry-B0_C4OnP.cjs.map +0 -1
  81. package/dist/InMemoryRunEventBusRegistry-C2U83Hmv.js +0 -238
  82. package/dist/InMemoryRunEventBusRegistry-C2U83Hmv.js.map +0 -1
  83. package/dist/bootstrap-CL68rqWg.js.map +0 -1
  84. package/dist/bootstrap-Cko6udwL.cjs.map +0 -1
  85. package/dist/runtime-284ok0cm.js.map +0 -1
  86. package/dist/runtime-B3Og-_St.cjs.map +0 -1
@@ -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,346 @@ 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
+
258
669
  //#endregion
259
670
  //#region src/workflow/definition/NodeIterationIdFactory.ts
260
671
  /**
@@ -338,6 +749,35 @@ var WorkflowExecutableNodeClassifierFactory = class {
338
749
  }
339
750
  };
340
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
+
341
781
  //#endregion
342
782
  //#region src/events/ConnectionInvocationEventPublisher.ts
343
783
  /**
@@ -392,15 +832,6 @@ var NodeEventPublisher = class {
392
832
  }
393
833
  };
394
834
 
395
- //#endregion
396
- //#region \0@oxc-project+runtime@0.95.0/helpers/decorate.js
397
- function __decorate(decorators, target, key, desc) {
398
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
399
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
400
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
401
- return c > 3 && r && Object.defineProperty(target, key, r), r;
402
- }
403
-
404
835
  //#endregion
405
836
  //#region src/binaries/DefaultNodeBinaryAttachmentServiceFactory.ts
406
837
  var DefaultNodeBinaryAttachmentService = class DefaultNodeBinaryAttachmentService {
@@ -699,23 +1130,22 @@ var ActivationEnqueueService = class {
699
1130
  }
700
1131
  };
701
1132
 
702
- //#endregion
703
- //#region \0@oxc-project+runtime@0.95.0/helpers/decorateMetadata.js
704
- function __decorateMetadata(k, v) {
705
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
706
- }
707
-
708
- //#endregion
709
- //#region \0@oxc-project+runtime@0.95.0/helpers/decorateParam.js
710
- function __decorateParam(paramIndex, decorator) {
711
- return function(target, key) {
712
- decorator(target, key, paramIndex);
713
- };
714
- }
715
-
716
1133
  //#endregion
717
1134
  //#region src/execution/ChildExecutionScopeFactory.ts
718
- let ChildExecutionScopeFactory = class ChildExecutionScopeFactory$1 {
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 {
719
1149
  constructor(activationIdFactory) {
720
1150
  this.activationIdFactory = activationIdFactory;
721
1151
  }
@@ -741,11 +1171,6 @@ let ChildExecutionScopeFactory = class ChildExecutionScopeFactory$1 {
741
1171
  };
742
1172
  }
743
1173
  };
744
- ChildExecutionScopeFactory = __decorate([
745
- injectable(),
746
- __decorateParam(0, inject(CoreTokens.ActivationIdFactory)),
747
- __decorateMetadata("design:paramtypes", [Object])
748
- ], ChildExecutionScopeFactory);
749
1174
 
750
1175
  //#endregion
751
1176
  //#region src/contracts/itemMeta.ts
@@ -887,6 +1312,20 @@ var NodeActivationRequestInputPreparer = class {
887
1312
  }
888
1313
  };
889
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
+
890
1329
  //#endregion
891
1330
  //#region src/execution/CredentialResolverFactory.ts
892
1331
  var CredentialResolverFactory = class {
@@ -1122,6 +1561,28 @@ var NoOpExecutionTelemetryFactory = class {
1122
1561
  }
1123
1562
  };
1124
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
+
1125
1586
  //#endregion
1126
1587
  //#region src/contracts/CodemationTelemetryAttributeNames.ts
1127
1588
  var CodemationTelemetryAttributeNames = class {
@@ -1166,19 +1627,6 @@ var CodemationTelemetryMetricNames = class {
1166
1627
  static gmailAttachmentBytes = "codemation.gmail.attachment_bytes";
1167
1628
  };
1168
1629
 
1169
- //#endregion
1170
- //#region src/contracts/runFinishedAtFactory.ts
1171
- /** Derives workflow end time from persisted run root or node snapshots for run listings. */
1172
- var RunFinishedAtFactory = class {
1173
- static resolveIso(state) {
1174
- if (state.finishedAt && state.status !== "running" && state.status !== "pending") return state.finishedAt;
1175
- if (state.status === "running" || state.status === "pending") return;
1176
- let max;
1177
- for (const snap of Object.values(state.nodeSnapshotsByNodeId)) if (snap?.finishedAt && (!max || snap.finishedAt > max)) max = snap.finishedAt;
1178
- return max;
1179
- }
1180
- };
1181
-
1182
1630
  //#endregion
1183
1631
  //#region src/contracts/workflowTypes.ts
1184
1632
  function nodeRef(nodeId) {
@@ -1186,15 +1634,6 @@ function nodeRef(nodeId) {
1186
1634
  }
1187
1635
  const branchRef = (index) => `$${index}`;
1188
1636
 
1189
- //#endregion
1190
- //#region src/contracts/workflowActivationPolicy.ts
1191
- /** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */
1192
- var AllWorkflowsActiveWorkflowActivationPolicy = class {
1193
- isActive(_workflowId) {
1194
- return true;
1195
- }
1196
- };
1197
-
1198
1637
  //#endregion
1199
1638
  //#region src/execution/ExecutionTelemetryCostTrackingDecoratorFactory.ts
1200
1639
  var ExecutionTelemetryCostTrackingDecoratorFactory = class {
@@ -1268,11 +1707,12 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
1268
1707
  //#region src/execution/DefaultExecutionContextFactory.ts
1269
1708
  var DefaultExecutionContextFactory = class {
1270
1709
  telemetryDecoratorFactory = new ExecutionTelemetryCostTrackingDecoratorFactory();
1271
- 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) {
1272
1711
  this.binaryStorage = binaryStorage;
1273
1712
  this.telemetryFactory = telemetryFactory;
1274
1713
  this.costTrackingFactory = costTrackingFactory;
1275
1714
  this.currentDate = currentDate;
1715
+ this.collections = collections;
1276
1716
  }
1277
1717
  create(args) {
1278
1718
  const baseTelemetry = args.telemetry ?? this.telemetryFactory.create({
@@ -1297,7 +1737,9 @@ var DefaultExecutionContextFactory = class {
1297
1737
  nodeState: args.nodeState,
1298
1738
  telemetry,
1299
1739
  binary: new DefaultExecutionBinaryService(this.binaryStorage, args.workflowId, args.runId, this.currentDate),
1300
- getCredential: args.getCredential
1740
+ getCredential: args.getCredential,
1741
+ testContext: args.testContext,
1742
+ collections: this.collections
1301
1743
  };
1302
1744
  }
1303
1745
  };
@@ -2134,7 +2576,12 @@ var NodeInstanceFactory = class {
2134
2576
  }
2135
2577
  createNodes(workflow) {
2136
2578
  const nodeInstances = /* @__PURE__ */ new Map();
2137
- 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
+ }
2138
2585
  return nodeInstances;
2139
2586
  }
2140
2587
  createNode(definition) {
@@ -2433,7 +2880,8 @@ var WorkflowRunExecutionContextFactory = class {
2433
2880
  engineMaxSubworkflowDepth: args.engineMaxSubworkflowDepth,
2434
2881
  data: args.data,
2435
2882
  nodeState: args.nodeState,
2436
- getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId)
2883
+ getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId),
2884
+ testContext: args.testContext
2437
2885
  });
2438
2886
  }
2439
2887
  };
@@ -2600,7 +3048,8 @@ var RunContinuationService = class {
2600
3048
  engineMaxNodeActivations: limits.engineMaxNodeActivations,
2601
3049
  engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
2602
3050
  data,
2603
- 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
2604
3053
  });
2605
3054
  data.setOutputs(args.nodeId, args.outputs);
2606
3055
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -3121,7 +3570,8 @@ var RunContinuationService = class {
3121
3570
  engineMaxNodeActivations: webhookLimits.engineMaxNodeActivations,
3122
3571
  engineMaxSubworkflowDepth: webhookLimits.engineMaxSubworkflowDepth,
3123
3572
  data,
3124
- 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
3125
3575
  });
3126
3576
  const request = this.nodeActivationRequestComposer.createFromPlannedActivation({
3127
3577
  next,
@@ -3212,7 +3662,8 @@ var RunContinuationService = class {
3212
3662
  engineMaxNodeActivations: limits.engineMaxNodeActivations,
3213
3663
  engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
3214
3664
  data,
3215
- 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
3216
3667
  });
3217
3668
  const activationId = pendingExecution.activationId;
3218
3669
  return {
@@ -3604,7 +4055,7 @@ var RunPolicySnapshotFactory = class {
3604
4055
  //#endregion
3605
4056
  //#region src/orchestration/RunStartService.ts
3606
4057
  var RunStartService = class {
3607
- 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) {
3608
4059
  this.runIdFactory = runIdFactory;
3609
4060
  this.workflowExecutionRepository = workflowExecutionRepository;
3610
4061
  this.runDataFactory = runDataFactory;
@@ -3618,6 +4069,8 @@ var RunStartService = class {
3618
4069
  this.waiters = waiters;
3619
4070
  this.workflowPolicyRuntimeDefaults = workflowPolicyRuntimeDefaults;
3620
4071
  this.executionLimitsPolicy = executionLimitsPolicy;
4072
+ this.nodeEventPublisher = nodeEventPublisher;
4073
+ this.persistedRunStateTerminalBuilder = persistedRunStateTerminalBuilder;
3621
4074
  }
3622
4075
  async runWorkflow(workflow, startAt, items, parent, executionOptions, persistedStateOverrides) {
3623
4076
  const runId = this.runIdFactory.makeRunId();
@@ -3648,9 +4101,28 @@ var RunStartService = class {
3648
4101
  engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations,
3649
4102
  engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth,
3650
4103
  data,
3651
- nodeState: this.nodeStatePublisherFactory.create(runId, workflow.id, parent)
4104
+ nodeState: this.nodeStatePublisherFactory.create(runId, workflow.id, parent),
4105
+ testContext: mergedExecutionOptions.testContext
3652
4106
  });
3653
- 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;
3654
4126
  const startDefinition = topology.defsById.get(startAt);
3655
4127
  if (!startDefinition) throw new Error(`Unknown start nodeId: ${startAt}`);
3656
4128
  const initialNodeSnapshotsByNodeId = {};
@@ -3729,7 +4201,25 @@ var RunStartService = class {
3729
4201
  policySnapshot,
3730
4202
  engineCounters: { completedNodeActivations: 0 }
3731
4203
  });
3732
- 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;
3733
4223
  const plan = CurrentStateFrontierPlanner.createFromTopology(topology).plan({
3734
4224
  currentState: this.createRunCurrentState(request.currentState, mutableState),
3735
4225
  stopCondition: control.stopCondition,
@@ -3747,7 +4237,8 @@ var RunStartService = class {
3747
4237
  engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations,
3748
4238
  engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth,
3749
4239
  data,
3750
- 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
3751
4242
  });
3752
4243
  return await this.scheduleInitialPlan({
3753
4244
  runId,
@@ -3922,6 +4413,57 @@ var RunStartService = class {
3922
4413
  this.waiters.resolveRunCompletion(result);
3923
4414
  return result;
3924
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
+ }
3925
4467
  };
3926
4468
 
3927
4469
  //#endregion
@@ -4395,6 +4937,128 @@ var InMemoryRunDataFactory = class {
4395
4937
  }
4396
4938
  };
4397
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
+
4398
5062
  //#endregion
4399
5063
  //#region src/orchestration/NodeExecutionRequestHandlerService.ts
4400
5064
  var NodeExecutionRequestHandlerService = class {
@@ -4434,7 +5098,8 @@ var NodeExecutionRequestHandlerService = class {
4434
5098
  engineMaxNodeActivations: limits.engineMaxNodeActivations,
4435
5099
  engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
4436
5100
  data,
4437
- nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent)
5101
+ nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent),
5102
+ testContext: state.executionOptions?.testContext
4438
5103
  });
4439
5104
  const inputsByPort = pendingExecution.inputsByPort;
4440
5105
  const portKeys = Object.keys(inputsByPort);
@@ -4824,7 +5489,7 @@ var EngineWorkflowPlanningFactory = class {
4824
5489
  var TriggerRuntimeService = class {
4825
5490
  credentialResolverFactory;
4826
5491
  triggerCleanupHandlesByKey = /* @__PURE__ */ new Map();
4827
- 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) {
4828
5493
  this.workflowRepository = workflowRepository;
4829
5494
  this.workflowActivationPolicy = workflowActivationPolicy;
4830
5495
  this.runIdFactory = runIdFactory;
@@ -4836,6 +5501,8 @@ var TriggerRuntimeService = class {
4836
5501
  this.emitHandler = emitHandler;
4837
5502
  this.executionLimitsPolicy = executionLimitsPolicy;
4838
5503
  this.diagnostics = diagnostics;
5504
+ this.pollingTriggerRuntime = pollingTriggerRuntime;
5505
+ this.pollingTriggerDedupWindow = pollingTriggerDedupWindow;
4839
5506
  this.credentialResolverFactory = credentialResolverFactory;
4840
5507
  }
4841
5508
  async startTriggers() {
@@ -4891,6 +5558,7 @@ var TriggerRuntimeService = class {
4891
5558
  async startTriggersForWorkflow(wf) {
4892
5559
  for (const def of wf.nodes) {
4893
5560
  if (def.kind !== "trigger") continue;
5561
+ if (def.config.triggerKind === "test") continue;
4894
5562
  const node$1 = this.nodeResolver.resolve(def.type);
4895
5563
  const data = this.runDataFactory.create();
4896
5564
  const triggerRunId = this.runIdFactory.makeRunId();
@@ -4900,6 +5568,9 @@ var TriggerRuntimeService = class {
4900
5568
  };
4901
5569
  await this.stopTrigger(trigger);
4902
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);
4903
5574
  let nextState;
4904
5575
  try {
4905
5576
  nextState = await node$1.setup({
@@ -4912,12 +5583,9 @@ var TriggerRuntimeService = class {
4912
5583
  trigger,
4913
5584
  config: def.config,
4914
5585
  previousState: previousState?.state,
4915
- registerCleanup: (cleanup) => {
4916
- this.registerTriggerCleanupHandle(trigger, cleanup);
4917
- },
4918
- emit: async (items) => {
4919
- await this.emitHandler.emit(wf, def.id, items);
4920
- }
5586
+ registerCleanup,
5587
+ emit,
5588
+ polling
4921
5589
  });
4922
5590
  } catch (triggerError) {
4923
5591
  await this.stopTrigger(trigger);
@@ -4936,6 +5604,7 @@ var TriggerRuntimeService = class {
4936
5604
  async stopTriggersForWorkflow(workflow) {
4937
5605
  for (const node$1 of workflow.nodes) {
4938
5606
  if (node$1.kind !== "trigger") continue;
5607
+ if (node$1.config.triggerKind === "test") continue;
4939
5608
  await this.stopTrigger({
4940
5609
  workflowId: workflow.id,
4941
5610
  nodeId: node$1.id
@@ -4976,6 +5645,7 @@ var TriggerRuntimeService = class {
4976
5645
  const out = [];
4977
5646
  for (const def of wf.nodes) {
4978
5647
  if (def.kind !== "trigger") continue;
5648
+ if (def.config.triggerKind === "test") continue;
4979
5649
  out.push(this.describeTriggerNode(def));
4980
5650
  }
4981
5651
  return out;
@@ -4993,6 +5663,22 @@ var TriggerRuntimeService = class {
4993
5663
  if (this.diagnostics) this.diagnostics.warn(message);
4994
5664
  else console.warn(`[engine] ${message}`);
4995
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
+ }
4996
5682
  isTestableTriggerNode(node$1) {
4997
5683
  return typeof node$1.getTestItems === "function";
4998
5684
  }
@@ -5144,12 +5830,15 @@ var EngineFactory = class {
5144
5830
  const storagePolicyEvaluator = new WorkflowStoragePolicyEvaluator(deps.nodeResolver);
5145
5831
  const terminalPersistence = new RunTerminalPersistenceCoordinator(deps.workflowExecutionRepository, storagePolicyEvaluator);
5146
5832
  const policyErrorServices = new WorkflowPolicyErrorServices(deps.nodeResolver);
5147
- 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);
5148
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);
5149
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);
5150
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) => {
5151
5840
  await runStartService.runWorkflow(workflow, triggerNodeId, items, void 0);
5152
- } }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics);
5841
+ } }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics, pollingTriggerRuntime, pollingTriggerDedupWindow);
5153
5842
  const engine = new Engine({
5154
5843
  liveWorkflowRepository: deps.liveWorkflowRepository,
5155
5844
  tokenRegistry: deps.tokenRegistry,
@@ -5440,5 +6129,5 @@ var WorkflowRepositoryWebhookTriggerMatcherFactory = class {
5440
6129
  };
5441
6130
 
5442
6131
  //#endregion
5443
- export { CostTrackingTelemetryMetricNames as $, NodeExecutor as A, StackTraceCallSitePathResolver as At, nodeRef as B, registry as Bt, StaticCostCatalog as C, resolveItemExprsInUnknown as Ct, PersistedWorkflowTokenRegistry as D, tool as Dt, WorkflowSnapshotCodec as E, node as Et, InProcessRetryRunner as F, injectAll as Ft, NoOpExecutionTelemetryFactory as G, CodemationTelemetryMetricNames as H, CoreTokens as Ht, CatalogBackedCostTrackingTelemetryFactory as I, injectable as It, NoOpTelemetrySpanScope as J, NoOpExecutionTelemetry as K, DefaultExecutionContextFactory as L, instanceCachingFactory as Lt, RunnableOutputBehaviorResolver as M, container$1 as Mt, NodeOutputNormalizer as N, delay as Nt, MissingRuntimeTriggerToken as O, InjectableRuntimeDecoratorComposer as Ot, ItemExprResolver as P, inject as Pt, CostTrackingTelemetryAttributeNames as Q, AllWorkflowsActiveWorkflowActivationPolicy as R, instancePerContainerCachingFactory as Rt, RunPolicySnapshotFactory as S, resolveItemExprsForExecution as St, NodeInstanceFactory as T, getPersistedRuntimeTypeMetadata as Tt, GenAiTelemetryAttributeNames as U, RunFinishedAtFactory as V, singleton as Vt, CodemationTelemetryAttributeNames as W, NoOpCostTrackingTelemetryFactory as X, NoOpTelemetryArtifactReference as Y, NoOpCostTrackingTelemetry as Z, LocalOnlyScheduler as _, WorkflowExecutableNodeClassifier as _t, InMemoryLiveWorkflowRepository as a, isPortsEmission as at, DefaultDrivingScheduler as b, isItemExpr as bt, EngineFactory as c, CredentialResolverFactory as ct, InMemoryBinaryStorage as d, DefaultExecutionBinaryService as dt, CredentialUnboundError as et, WorkflowStoragePolicyEvaluator as f, UnavailableBinaryStorage as ft, EngineExecutionLimitsPolicy as g, WorkflowExecutableNodeClassifierFactory as gt, ENGINE_EXECUTION_LIMITS_DEFAULTS as h, ConnectionInvocationEventPublisher as ht, RunIntentService as i, emitPorts as it, InProcessRetryRunnerFactory as j, PersistedRuntimeTypeNameResolver as jt, NodeExecutorFactory as k, PersistedRuntimeTypeMetadataStore as kt, Engine as l, getOriginIndexFromItem as lt, RunTerminalPersistenceCoordinator as m, NodeEventPublisher as mt, WorkflowRepositoryWebhookTriggerMatcher as n, RetryPolicy as nt, EngineWorkflowRunnerServiceFactory as o, isUnbrandedPortsEmissionShape as ot, WorkflowPolicyErrorServices as p, __decorate 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, ChildExecutionScopeFactory as ut, InlineDrivingScheduler as v, NodeIterationIdFactory as vt, NodeInstanceFactoryFactory as w, chatModel as wt, ConfigDrivenOffloadPolicy as x, itemExpr as xt, HintOnlyOffloadPolicy as y, ConnectionNodeIdFactory as yt, branchRef as z, predicateAwareClassFactory as zt };
5444
- //# sourceMappingURL=runtime-284ok0cm.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