@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
@@ -6619,6 +6619,7 @@ var port = object$1({
6619
6619
  nullable: boolean(),
6620
6620
  handle: text
6621
6621
  });
6622
+ var workflowInputDefs = array(port.strict());
6622
6623
  var input = port.extend({ value: json.optional() });
6623
6624
  var group = object$1({
6624
6625
  collapsed: boolean().optional(),
@@ -6776,6 +6777,11 @@ var managedFields = object$1({
6776
6777
  messageHandle: text,
6777
6778
  inputs: record$1(text, agentValue)
6778
6779
  }).optional()
6780
+ }),
6781
+ strictObject({
6782
+ kind: literal("workflow"),
6783
+ flowId: text,
6784
+ revisionId: text
6779
6785
  })
6780
6786
  ])
6781
6787
  });
@@ -6884,6 +6890,12 @@ var base = {
6884
6890
  timeoutMs: number().optional()
6885
6891
  };
6886
6892
  var node = union([
6893
+ strictObject({
6894
+ ...base,
6895
+ kind: literal("outputs"),
6896
+ outputDefs: array(port.strict()),
6897
+ outputMappings: inputs
6898
+ }).omit({ inputs: true }),
6887
6899
  object$1({
6888
6900
  ...base,
6889
6901
  inputs: record$1(text, never()),
@@ -6916,6 +6928,11 @@ var node = union([
6916
6928
  ...trigger,
6917
6929
  kind: literal("manual")
6918
6930
  }),
6931
+ strictObject({
6932
+ ...trigger,
6933
+ kind: literal("start"),
6934
+ inputDefs: workflowInputDefs
6935
+ }),
6919
6936
  strictObject({
6920
6937
  ...trigger,
6921
6938
  kind: literal("error"),
@@ -6980,7 +6997,7 @@ var module = object$1({
6980
6997
  imports: strings,
6981
6998
  source: text
6982
6999
  });
6983
- var document = preprocess(rejectRetiredDefinitions, object$1({
7000
+ var document = preprocess(normalizeDocument, object$1({
6984
7001
  bindings: record$1(text, binding),
6985
7002
  graph
6986
7003
  }));
@@ -6989,7 +7006,9 @@ object$1({
6989
7006
  literal(2),
6990
7007
  literal(4),
6991
7008
  literal(5),
6992
- literal(6)
7009
+ literal(6),
7010
+ literal(7),
7011
+ literal(8)
6993
7012
  ]),
6994
7013
  document,
6995
7014
  modules: record$1(text, module)
@@ -6997,13 +7016,19 @@ object$1({
6997
7016
  kind: literal("open-flow-flow-revision"),
6998
7017
  version: literal(1)
6999
7018
  });
7000
- function rejectRetiredDefinitions(value) {
7019
+ function normalizeDocument(value) {
7001
7020
  const candidate = record(value);
7002
7021
  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.");
7003
7022
  if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => Object.hasOwn(record(candidateNode), "taskId"))) throw new TypeError("Task references are no longer supported.");
7004
7023
  const subflows = candidate.subflows;
7005
7024
  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.");
7006
7025
  if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => record(candidateNode).kind === "subflow")) throw new TypeError("Subflow nodes are no longer supported.");
7026
+ if ([
7027
+ "inputDefs",
7028
+ "outputDefs",
7029
+ "outputMappings"
7030
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
7031
+ 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.");
7007
7032
  return value;
7008
7033
  }
7009
7034
  function record(value) {
@@ -7203,6 +7228,7 @@ function conditionOperands(node) {
7203
7228
  }] : []])));
7204
7229
  }
7205
7230
  function nodeInputMappings(node) {
7231
+ if (node.kind == "outputs") return node.outputMappings;
7206
7232
  if (node.kind != "condition") return "inputs" in node ? node.inputs : {};
7207
7233
  return Object.fromEntries(conditionOperands(node).flatMap(({ handle, operand }) => operand.kind == "source" ? [[handle, {
7208
7234
  kind: "sources",
@@ -7433,6 +7459,17 @@ function decodeConnectorCapabilities(value) {
7433
7459
  };
7434
7460
  });
7435
7461
  }
7462
+ function isTriggerNode(node) {
7463
+ return [
7464
+ "manual",
7465
+ "start",
7466
+ "error",
7467
+ "webhook",
7468
+ "cron",
7469
+ "poll",
7470
+ "integration"
7471
+ ].includes(node.kind);
7472
+ }
7436
7473
  //#endregion
7437
7474
  //#region src/json-schema-subset/utils.ts
7438
7475
  var nextId = 0;
@@ -11298,6 +11335,7 @@ function triggerOutputDefinitions(trigger) {
11298
11335
  switch (trigger.kind) {
11299
11336
  case "error": return errorOutputs;
11300
11337
  case "manual": return [];
11338
+ case "start": return trigger.inputDefs;
11301
11339
  case "cron": return cronOutputs;
11302
11340
  case "poll":
11303
11341
  case "integration": return trigger.definition.outputs;
@@ -11317,6 +11355,15 @@ function matchesTriggerOutputs(trigger, outputs) {
11317
11355
  const ports = triggerOutputDefinitions(trigger);
11318
11356
  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)));
11319
11357
  }
11358
+ /** Resolve caller-supplied Start parameters into the complete output snapshot used by execution. */
11359
+ function normalizeTriggerOutputs(trigger, outputs) {
11360
+ if (!isJsonObject(outputs)) return;
11361
+ const normalized = trigger.kind == "start" ? {
11362
+ ...outputs,
11363
+ ...Object.fromEntries(trigger.inputDefs.filter((port) => port.nullable && !Object.hasOwn(outputs, port.handle)).map((port) => [port.handle, null]))
11364
+ } : outputs;
11365
+ return matchesTriggerOutputs(trigger, normalized) ? normalized : void 0;
11366
+ }
11320
11367
  //#endregion
11321
11368
  //#region src/execution/common/engineContract.ts
11322
11369
  var currentEngineContract = "open-flow-engine/v5";
@@ -11711,16 +11758,22 @@ function canonicalOperand(operand) {
11711
11758
  };
11712
11759
  }
11713
11760
  function canonicalNode(value) {
11714
- if (!("inputs" in value)) return canonicalTriggerNode(value);
11761
+ if (isTriggerNode(value)) return canonicalTriggerNode(value);
11715
11762
  const common = {
11716
11763
  ...value.description == null ? {} : { description: value.description },
11717
11764
  ...value.icon == null ? {} : { icon: value.icon },
11718
- inputs: canonicalInputs(value.inputs),
11765
+ ...value.kind == "outputs" ? {} : { inputs: canonicalInputs(value.inputs) },
11719
11766
  ...value.name == null ? {} : { name: value.name },
11720
11767
  ...value.maxExecutions == null ? {} : { maxExecutions: value.maxExecutions },
11721
11768
  ...value.timeoutMs == null ? {} : { timeoutMs: value.timeoutMs }
11722
11769
  };
11723
11770
  switch (value.kind) {
11771
+ case "outputs": return {
11772
+ ...common,
11773
+ kind: value.kind,
11774
+ outputDefs: canonicalPorts(value.outputDefs),
11775
+ outputMappings: canonicalInputs(value.outputMappings)
11776
+ };
11724
11777
  case "condition": return {
11725
11778
  ...common,
11726
11779
  cases: value.cases.map((item) => ({
@@ -11900,6 +11953,10 @@ function canonicalTriggerNode(trigger) {
11900
11953
  ...trigger.sourceFlowIds == null ? {} : { sourceFlowIds: [...trigger.sourceFlowIds] }
11901
11954
  };
11902
11955
  case "manual": return common(trigger.kind);
11956
+ case "start": return {
11957
+ ...common(trigger.kind),
11958
+ inputDefs: canonicalPorts(trigger.inputDefs)
11959
+ };
11903
11960
  case "webhook": return {
11904
11961
  ...common(trigger.kind),
11905
11962
  bodyFields: trigger.bodyFields.map((input) => ({
@@ -11982,7 +12039,10 @@ function graphDiagnostic(code, message, path, values, mismatch) {
11982
12039
  };
11983
12040
  }
11984
12041
  function validateTrigger(triggerId, trigger, path, diagnostics) {
11985
- const outputHandles = triggerOutputDefinitions(trigger).map((port) => port.handle);
12042
+ if (trigger.kind == "start") return;
12043
+ const outputs = triggerOutputDefinitions(trigger);
12044
+ if (outputs.some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", path));
12045
+ const outputHandles = outputs.map((port) => port.handle);
11986
12046
  if (new Set(outputHandles).size !== outputHandles.length) diagnostics.push(graphDiagnostic("graph.port-duplicate", "Trigger output handles must be unique.", `${path}/definition/outputs`));
11987
12047
  if (trigger.kind == "webhook") {
11988
12048
  if (!webhookSupportsBody(trigger.method) && trigger.bodyFields.length > 0) diagnostics.push(graphDiagnostic("trigger.webhook-body-unsupported", "GET Webhook triggers cannot declare request body fields.", `${path}/bodyFields`));
@@ -12008,6 +12068,7 @@ function validateTrigger(triggerId, trigger, path, diagnostics) {
12008
12068
  }
12009
12069
  function nodeInputPorts(node) {
12010
12070
  switch (node.kind) {
12071
+ case "outputs": return portsByHandle(node.outputDefs);
12011
12072
  case "condition": return conditionInputPorts(node);
12012
12073
  case "value": return {};
12013
12074
  case "task": return portsByHandle([...node.task.inputs, ...node.additionalInputs ?? []]);
@@ -12018,6 +12079,7 @@ function nodeInputPorts(node) {
12018
12079
  case "poll":
12019
12080
  case "error":
12020
12081
  case "manual":
12082
+ case "start":
12021
12083
  case "webhook": return {};
12022
12084
  }
12023
12085
  }
@@ -12045,6 +12107,12 @@ function resolutionOutputPorts(node) {
12045
12107
  pending: objectPort({
12046
12108
  inputs,
12047
12109
  prompt: { type: "string" },
12110
+ pageUrl: { type: "string" },
12111
+ message: {
12112
+ type: "string",
12113
+ minLength: 1,
12114
+ pattern: "\\S"
12115
+ },
12048
12116
  ...Object.fromEntries(actions.map((action) => [`${action}Url`, { type: "string" }])),
12049
12117
  expiresAt: { type: "string" }
12050
12118
  }),
@@ -12058,6 +12126,7 @@ function resolutionOutputPorts(node) {
12058
12126
  }
12059
12127
  function nodeOutputPorts(node) {
12060
12128
  switch (node.kind) {
12129
+ case "outputs":
12061
12130
  case "condition": return {};
12062
12131
  case "value": return portsByHandle(node.values);
12063
12132
  case "task": return portsByHandle(node.task.outputs);
@@ -12068,6 +12137,7 @@ function nodeOutputPorts(node) {
12068
12137
  case "poll":
12069
12138
  case "error":
12070
12139
  case "manual":
12140
+ case "start":
12071
12141
  case "webhook": return triggerOutputPorts(node);
12072
12142
  }
12073
12143
  }
@@ -12185,7 +12255,7 @@ function graphPaths(graph) {
12185
12255
  routes.push(next);
12186
12256
  }
12187
12257
  }
12188
- const nextRoutes = edges.length == 0 ? "inputs" in node ? [{}] : [{ $trigger: id }] : routes;
12258
+ const nextRoutes = edges.length == 0 ? isTriggerNode(node) ? [{ $trigger: id }] : [{}] : routes;
12189
12259
  const previous = paths.get(id) ?? [];
12190
12260
  if (parents.size != (ancestors.get(id)?.size ?? 0) || resolutions.size != (resolutionOutputs.get(id)?.size ?? 0) || nextRoutes.length != previous.length || nextRoutes.some((route) => !previous.some((known) => routeCovers(known, route) && routeCovers(route, known)))) changed = true;
12191
12261
  ancestors.set(id, parents);
@@ -12268,14 +12338,16 @@ function validateGraph(graph, document, path, diagnostics) {
12268
12338
  const analysis = graphPaths(graph);
12269
12339
  const errorTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "error");
12270
12340
  if (errorTriggers.length > 1) for (const [nodeId] of errorTriggers) diagnostics.push(graphDiagnostic("graph.error-trigger-duplicate", "A graph can contain only one Flow Error node.", `${path}/nodes/${nodeId}`));
12271
- const manualTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "manual");
12272
- if (manualTriggers.length > 1) for (const [nodeId] of manualTriggers) diagnostics.push(graphDiagnostic("graph.manual-trigger-duplicate", "A graph can contain only one manual Trigger.", `${path}/nodes/${nodeId}`));
12341
+ const outputNodes = Object.entries(graph.nodes).filter(([, node]) => node.kind == "outputs");
12342
+ if (outputNodes.length > 1) for (const [nodeId] of outputNodes) diagnostics.push(graphDiagnostic("graph.outputs-duplicate", "A graph can contain only one Outputs node.", `${path}/nodes/${nodeId}`));
12343
+ const startTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "manual" || node.kind == "start");
12344
+ if (startTriggers.length > 1) for (const [nodeId] of startTriggers) diagnostics.push(graphDiagnostic("graph.start-trigger-duplicate", "A graph can contain only one Start Trigger.", `${path}/nodes/${nodeId}`));
12273
12345
  const seen = /* @__PURE__ */ new Set();
12274
12346
  for (const [index, edge] of graph.edges.entries()) {
12275
12347
  const edgePath = `${path}/edges/${index}`;
12276
12348
  const source = graph.nodes[edge.source];
12277
12349
  const target = graph.nodes[edge.target];
12278
- if (source == null || target == null || !("inputs" in target)) diagnostics.push(graphDiagnostic("graph.edge-invalid", "Execution edges require an existing source and an executable target.", edgePath));
12350
+ if (source == null || source.kind == "outputs" || target == null || isTriggerNode(target)) diagnostics.push(graphDiagnostic("graph.edge-invalid", "Execution edges require an existing source and an executable target.", edgePath));
12279
12351
  else if (source.kind == "condition" || isResolutionNode(source)) {
12280
12352
  const exits = isResolutionNode(source) ? Object.keys(resolutionOutputPorts(source)) : [...source.cases.map((item) => item.output), otherwiseOutput];
12281
12353
  if (edge.sourceHandle == null || !exits.some((exit) => exit == edge.sourceHandle)) diagnostics.push(graphDiagnostic("graph.edge-invalid", "Choose a declared execution branch.", edgePath));
@@ -12290,13 +12362,12 @@ function validateGraph(graph, document, path, diagnostics) {
12290
12362
  }
12291
12363
  for (const [nodeId, node] of Object.entries(graph.nodes)) {
12292
12364
  const nodePath = `${path}/nodes/${nodeId}`;
12293
- if ("inputs" in node && node.maxExecutions != null && (!Number.isSafeInteger(node.maxExecutions) || node.maxExecutions < 1)) diagnostics.push(graphDiagnostic("node.max-executions-invalid", "Maximum executions must be a positive safe integer.", `${nodePath}/maxExecutions`));
12294
- if (!("inputs" in node)) {
12295
- if (triggerOutputDefinitions(node).some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", nodePath));
12365
+ if (!isTriggerNode(node) && node.maxExecutions != null && (!Number.isSafeInteger(node.maxExecutions) || node.maxExecutions < 1)) diagnostics.push(graphDiagnostic("node.max-executions-invalid", "Maximum executions must be a positive safe integer.", `${nodePath}/maxExecutions`));
12366
+ if (isTriggerNode(node)) {
12296
12367
  validateTrigger(nodeId, node, nodePath, diagnostics);
12297
12368
  continue;
12298
12369
  }
12299
- for (const [handle, mapping] of Object.entries(nodeInputMappings(node))) if (!mappingAvailable(graph, nodeId, mapping, analysis)) diagnostics.push(graphDiagnostic("graph.source-unavailable", "Input sources must reference execution ancestors, respect pending Wait decisions, and never provide multiple values on the same path.", `${nodePath}/inputs/${handle}`));
12370
+ for (const [handle, mapping] of Object.entries(nodeInputMappings(node))) if (!mappingAvailable(graph, nodeId, mapping, analysis)) diagnostics.push(graphDiagnostic("graph.source-unavailable", "Input sources must reference execution ancestors, respect pending Wait decisions, and never provide multiple values on the same path.", node.kind == "outputs" ? `${nodePath}/outputMappings/${handle.replaceAll("~", "~0").replaceAll("/", "~1")}` : `${nodePath}/inputs/${handle}`));
12300
12371
  const inputPorts = nodeInputPorts(node);
12301
12372
  if (node.kind == "task") {
12302
12373
  const ports = [...node.task.inputs, ...node.additionalInputs ?? []];
@@ -12313,7 +12384,7 @@ function validateGraph(graph, document, path, diagnostics) {
12313
12384
  if ([...Object.values(inputPorts), ...Object.values(nodeOutputPorts(node))].some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", nodePath));
12314
12385
  const inputs = new Set(Object.keys(inputPorts));
12315
12386
  for (const [handle, mapping] of Object.entries(nodeInputMappings(node))) {
12316
- const mappingPath = `${nodePath}/inputs/${handle}`;
12387
+ const mappingPath = node.kind == "outputs" ? `${nodePath}/outputMappings/${handle.replaceAll("~", "~0").replaceAll("/", "~1")}` : `${nodePath}/inputs/${handle}`;
12317
12388
  if (!inputs.has(handle)) diagnostics.push(graphDiagnostic("graph.input-missing", `Node "${nodeId}" does not expose input "${handle}".`, mappingPath, {
12318
12389
  handle,
12319
12390
  nodeId
@@ -12363,6 +12434,14 @@ function validateGraph(graph, document, path, diagnostics) {
12363
12434
  }
12364
12435
  function validateFlowGraph(revision) {
12365
12436
  const diagnostics = [];
12437
+ for (const [id, node] of Object.entries(revision.document.graph.nodes)) {
12438
+ if (node.kind != "start" && node.kind != "outputs") continue;
12439
+ const field = node.kind == "start" ? "inputDefs" : "outputDefs";
12440
+ const ports = node.kind == "start" ? node.inputDefs : node.outputDefs;
12441
+ const path = `/document/graph/nodes/${id.replaceAll("~", "~0").replaceAll("/", "~1")}/${field}`;
12442
+ if (new Set(ports.map((port) => port.handle)).size != ports.length) diagnostics.push(graphDiagnostic("graph.port-duplicate", "Workflow interface names must be unique.", path));
12443
+ if (ports.some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", path));
12444
+ }
12366
12445
  for (const [bindingId, binding] of Object.entries(revision.document.bindings)) if (binding.kind == "variable" && !validVariableName(binding.target)) diagnostics.push(graphDiagnostic("binding.variable-invalid", `Variable binding "${bindingId}" has an invalid target.`, `/document/bindings/${bindingId}/target`, { bindingId }));
12367
12446
  validateGraph(revision.document.graph, revision.document, "/document/graph", diagnostics);
12368
12447
  return diagnostics;
@@ -24050,7 +24129,7 @@ function flowDependencies(content, triggerId) {
24050
24129
  }
24051
24130
  function visitGraph(value) {
24052
24131
  for (const [, node] of entries(value.nodes)) {
24053
- if ("inputs" in node) visitInputMappings(nodeInputMappings(node));
24132
+ if (!isTriggerNode(node)) visitInputMappings(nodeInputMappings(node));
24054
24133
  switch (node.kind) {
24055
24134
  case "condition": break;
24056
24135
  case "task": if ("moduleId" in node.task) visitModule(node.task.moduleId);
@@ -24066,21 +24145,29 @@ function flowDependencies(content, triggerId) {
24066
24145
  }
24067
24146
  async function flowClosure(content) {
24068
24147
  const dependencies = flowDependencies(content);
24069
- const { bindings, modules } = dependencies;
24070
24148
  return {
24071
24149
  dependencies,
24072
- digest: await digestBytes(canonicalJsonBytes({
24073
- bindings: Object.fromEntries([...bindings].toSorted().map((id) => [id, content.document.bindings[id] ?? null])),
24074
- graph: canonicalRevisionGraph(content, content.document.graph),
24075
- kind: "open-flow-semantic-closure",
24076
- ...content.modelVersion < 6 ? { subflows: {} } : {},
24077
- modelVersion: content.modelVersion,
24078
- modules: Object.fromEntries([...modules].toSorted().map((id) => [id, content.modules[id] == null ? null : canonicalModule(content.modules[id])])),
24079
- ...content.modelVersion < 6 ? { tasks: {} } : {},
24080
- version: 2
24081
- }))
24150
+ digest: await digestBytes(closureBytes(content, dependencies))
24082
24151
  };
24083
24152
  }
24153
+ /** Canonical semantic bytes, also used by transactional storage upgrades. */
24154
+ function encodeFlowClosure(content, triggerId) {
24155
+ const scoped = triggerId == null ? content : runRevision(content, triggerId);
24156
+ return closureBytes(scoped, flowDependencies(scoped));
24157
+ }
24158
+ function closureBytes(content, dependencies) {
24159
+ const { bindings, modules } = dependencies;
24160
+ return canonicalJsonBytes({
24161
+ bindings: Object.fromEntries([...bindings].toSorted().map((id) => [id, content.document.bindings[id] ?? null])),
24162
+ graph: canonicalRevisionGraph(content, content.document.graph),
24163
+ kind: "open-flow-semantic-closure",
24164
+ ...content.modelVersion < 6 ? { subflows: {} } : {},
24165
+ modelVersion: content.modelVersion,
24166
+ modules: Object.fromEntries([...modules].toSorted().map((id) => [id, content.modules[id] == null ? null : canonicalModule(content.modules[id])])),
24167
+ ...content.modelVersion < 6 ? { tasks: {} } : {},
24168
+ version: 2
24169
+ });
24170
+ }
24084
24171
  function variableBindings(revision, bindingIds) {
24085
24172
  return Object.fromEntries([...bindingIds].flatMap((bindingId) => {
24086
24173
  const binding = revision.document.bindings[bindingId];
@@ -24097,6 +24184,7 @@ function flowResourceReferences(content) {
24097
24184
  });
24098
24185
  }
24099
24186
  return {
24187
+ calledFlowIds: [...new Set(Object.values(content.document.graph.nodes).flatMap((node) => node.kind == "task" && "executor" in node.task && node.task.executor.kind == "workflow" && node.task.executor.flowId ? [node.task.executor.flowId] : []))].toSorted(),
24100
24188
  variableNames: [...new Set(Object.values(variableBindings(content, flowDependencies(content).bindings)))].toSorted(),
24101
24189
  connections: [...connections].toSorted(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([, value]) => value),
24102
24190
  errorSourceFlowIds: [...new Set(Object.values(content.document.graph.nodes).flatMap((node) => node.kind == "error" ? node.sourceFlowIds ?? [] : []))].toSorted()
@@ -24107,18 +24195,30 @@ function validRunTrigger(revision, value) {
24107
24195
  const trigger = value;
24108
24196
  if (Object.keys(trigger).some((key) => key != "nodeId" && key != "outputs") || typeof trigger.nodeId != "string" || !Object.hasOwn(trigger, "outputs")) return false;
24109
24197
  const node = revision.document.graph.nodes[trigger.nodeId];
24110
- return node != null && !("inputs" in node) && matchesTriggerOutputs(node, trigger.outputs);
24198
+ return node != null && isTriggerNode(node) && matchesTriggerOutputs(node, trigger.outputs);
24199
+ }
24200
+ function normalizeRunTrigger(revision, value) {
24201
+ if (value == null || typeof value != "object" || Array.isArray(value)) return;
24202
+ const trigger = value;
24203
+ if (Object.keys(trigger).some((key) => key != "nodeId" && key != "outputs") || typeof trigger.nodeId != "string" || !Object.hasOwn(trigger, "outputs")) return;
24204
+ const node = revision.document.graph.nodes[trigger.nodeId];
24205
+ if (node == null || !isTriggerNode(node)) return;
24206
+ const outputs = normalizeTriggerOutputs(node, trigger.outputs);
24207
+ return outputs == null ? void 0 : {
24208
+ nodeId: trigger.nodeId,
24209
+ outputs
24210
+ };
24111
24211
  }
24112
24212
  function validateFlowInputs(revision, value) {
24113
24213
  if (value == null || typeof value != "object" || Array.isArray(value)) return "invalid";
24114
24214
  const graph = revision.document.graph;
24115
24215
  for (const [nodeId, candidate] of Object.entries(value)) {
24116
24216
  const node = graph.nodes[nodeId];
24117
- if (node == null || !("inputs" in node) || node.kind == "condition" || candidate == null || typeof candidate != "object" || Array.isArray(candidate)) return "invalid";
24217
+ if (node == null || isTriggerNode(node) || node.kind == "condition" || candidate == null || typeof candidate != "object" || Array.isArray(candidate)) return "invalid";
24118
24218
  const inputs = nodeInputPorts(node);
24119
24219
  for (const handle of Object.keys(candidate)) {
24120
24220
  const port = inputs[handle];
24121
- if (port == null || hasRetiredRef(port.jsonSchema) || node.inputs[handle] != null || Object.hasOwn(port, "value")) return "invalid";
24221
+ if (port == null || hasRetiredRef(port.jsonSchema) || nodeInputMappings(node)[handle] != null || Object.hasOwn(port, "value")) return "invalid";
24122
24222
  }
24123
24223
  }
24124
24224
  return "valid";
@@ -24202,6 +24302,17 @@ async function validateFlow(revision, engine) {
24202
24302
  message,
24203
24303
  path: `/document/graph/nodes/${nodeId}/task/executor`
24204
24304
  });
24305
+ if (task.executor.kind == "connector" && task.executor.action == "leina.send_notification") {
24306
+ const mapping = node.inputs.leinaId;
24307
+ const value = inputValue(mapping, nodeInputPorts(node).leinaId?.value);
24308
+ if ((mapping?.kind != "sources" || mapping.sources.length == 0) && (typeof value != "string" || value.trim().length == 0)) checked.diagnostics.push({
24309
+ code: "leina.robot-required",
24310
+ column: 0,
24311
+ line: 1,
24312
+ message: "Select a Leina robot or bind its identifier to an input source.",
24313
+ path: `/document/graph/nodes/${nodeId}/inputs/leinaId`
24314
+ });
24315
+ }
24205
24316
  if (task.executor.kind == "connector" && task.executor.action.length == 0) checked.diagnostics.push({
24206
24317
  code: "task.connector-incomplete",
24207
24318
  column: 0,
@@ -24235,7 +24346,10 @@ function runRevision(revision, triggerId) {
24235
24346
  for (const nodeId of reachable) {
24236
24347
  const node = graph.nodes[nodeId];
24237
24348
  if (node == null) continue;
24238
- nodes[nodeId] = !("inputs" in node) ? node : {
24349
+ nodes[nodeId] = node.kind == "outputs" ? {
24350
+ ...node,
24351
+ outputMappings: inputs(nodeId, node.outputMappings)
24352
+ } : isTriggerNode(node) ? node : {
24239
24353
  ...node,
24240
24354
  inputs: inputs(nodeId, node.inputs)
24241
24355
  };
@@ -24264,7 +24378,7 @@ async function prepareFlow(revision, engineContract, triggerId) {
24264
24378
  if (engine == null) return { kind: "engine-unsupported" };
24265
24379
  if (triggerId != null) {
24266
24380
  const trigger = revision.document.graph.nodes[triggerId];
24267
- if (trigger == null || "inputs" in trigger) return {
24381
+ if (trigger == null || !isTriggerNode(trigger)) return {
24268
24382
  kind: "flow-invalid",
24269
24383
  validation: {
24270
24384
  closure: await flowClosure(revision),
@@ -24287,10 +24401,15 @@ async function prepareFlow(revision, engineContract, triggerId) {
24287
24401
  validation
24288
24402
  };
24289
24403
  const { closure } = validation;
24404
+ const start = Object.values(revision.document.graph.nodes).find((node) => node.kind == "start");
24405
+ const outputs = Object.values(revision.document.graph.nodes).find((node) => node.kind == "outputs");
24290
24406
  return {
24291
24407
  flow: {
24292
24408
  closureDigest: closure.digest,
24293
24409
  engineContract,
24410
+ inputDefs: start?.inputDefs ?? [],
24411
+ outputDefs: outputs?.outputDefs ?? [],
24412
+ outputMappings: outputs?.outputMappings ?? {},
24294
24413
  graph: revision.document.graph,
24295
24414
  modules: Object.fromEntries([...closure.dependencies.modules].toSorted().map((id) => [id, revision.modules[id]]))
24296
24415
  },
@@ -24324,4 +24443,4 @@ function codeActions(flow) {
24324
24443
  return Object.values(flow.graph.nodes).flatMap((node) => node.kind == "task" && "moduleId" in node.task ? node.task.capabilities ?? [] : []);
24325
24444
  }
24326
24445
  //#endregion
24327
- export { agentActions, agentInput, agentToolInput, agentToolSchema, availableOutputs, codeActions, connectionUsage, createRuntimeProgram, flowClosure, flowDependencies, flowResourceReferences, graphOrder, matchesSchema, matchesTriggerOutputs, nodeInputPorts, prepareFlow, removeConnectionUsage, renderPrompt, schemaValidationErrors, triggerOutputDefinitions, triggerOutputPorts, validRunTrigger, validateFlow, validateFlowInputs, validateModules, variableBindings, variableInputCompatible };
24446
+ export { agentActions, agentInput, agentToolInput, agentToolSchema, availableOutputs, codeActions, connectionUsage, createRuntimeProgram, encodeFlowClosure, flowClosure, flowDependencies, flowResourceReferences, graphOrder, matchesSchema, matchesTriggerOutputs, nodeInputPorts, normalizeRunTrigger, normalizeTriggerOutputs, prepareFlow, removeConnectionUsage, renderPrompt, schemaValidationErrors, triggerOutputDefinitions, triggerOutputPorts, validRunTrigger, validateFlow, validateFlowInputs, validateModules, variableBindings, variableInputCompatible };
@@ -6702,6 +6702,7 @@ var port = object({
6702
6702
  nullable: boolean(),
6703
6703
  handle: text
6704
6704
  });
6705
+ var workflowInputDefs = array(port.strict());
6705
6706
  var input = port.extend({ value: json.optional() });
6706
6707
  var group = object({
6707
6708
  collapsed: boolean().optional(),
@@ -6859,6 +6860,11 @@ var managedFields = object({
6859
6860
  messageHandle: text,
6860
6861
  inputs: record$2(text, agentValue)
6861
6862
  }).optional()
6863
+ }),
6864
+ strictObject({
6865
+ kind: literal("workflow"),
6866
+ flowId: text,
6867
+ revisionId: text
6862
6868
  })
6863
6869
  ])
6864
6870
  });
@@ -6967,6 +6973,12 @@ var base = {
6967
6973
  timeoutMs: number().optional()
6968
6974
  };
6969
6975
  var node = union([
6976
+ strictObject({
6977
+ ...base,
6978
+ kind: literal("outputs"),
6979
+ outputDefs: array(port.strict()),
6980
+ outputMappings: inputs
6981
+ }).omit({ inputs: true }),
6970
6982
  object({
6971
6983
  ...base,
6972
6984
  inputs: record$2(text, never()),
@@ -6999,6 +7011,11 @@ var node = union([
6999
7011
  ...trigger,
7000
7012
  kind: literal("manual")
7001
7013
  }),
7014
+ strictObject({
7015
+ ...trigger,
7016
+ kind: literal("start"),
7017
+ inputDefs: workflowInputDefs
7018
+ }),
7002
7019
  strictObject({
7003
7020
  ...trigger,
7004
7021
  kind: literal("error"),
@@ -7063,7 +7080,7 @@ var module = object({
7063
7080
  imports: strings,
7064
7081
  source: text
7065
7082
  });
7066
- var document = preprocess(rejectRetiredDefinitions, object({
7083
+ var document = preprocess(normalizeDocument, object({
7067
7084
  bindings: record$2(text, binding),
7068
7085
  graph
7069
7086
  }));
@@ -7072,7 +7089,9 @@ object({
7072
7089
  literal(2),
7073
7090
  literal(4),
7074
7091
  literal(5),
7075
- literal(6)
7092
+ literal(6),
7093
+ literal(7),
7094
+ literal(8)
7076
7095
  ]),
7077
7096
  document,
7078
7097
  modules: record$2(text, module)
@@ -7080,13 +7099,19 @@ object({
7080
7099
  kind: literal("open-flow-flow-revision"),
7081
7100
  version: literal(1)
7082
7101
  });
7083
- function rejectRetiredDefinitions(value) {
7102
+ function normalizeDocument(value) {
7084
7103
  const candidate = record$1(value);
7085
7104
  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.");
7086
7105
  if (Object.values(record$1(record$1(candidate.graph).nodes)).some((candidateNode) => Object.hasOwn(record$1(candidateNode), "taskId"))) throw new TypeError("Task references are no longer supported.");
7087
7106
  const subflows = candidate.subflows;
7088
7107
  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.");
7089
7108
  if (Object.values(record$1(record$1(candidate.graph).nodes)).some((candidateNode) => record$1(candidateNode).kind === "subflow")) throw new TypeError("Subflow nodes are no longer supported.");
7109
+ if ([
7110
+ "inputDefs",
7111
+ "outputDefs",
7112
+ "outputMappings"
7113
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
7114
+ if (Object.values(record$1(record$1(candidate.graph).nodes)).some((candidateNode) => record$1(candidateNode).kind == "start" && Object.hasOwn(record$1(candidateNode), "parameters"))) throw new TypeError("Legacy Start.parameters is unsupported; configure node.inputDefs.");
7090
7115
  return value;
7091
7116
  }
7092
7117
  function record$1(value) {
@@ -1,13 +1,26 @@
1
1
  import type { RevisionContent } from '../browser/flow-change.js';
2
2
  import type { Publication, TriggerBinding } from './control-api.js';
3
3
  import { z } from 'zod';
4
+ import { flowInputFieldsView } from './authoringSchema.js';
4
5
  declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6
+ nodeId: z.ZodString;
7
+ name: z.ZodString;
8
+ description: z.ZodOptional<z.ZodString>;
9
+ type: z.ZodLiteral<"start">;
10
+ config: z.ZodObject<{
11
+ inputDefs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
12
+ schema: z.ZodOptional<z.ZodJSONSchema>;
13
+ nullable: z.ZodOptional<z.ZodBoolean>;
14
+ description: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strict>>>;
16
+ }, z.core.$strict>;
17
+ }, z.core.$strip>, z.ZodObject<{
5
18
  nodeId: z.ZodString;
6
19
  name: z.ZodString;
7
20
  description: z.ZodOptional<z.ZodString>;
8
21
  type: z.ZodLiteral<"manual">;
9
- config: z.ZodObject<{}, z.core.$strict>;
10
- }, z.core.$strict>, z.ZodObject<{
22
+ config: z.ZodObject<{}, z.core.$strip>;
23
+ }, z.core.$strip>, z.ZodObject<{
11
24
  nodeId: z.ZodString;
12
25
  name: z.ZodString;
13
26
  description: z.ZodOptional<z.ZodString>;
@@ -36,7 +49,7 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
36
49
  }, z.core.$strict>>;
37
50
  }, z.core.$strict>;
38
51
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
39
- }, z.core.$strict>, z.ZodObject<{
52
+ }, z.core.$strip>, z.ZodObject<{
40
53
  nodeId: z.ZodString;
41
54
  name: z.ZodString;
42
55
  description: z.ZodOptional<z.ZodString>;
@@ -59,7 +72,7 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
59
72
  }, z.core.$strip>]>>;
60
73
  }, z.core.$strict>;
61
74
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
62
- }, z.core.$strict>, z.ZodObject<{
75
+ }, z.core.$strip>, z.ZodObject<{
63
76
  nodeId: z.ZodString;
64
77
  name: z.ZodString;
65
78
  description: z.ZodOptional<z.ZodString>;
@@ -68,7 +81,7 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
68
81
  sourceFlowIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
69
82
  }, z.core.$strict>;
70
83
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
71
- }, z.core.$strict>, z.ZodObject<{
84
+ }, z.core.$strip>, z.ZodObject<{
72
85
  nodeId: z.ZodString;
73
86
  name: z.ZodString;
74
87
  description: z.ZodOptional<z.ZodString>;
@@ -76,9 +89,9 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
76
89
  inputs: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
77
90
  kind: z.ZodLiteral<"value">;
78
91
  value: z.ZodJSONSchema;
79
- }, z.core.$strict>, z.ZodObject<{
92
+ }, z.core.$strip>, z.ZodObject<{
80
93
  kind: z.ZodLiteral<"unset">;
81
- }, z.core.$strict>], "kind">>;
94
+ }, z.core.$strip>], "kind">>;
82
95
  type: z.ZodLiteral<"poll">;
83
96
  config: z.ZodObject<{
84
97
  key: z.ZodString;
@@ -100,7 +113,7 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
100
113
  }, z.core.$strip>]>>;
101
114
  }, z.core.$strict>;
102
115
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
103
- }, z.core.$strict>, z.ZodObject<{
116
+ }, z.core.$strip>, z.ZodObject<{
104
117
  nodeId: z.ZodString;
105
118
  name: z.ZodString;
106
119
  description: z.ZodOptional<z.ZodString>;
@@ -108,25 +121,27 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
108
121
  inputs: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
109
122
  kind: z.ZodLiteral<"value">;
110
123
  value: z.ZodJSONSchema;
111
- }, z.core.$strict>, z.ZodObject<{
124
+ }, z.core.$strip>, z.ZodObject<{
112
125
  kind: z.ZodLiteral<"unset">;
113
- }, z.core.$strict>], "kind">>;
126
+ }, z.core.$strip>], "kind">>;
114
127
  type: z.ZodLiteral<"integration">;
115
128
  config: z.ZodObject<{
116
129
  key: z.ZodString;
117
130
  connectionId: z.ZodOptional<z.ZodString>;
118
131
  }, z.core.$strict>;
119
132
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
120
- }, z.core.$strict>], "type">;
133
+ }, z.core.$strip>], "type">;
121
134
  export type LiveEntry = z.infer<typeof entrySchema>;
122
135
  export type LiveDetails = {
123
136
  readonly flowId: string;
124
137
  readonly version: 1;
125
138
  } & ({
139
+ readonly inputDefs: null;
126
140
  readonly publication: null;
127
141
  readonly status: 'not-published';
128
142
  readonly entries: readonly [];
129
143
  } | {
144
+ readonly inputDefs: z.infer<typeof flowInputFieldsView>;
130
145
  readonly publication: Publication;
131
146
  readonly status: 'runnable' | 'suspended';
132
147
  readonly enabled: boolean;