@oomol-lab/open-flow 0.1.0-beta.65 → 0.1.0-beta.67

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 (54) hide show
  1. package/dist/browser/{createResourceDialog-BAJXbzNH.js → createResourceDialog-BQVD8Rqb.js} +2 -2
  2. package/dist/browser/{icons-Db2Jb2iX.js → dialog-CS2Vt2if.js} +5736 -5621
  3. package/dist/browser/event-sources.d.ts +4 -1
  4. package/dist/browser/flow-authoring-node.d.ts +14 -3
  5. package/dist/browser/flow-authoring.js +120 -24
  6. package/dist/browser/flow-change-schema.d.ts +3 -1
  7. package/dist/browser/flow-change.d.ts +15 -3
  8. package/dist/browser/flow-change.js +117 -21
  9. package/dist/browser/{flowChanges-DkvG5uDq.js → flowChanges-VB9Y4iy7.js} +3423 -2380
  10. package/dist/browser/{flowRunInputEditorStore-B2Rw4VsT.js → flowRunInputEditorStore-DJqmR6Qh.js} +3 -2
  11. package/dist/browser/{flowWorkspace-BEp-lxqF.js → flowWorkspace-C1hlTnZq.js} +1410 -799
  12. package/dist/browser/preview.css +273 -119
  13. package/dist/browser/preview.js +17118 -15810
  14. package/dist/browser/theme.css +1 -0
  15. package/dist/browser/ui.css +119 -7
  16. package/dist/browser/ui.js +8 -5
  17. package/dist/browser/workbench-contract.d.ts +1 -1
  18. package/dist/browser/workbench.css +282 -162
  19. package/dist/browser/workbench.d.ts +0 -1
  20. package/dist/browser/workbench.js +503 -173
  21. package/dist/browser/{workbenchSelect-C-jf6NIM.js → workbenchSelect-CpXhjUou.js} +1 -1
  22. package/dist/command/index.js +49 -49
  23. package/dist/common/authoring.d.ts +7 -5
  24. package/dist/common/authoringExamples.d.ts +4 -4
  25. package/dist/common/authoringFields.d.ts +20 -0
  26. package/dist/common/authoringSchema.d.ts +404 -15
  27. package/dist/common/control-api-conformance.js +415 -146
  28. package/dist/common/control-api.d.ts +67 -8
  29. package/dist/common/control-api.js +3587 -3443
  30. package/dist/common/control-requests.d.ts +10 -3
  31. package/dist/common/control-requests.js +425 -49
  32. package/dist/common/decision.js +33 -7
  33. package/dist/common/flow-encoding.d.ts +4 -2
  34. package/dist/common/flow-encoding.js +151 -14
  35. package/dist/common/flow-graph.d.ts +1 -1
  36. package/dist/common/flow-semantics.d.ts +12 -2
  37. package/dist/common/flow-semantics.js +157 -41
  38. package/dist/common/integration-trigger.js +33 -7
  39. package/dist/common/liveDetails.d.ts +26 -11
  40. package/dist/common/mcp.d.ts +6 -3
  41. package/dist/common/mcp.js +219 -90
  42. package/dist/common/openapi.js +33 -7
  43. package/dist/common/poll-trigger.js +33 -7
  44. package/dist/common/run-events.d.ts +2 -0
  45. package/dist/common/run-events.js +9 -3
  46. package/dist/common/scheduler.d.ts +10 -1
  47. package/dist/common/scheduler.js +172 -49
  48. package/dist/common/trigger-contract.d.ts +2 -0
  49. package/dist/common/webhook-trigger.js +33 -7
  50. package/dist/common/workflow.d.ts +93 -0
  51. package/dist/common/workflow.js +10492 -0
  52. package/package.json +5 -1
  53. package/skills/open-flow/SKILL.md +9 -0
  54. package/skills/open-flow/references/flow-authoring.md +28 -16
@@ -9496,6 +9496,7 @@ function webhookSupportsBody(method) {
9496
9496
  return method !== "GET";
9497
9497
  }
9498
9498
  var text = string();
9499
+ var actionConnection = text.describe("Account selection: omit while unconfigured; use an account ID to select it; use \"\" to explicitly defer configuration. Deferred Actions fail if called; deferred Agent tools are excluded from the callable tool set. Not supported by Triggers.");
9499
9500
  var json = json$1();
9500
9501
  var strings = array(text);
