@oomol-lab/open-flow 0.1.0-beta.64 → 0.1.0-beta.66

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 (50) hide show
  1. package/dist/browser/{createResourceDialog-BAJXbzNH.js → createResourceDialog-C-Si_cYs.js} +2 -2
  2. package/dist/browser/flow-authoring-node.d.ts +12 -3
  3. package/dist/browser/flow-authoring.js +135 -21
  4. package/dist/browser/flow-change-schema.d.ts +3 -1
  5. package/dist/browser/flow-change.d.ts +15 -3
  6. package/dist/browser/flow-change.js +111 -16
  7. package/dist/browser/{flowChanges-BAMkSaKF.js → flowChanges-T4_R5p1f.js} +3031 -2124
  8. package/dist/browser/{flowRunInputEditorStore-B2Rw4VsT.js → flowRunInputEditorStore-DJqmR6Qh.js} +3 -2
  9. package/dist/browser/{flowWorkspace-DxLc1Ybv.js → flowWorkspace-C0J5C0oM.js} +754 -163
  10. package/dist/browser/{icons-Db2Jb2iX.js → icons-BD3m0RQq.js} +4484 -4370
  11. package/dist/browser/preview.css +160 -64
  12. package/dist/browser/preview.js +6487 -5232
  13. package/dist/browser/ui.css +93 -3
  14. package/dist/browser/ui.js +8 -5
  15. package/dist/browser/workbench.css +160 -64
  16. package/dist/browser/workbench.js +175 -59
  17. package/dist/browser/{workbenchSelect-C-jf6NIM.js → workbenchSelect-B-PFpF_Q.js} +1 -1
  18. package/dist/command/index.js +49 -49
  19. package/dist/common/authoring.d.ts +7 -5
  20. package/dist/common/authoringExamples.d.ts +3 -3
  21. package/dist/common/authoringFields.d.ts +20 -0
  22. package/dist/common/authoringSchema.d.ts +404 -15
  23. package/dist/common/connectorDecoders.d.ts +2 -1
  24. package/dist/common/control-api-conformance.js +403 -137
  25. package/dist/common/control-api.d.ts +70 -7
  26. package/dist/common/control-api.js +3587 -3428
  27. package/dist/common/control-requests.d.ts +10 -3
  28. package/dist/common/control-requests.js +463 -48
  29. package/dist/common/decision.js +28 -3
  30. package/dist/common/flow-encoding.d.ts +4 -2
  31. package/dist/common/flow-encoding.js +144 -10
  32. package/dist/common/flow-graph.d.ts +1 -1
  33. package/dist/common/flow-semantics.d.ts +12 -2
  34. package/dist/common/flow-semantics.js +152 -33
  35. package/dist/common/integration-trigger.js +28 -3
  36. package/dist/common/liveDetails.d.ts +26 -11
  37. package/dist/common/mcp.d.ts +6 -3
  38. package/dist/common/mcp.js +3541 -3403
  39. package/dist/common/openapi.js +28 -3
  40. package/dist/common/poll-trigger.js +28 -3
  41. package/dist/common/run-events.d.ts +2 -0
  42. package/dist/common/run-events.js +9 -3
  43. package/dist/common/scheduler.d.ts +11 -1
  44. package/dist/common/scheduler.js +216 -48
  45. package/dist/common/trigger-contract.d.ts +2 -0
  46. package/dist/common/webhook-trigger.js +28 -3
  47. package/dist/common/workflow.d.ts +93 -0
  48. package/dist/common/workflow.js +10491 -0
  49. package/package.json +5 -1
  50. package/skills/open-flow/references/flow-authoring.md +26 -16
@@ -9504,6 +9504,7 @@ var port = object({
9504
9504
  nullable: boolean(),
9505
9505
  handle: text
9506
9506
  });
9507
+ var workflowInputDefs = array(port.strict());
9507
9508
  var input = port.extend({ value: json.optional() });
9508
9509
  var group = object({
9509
9510
  collapsed: boolean().optional(),
@@ -9661,6 +9662,11 @@ var managedFields = object({
9661
9662
  messageHandle: text,
9662
9663
  inputs: record$1(text, agentValue)
9663
9664
  }).optional()
9665
+ }),
9666
+ strictObject({
9667
+ kind: literal("workflow"),
9668
+ flowId: text,
9669
+ revisionId: text
9664
9670
  })
9665
9671
  ])
9666
9672
  });
@@ -9769,6 +9775,12 @@ var base = {
9769
9775
  timeoutMs: number().optional()
9770
9776
  };