9501
9502
  var port = object({
@@ -9504,6 +9505,7 @@ var port = object({
9504
9505
  nullable: boolean(),
9505
9506
  handle: text
9506
9507
  });
9508
+ var workflowInputDefs = array(port.strict());
9507
9509
  var input = port.extend({ value: json.optional() });
9508
9510
  var group = object({
9509
9511
  collapsed: boolean().optional(),
@@ -9550,7 +9552,7 @@ var capability = union([
9550
9552
  mode: literal("independent"),
9551
9553
  actions: array(strictObject({
9552
9554
  action: text,
9553
- connectionId: text.optional()
9555
+ connectionId: actionConnection.optional()
9554
9556
  }))
9555
9557
  }),
9556
9558
  strictObject({
@@ -9610,7 +9612,7 @@ var managedFields = object({
9610
9612
  object({
9611
9613
  kind: literal("connector"),
9612
9614
  action: text,
9613
- connectionId: text.optional(),
9615
+ connectionId: actionConnection.optional(),
9614
9616
  outputMode: literal("value").optional()
9615
9617
  }),
9616
9618
  object({
@@ -9650,17 +9652,22 @@ var managedFields = object({
9650
9652
  name: text,
9651
9653
  description: text,
9652
9654
  action: text,
9653
- connectionId: text.optional(),
9655
+ connectionId: actionConnection.optional(),
9654
9656
  approval: boolean(),
9655
9657
  inputs: array(input.extend({ source: agentInput$1 }))
9656
9658
  })),
9657
9659
  notification: object({
9658
9660
  action: text,
9659
- connectionId: text.optional(),
9661
+ connectionId: actionConnection.optional(),
9660
9662
  inputDefinitions: array(input),
9661
9663
  messageHandle: text,
9662
9664
  inputs: record$1(text, agentValue)
9663
9665
  }).optional()
9666
+ }),
9667
+ strictObject({
9668
+ kind: literal("workflow"),
9669
+ flowId: text,
9670
+ revisionId: text
9664
9671
  })
9665
9672
  ])
9666
9673
  });
@@ -9769,6 +9776,12 @@ var base = {
9769
9776
  timeoutMs: number().optional()
9770
9777
  };
9771
9778
  var node = union([
9779
+ strictObject({
9780
+ ...base,
9781
+ kind: literal("outputs"),
9782
+ outputDefs: array(port.strict()),
9783
+ outputMappings: inputs
9784
+ }).omit({ inputs: true }),
9772
9785
  object({
9773
9786
  ...base,
9774
9787
  inputs: record$1(text, never()),
@@ -9801,6 +9814,11 @@ var node = union([
9801
9814
  ...trigger,
9802
9815
  kind: literal("manual")
9803
9816
  }),
9817
+ strictObject({
9818
+ ...trigger,
9819
+ kind: literal("start"),
9820
+ inputDefs: workflowInputDefs
9821
+ }),
9804
9822
  strictObject({
9805
9823
  ...trigger,
9806
9824
  kind: literal("error"),
@@ -9865,7 +9883,7 @@ var module = object({
9865
9883
  imports: strings,
9866
9884
  source: text
9867
9885
  });
9868
- var document = preprocess(rejectRetiredDefinitions, object({
9886
+ var document = preprocess(normalizeDocument, object({
9869
9887
  bindings: record$1(text, binding),
9870
9888
  graph
9871
9889
  }));
@@ -9874,7 +9892,9 @@ object({
9874
9892
  literal(2),
9875
9893
  literal(4),
9876
9894
  literal(5),
9877
- literal(6)
9895
+ literal(6),
9896
+ literal(7),
9897
+ literal(8)
9878
9898
  ]),
9879
9899
  document,
9880
9900
  modules: record$1(text, module)
@@ -9882,13 +9902,19 @@ object({
9882
9902
  kind: literal("open-flow-flow-revision"),
9883
9903
  version: literal(1)
9884
9904
  });
9885
- function rejectRetiredDefinitions(value) {
9905
+ function normalizeDocument(value) {
9886
9906
  const candidate = record(value);
9887
9907
  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
9908
  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
9909
  const subflows = candidate.subflows;
9890
9910
  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
9911
  if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => record(candidateNode).kind === "subflow")) throw new TypeError("Subflow nodes are no longer supported.");
9912
+ if ([
9913
+ "inputDefs",
9914
+ "outputDefs",
9915
+ "outputMappings"
9916
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
9917
+ 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
9918
  return value;
9893
9919
  }
9894
9920
  function record(value) {
@@ -10088,6 +10114,7 @@ function conditionOperands(node) {
10088
10114
  }] : []])));
10089
10115
  }
10090
10116
  function nodeInputMappings(node) {
10117
+ if (node.kind == "outputs") return node.outputMappings;
10091
10118
  if (node.kind != "condition") return "inputs" in node ? node.inputs : {};
10092
10119
  return Object.fromEntries(conditionOperands(node).flatMap(({ handle, operand }) => operand.kind == "source" ? [[handle, {
10093
10120
  kind: "sources",
@@ -10243,6 +10270,17 @@ function selectConditionBranches(node, values) {
10243
10270
  function portsByHandle(ports) {
10244
10271
  return Object.fromEntries(ports.flatMap((port) => "handle" in port ? [[port.handle, port]] : []));
10245
10272
  }
10273
+ function isTriggerNode(node) {
10274
+ return [
10275
+ "manual",
10276
+ "start",
10277
+ "error",
10278
+ "webhook",
10279
+ "cron",
10280
+ "poll",
10281
+ "integration"
10282
+ ].includes(node.kind);
10283
+ }
10246
10284
  //#endregion
10247
10285
  //#region src/flow/common/agent.ts
10248
10286
  var schema = lazy(() => union([boolean(), strictObject({
@@ -10515,6 +10553,7 @@ function triggerOutputDefinitions(trigger) {
10515
10553
  switch (trigger.kind) {
10516
10554
  case "error": return errorOutputs;
10517
10555
  case "manual": return [];
10556
+ case "start": return trigger.inputDefs;
10518
10557
  case "cron": return cronOutputs;
10519
10558
  case "poll":
10520
10559
  case "integration": return trigger.definition.outputs;
@@ -10534,11 +10573,37 @@ function matchesTriggerOutputs(trigger, outputs) {
10534
10573
  const ports = triggerOutputDefinitions(trigger);
10535
10574
  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
10575
  }
10576
+ /** Resolve caller-supplied Start parameters into the complete output snapshot used by execution. */
10577
+ function normalizeTriggerOutputs(trigger, outputs) {
10578
+ if (!isJsonObject(outputs)) return;
10579
+ const normalized = trigger.kind == "start" ? {
10580
+ ...outputs,
10581
+ ...Object.fromEntries(trigger.inputDefs.filter((port) => port.nullable && !Object.hasOwn(outputs, port.handle)).map((port) => [port.handle, null]))
10582
+ } : outputs;
10583
+ return matchesTriggerOutputs(trigger, normalized) ? normalized : void 0;
10584
+ }
10537
10585
  //#endregion
10538
10586
  //#region src/flow/common/graph.ts
10539
10587
  function isResolutionNode(node) {
10540
10588
  return node?.kind == "approval" || node?.kind == "wait";
10541
10589
  }
10590
+ function nodeInputPorts(node) {
10591
+ switch (node.kind) {
10592
+ case "outputs": return portsByHandle(node.outputDefs);
10593
+ case "condition": return conditionInputPorts(node);
10594
+ case "value": return {};
10595
+ case "task": return portsByHandle([...node.task.inputs, ...node.additionalInputs ?? []]);
10596
+ case "approval":
10597
+ case "wait": return portsByHandle(node.inputDefinitions);
10598
+ case "cron":
10599
+ case "integration":
10600
+ case "poll":
10601
+ case "error":
10602
+ case "manual":
10603
+ case "start":
10604
+ case "webhook": return {};
10605
+ }
10606
+ }
10542
10607
  function resolutionActions(node) {
10543
10608
  return node.kind == "wait" ? ["continue"] : ["approve", "reject"];
10544
10609
  }
@@ -10582,6 +10647,7 @@ function resolutionOutputPorts(node) {
10582
10647
  }
10583
10648
  function nodeOutputPorts(node) {
10584
10649
  switch (node.kind) {
10650
+ case "outputs":
10585
10651
  case "condition": return {};
10586
10652
  case "value": return portsByHandle(node.values);
10587
10653
  case "task": return portsByHandle(node.task.outputs);
@@ -10592,6 +10658,7 @@ function nodeOutputPorts(node) {
10592
10658
  case "poll":
10593
10659
  case "error":
10594
10660
  case "manual":
10661
+ case "start":
10595
10662
  case "webhook": return triggerOutputPorts(node);
10596
10663
  }
10597
10664
  }
@@ -10658,7 +10725,7 @@ var Dependencies = class {
10658
10725
  stack.delete(id);
10659
10726
  };
10660
10727
  const ids = Object.keys(graph.nodes).toSorted();
10661
- for (const triggerId of ids.filter((id) => !("inputs" in graph.nodes[id]))) visit(triggerId);
10728
+ for (const triggerId of ids.filter((id) => isTriggerNode(graph.nodes[id]))) visit(triggerId);
10662
10729
  for (const id of ids) visit(id);
10663
10730
  for (const edge of this.forward) {
10664
10731
  const edges = this.incoming.get(edge.target) ?? [];
@@ -10733,7 +10800,7 @@ var Dependencies = class {
10733
10800
  }
10734
10801
  start(nodeId, outputs) {
10735
10802
  for (const [id, node] of Object.entries(this.graph.nodes)) {
10736
- if ("inputs" in node) continue;
10803
+ if (!isTriggerNode(node)) continue;
10737
10804
  const state = this.state.nodes[id];
10738
10805
  state.status = id == nodeId ? "completed" : "skipped";
10739
10806
  if (id == nodeId) {
@@ -10902,7 +10969,7 @@ var withWaitNotificationMessage = withWaitNotificationMessage$1;
10902
10969
  var normalizeWaitComment = normalizeWaitComment$1;
10903
10970
  var PortValidationError = class extends Error {};
10904
10971
  function usesPending(graph, nodeId) {
10905
- 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")));
10972
+ 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")));
10906
10973
  }
10907
10974
  var waitRetentionMs = 12e4;
10908
10975
  function nodeFailure(error, project) {
@@ -10911,19 +10978,11 @@ function nodeFailure(error, project) {
10911
10978
  message: error instanceof Error ? error.message : String(error)
10912
10979
  };
10913
10980
  }
10914
- function nodePorts(node) {
10915
- switch (node.kind) {
10916
- case "condition": return conditionInputPorts(node);
10917
- case "value": return {};
10918
- case "task": return portsByHandle([...node.task.inputs, ...node.additionalInputs ?? []]);
10919
- case "approval":
10920
- case "wait": return portsByHandle(node.inputDefinitions);
10921
- }
10922
- }
10923
10981
  function nodeTitle(node) {
10924
10982
  if (node.name != null) return node.name;
10925
10983
  switch (node.kind) {
10926
10984
  case "condition": return;
10985
+ case "outputs": return "Workflow Outputs";
10927
10986
  case "value": return "Fixed Values";
10928
10987
  case "task": return node.task.name;
10929
10988
  case "approval": return "Approval";
@@ -10979,7 +11038,8 @@ function decodeFlowRunCheckpoint(input) {
10979
11038
  "inputs",
10980
11039
  "results",
10981
11040
  "version",
10982
- "waits"
11041
+ "waits",
11042
+ ...source.calls === void 0 ? [] : ["calls"]
10983
11043
  ], "Flow Run checkpoint");
10984
11044
  if (source.version != 5) throw new Error("Flow Run checkpoint version is unsupported.");
10985
11045
  const bindingValues = Object.fromEntries(Object.entries(checkpointRecord(source.bindingValues, "Checkpoint bindings")).map(([id, value]) => {
@@ -11003,7 +11063,14 @@ function decodeFlowRunCheckpoint(input) {
11003
11063
  value: json$1(),
11004
11064
  waitId: string().min(1),
11005
11065
  pending: json$1().optional()
11006
- })).min(1).parse(source.waits);
11066
+ })).parse(source.waits);
11067
+ const calls = array(strictObject({
11068
+ jobId: string().min(1),
11069
+ nodeId: string().min(1),
11070
+ childRunId: string().min(1),
11071
+ input: record$1(string(), json$1())
11072
+ })).parse(source.calls ?? []);
11073
+ if (pendingWaits.length + calls.length == 0) throw new Error("Checkpoint has no pending execution.");
11007
11074
  const agents = record$1(string(), strictObject({
11008
11075
  invocationId: string().min(1),
11009
11076
  input: record$1(string(), json$1()),
@@ -11017,6 +11084,10 @@ function decodeFlowRunCheckpoint(input) {
11017
11084
  jobs.add(pending.jobId);
11018
11085
  waits.add(pending.waitId);
11019
11086
  }
11087
+ for (const call of calls) {
11088
+ 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.");
11089
+ jobs.add(call.jobId);
11090
+ }
11020
11091
  if (Object.values(dependencies.nodes).some((state) => state.status == "running" && !jobs.has(state.jobId))) throw new Error("Checkpoint dependency has no waiting execution.");
11021
11092
  if (Object.keys(agents).some((id) => !jobs.has(id))) throw new Error("Checkpoint Agent has no waiting execution.");
11022
11093
  return {
@@ -11027,7 +11098,8 @@ function decodeFlowRunCheckpoint(input) {
11027
11098
  inputs,
11028
11099
  results,
11029
11100
  version: 5,
11030
- waits: pendingWaits
11101
+ waits: pendingWaits,
11102
+ ...source.calls === void 0 ? {} : { calls }
11031
11103
  };
11032
11104
  }
11033
11105
  function jsonEqual(left, right) {
@@ -11079,14 +11151,14 @@ function agentApproval(config, checkpoint, inputs) {
11079
11151
  }
11080
11152
  function validateOutputs(nodeId, node, value) {
11081
11153
  const raw = outputRecord(value, nodeId);
11082
- const discardUndeclared = node.kind == "task" && "executor" in node.task && node.task.executor.kind == "connector";
11083
- const ports = isResolutionNode(node) ? resolutionOutputPorts(node) : node.kind == "task" ? portsByHandle(node.task.outputs) : node.kind == "value" ? portsByHandle(node.values) : {};
11154
+ const discardUndeclared = node.kind == "task" && "executor" in node.task && (node.task.executor.kind == "connector" || node.task.executor.kind == "workflow");
11155
+ const ports = node.kind == "outputs" ? nodeInputPorts(node) : isResolutionNode(node) ? resolutionOutputPorts(node) : node.kind == "task" ? portsByHandle(node.task.outputs) : node.kind == "value" ? portsByHandle(node.values) : {};
11084
11156
  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);
11085
11157
  const complete = node.kind == "condition" || isResolutionNode(node) ? outputs : {
11086
11158
  ...Object.fromEntries(Object.keys(ports).map((handle) => [handle, null])),
11087
11159
  ...outputs
11088
11160
  };
11089
- const validated = {};
11161
+ const validated = [];
11090
11162
  for (const [handle, output] of Object.entries(complete)) {
11091
11163
  const port = ports[handle];
11092
11164
  if (port == null) {
@@ -11094,9 +11166,9 @@ function validateOutputs(nodeId, node, value) {
11094
11166
  throw new PortValidationError(`Node "${nodeId}" output "${handle}" does not match its declaration.`);
11095
11167
  }
11096
11168
  if (!(output === null && port.nullable) && !matchesSchema(output, port.jsonSchema)) throw new PortValidationError(`Node "${nodeId}" output "${handle}" does not match its declaration.`);
11097
- validated[handle] = output;
11169
+ validated.push([handle, output]);
11098
11170
  }
11099
- return validated;
11171
+ return Object.fromEntries(validated);
11100
11172
  }
11101
11173
  function validateCheckpoint(target, checkpoint, resolveInputs) {
11102
11174
  const launch = checkpoint.inputs;
@@ -11107,14 +11179,14 @@ function validateCheckpoint(target, checkpoint, resolveInputs) {
11107
11179
  if (graph == null) throw new Error("Checkpoint execution counts reference an unknown graph.");
11108
11180
  for (const [id, count] of Object.entries(counts)) {
11109
11181
  const node = graph.nodes[id];
11110
- if (node == null || !("inputs" in node) || count > (node.maxExecutions ?? 1e3)) throw new Error("Checkpoint execution count is invalid.");
11182
+ if (node == null || isTriggerNode(node) || count > (node.maxExecutions ?? 1e3)) throw new Error("Checkpoint execution count is invalid.");
11111
11183
  }
11112
11184
  }
11113
11185
  const validateResults = (results, frame = false) => {
11114
11186
  for (const [id, outputs] of Object.entries(results)) {
11115
11187
  const node = target.graph.nodes[id];
11116
11188
  if (node == null) throw new Error("Checkpoint result node is missing.");
11117
- if (!("inputs" in node)) {
11189
+ if (isTriggerNode(node)) {
11118
11190
  if (!matchesTriggerOutputs(node, outputs)) throw new Error("Checkpoint Trigger output is invalid.");
11119
11191
  } else {
11120
11192
  if (checkpoint.counts[""]?.[id] == null) throw new Error("Checkpoint execution count is missing.");
@@ -11125,20 +11197,20 @@ function validateCheckpoint(target, checkpoint, resolveInputs) {
11125
11197
  }
11126
11198
  };
11127
11199
  validateResults(Object.fromEntries(Object.entries(checkpoint.results).map(([id, result]) => [id, result.outputs])));
11128
- const triggerIds = Object.keys(checkpoint.results).filter((id) => !("inputs" in target.graph.nodes[id]));
11200
+ const triggerIds = Object.keys(checkpoint.results).filter((id) => isTriggerNode(target.graph.nodes[id]));
11129
11201
  if (triggerIds.length != 1) throw new Error("Checkpoint must contain exactly one selected Trigger.");
11130
11202
  const pendingCounts = /* @__PURE__ */ new Map();
11131
- for (const waiting of checkpoint.waits) pendingCounts.set(waiting.nodeId, (pendingCounts.get(waiting.nodeId) ?? 0) + 1);
11203
+ for (const waiting of [...checkpoint.waits, ...checkpoint.calls ?? []]) pendingCounts.set(waiting.nodeId, (pendingCounts.get(waiting.nodeId) ?? 0) + 1);
11132
11204
  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.");
11133
11205
  for (const [id, values] of Object.entries(launch)) {
11134
11206
  const node = target.graph.nodes[id];
11135
- 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.");
11207
+ if (isTriggerNode(node) || Object.keys(values).some((handle) => nodeInputPorts(node)[handle] == null)) throw new Error("Checkpoint launch inputs do not match the prepared graph.");
11136
11208
  }
11137
11209
  for (const [nodeId, state] of Object.entries(checkpoint.dependencies.nodes)) {
11138
11210
  const frame = dependencyValues(state.input);
11139
11211
  validateResults(frame, true);
11140
- if ("inputs" in target.graph.nodes[nodeId] && (state.status == "running" || state.status == "completed")) {
11141
- const triggers = Object.keys(frame).filter((id) => !("inputs" in target.graph.nodes[id]));
11212
+ if (!isTriggerNode(target.graph.nodes[nodeId]) && (state.status == "running" || state.status == "completed")) {
11213
+ const triggers = Object.keys(frame).filter((id) => isTriggerNode(target.graph.nodes[id]));
11142
11214
  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.");
11143
11215
  }
11144
11216
  if (state.output != null) validateResults({ [nodeId]: state.output }, state.status == "running");
@@ -11147,9 +11219,13 @@ function validateCheckpoint(target, checkpoint, resolveInputs) {
11147
11219
  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.");
11148
11220
  }
11149
11221
  }
11222
+ for (const call of checkpoint.calls ?? []) {
11223
+ const node = target.graph.nodes[call.nodeId];
11224
+ 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.");
11225
+ }
11150
11226
  for (const waiting of checkpoint.waits) {
11151
11227
  const node = target.graph.nodes[waiting.nodeId];
11152
- if (node == null || !("inputs" in node)) throw new Error("Checkpoint waiting node is missing.");
11228
+ if (node == null || isTriggerNode(node)) throw new Error("Checkpoint waiting node is missing.");
11153
11229
  const state = checkpoint.dependencies.nodes[waiting.nodeId];
11154
11230
  const expectedOutput = waiting.pending == null ? void 0 : { pending: waiting.pending };
11155
11231
  if (state.output == null != (expectedOutput == null) || state.output != null && !jsonEqual(state.output, expectedOutput)) throw new Error("Checkpoint waiting dependency output is inconsistent.");
@@ -11178,7 +11254,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11178
11254
  runId,
11179
11255
  type: "run.started"
11180
11256
  });
11181
- const order = Object.keys(target.graph.nodes).filter((id) => "inputs" in target.graph.nodes[id]);
11257
+ const order = Object.keys(target.graph.nodes).filter((id) => !isTriggerNode(target.graph.nodes[id]));
11182
11258
  const outgoing = /* @__PURE__ */ new Map();
11183
11259
  for (const edge of target.graph.edges) {
11184
11260
  const targets = outgoing.get(edge.source) ?? [];
@@ -11193,10 +11269,10 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11193
11269
  if (resume == null) {
11194
11270
  if (trigger != null) {
11195
11271
  const node = target.graph.nodes[trigger.nodeId];
11196
- if (node == null || "inputs" in node || !matchesTriggerOutputs(node, trigger.outputs)) throw new Error("Trigger outputs are invalid.");
11272
+ if (node == null || !isTriggerNode(node) || !matchesTriggerOutputs(node, trigger.outputs)) throw new Error("Trigger outputs are invalid.");
11197
11273
  }
11198
11274
  for (const [id, node] of Object.entries(target.graph.nodes)) {
11199
- if ("inputs" in node) continue;
11275
+ if (!isTriggerNode(node)) continue;
11200
11276
  if (trigger?.nodeId == id) completed.set(id, {
11201
11277
  jobId: id,
11202
11278
  outputs: trigger.outputs
@@ -11207,6 +11283,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11207
11283
  const runNode = yield* FiberSet.runtime(active)();
11208
11284
  let firstCause;
11209
11285
  let firstFailure;
11286
+ const pendingCalls = new Map((resume?.checkpoint.calls ?? []).map((call) => [call.jobId, call]));
11210
11287
  const pendingWaits = new Map((resume?.checkpoint.waits ?? []).map((wait) => [wait.jobId, wait]));
11211
11288
  const changes = yield* Queue.unbounded();
11212
11289
  let remainingMs = context.remainingMs;
@@ -11236,7 +11313,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11236
11313
  const resolveInputs = (nodeId, node) => {
11237
11314
  const mappings = nodeInputMappings(node);
11238
11315
  const frame = dependencies.inputValues(nodeId);
11239
- 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")]));
11316
+ 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")]));
11240
11317
  };
11241
11318
  const commit = (nodeId, jobId, outputs, releasedHandles = Object.keys(outputs)) => Effect.uninterruptible(Effect.gen(function* () {
11242
11319
  yield* context.emit({
@@ -11265,7 +11342,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11265
11342
  const mapping = nodeInputMappings(node)[handle];
11266
11343
  return mapping?.kind != "sources" || mapping.sources.every((source) => source.kind != "binding");
11267
11344
  }));
11268
- if (resolution == null) yield* context.emit({
11345
+ if (resolution == null && !pendingCalls.has(jobId)) yield* context.emit({
11269
11346
  inputs: projectedInputs,
11270
11347
  jobId,
11271
11348
  nodeId,
@@ -11276,6 +11353,9 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11276
11353
  });
11277
11354
  let outputs;
11278
11355
  switch (node.kind) {
11356
+ case "outputs":
11357
+ outputs = nodeInputs;
11358
+ break;
11279
11359
  case "condition": return {
11280
11360
  kind: "completed",
11281
11361
  outputs: {},
@@ -11289,6 +11369,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11289
11369
  const previousIds = dependencies.state.nodes[nodeId].previous;
11290
11370
  const additional = new Set((node.additionalInputs ?? []).map((port) => port.handle));
11291
11371
  const result = yield* context.invokeTask({
11372
+ ...pendingCalls.has(jobId) ? { workflowRunId: pendingCalls.get(jobId).childRunId } : {},
11292
11373
  additionalInputs: Object.fromEntries(Object.entries(nodeInputs).filter(([handle]) => additional.has(handle))),
11293
11374
  blockId: "moduleId" in node.task ? node.task.moduleId : nodeId,
11294
11375
  flowId: target.flowId,
@@ -11315,7 +11396,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11315
11396
  const previous = target.graph.nodes[previousId];
11316
11397
  return {
11317
11398
  id: previousId,
11318
- name: previous.name ?? ("inputs" in previous ? nodeTitle(previous) : void 0) ?? previousId,
11399
+ name: previous.name ?? (!isTriggerNode(previous) ? nodeTitle(previous) : void 0) ?? previousId,
11319
11400
  outputs: frame[previousId],
11320
11401
  outputDefs: Object.entries(nodeOutputPorts(previous)).map(([handle, definition]) => Object.assign({
11321
11402
  handle,
@@ -11327,7 +11408,21 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11327
11408
  }
11328
11409
  } : { kind: "managed" }
11329
11410
  });
11330
- if (config != null) {
11411
+ if ("executor" in node.task && node.task.executor.kind == "workflow") {
11412
+ const response = discriminatedUnion("kind", [strictObject({
11413
+ kind: literal("calling"),
11414
+ childRunId: string().min(1)
11415
+ }), strictObject({
11416
+ kind: literal("completed"),
11417
+ outputs: record$1(string(), json$1())
11418
+ })]).parse(result);
11419
+ if (response.kind == "calling") return {
11420
+ kind: "calling",
11421
+ childRunId: response.childRunId,
11422
+ input: nodeInputs
11423
+ };
11424
+ outputs = response.outputs;
11425
+ } else if (config != null) {
11331
11426
  const response = agentResultSchema.parse(result);
11332
11427
  if (response.kind == "suspended") {
11333
11428
  const checkpoint = response.checkpoint;
@@ -11396,6 +11491,16 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11396
11491
  yield* Queue.offer(changes, void 0);
11397
11492
  });
11398
11493
  const settleNode = (nodeId, jobId, result) => {
11494
+ if (result.kind == "calling") {
11495
+ pendingCalls.set(jobId, {
11496
+ jobId,
11497
+ nodeId,
11498
+ childRunId: result.childRunId,
11499
+ input: result.input
11500
+ });
11501
+ return Effect.void;
11502
+ }
11503
+ pendingCalls.delete(jobId);
11399
11504
  if (result.kind == "completed") {
11400
11505
  delete agents[jobId];
11401
11506
  return commit(nodeId, jobId, result.outputs, result.releasedHandles);
@@ -11423,7 +11528,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11423
11528
  const executeReady = (nodeId) => {
11424
11529
  if (firstCause != null) return;
11425
11530
  const node = target.graph.nodes[nodeId];
11426
- if (!("inputs" in node)) return;
11531
+ if (isTriggerNode(node)) return;
11427
11532
  const jobId = context.createId();
11428
11533
  const count = counts[nodeId] ?? 0;
11429
11534
  const limit = node.maxExecutions ?? 1e3;
@@ -11511,18 +11616,22 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11511
11616
  return yield* Effect.failCause(firstCause);
11512
11617
  }
11513
11618
  if (pendingWaits.size > 0 && context.waits != null) applyResolutions(yield* context.waits.resolutions([...pendingWaits.values()].map((wait) => wait.waitId), false), now);
11619
+ for (const call of pendingCalls.values()) yield* observe(call.nodeId, call.jobId, Effect.gen(function* () {
11620
+ const result = yield* executeNode(call.nodeId, target.graph.nodes[call.nodeId], call.jobId, call.input);
11621
+ yield* settleNode(call.nodeId, call.jobId, result);
11622
+ })).pipe(Effect.catch(() => Effect.void));
11514
11623
  const ready = dependencies.ready();
11515
11624
  for (const nodeId of ready) executeReady(nodeId);
11516
11625
  const running = yield* FiberSet.size(active);
11517
11626
  if (firstCause != null) continue;
11518
- if (running == 0 && pendingWaits.size == 0 && ready.length == 0) {
11627
+ if (running == 0 && pendingWaits.size == 0 && pendingCalls.size == 0 && ready.length == 0) {
11519
11628
  if (dependencies.incomplete) return yield* Effect.fail(/* @__PURE__ */ new Error("Execution graph contains unresolved dependencies."));
11520
11629
  break;
11521
11630
  }
11522
11631
  if (running > 0 || ready.length > 0) idleSince = void 0;
11523
11632
  else idleSince ??= now;
11524
11633
  const left = idleSince == null ? remainingMs : waitRetentionMs - (now - idleSince);
11525
- if (idleSince != null && left <= 0) {
11634
+ if (idleSince != null && (left <= 0 || pendingCalls.size > 0)) {
11526
11635
  const checkpoint = {
11527
11636
  bindingValues: context.bindingValues,
11528
11637
  inputs: launch,
@@ -11531,7 +11640,8 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11531
11640
  dependencies: dependencies.state,
11532
11641
  version: 5,
11533
11642
  agents,
11534
- waits: [...pendingWaits.values()]
11643
+ waits: [...pendingWaits.values()],
11644
+ ...pendingCalls.size == 0 ? {} : { calls: [...pendingCalls.values()] }
11535
11645
  };
11536
11646
  const encoded = JSON.stringify(checkpoint);
11537
11647
  if (new TextEncoder().encode(encoded).byteLength > 16777216) return yield* Effect.fail(/* @__PURE__ */ new Error("Flow Run checkpoint exceeds 16 MiB."));
@@ -11544,6 +11654,7 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11544
11654
  const activity = Queue.take(changes).pipe(Effect.as({}));
11545
11655
  const decision = pendingWaits.size == 0 || context.waits == null ? Effect.never : context.waits.resolutions([...pendingWaits.values()].map((wait) => wait.waitId), true);
11546
11656
  let next = Effect.raceFirst(activity, decision);
11657
+ if (pendingCalls.size > 0) next = Effect.raceFirst(next, Effect.sleep(1e3).pipe(Effect.as({})));
11547
11658
  if (left != null) next = Effect.raceFirst(next, Effect.sleep(Math.max(0, left)).pipe(Effect.as({})));
11548
11659
  applyResolutions(yield* next, yield* Clock.currentTimeMillis);
11549
11660
  }
@@ -11552,8 +11663,11 @@ function runGraph(context, target, runId, launchInputs = {}, trigger, resume) {
11552
11663
  runId,
11553
11664
  type: "run.progress"
11554
11665
  });
11666
+ const outputNodeId = order.find((nodeId) => target.graph.nodes[nodeId]?.kind == "outputs");
11667
+ const businessOutputs = outputNodeId == null ? void 0 : completed.get(outputNodeId)?.outputs;
11555
11668
  const result = {
11556
11669
  kind: "node-results",
11670
+ ...businessOutputs == null ? {} : { outputs: businessOutputs },
11557
11671
  nodes: resultNodes.flatMap((nodeId) => {
11558
11672
  const saved = completed.get(nodeId);
11559
11673
  return saved == null ? [] : [{
@@ -11603,7 +11717,13 @@ function runFlow(prepared, options) {
11603
11717
  if (checkpoint != null && new TextEncoder().encode(JSON.stringify(checkpoint)).byteLength > 16777216) return yield* Effect.fail(/* @__PURE__ */ new Error("Flow Run checkpoint exceeds 16 MiB."));
11604
11718
  if (checkpoint == null && options.trigger == null) return yield* Effect.fail(/* @__PURE__ */ new Error("A Flow Run requires a Trigger seed."));
11605
11719
  const triggerNode = options.trigger == null ? void 0 : prepared.graph.nodes[options.trigger.nodeId];
11606
- 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}".`));
11720
+ 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}".`));
11721
+ const triggerOutputs = triggerNode == null || !isTriggerNode(triggerNode) ? void 0 : normalizeTriggerOutputs(triggerNode, options.trigger.outputs);
11722
+ if (options.trigger != null && triggerOutputs == null) return yield* Effect.fail(/* @__PURE__ */ new Error("Trigger outputs are invalid."));
11723
+ const trigger = options.trigger == null ? void 0 : {
11724
+ nodeId: options.trigger.nodeId,
11725
+ outputs: triggerOutputs
11726
+ };
11607
11727
  return yield* runGraph({
11608
11728
  failures: /* @__PURE__ */ new WeakMap(),
11609
11729
  counts: Object.fromEntries(Object.entries(checkpoint?.counts ?? {}).map(([scope, counts]) => [scope, { ...counts }])),
@@ -11617,8 +11737,11 @@ function runFlow(prepared, options) {
11617
11737
  remainingMs: options.remainingMs
11618
11738
  }, {
11619
11739
  flowId: options.flowId,
11620
- graph: prepared.graph
11621
- }, options.runId, options.inputs, options.trigger, checkpoint == null ? void 0 : { checkpoint });
11740
+ graph: prepared.graph,
11741
+ inputDefs: prepared.inputDefs,
11742
+ outputDefs: prepared.outputDefs,
11743
+ outputMappings: prepared.outputMappings
11744
+ }, options.runId, options.inputs, trigger, checkpoint == null ? void 0 : { checkpoint });
11622
11745
  });
11623
11746
  }
11624
11747
  //#endregion
@@ -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;