9771
9777
  var node = union([
9778
+ strictObject({
9779
+ ...base,
9780
+ kind: literal("outputs"),
9781
+ outputDefs: array(port.strict()),
9782
+ outputMappings: inputs
9783
+ }).omit({ inputs: true }),
9772
9784
  object({
9773
9785
  ...base,
9774
9786
  inputs: record$1(text, never()),
@@ -9801,6 +9813,11 @@ var node = union([
9801
9813
  ...trigger,
9802
9814
  kind: literal("manual")
9803
9815
  }),
9816
+ strictObject({
9817
+ ...trigger,
9818
+ kind: literal("start"),
9819
+ inputDefs: workflowInputDefs
9820
+ }),
9804
9821
  strictObject({
9805
9822
  ...trigger,
9806
9823
  kind: literal("error"),
@@ -9865,7 +9882,7 @@ var module = object({
9865
9882
  imports: strings,
9866
9883
  source: text
9867
9884
  });
9868
- var document = preprocess(rejectRetiredDefinitions, object({
9885
+ var document = preprocess(normalizeDocument, object({
9869
9886
  bindings: record$1(text, binding),
9870
9887
  graph
9871
9888
  }));
@@ -9874,7 +9891,9 @@ object({
9874
9891
  literal(2),
9875
9892
  literal(4),
9876
9893
  literal(5),
9877
- literal(6)
9894
+ literal(6),
9895
+ literal(7),
9896
+ literal(8)
9878
9897
  ]),
9879
9898
  document,
9880
9899
  modules: record$1(text, module)
@@ -9882,13 +9901,19 @@ object({
9882
9901
  kind: literal("open-flow-flow-revision"),
9883
9902
  version: literal(1)
9884
9903
  });
9885
- function rejectRetiredDefinitions(value) {
9904
+ function normalizeDocument(value) {
9886
9905
  const candidate = record(value);
9887
9906
  if (candidate.tasks !== void 0 && (candidate.tasks === null || typeof candidate.tasks !== "object" || Array.isArray(candidate.tasks) || Object.keys(candidate.tasks).length > 0)) throw new TypeError("Independent Task definitions are no longer supported.");
9888
9907
  if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => Object.hasOwn(record(candidateNode), "taskId"))) throw new TypeError("Task references are no longer supported.");
9889
9908
  const subflows = candidate.subflows;
9890
9909
  if (subflows !== void 0 && (subflows === null || typeof subflows !== "object" || Array.isArray(subflows) || Object.keys(subflows).length > 0)) throw new TypeError("Subflows are no longer supported.");
9891
9910
  if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => record(candidateNode).kind === "subflow")) throw new TypeError("Subflow nodes are no longer supported.");
9911
+ if ([
9912
+ "inputDefs",
9913
+ "outputDefs",
9914
+ "outputMappings"
9915
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
9916
+ if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => record(candidateNode).kind == "start" && Object.hasOwn(record(candidateNode), "parameters"))) throw new TypeError("Legacy Start.parameters is unsupported; configure node.inputDefs.");
9892
9917
  return value;
9893
9918
  }
9894
9919
  function record(value) {
@@ -10088,6 +10113,7 @@ function conditionOperands(node) {
10088
10113
  }] : []])));
10089
10114
  }
10090
10115
  function nodeInputMappings(node) {
10116
+ if (node.kind == "outputs") return node.outputMappings;
10091
10117
  if (node.kind != "condition") return "inputs" in node ? node.inputs : {};
10092
10118
  return Object.fromEntries(conditionOperands(node).flatMap(({ handle, operand }) => operand.kind == "source" ? [[handle, {
10093
10119
  kind: "sources",
@@ -10243,6 +10269,17 @@ function selectConditionBranches(node, values) {
10243
10269
  function portsByHandle(ports) {
10244
10270
  return Object.fromEntries(ports.flatMap((port) => "handle" in port ? [[port.handle, port]] : []));
10245
10271
  }
10272
+ function isTriggerNode(node) {
10273
+ return [
10274
+ "manual",
10275
+ "start",
10276
+ "error",
10277
+ "webhook",
10278
+ "cron",
10279
+ "poll",
10280
+ "integration"
10281
+ ].includes(node.kind);
10282
+ }
10246
10283
  //#endregion
10247
10284
  //#region src/flow/common/agent.ts
10248
10285
  var schema = lazy(() => union([boolean(), strictObject({
@@ -10515,6 +10552,7 @@ function triggerOutputDefinitions(trigger) {
10515
10552
  switch (trigger.kind) {
10516
10553
  case "error": return errorOutputs;
10517
10554
  case "manual": return [];
10555
+ case "start": return trigger.inputDefs;
10518
10556
  case "cron": return cronOutputs;
10519
10557
  case "poll":
10520
10558
  case "integration": return trigger.definition.outputs;
@@ -10534,11 +10572,37 @@ function matchesTriggerOutputs(trigger, outputs) {
10534
10572
  const ports = triggerOutputDefinitions(trigger);
10535
10573
  return new Set(ports.map((port) => port.handle)).size === ports.length && Object.keys(outputs).length === ports.length && ports.every((port) => Object.hasOwn(outputs, port.handle) && (outputs[port.handle] === null && port.nullable || matchesSchema(outputs[port.handle], port.jsonSchema)));
10536
10574
  }
10575
+ /** Resolve caller-supplied Start parameters into the complete output snapshot used by execution. */
10576
+ function normalizeTriggerOutputs(trigger, outputs) {
10577
+ if (!isJsonObject(outputs)) return;
10578
+ const normalized = trigger.kind == "start" ? {
10579
+ ...outputs,
10580
+ ...Object.fromEntries(trigger.inputDefs.filter((port) => port.nullable && !Object.hasOwn(outputs, port.handle)).map((port) => [port.handle, null]))
10581
+ } : outputs;
10582
+ return matchesTriggerOutputs(trigger, normalized) ? normalized : void 0;
10583
+ }
10537
10584
  //#endregion
10538
10585
  //#region src/flow/common/graph.ts
10539
10586
  function isResolutionNode(node) {
10540
10587
  return node?.kind == "approval" || node?.kind == "wait";
10541
10588
  }
10589
+ function nodeInputPorts(node) {
10590
+ switch (node.kind) {
10591
+ case "outputs": return portsByHandle(node.outputDefs);
10592
+ case "condition": return conditionInputPorts(node);
10593
+ case "value": return {};
10594
+ case "task": return portsByHandle([...node.task.inputs, ...node.additionalInputs ?? []]);
10595
+ case "approval":
10596
+ case "wait": return portsByHandle(node.inputDefinitions);
10597
+ case "cron":
10598
+ case "integration":
10599
+ case "poll":
10600
+ case "error":
10601
+ case "manual":
10602
+ case "start":
10603
+ case "webhook": return {};
10604
+ }
10605
+ }
10542
10606
  function resolutionActions(node) {
10543
10607
  return node.kind == "wait" ? ["continue"] : ["approve", "reject"];
10544
10608
  }
@@ -10563,6 +10627,12 @@ function resolutionOutputPorts(node) {
10563
10627
  pending: objectPort({
10564
10628
  inputs,
10565
10629
  prompt: { type: "string" },
10630
+ pageUrl: { type: "string" },
10631
+ message: {
10632
+ type: "string",
10633
+ minLength: 1,
10634
+ pattern: "\\S"
10635
+ },
10566
10636
  ...Object.fromEntries(actions.map((action) => [`${action}Url`, { type: "string" }])),
10567
10637
  expiresAt: { type: "string" }
10568
10638
  }),
@@ -10576,6 +10646,7 @@ function resolutionOutputPorts(node) {
10576
10646
  }
10577
10647
  function nodeOutputPorts(node) {
10578
10648
  switch (node.kind) {
10649
+ case "outputs":
10579
10650
  case "condition": return {};
10580
10651
  case "value": return portsByHandle(node.values);
10581
10652
  case "task": return portsByHandle(node.task.outputs);
@@ -10586,6 +10657,7 @@ function nodeOutputPorts(node) {
10586
10657
  case "poll":
10587
10658
  case "error":
10588
10659
  case "manual":
10660
+ case "start":
10589
10661
  case "webhook": return triggerOutputPorts(node);
10590
10662
  }
10591
10663
  }
@@ -10652,7 +10724,7 @@ var Dependencies = class {
10652
10724
  stack.delete(id);
10653
10725
  };
10654
10726
  const ids = Object.keys(graph.nodes).toSorted();
10655
- for (const triggerId of ids.filter((id) => !("inputs" in graph.nodes[id]))) visit(triggerId);
10727
+ for (const triggerId of ids.filter((id) => isTriggerNode(graph.nodes[id]))) visit(triggerId);
10656
10728
  for (const id of ids) visit(id);
10657
10729
  for (const edge of this.forward) {
10658
10730
  const edges = this.incoming.get(edge.target) ?? [];
@@ -10727,7 +10799,7 @@ var Dependencies = class {
10727
10799
  }
10728
10800
  start(nodeId, outputs) {
10729
10801
  for (const [id, node] of Object.entries(this.graph.nodes)) {
10730
- if ("inputs" in node) continue;
10802
+ if (!isTriggerNode(node)) continue;
10731
10803
  const state = this.state.nodes[id];
10732
10804
  state.status = id == nodeId ? "completed" : "skipped";
10733
10805
  if (id == nodeId) {
@@ -10875,12 +10947,28 @@ var waitCommentSchema = string().trim().refine((value) => [...value].length <= 2
10875
10947
  function normalizeWaitComment$1(value) {
10876
10948
  return waitCommentSchema.parse(value) || null;
10877
10949
  }
10950
+ function withWaitNotificationMessage$1(value) {
10951
+ const source = schemaObject(value);
10952
+ if (source == null || source.pageUrl !== void 0 && source.message !== void 0) return value;
10953
+ const pageUrl = source.pageUrl === void 0 ? source.continueUrl ?? source.approveUrl : source.pageUrl;
10954
+ if (typeof pageUrl != "string" || typeof source.prompt != "string" || typeof source.expiresAt != "string") return value;
10955
+ return {
10956
+ ...source,
10957
+ pageUrl,
10958
+ message: source.message === void 0 ? [
10959
+ source.prompt,
10960
+ `Expires at: ${source.expiresAt}`,
10961
+ `Review request: ${pageUrl}`
10962
+ ].join("\n\n") : source.message
10963
+ };
10964
+ }
10878
10965
  //#endregion
10879
10966
  //#region src/execution/common/scheduler.ts
10967
+ var withWaitNotificationMessage = withWaitNotificationMessage$1;
10880
10968
  var normalizeWaitComment = normalizeWaitComment$1;
10881
10969
  var PortValidationError = class extends Error {};
10882
10970
  function usesPending(graph, nodeId) {
10883
- return graph.edges.some((edge) => edge.source == nodeId && edge.sourceHandle == "pending") || Object.values(graph.nodes).some((node) => "inputs" in node && Object.values(node.inputs).some((mapping) => mapping.kind == "sources" && mapping.sources.some((source) => source.kind == "node" && source.nodeId == nodeId && source.output == "pending")));
10971
+ return graph.edges.some((edge) => edge.source == nodeId && edge.sourceHandle == "pending") || Object.values(graph.nodes).some((node) => !isTriggerNode(node) && Object.values(nodeInputMappings(node)).some((mapping) => mapping.kind == "sources" && mapping.sources.some((source) => source.kind == "node" && source.nodeId == nodeId && source.output == "pending")));
10884
10972
  }
10885
10973
  var waitRetentionMs = 12e4;
10886
10974
  function nodeFailure(error, project) {
@@ -10889,19 +10977,11 @@ function nodeFailure(error, project) {
10889
10977
  message: error instanceof Error ? error.message : String(error)
10890
10978
  };
10891
10979
  }
10892
- function nodePorts(node) {
10893
- switch (node.kind) {
10894
- case "condition": return conditionInputPorts(node);
10895
- case "value": return {};
10896
- case "task": return portsByHandle([...node.task.inputs, ...node.additionalInputs ?? []]);
10897
- case "approval":
10898
- case "wait": return portsByHandle(node.inputDefinitions);
10899
- }
10900
- }
10901
10980
  function nodeTitle(node) {
10902
10981
  if (node.name != null) return node.name;
10903
10982
  switch (node.kind) {
10904
10983
  case "condition": return;
10984
+ case "outputs": return "Workflow Outputs";
10905
10985
  case "value": return "Fixed Values";
10906
10986
  case "task": return node.task.name;
10907
10987
  case "approval": return "Approval";
@@ -10957,7 +11037,8 @@ function decodeFlowRunCheckpoint(input) {
10957
11037
  "inputs",
10958
11038
  "results",
10959
11039
  "version",
10960
- "waits"
11040
+ "waits",
11041
+ ...source.calls === void 0 ? [] : ["calls"]
10961
11042
  ], "Flow Run checkpoint");
10962
11043
  if (source.version != 5) throw new Error("Flow Run checkpoint version is unsupported.");
10963
11044
  const bindingValues = Object.fromEntries(Object.entries(checkpointRecord(source.bindingValues, "Checkpoint bindings")).map(([id, value]) => {
@@ -10981,7 +11062,14 @@ function decodeFlowRunCheckpoint(input) {
10981
11062
  value: json$1(),
10982
11063
  waitId: string().min(1),
10983
11064
  pending: json$1().optional()
10984
- })).min(1).parse(source.waits);
11065
+ })).parse(source.waits);
11066
+ const calls = array(strictObject({
11067
+ jobId: string().min(1),
11068
+ nodeId: string().min(1),
11069
+ childRunId: string().min(1),
11070
+ input: record$1(string(), json$1())
11071
+ })).parse(source.calls ?? []);
11072
+ if (pendingWaits.length + calls.length == 0) throw new Error("Checkpoint has no pending execution.");
10985
11073
  const agents = record$1(string(), strictObject({
10986
11074
  invocationId: string().min(1),
10987
11075
  input: record$1(string(), json$1()),
@@ -10995,6 +11083,10 @@ function decodeFlowRunCheckpoint(input) {
10995
11083
  jobs.add(pending.jobId);
10996
11084
  waits.add(pending.waitId);
10997
11085
  }
11086
+ for (const call of calls) {
11087
+ if (jobs.has(call.jobId) || dependencies.nodes[call.nodeId]?.status != "running" || dependencies.nodes[call.nodeId]?.jobId != call.jobId || Object.values(results).some((result) => result.jobId == call.jobId)) throw new Error("Checkpoint call execution conflicts.");
11088
+ jobs.add(call.jobId);
11089
+ }
10998
11090
  if (Object.values(dependencies.nodes).some((state) => state.status == "running" && !jobs.has(state.jobId))) throw new Error("Checkpoint dependency has no waiting execution.");
10999
11091
  if (Object.keys(agents).some((id) => !jobs.has(id))) throw new Error("Checkpoint Agent has no waiting execution.");
11000
11092
  return {
@@ -11005,7 +11097,8 @@ function decodeFlowRunCheckpoint(input) {
11005
11097
  inputs,
11006
11098
  results,
11007
11099
  version: 5,
11008
- waits: pendingWaits
11100
+ waits: pendingWaits,
11101
+ ...source.calls === void 0 ? {} : { calls }
11009
11102
  };
11010
11103
  }
11011
11104
  function jsonEqual(left, right) {
@@ -11057,14 +11150,14 @@ function agentApproval(config, checkpoint, inputs) {
11057
11150
  }
11058
11151
  function validateOutputs(nodeId, node, value) {
11059
11152
  const raw = outputRecord(value, nodeId);
11060
- const discardUndeclared = node.kind == "task" && "executor" in node.task && node.task.executor.kind == "connector";
11061
- const ports = isResolutionNode(node) ? resolutionOutputPorts(node) : node.kind == "task" ? portsByHandle(node.task.outputs) : node.kind == "value" ? portsByHandle(node.values) : {};
11153
+ const discardUndeclared = node.kind == "task" && "executor" in node.task && (node.task.executor.kind == "connector" || node.task.executor.kind == "workflow");
11154
+ const ports = node.kind == "outputs" ? nodeInputPorts(node) : isResolutionNode(node) ? resolutionOutputPorts(node) : node.kind == "task" ? portsByHandle(node.task.outputs) : node.kind == "value" ? portsByHandle(node.values) : {};
11062
11155
  const outputs = outputRecord(checkpointJson(Object.fromEntries(Object.entries(raw).map(([handle, item]) => [handle, Object.hasOwn(ports, handle) && item === void 0 ? null : item])), `Node "${nodeId}" outputs`), nodeId);
11063
11156
  const complete = node.kind == "condition" || isResolutionNode(node) ? outputs : {
11064
11157
  ...Object.fromEntries(Object.keys(ports).map((handle) => [handle, null])),
11065
11158
  ...outputs
11066
11159
  };
11067
- const validated = {};
11160
+ const validated = [];
11068
11161
  for (const [handle, output] of Object.entries(complete)) {
11069
11162
  const port = ports[handle];
11070
11163
  if (port == null) {
@@ -11072,9 +11165,9 @@ function validateOutputs(nodeId, node, value) {
11072
11165
  throw new PortValidationError(`Node "${nodeId}" output "${handle}" does not match its declaration.`);
11073
11166
  }
11074
11167
  if (!(output === null && port.nullable) && !matchesSchema(output, port.jsonSchema)) throw new PortValidationError(`Node "${nodeId}" output "${handle}" does not match its declaration.`);
11075
- validated[handle] = output;
11168
+ validated.push([handle, output]);
11076
11169
  }
11077
- return validated;
11170
+ return Object.fromEntries(validated);
11078
11171
  }
11079
11172
  function validateCheckpoint(target, checkpoint, resolveInputs) {
11080
11173
  const launch = checkpoint.inputs;
@@ -11085,14 +11178,14 @@ function validateCheckpoint(target, checkpoint, resolveInputs) {
11085
11178
  if (graph == null) throw new Error("Checkpoint execution counts reference an unknown graph.");
11086
11179
  for (const [id, count] of Object.entries(counts)) {
11087
11180
  const node = graph.nodes[id];
11088
- if (node == null || !("inputs" in node) || count > (node.maxExecutions ?? 1e3)) throw new Error("Checkpoint execution count is invalid.");
11181
+ if (node == null || isTriggerNode(node) || count > (node.maxExecutions ?? 1e3)) throw new Error("Checkpoint execution count is invalid.");
11089
11182
  }
11090
11183
  }
11091
11184
  const validateResults = (results, frame = false) => {
11092
11185
  for (const [id, outputs] of Object.entries(results)) {
11093
11186
  const node = target.graph.nodes[id];
11094
11187
  if (node == null) throw new Error("Checkpoint result node is missing.");
11095
- if (!("inputs" in node)) {
11188
+ if (isTriggerNode(node)) {
11096
11189
  if (!matchesTriggerOutputs(node, outputs)) throw new Error("Checkpoint Trigger output is invalid.");
11097
11190
  } else {
11098
11191
  if (checkpoint.counts[""]?.[id] == null) throw new Error("Checkpoint execution count is missing.");
@@ -11103,20 +11196,20 @@ function validateCheckpoint(target, checkpoint, resolveInputs) {
11103
11196
  }
11104
11197
  };
11105
11198
  validateResults(Object.fromEntries(Object.entries(checkpoint.results).map(([id, result]) => [id, result.outputs])));
11106
- const triggerIds = Object.keys(checkpoint.results).filter((id) => !("inputs" in target.graph.nodes[id]));
11199
+ const triggerIds = Object.keys(checkpoint.results).filter((id) => isTriggerNode(target.graph.nodes[id]));
11107
11200
  if (triggerIds.length != 1) throw new Error("Checkpoint must contain exactly one selected Trigger.");
11108
11201
  const pendingCounts = /* @__PURE__ */ new Map();
11109
- for (const waiting of checkpoint.waits) pendingCounts.set(waiting.nodeId, (pendingCounts.get(waiting.nodeId) ?? 0) + 1);
11202
+ for (const waiting of [...checkpoint.waits, ...checkpoint.calls ?? []]) pendingCounts.set(waiting.nodeId, (pendingCounts.get(waiting.nodeId) ?? 0) + 1);
11110
11203
  for (const [id, count] of pendingCounts) if ((checkpoint.counts[""]?.[id] ?? 0) < count + (checkpoint.results[id] == null ? 0 : 1)) throw new Error("Checkpoint waiting execution count is incomplete.");
11111
11204
  for (const [id, values] of Object.entries(launch)) {
11112
11205
  const node = target.graph.nodes[id];
11113
- if (!("inputs" in node) || Object.keys(values).some((handle) => nodePorts(node)[handle] == null)) throw new Error("Checkpoint launch inputs do not match the prepared graph.");
11206
+ if (isTriggerNode(node) || Object.keys(values).some((handle) => nodeInputPorts(node)[handle] == null)) throw new Error("Checkpoint launch inputs do not match the prepared graph.");
11114
11207
  }
11115
11208
  for (const [nodeId, state] of Object.entries(checkpoint.dependencies.nodes)) {
11116
11209
  const frame = dependencyValues(state.input);
11117
11210
  validateResults(frame, true);
11118
- if ("inputs" in target.graph.nodes[nodeId] && (state.status == "running" || state.status == "completed")) {
11119
- const triggers = Object.keys(frame).filter((id) => !("inputs" in target.graph.nodes[id]));
11211
+ if (!isTriggerNode(target.graph.nodes[nodeId]) && (state.status == "running" || state.status == "completed")) {
11212
+ const triggers = Object.keys(frame).filter((id) => isTriggerNode(target.graph.nodes[id]));
11120
11213
  if (triggers.length != 1 || triggers[0] != triggerIds[0] || !jsonEqual(frame[triggers[0]], checkpoint.results[triggers[0]].outputs)) throw new Error("Checkpoint input Trigger does not match the Run.");
11121
11214
  }
11122
11215
  if (state.output != null) validateResults({ [nodeId]: state.output }, state.status == "running");
@@ -11125,9 +11218,13 @@ function validateCheckpoint(target, checkpoint, resolveInputs) {
11125
11218
  if (result == null || state.jobId != null && state.jobId != result.jobId || !jsonEqual(state.output, result.outputs)) throw new Error("Checkpoint completed dependency conflicts with its result.");
11126
11219
  }
11127
11220
  }
11221
+ for (const call of checkpoint.calls ?? []) {
11222
+ const node = target.graph.nodes[call.nodeId];
11223
+ if (node?.kind != "task" || !("executor" in node.task) || node.task.executor.kind != "workflow" || !jsonEqual(resolveInputs(call.nodeId, node), call.input) || checkpoint.agents[call.jobId] != null || checkpoint.dependencies.nodes[call.nodeId]?.output != null) throw new Error("Checkpoint workflow call does not match its node.");
11224
+ }
11128
11225
  for (const waiting of checkpoint.waits) {
11129
11226
  const node = target.graph.nodes[waiting.nodeId];
11130
- if (node == null || !("inputs" in node)) throw new Error("Checkpoint waiting node is missing.");
11227
+ if (node == null || isTriggerNode(node)) throw new Error("Checkpoint waiting node is missing.");
11131
11228
  const state = checkpoint.dependencies.nodes[waiting.nodeId];
11132
11229
  const expectedOutput = waiting.pending == null ? void 0 : { pending: waiting.pending };
11133
11230
  if (state.output == null != (expectedOutput == null) || state.output != null && !jsonEqual(state.output, expectedOutput)) throw new Error("Checkpoint waiting dependency output is inconsistent.");
@@ -11156,7 +11253,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11156
11253
  runId,
11157
11254
  type: "run.started"
11158
11255
  });
11159
- const order = Object.keys(target.graph.nodes).filter((id) => "inputs" in target.graph.nodes[id]);
11256
+ const order = Object.keys(target.graph.nodes).filter((id) => !isTriggerNode(target.graph.nodes[id]));
11160
11257
  const outgoing = /* @__PURE__ */ new Map();
11161
11258
  for (const edge of target.graph.edges) {
11162
11259
  const targets = outgoing.get(edge.source) ?? [];
@@ -11171,10 +11268,10 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11171
11268
  if (resume == null) {
11172
11269
  if (trigger != null) {
11173
11270
  const node = target.graph.nodes[trigger.nodeId];
11174
- if (node == null || "inputs" in node || !matchesTriggerOutputs(node, trigger.outputs)) throw new Error("Trigger outputs are invalid.");
11271
+ if (node == null || !isTriggerNode(node) || !matchesTriggerOutputs(node, trigger.outputs)) throw new Error("Trigger outputs are invalid.");
11175
11272
  }
11176
11273
  for (const [id, node] of Object.entries(target.graph.nodes)) {
11177
- if ("inputs" in node) continue;
11274
+ if (!isTriggerNode(node)) continue;
11178
11275
  if (trigger?.nodeId == id) completed.set(id, {
11179
11276
  jobId: id,
11180
11277
  outputs: trigger.outputs
@@ -11185,6 +11282,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11185
11282
  const runNode = yield* FiberSet.runtime(active)();
11186
11283
  let firstCause;
11187
11284
  let firstFailure;
11285
+ const pendingCalls = new Map((resume?.checkpoint.calls ?? []).map((call) => [call.jobId, call]));
11188
11286
  const pendingWaits = new Map((resume?.checkpoint.waits ?? []).map((wait) => [wait.jobId, wait]));
11189
11287
  const changes = yield* Queue.unbounded();
11190
11288
  let remainingMs = context.remainingMs;
@@ -11214,7 +11312,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11214
11312
  const resolveInputs = (nodeId, node) => {
11215
11313
  const mappings = nodeInputMappings(node);
11216
11314
  const frame = dependencies.inputValues(nodeId);
11217
- return Object.fromEntries(Object.entries(nodePorts(node)).map(([handle, port]) => [handle, resolveInput(mappings[handle], port, launch[nodeId]?.[handle], `Node "${nodeId}" input "${handle}"`, frame, node.kind == "condition")]));
11315
+ return Object.fromEntries(Object.entries(nodeInputPorts(node)).map(([handle, port]) => [handle, resolveInput(mappings[handle], port, launch[nodeId]?.[handle], `Node "${nodeId}" input "${handle}"`, frame, node.kind == "condition")]));
11218
11316
  };
11219
11317
  const commit = (nodeId, jobId, outputs, releasedHandles = Object.keys(outputs)) => Effect.uninterruptible(Effect.gen(function* () {
11220
11318
  yield* context.emit({
@@ -11243,7 +11341,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11243
11341
  const mapping = nodeInputMappings(node)[handle];
11244
11342
  return mapping?.kind != "sources" || mapping.sources.every((source) => source.kind != "binding");
11245
11343
  }));
11246
- if (resolution == null) yield* context.emit({
11344
+ if (resolution == null && !pendingCalls.has(jobId)) yield* context.emit({
11247
11345
  inputs: projectedInputs,
11248
11346
  jobId,
11249
11347
  nodeId,
@@ -11254,6 +11352,9 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11254
11352
  });
11255
11353
  let outputs;
11256
11354
  switch (node.kind) {
11355
+ case "outputs":
11356
+ outputs = nodeInputs;
11357
+ break;
11257
11358
  case "condition": return {
11258
11359
  kind: "completed",
11259
11360
  outputs: {},
@@ -11267,6 +11368,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11267
11368
  const previousIds = dependencies.state.nodes[nodeId].previous;
11268
11369
  const additional = new Set((node.additionalInputs ?? []).map((port) => port.handle));
11269
11370
  const result = yield* context.invokeTask({
11371
+ ...pendingCalls.has(jobId) ? { workflowRunId: pendingCalls.get(jobId).childRunId } : {},
11270
11372
  additionalInputs: Object.fromEntries(Object.entries(nodeInputs).filter(([handle]) => additional.has(handle))),
11271
11373
  blockId: "moduleId" in node.task ? node.task.moduleId : nodeId,
11272
11374
  flowId: target.flowId,
@@ -11293,7 +11395,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11293
11395
  const previous = target.graph.nodes[previousId];
11294
11396
  return {
11295
11397
  id: previousId,
11296
- name: previous.name ?? ("inputs" in previous ? nodeTitle(previous) : void 0) ?? previousId,
11398
+ name: previous.name ?? (!isTriggerNode(previous) ? nodeTitle(previous) : void 0) ?? previousId,
11297
11399
  outputs: frame[previousId],
11298
11400
  outputDefs: Object.entries(nodeOutputPorts(previous)).map(([handle, definition]) => Object.assign({
11299
11401
  handle,
@@ -11305,7 +11407,21 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11305
11407
  }
11306
11408
  } : { kind: "managed" }
11307
11409
  });
11308
- if (config != null) {
11410
+ if ("executor" in node.task && node.task.executor.kind == "workflow") {
11411
+ const response = discriminatedUnion("kind", [strictObject({
11412
+ kind: literal("calling"),
11413
+ childRunId: string().min(1)
11414
+ }), strictObject({
11415
+ kind: literal("completed"),
11416
+ outputs: record$1(string(), json$1())
11417
+ })]).parse(result);
11418
+ if (response.kind == "calling") return {
11419
+ kind: "calling",
11420
+ childRunId: response.childRunId,
11421
+ input: nodeInputs
11422
+ };
11423
+ outputs = response.outputs;
11424
+ } else if (config != null) {
11309
11425
  const response = agentResultSchema.parse(result);
11310
11426
  if (response.kind == "suspended") {
11311
11427
  const checkpoint = response.checkpoint;
@@ -11349,7 +11465,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11349
11465
  const node = target.graph.nodes[nodeId];
11350
11466
  const waitId = nanoid$1();
11351
11467
  const notify = isResolutionNode(node) && usesPending(target.graph, nodeId);
11352
- const pending = yield* context.waits.create({
11468
+ const notification = yield* context.waits.create({
11353
11469
  jobId,
11354
11470
  nodeId,
11355
11471
  value,
@@ -11359,6 +11475,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11359
11475
  prompt: isResolutionNode(node) ? node.prompt : JSON.stringify(value, null, 2),
11360
11476
  ...isResolutionNode(node) ? {} : { notification: agentNotice(node, agents[jobId].input) }
11361
11477
  });
11478
+ const pending = notification == null ? notification : withWaitNotificationMessage(notification);
11362
11479
  if (notify) {
11363
11480
  validateOutputs(nodeId, node, { pending });
11364
11481
  dependencies.release(nodeId, { pending }, ["pending"], false);
@@ -11373,6 +11490,16 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11373
11490
  yield* Queue.offer(changes, void 0);
11374
11491
  });
11375
11492
  const settleNode = (nodeId, jobId, result) => {
11493
+ if (result.kind == "calling") {
11494
+ pendingCalls.set(jobId, {
11495
+ jobId,
11496
+ nodeId,
11497
+ childRunId: result.childRunId,
11498
+ input: result.input
11499
+ });
11500
+ return Effect.void;
11501
+ }
11502
+ pendingCalls.delete(jobId);
11376
11503
  if (result.kind == "completed") {
11377
11504
  delete agents[jobId];
11378
11505
  return commit(nodeId, jobId, result.outputs, result.releasedHandles);
@@ -11400,7 +11527,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11400
11527
  const executeReady = (nodeId) => {
11401
11528
  if (firstCause != null) return;
11402
11529
  const node = target.graph.nodes[nodeId];
11403
- if (!("inputs" in node)) return;
11530
+ if (isTriggerNode(node)) return;
11404
11531
  const jobId = context.createId();
11405
11532
  const count = counts[nodeId] ?? 0;
11406
11533
  const limit = node.maxExecutions ?? 1e3;
@@ -11488,18 +11615,22 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11488
11615
  return yield* Effect.failCause(firstCause);
11489
11616
  }
11490
11617
  if (pendingWaits.size > 0 && context.waits != null) applyResolutions(yield* context.waits.resolutions([...pendingWaits.values()].map((wait) => wait.waitId), false), now);
11618
+ for (const call of pendingCalls.values()) yield* observe(call.nodeId, call.jobId, Effect.gen(function* () {
11619
+ const result = yield* executeNode(call.nodeId, target.graph.nodes[call.nodeId], call.jobId, call.input);
11620
+ yield* settleNode(call.nodeId, call.jobId, result);
11621
+ })).pipe(Effect.catch(() => Effect.void));
11491
11622
  const ready = dependencies.ready();
11492
11623
  for (const nodeId of ready) executeReady(nodeId);
11493
11624
  const running = yield* FiberSet.size(active);
11494
11625
  if (firstCause != null) continue;
11495
- if (running == 0 && pendingWaits.size == 0 && ready.length == 0) {
11626
+ if (running == 0 && pendingWaits.size == 0 && pendingCalls.size == 0 && ready.length == 0) {
11496
11627
  if (dependencies.incomplete) return yield* Effect.fail(/* @__PURE__ */ new Error("Execution graph contains unresolved dependencies."));
11497
11628
  break;
11498
11629
  }
11499
11630
  if (running > 0 || ready.length > 0) idleSince = void 0;
11500
11631
  else idleSince ??= now;
11501
11632
  const left = idleSince == null ? remainingMs : waitRetentionMs - (now - idleSince);
11502
- if (idleSince != null && left <= 0) {
11633
+ if (idleSince != null && (left <= 0 || pendingCalls.size > 0)) {
11503
11634
  const checkpoint = {
11504
11635
  bindingValues: context.bindingValues,
11505
11636
  inputs: launch,
@@ -11508,7 +11639,8 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11508
11639
  dependencies: dependencies.state,
11509
11640
  version: 5,
11510
11641
  agents,
11511
- waits: [...pendingWaits.values()]
11642
+ waits: [...pendingWaits.values()],
11643
+ ...pendingCalls.size == 0 ? {} : { calls: [...pendingCalls.values()] }
11512
11644
  };
11513
11645
  const encoded = JSON.stringify(checkpoint);
11514
11646
  if (new TextEncoder().encode(encoded).byteLength > 16777216) return yield* Effect.fail(/* @__PURE__ */ new Error("Flow Run checkpoint exceeds 16 MiB."));
@@ -11521,6 +11653,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11521
11653
  const activity = Queue.take(changes).pipe(Effect.as({}));
11522
11654
  const decision = pendingWaits.size == 0 || context.waits == null ? Effect.never : context.waits.resolutions([...pendingWaits.values()].map((wait) => wait.waitId), true);
11523
11655
  let next = Effect.raceFirst(activity, decision);
11656
+ if (pendingCalls.size > 0) next = Effect.raceFirst(next, Effect.sleep(1e3).pipe(Effect.as({})));
11524
11657
  if (left != null) next = Effect.raceFirst(next, Effect.sleep(Math.max(0, left)).pipe(Effect.as({})));
11525
11658
  applyResolutions(yield* next, yield* Clock.currentTimeMillis);
11526
11659
  }
@@ -11529,8 +11662,11 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11529
11662
  runId,
11530
11663
  type: "run.progress"
11531
11664
  });
11665
+ const outputNodeId = order.find((nodeId) => target.graph.nodes[nodeId]?.kind == "outputs");
11666
+ const businessOutputs = outputNodeId == null ? void 0 : completed.get(outputNodeId)?.outputs;
11532
11667
  const result = {
11533
11668
  kind: "node-results",
11669
+ ...businessOutputs == null ? {} : { outputs: businessOutputs },
11534
11670
  nodes: resultNodes.flatMap((nodeId) => {
11535
11671
  const saved = completed.get(nodeId);
11536
11672
  return saved == null ? [] : [{
@@ -11553,11 +11689,40 @@ function runFlow(prepared, options) {
11553
11689
  const emit = options.emit ?? (() => Effect.void);
11554
11690
  return Effect.gen(function* () {
11555
11691
  if (options.resume != null && (options.inputs != null || options.trigger != null || options.bindingValues != null)) return yield* Effect.fail(/* @__PURE__ */ new Error("A resumed Flow Run cannot accept launch inputs, binding values, or a Trigger seed."));
11556
- const checkpoint = options.resume == null ? void 0 : decodeFlowRunCheckpoint(options.resume.checkpoint);
11692
+ const decoded = options.resume == null ? void 0 : decodeFlowRunCheckpoint(options.resume.checkpoint);
11693
+ const outputs = (nodeId, value) => isResolutionNode(prepared.graph.nodes[nodeId]) && value.pending != null ? {
11694
+ ...value,
11695
+ pending: withWaitNotificationMessage(value.pending)
11696
+ } : value;
11697
+ const checkpoint = decoded == null ? void 0 : {
11698
+ ...decoded,
11699
+ results: Object.fromEntries(Object.entries(decoded.results).map(([id, result]) => [id, {
11700
+ ...result,
11701
+ outputs: outputs(id, result.outputs)
11702
+ }])),
11703
+ dependencies: {
11704
+ ...decoded.dependencies,
11705
+ nodes: Object.fromEntries(Object.entries(decoded.dependencies.nodes).map(([id, state]) => [id, {
11706
+ ...state,
11707
+ ...state.output == null ? {} : { output: outputs(id, state.output) },
11708
+ input: Object.fromEntries(Object.entries(state.input).map(([source, result]) => [source, {
11709
+ ...result,
11710
+ outputs: outputs(source, result.outputs)
11711
+ }]))
11712
+ }]))
11713
+ },
11714
+ waits: decoded.waits.map((wait) => wait.pending == null ? wait : Object.assign({}, wait, { pending: withWaitNotificationMessage(wait.pending) }))
11715
+ };
11557
11716
  if (checkpoint != null && new TextEncoder().encode(JSON.stringify(checkpoint)).byteLength > 16777216) return yield* Effect.fail(/* @__PURE__ */ new Error("Flow Run checkpoint exceeds 16 MiB."));
11558
11717
  if (checkpoint == null && options.trigger == null) return yield* Effect.fail(/* @__PURE__ */ new Error("A Flow Run requires a Trigger seed."));
11559
11718
  const triggerNode = options.trigger == null ? void 0 : prepared.graph.nodes[options.trigger.nodeId];
11560
- if (options.trigger != null && (triggerNode == null || "inputs" in triggerNode)) return yield* Effect.fail(/* @__PURE__ */ new Error(`Node "${options.trigger.nodeId}" is not a TriggerNode in Flow "${options.flowId}".`));
11719
+ if (options.trigger != null && (triggerNode == null || !isTriggerNode(triggerNode))) return yield* Effect.fail(/* @__PURE__ */ new Error(`Node "${options.trigger.nodeId}" is not a TriggerNode in Flow "${options.flowId}".`));
11720
+ const triggerOutputs = triggerNode == null || !isTriggerNode(triggerNode) ? void 0 : normalizeTriggerOutputs(triggerNode, options.trigger.outputs);
11721
+ if (options.trigger != null && triggerOutputs == null) return yield* Effect.fail(/* @__PURE__ */ new Error("Trigger outputs are invalid."));
11722
+ const trigger = options.trigger == null ? void 0 : {
11723
+ nodeId: options.trigger.nodeId,
11724
+ outputs: triggerOutputs
11725
+ };
11561
11726
  return yield* runGraph({
11562
11727
  failures: /* @__PURE__ */ new WeakMap(),
11563
11728
  counts: Object.fromEntries(Object.entries(checkpoint?.counts ?? {}).map(([scope, counts]) => [scope, { ...counts }])),
@@ -11571,9 +11736,12 @@ function runFlow(prepared, options) {
11571
11736
  remainingMs: options.remainingMs
11572
11737
  }, {
11573
11738
  flowId: options.flowId,
11574
- graph: prepared.graph
11575
- }, options.runId, options.inputs, options.trigger, checkpoint == null ? void 0 : { checkpoint });
11739
+ graph: prepared.graph,
11740
+ inputDefs: prepared.inputDefs,
11741
+ outputDefs: prepared.outputDefs,
11742
+ outputMappings: prepared.outputMappings
11743
+ }, options.runId, options.inputs, trigger, checkpoint == null ? void 0 : { checkpoint });
11576
11744
  });
11577
11745
  }
11578
11746
  //#endregion
11579
- export { PortValidationError, decodeFlowRunCheckpoint, normalizeWaitComment, runFlow, waitRetentionMs };
11747
+ export { PortValidationError, decodeFlowRunCheckpoint, normalizeWaitComment, runFlow, waitRetentionMs, withWaitNotificationMessage };
@@ -7,3 +7,5 @@ export declare const webhookOutputs: readonly Port[];
7
7
  export declare function triggerOutputDefinitions(trigger: TriggerNode): readonly Port[];
8
8
  export declare function triggerOutputPorts(trigger: TriggerNode): Readonly<Record<string, PortDefinition>>;
9
9
  export declare function matchesTriggerOutputs(trigger: TriggerNode, outputs: unknown): outputs is Readonly<Record<string, JsonValue>>;
10
+ /** Resolve caller-supplied Start parameters into the complete output snapshot used by execution. */
11
+ export declare function normalizeTriggerOutputs(trigger: TriggerNode, outputs: unknown): Readonly<Record<string, JsonValue>> | undefined;