@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
@@ -6611,6 +6611,7 @@ function webhookSupportsBody(method) {
6611
6611
  return method !== "GET";
6612
6612
  }
6613
6613
  var text = string();
6614
+ 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.");
6614
6615
  var json = json$1();
6615
6616
  var strings = array(text);
6616
6617
  var port = object$1({
@@ -6619,6 +6620,7 @@ var port = object$1({
6619
6620
  nullable: boolean(),
6620
6621
  handle: text
6621
6622
  });
6623
+ var workflowInputDefs = array(port.strict());
6622
6624
  var input = port.extend({ value: json.optional() });
6623
6625
  var group = object$1({
6624
6626
  collapsed: boolean().optional(),
@@ -6665,7 +6667,7 @@ var capability = union([
6665
6667
  mode: literal("independent"),
6666
6668
  actions: array(strictObject({
6667
6669
  action: text,
6668
- connectionId: text.optional()
6670
+ connectionId: actionConnection.optional()
6669
6671
  }))
6670
6672
  }),
6671
6673
  strictObject({
@@ -6725,7 +6727,7 @@ var managedFields = object$1({
6725
6727
  object$1({
6726
6728
  kind: literal("connector"),
6727
6729
  action: text,
6728
- connectionId: text.optional(),
6730
+ connectionId: actionConnection.optional(),
6729
6731
  outputMode: literal("value").optional()
6730
6732
  }),
6731
6733
  object$1({
@@ -6765,17 +6767,22 @@ var managedFields = object$1({
6765
6767
  name: text,
6766
6768
  description: text,
6767
6769
  action: text,
6768
- connectionId: text.optional(),
6770
+ connectionId: actionConnection.optional(),
6769
6771
  approval: boolean(),
6770
6772
  inputs: array(input.extend({ source: agentInput$1 }))
6771
6773
  })),
6772
6774
  notification: object$1({
6773
6775
  action: text,
6774
- connectionId: text.optional(),
6776
+ connectionId: actionConnection.optional(),
6775
6777
  inputDefinitions: array(input),
6776
6778
  messageHandle: text,
6777
6779
  inputs: record$1(text, agentValue)
6778
6780
  }).optional()
6781
+ }),
6782
+ strictObject({
6783
+ kind: literal("workflow"),
6784
+ flowId: text,
6785
+ revisionId: text
6779
6786
  })
6780
6787
  ])
6781
6788
  });
@@ -6884,6 +6891,12 @@ var base = {
6884
6891
  timeoutMs: number().optional()
6885
6892
  };
6886
6893
  var node = union([
6894
+ strictObject({
6895
+ ...base,
6896
+ kind: literal("outputs"),
6897
+ outputDefs: array(port.strict()),
6898
+ outputMappings: inputs
6899
+ }).omit({ inputs: true }),
6887
6900
  object$1({
6888
6901
  ...base,
6889
6902
  inputs: record$1(text, never()),
@@ -6916,6 +6929,11 @@ var node = union([
6916
6929
  ...trigger,
6917
6930
  kind: literal("manual")
6918
6931
  }),
6932
+ strictObject({
6933
+ ...trigger,
6934
+ kind: literal("start"),
6935
+ inputDefs: workflowInputDefs
6936
+ }),
6919
6937
  strictObject({
6920
6938
  ...trigger,
6921
6939
  kind: literal("error"),
@@ -6980,7 +6998,7 @@ var module = object$1({
6980
6998
  imports: strings,
6981
6999
  source: text
6982
7000
  });
6983
- var document = preprocess(rejectRetiredDefinitions, object$1({
7001
+ var document = preprocess(normalizeDocument, object$1({
6984
7002
  bindings: record$1(text, binding),
6985
7003
  graph
6986
7004
  }));
@@ -6989,7 +7007,9 @@ object$1({
6989
7007
  literal(2),
6990
7008
  literal(4),
6991
7009
  literal(5),
6992
- literal(6)
7010
+ literal(6),
7011
+ literal(7),
7012
+ literal(8)
6993
7013
  ]),
6994
7014
  document,
6995
7015
  modules: record$1(text, module)
@@ -6997,13 +7017,19 @@ object$1({
6997
7017
  kind: literal("open-flow-flow-revision"),
6998
7018
  version: literal(1)
6999
7019
  });
7000
- function rejectRetiredDefinitions(value) {
7020
+ function normalizeDocument(value) {
7001
7021
  const candidate = record(value);
7002
7022
  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
7023
  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
7024
  const subflows = candidate.subflows;
7005
7025
  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
7026
  if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => record(candidateNode).kind === "subflow")) throw new TypeError("Subflow nodes are no longer supported.");
7027
+ if ([
7028
+ "inputDefs",
7029
+ "outputDefs",
7030
+ "outputMappings"
7031
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
7032
+ 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
7033
  return value;
7008
7034
  }
7009
7035
  function record(value) {
@@ -7203,6 +7229,7 @@ function conditionOperands(node) {
7203
7229
  }] : []])));
7204
7230
  }
7205
7231
  function nodeInputMappings(node) {
7232
+ if (node.kind == "outputs") return node.outputMappings;
7206
7233
  if (node.kind != "condition") return "inputs" in node ? node.inputs : {};
7207
7234
  return Object.fromEntries(conditionOperands(node).flatMap(({ handle, operand }) => operand.kind == "source" ? [[handle, {
7208
7235
  kind: "sources",
@@ -7341,7 +7368,7 @@ function decodeConnectorCapabilities(value) {
7341
7368
  const actions = source.actions.map((entry) => {
7342
7369
  if (entry == null || typeof entry != "object" || Array.isArray(entry)) throw new TypeError("Invalid Connector Action.");
7343
7370
  const action = entry;
7344
- if (Object.keys(action).some((key) => !["action", "connectionId"].includes(key)) || typeof action.action != "string" || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_.-]+$/.test(action.action) || Object.hasOwn(action, "connectionId") && (typeof action.connectionId != "string" || action.connectionId.length == 0)) throw new TypeError("Invalid Connector Action permission.");
7371
+ if (Object.keys(action).some((key) => !["action", "connectionId"].includes(key)) || typeof action.action != "string" || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_.-]+$/.test(action.action) || Object.hasOwn(action, "connectionId") && typeof action.connectionId != "string") throw new TypeError("Invalid Connector Action permission.");
7345
7372
  return action.connectionId == null ? { action: action.action } : {
7346
7373
  action: action.action,
7347
7374
  connectionId: action.connectionId
@@ -7433,6 +7460,17 @@ function decodeConnectorCapabilities(value) {
7433
7460
  };
7434
7461
  });
7435
7462
  }
7463
+ function isTriggerNode(node) {
7464
+ return [
7465
+ "manual",
7466
+ "start",
7467
+ "error",
7468
+ "webhook",
7469
+ "cron",
7470
+ "poll",
7471
+ "integration"
7472
+ ].includes(node.kind);
7473
+ }
7436
7474
  //#endregion
7437
7475
  //#region src/json-schema-subset/utils.ts
7438
7476
  var nextId = 0;
@@ -11060,6 +11098,7 @@ function clearNodeConnections(graph, connectionId) {
11060
11098
  if ("executor" in node.task) {
11061
11099
  const executor = node.task.executor;
11062
11100
  const clear = (value) => {
11101
+ if (value.connectionId === "") return value;
11063
11102
  if (connectionId != null && value.connectionId != connectionId) return value;
11064
11103
  const { connectionId: _, ...rest } = value;
11065
11104
  return rest;
@@ -11104,6 +11143,7 @@ function clearNodeConnections(graph, connectionId) {
11104
11143
  return {
11105
11144
  ...capability,
11106
11145
  actions: capability.actions.map((action) => {
11146
+ if (action.connectionId === "") return action;
11107
11147
  if (connectionId != null && action.connectionId != connectionId) return action;
11108
11148
  const { connectionId: _, ...remaining } = action;
11109
11149
  return remaining;
@@ -11298,6 +11338,7 @@ function triggerOutputDefinitions(trigger) {
11298
11338
  switch (trigger.kind) {
11299
11339
  case "error": return errorOutputs;
11300
11340
  case "manual": return [];
11341
+ case "start": return trigger.inputDefs;
11301
11342
  case "cron": return cronOutputs;
11302
11343
  case "poll":
11303
11344
  case "integration": return trigger.definition.outputs;
@@ -11317,6 +11358,15 @@ function matchesTriggerOutputs(trigger, outputs) {
11317
11358
  const ports = triggerOutputDefinitions(trigger);
11318
11359
  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
11360
  }
11361
+ /** Resolve caller-supplied Start parameters into the complete output snapshot used by execution. */
11362
+ function normalizeTriggerOutputs(trigger, outputs) {
11363
+ if (!isJsonObject(outputs)) return;
11364
+ const normalized = trigger.kind == "start" ? {
11365
+ ...outputs,
11366
+ ...Object.fromEntries(trigger.inputDefs.filter((port) => port.nullable && !Object.hasOwn(outputs, port.handle)).map((port) => [port.handle, null]))
11367
+ } : outputs;
11368
+ return matchesTriggerOutputs(trigger, normalized) ? normalized : void 0;
11369
+ }
11320
11370
  //#endregion
11321
11371
  //#region src/execution/common/engineContract.ts
11322
11372
  var currentEngineContract = "open-flow-engine/v5";
@@ -11559,7 +11609,7 @@ function agentConfigIssues(task) {
11559
11609
  ids.add(tool.id);
11560
11610
  names.add(tool.name);
11561
11611
  if (tool.description.trim().length == 0) issues.push(`Tool ${tool.name} requires a description.`);
11562
- if (!/^[A-Za-z0-9_-]+\.[A-Za-z0-9_.-]+$/.test(tool.action) || tool.connectionId === "") issues.push(`Tool ${tool.name} has an invalid Action or Connection.`);
11612
+ if (!/^[A-Za-z0-9_-]+\.[A-Za-z0-9_.-]+$/.test(tool.action)) issues.push(`Tool ${tool.name} has an invalid Action or Connection.`);
11563
11613
  const fields = /* @__PURE__ */ new Set();
11564
11614
  for (const port of tool.inputs) {
11565
11615
  if (port.handle.length == 0 || fields.has(port.handle)) issues.push(`Tool ${tool.name} has an empty or duplicate input.`);
@@ -11711,16 +11761,22 @@ function canonicalOperand(operand) {
11711
11761
  };
11712
11762
  }
11713
11763
  function canonicalNode(value) {
11714
- if (!("inputs" in value)) return canonicalTriggerNode(value);
11764
+ if (isTriggerNode(value)) return canonicalTriggerNode(value);
11715
11765
  const common = {
11716
11766
  ...value.description == null ? {} : { description: value.description },
11717
11767
  ...value.icon == null ? {} : { icon: value.icon },
11718
- inputs: canonicalInputs(value.inputs),
11768
+ ...value.kind == "outputs" ? {} : { inputs: canonicalInputs(value.inputs) },
11719
11769
  ...value.name == null ? {} : { name: value.name },
11720
11770
  ...value.maxExecutions == null ? {} : { maxExecutions: value.maxExecutions },
11721
11771
  ...value.timeoutMs == null ? {} : { timeoutMs: value.timeoutMs }
11722
11772
  };
11723
11773
  switch (value.kind) {
11774
+ case "outputs": return {
11775
+ ...common,
11776
+ kind: value.kind,
11777
+ outputDefs: canonicalPorts(value.outputDefs),
11778
+ outputMappings: canonicalInputs(value.outputMappings)
11779
+ };
11724
11780
  case "condition": return {
11725
11781
  ...common,
11726
11782
  cases: value.cases.map((item) => ({
@@ -11900,6 +11956,10 @@ function canonicalTriggerNode(trigger) {
11900
11956
  ...trigger.sourceFlowIds == null ? {} : { sourceFlowIds: [...trigger.sourceFlowIds] }
11901
11957
  };
11902
11958
  case "manual": return common(trigger.kind);
11959
+ case "start": return {
11960
+ ...common(trigger.kind),
11961
+ inputDefs: canonicalPorts(trigger.inputDefs)
11962
+ };
11903
11963
  case "webhook": return {
11904
11964
  ...common(trigger.kind),
11905
11965
  bodyFields: trigger.bodyFields.map((input) => ({
@@ -11982,7 +12042,10 @@ function graphDiagnostic(code, message, path, values, mismatch) {
11982
12042
  };
11983
12043
  }
11984
12044
  function validateTrigger(triggerId, trigger, path, diagnostics) {
11985
- const outputHandles = triggerOutputDefinitions(trigger).map((port) => port.handle);
12045
+ if (trigger.kind == "start") return;
12046
+ const outputs = triggerOutputDefinitions(trigger);
12047
+ if (outputs.some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", path));
12048
+ const outputHandles = outputs.map((port) => port.handle);
11986
12049
  if (new Set(outputHandles).size !== outputHandles.length) diagnostics.push(graphDiagnostic("graph.port-duplicate", "Trigger output handles must be unique.", `${path}/definition/outputs`));
11987
12050
  if (trigger.kind == "webhook") {
11988
12051
  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 +12071,7 @@ function validateTrigger(triggerId, trigger, path, diagnostics) {
12008
12071
  }
12009
12072
  function nodeInputPorts(node) {
12010
12073
  switch (node.kind) {
12074
+ case "outputs": return portsByHandle(node.outputDefs);
12011
12075
  case "condition": return conditionInputPorts(node);
12012
12076
  case "value": return {};
12013
12077
  case "task": return portsByHandle([...node.task.inputs, ...node.additionalInputs ?? []]);
@@ -12018,6 +12082,7 @@ function nodeInputPorts(node) {
12018
12082
  case "poll":
12019
12083
  case "error":
12020
12084
  case "manual":
12085
+ case "start":
12021
12086
  case "webhook": return {};
12022
12087
  }
12023
12088
  }
@@ -12064,6 +12129,7 @@ function resolutionOutputPorts(node) {
12064
12129
  }
12065
12130
  function nodeOutputPorts(node) {
12066
12131
  switch (node.kind) {
12132
+ case "outputs":
12067
12133
  case "condition": return {};
12068
12134
  case "value": return portsByHandle(node.values);
12069
12135
  case "task": return portsByHandle(node.task.outputs);
@@ -12074,6 +12140,7 @@ function nodeOutputPorts(node) {
12074
12140
  case "poll":
12075
12141
  case "error":
12076
12142
  case "manual":
12143
+ case "start":
12077
12144
  case "webhook": return triggerOutputPorts(node);
12078
12145
  }
12079
12146
  }
@@ -12191,7 +12258,7 @@ function graphPaths(graph) {
12191
12258
  routes.push(next);
12192
12259
  }
12193
12260
  }
12194
- const nextRoutes = edges.length == 0 ? "inputs" in node ? [{}] : [{ $trigger: id }] : routes;
12261
+ const nextRoutes = edges.length == 0 ? isTriggerNode(node) ? [{ $trigger: id }] : [{}] : routes;
12195
12262
  const previous = paths.get(id) ?? [];
12196
12263
  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;
12197
12264
  ancestors.set(id, parents);
@@ -12274,14 +12341,16 @@ function validateGraph(graph, document, path, diagnostics) {
12274
12341
  const analysis = graphPaths(graph);
12275
12342
  const errorTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "error");
12276
12343
  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}`));
12277
- const manualTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "manual");
12278
- 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}`));
12344
+ const outputNodes = Object.entries(graph.nodes).filter(([, node]) => node.kind == "outputs");
12345
+ 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}`));
12346
+ const startTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "manual" || node.kind == "start");
12347
+ 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}`));
12279
12348
  const seen = /* @__PURE__ */ new Set();
12280
12349
  for (const [index, edge] of graph.edges.entries()) {
12281
12350
  const edgePath = `${path}/edges/${index}`;
12282
12351
  const source = graph.nodes[edge.source];
12283
12352
  const target = graph.nodes[edge.target];
12284
- 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));
12353
+ 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));
12285
12354
  else if (source.kind == "condition" || isResolutionNode(source)) {
12286
12355
  const exits = isResolutionNode(source) ? Object.keys(resolutionOutputPorts(source)) : [...source.cases.map((item) => item.output), otherwiseOutput];
12287
12356
  if (edge.sourceHandle == null || !exits.some((exit) => exit == edge.sourceHandle)) diagnostics.push(graphDiagnostic("graph.edge-invalid", "Choose a declared execution branch.", edgePath));
@@ -12296,13 +12365,12 @@ function validateGraph(graph, document, path, diagnostics) {
12296
12365
  }
12297
12366
  for (const [nodeId, node] of Object.entries(graph.nodes)) {
12298
12367
  const nodePath = `${path}/nodes/${nodeId}`;
12299
- 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`));
12300
- if (!("inputs" in node)) {
12301
- if (triggerOutputDefinitions(node).some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", nodePath));
12368
+ 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`));
12369
+ if (isTriggerNode(node)) {
12302
12370
  validateTrigger(nodeId, node, nodePath, diagnostics);
12303
12371
  continue;
12304
12372
  }
12305
- 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}`));
12373
+ 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}`));
12306
12374
  const inputPorts = nodeInputPorts(node);
12307
12375
  if (node.kind == "task") {
12308
12376
  const ports = [...node.task.inputs, ...node.additionalInputs ?? []];
@@ -12319,7 +12387,7 @@ function validateGraph(graph, document, path, diagnostics) {
12319
12387
  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));
12320
12388
  const inputs = new Set(Object.keys(inputPorts));
12321
12389
  for (const [handle, mapping] of Object.entries(nodeInputMappings(node))) {
12322
- const mappingPath = `${nodePath}/inputs/${handle}`;
12390
+ const mappingPath = node.kind == "outputs" ? `${nodePath}/outputMappings/${handle.replaceAll("~", "~0").replaceAll("/", "~1")}` : `${nodePath}/inputs/${handle}`;
12323
12391
  if (!inputs.has(handle)) diagnostics.push(graphDiagnostic("graph.input-missing", `Node "${nodeId}" does not expose input "${handle}".`, mappingPath, {
12324
12392
  handle,
12325
12393
  nodeId
@@ -12369,6 +12437,14 @@ function validateGraph(graph, document, path, diagnostics) {
12369
12437
  }
12370
12438
  function validateFlowGraph(revision) {
12371
12439
  const diagnostics = [];
12440
+ for (const [id, node] of Object.entries(revision.document.graph.nodes)) {
12441
+ if (node.kind != "start" && node.kind != "outputs") continue;
12442
+ const field = node.kind == "start" ? "inputDefs" : "outputDefs";
12443
+ const ports = node.kind == "start" ? node.inputDefs : node.outputDefs;
12444
+ const path = `/document/graph/nodes/${id.replaceAll("~", "~0").replaceAll("/", "~1")}/${field}`;
12445
+ if (new Set(ports.map((port) => port.handle)).size != ports.length) diagnostics.push(graphDiagnostic("graph.port-duplicate", "Workflow interface names must be unique.", path));
12446
+ if (ports.some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", path));
12447
+ }
12372
12448
  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 }));
12373
12449
  validateGraph(revision.document.graph, revision.document, "/document/graph", diagnostics);
12374
12450
  return diagnostics;
@@ -24056,7 +24132,7 @@ function flowDependencies(content, triggerId) {
24056
24132
  }
24057
24133
  function visitGraph(value) {
24058
24134
  for (const [, node] of entries(value.nodes)) {
24059
- if ("inputs" in node) visitInputMappings(nodeInputMappings(node));
24135
+ if (!isTriggerNode(node)) visitInputMappings(nodeInputMappings(node));
24060
24136
  switch (node.kind) {
24061
24137
  case "condition": break;
24062
24138
  case "task": if ("moduleId" in node.task) visitModule(node.task.moduleId);
@@ -24072,21 +24148,29 @@ function flowDependencies(content, triggerId) {
24072
24148
  }
24073
24149
  async function flowClosure(content) {
24074
24150
  const dependencies = flowDependencies(content);
24075
- const { bindings, modules } = dependencies;
24076
24151
  return {
24077
24152
  dependencies,
24078
- digest: await digestBytes(canonicalJsonBytes({
24079
- bindings: Object.fromEntries([...bindings].toSorted().map((id) => [id, content.document.bindings[id] ?? null])),
24080
- graph: canonicalRevisionGraph(content, content.document.graph),
24081
- kind: "open-flow-semantic-closure",
24082
- ...content.modelVersion < 6 ? { subflows: {} } : {},
24083
- modelVersion: content.modelVersion,
24084
- modules: Object.fromEntries([...modules].toSorted().map((id) => [id, content.modules[id] == null ? null : canonicalModule(content.modules[id])])),
24085
- ...content.modelVersion < 6 ? { tasks: {} } : {},
24086
- version: 2
24087
- }))
24153
+ digest: await digestBytes(closureBytes(content, dependencies))
24088
24154
  };
24089
24155
  }
24156
+ /** Canonical semantic bytes, also used by transactional storage upgrades. */
24157
+ function encodeFlowClosure(content, triggerId) {
24158
+ const scoped = triggerId == null ? content : runRevision(content, triggerId);
24159
+ return closureBytes(scoped, flowDependencies(scoped));
24160
+ }
24161
+ function closureBytes(content, dependencies) {
24162
+ const { bindings, modules } = dependencies;
24163
+ return canonicalJsonBytes({
24164
+ bindings: Object.fromEntries([...bindings].toSorted().map((id) => [id, content.document.bindings[id] ?? null])),
24165
+ graph: canonicalRevisionGraph(content, content.document.graph),
24166
+ kind: "open-flow-semantic-closure",
24167
+ ...content.modelVersion < 6 ? { subflows: {} } : {},
24168
+ modelVersion: content.modelVersion,
24169
+ modules: Object.fromEntries([...modules].toSorted().map((id) => [id, content.modules[id] == null ? null : canonicalModule(content.modules[id])])),
24170
+ ...content.modelVersion < 6 ? { tasks: {} } : {},
24171
+ version: 2
24172
+ });
24173
+ }
24090
24174
  function variableBindings(revision, bindingIds) {
24091
24175
  return Object.fromEntries([...bindingIds].flatMap((bindingId) => {
24092
24176
  const binding = revision.document.bindings[bindingId];
@@ -24096,13 +24180,14 @@ function variableBindings(revision, bindingIds) {
24096
24180
  function flowResourceReferences(content) {
24097
24181
  const connections = /* @__PURE__ */ new Map();
24098
24182
  for (const use of connectionUsage(content.document)) {
24099
- if (use.connectionId == null) continue;
24183
+ if (use.connectionId == null || use.connectionId === "") continue;
24100
24184
  connections.set(JSON.stringify([use.providerId, use.connectionId]), {
24101
24185
  providerId: use.providerId,
24102
24186
  connectionId: use.connectionId
24103
24187
  });
24104
24188
  }
24105
24189
  return {
24190
+ 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(),
24106
24191
  variableNames: [...new Set(Object.values(variableBindings(content, flowDependencies(content).bindings)))].toSorted(),
24107
24192
  connections: [...connections].toSorted(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([, value]) => value),
24108
24193
  errorSourceFlowIds: [...new Set(Object.values(content.document.graph.nodes).flatMap((node) => node.kind == "error" ? node.sourceFlowIds ?? [] : []))].toSorted()
@@ -24113,18 +24198,30 @@ function validRunTrigger(revision, value) {
24113
24198
  const trigger = value;
24114
24199
  if (Object.keys(trigger).some((key) => key != "nodeId" && key != "outputs") || typeof trigger.nodeId != "string" || !Object.hasOwn(trigger, "outputs")) return false;
24115
24200
  const node = revision.document.graph.nodes[trigger.nodeId];
24116
- return node != null && !("inputs" in node) && matchesTriggerOutputs(node, trigger.outputs);
24201
+ return node != null && isTriggerNode(node) && matchesTriggerOutputs(node, trigger.outputs);
24202
+ }
24203
+ function normalizeRunTrigger(revision, value) {
24204
+ if (value == null || typeof value != "object" || Array.isArray(value)) return;
24205
+ const trigger = value;
24206
+ if (Object.keys(trigger).some((key) => key != "nodeId" && key != "outputs") || typeof trigger.nodeId != "string" || !Object.hasOwn(trigger, "outputs")) return;
24207
+ const node = revision.document.graph.nodes[trigger.nodeId];
24208
+ if (node == null || !isTriggerNode(node)) return;
24209
+ const outputs = normalizeTriggerOutputs(node, trigger.outputs);
24210
+ return outputs == null ? void 0 : {
24211
+ nodeId: trigger.nodeId,
24212
+ outputs
24213
+ };
24117
24214
  }
24118
24215
  function validateFlowInputs(revision, value) {
24119
24216
  if (value == null || typeof value != "object" || Array.isArray(value)) return "invalid";
24120
24217
  const graph = revision.document.graph;
24121
24218
  for (const [nodeId, candidate] of Object.entries(value)) {
24122
24219
  const node = graph.nodes[nodeId];
24123
- if (node == null || !("inputs" in node) || node.kind == "condition" || candidate == null || typeof candidate != "object" || Array.isArray(candidate)) return "invalid";
24220
+ if (node == null || isTriggerNode(node) || node.kind == "condition" || candidate == null || typeof candidate != "object" || Array.isArray(candidate)) return "invalid";
24124
24221
  const inputs = nodeInputPorts(node);
24125
24222
  for (const handle of Object.keys(candidate)) {
24126
24223
  const port = inputs[handle];
24127
- if (port == null || hasRetiredRef(port.jsonSchema) || node.inputs[handle] != null || Object.hasOwn(port, "value")) return "invalid";
24224
+ if (port == null || hasRetiredRef(port.jsonSchema) || nodeInputMappings(node)[handle] != null || Object.hasOwn(port, "value")) return "invalid";
24128
24225
  }
24129
24226
  }
24130
24227
  return "valid";
@@ -24208,6 +24305,17 @@ async function validateFlow(revision, engine) {
24208
24305
  message,
24209
24306
  path: `/document/graph/nodes/${nodeId}/task/executor`
24210
24307
  });
24308
+ if (task.executor.kind == "connector" && task.executor.action == "leina.send_notification") {
24309
+ const mapping = node.inputs.leinaId;
24310
+ const value = inputValue(mapping, nodeInputPorts(node).leinaId?.value);
24311
+ if ((mapping?.kind != "sources" || mapping.sources.length == 0) && (typeof value != "string" || value.trim().length == 0)) checked.diagnostics.push({
24312
+ code: "leina.robot-required",
24313
+ column: 0,
24314
+ line: 1,
24315
+ message: "Select a Leina robot or bind its identifier to an input source.",
24316
+ path: `/document/graph/nodes/${nodeId}/inputs/leinaId`
24317
+ });
24318
+ }
24211
24319
  if (task.executor.kind == "connector" && task.executor.action.length == 0) checked.diagnostics.push({
24212
24320
  code: "task.connector-incomplete",
24213
24321
  column: 0,
@@ -24241,7 +24349,10 @@ function runRevision(revision, triggerId) {
24241
24349
  for (const nodeId of reachable) {
24242
24350
  const node = graph.nodes[nodeId];
24243
24351
  if (node == null) continue;
24244
- nodes[nodeId] = !("inputs" in node) ? node : {
24352
+ nodes[nodeId] = node.kind == "outputs" ? {
24353
+ ...node,
24354
+ outputMappings: inputs(nodeId, node.outputMappings)
24355
+ } : isTriggerNode(node) ? node : {
24245
24356
  ...node,
24246
24357
  inputs: inputs(nodeId, node.inputs)
24247
24358
  };
@@ -24270,7 +24381,7 @@ async function prepareFlow(revision, engineContract, triggerId) {
24270
24381
  if (engine == null) return { kind: "engine-unsupported" };
24271
24382
  if (triggerId != null) {
24272
24383
  const trigger = revision.document.graph.nodes[triggerId];
24273
- if (trigger == null || "inputs" in trigger) return {
24384
+ if (trigger == null || !isTriggerNode(trigger)) return {
24274
24385
  kind: "flow-invalid",
24275
24386
  validation: {
24276
24387
  closure: await flowClosure(revision),
@@ -24293,10 +24404,15 @@ async function prepareFlow(revision, engineContract, triggerId) {
24293
24404
  validation
24294
24405
  };
24295
24406
  const { closure } = validation;
24407
+ const start = Object.values(revision.document.graph.nodes).find((node) => node.kind == "start");
24408
+ const outputs = Object.values(revision.document.graph.nodes).find((node) => node.kind == "outputs");
24296
24409
  return {
24297
24410
  flow: {
24298
24411
  closureDigest: closure.digest,
24299
24412
  engineContract,
24413
+ inputDefs: start?.inputDefs ?? [],
24414
+ outputDefs: outputs?.outputDefs ?? [],
24415
+ outputMappings: outputs?.outputMappings ?? {},
24300
24416
  graph: revision.document.graph,
24301
24417
  modules: Object.fromEntries([...closure.dependencies.modules].toSorted().map((id) => [id, revision.modules[id]]))
24302
24418
  },
@@ -24319,7 +24435,7 @@ function agentActions(flow) {
24319
24435
  const task = node.task;
24320
24436
  if (task.executor.kind != "agent") return [];
24321
24437
  const notice = task.executor.notification;
24322
- return [...task.executor.tools, ...notice != null ? [notice] : []].map((tool) => ({
24438
+ return [...task.executor.tools, ...notice != null ? [notice] : []].filter((tool) => tool.connectionId !== "").map((tool) => ({
24323
24439
  kind: "connector",
24324
24440
  action: tool.action,
24325
24441
  connections: tool.connectionId == null ? [] : [{ connectionId: tool.connectionId }]
@@ -24330,4 +24446,4 @@ function codeActions(flow) {
24330
24446
  return Object.values(flow.graph.nodes).flatMap((node) => node.kind == "task" && "moduleId" in node.task ? node.task.capabilities ?? [] : []);
24331
24447
  }
24332
24448
  //#endregion
24333
- 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 };
24449
+ 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 };
@@ -6694,6 +6694,7 @@ var webhookMethods = [
6694
6694
  "DELETE"
6695
6695
  ];
6696
6696
  var text = string();
6697
+ 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.");
6697
6698
  var json = json$1();
6698
6699
  var strings = array(text);
6699
6700
  var port = object({
@@ -6702,6 +6703,7 @@ var port = object({
6702
6703
  nullable: boolean(),
6703
6704
  handle: text
6704
6705
  });
6706
+ var workflowInputDefs = array(port.strict());
6705
6707
  var input = port.extend({ value: json.optional() });
6706
6708
  var group = object({
6707
6709
  collapsed: boolean().optional(),
@@ -6748,7 +6750,7 @@ var capability = union([
6748
6750
  mode: literal("independent"),
6749
6751
  actions: array(strictObject({
6750
6752
  action: text,
6751
- connectionId: text.optional()
6753
+ connectionId: actionConnection.optional()
6752
6754
  }))
6753
6755
  }),
6754
6756
  strictObject({
@@ -6808,7 +6810,7 @@ var managedFields = object({
6808
6810
  object({
6809
6811
  kind: literal("connector"),
6810
6812
  action: text,
6811
- connectionId: text.optional(),
6813
+ connectionId: actionConnection.optional(),
6812
6814
  outputMode: literal("value").optional()
6813
6815
  }),
6814
6816
  object({
@@ -6848,17 +6850,22 @@ var managedFields = object({
6848
6850
  name: text,
6849
6851
  description: text,
6850
6852
  action: text,
6851
- connectionId: text.optional(),
6853
+ connectionId: actionConnection.optional(),
6852
6854
  approval: boolean(),
6853
6855
  inputs: array(input.extend({ source: agentInput }))
6854
6856
  })),
6855
6857
  notification: object({
6856
6858
  action: text,
6857
- connectionId: text.optional(),
6859
+ connectionId: actionConnection.optional(),
6858
6860
  inputDefinitions: array(input),
6859
6861
  messageHandle: text,
6860
6862
  inputs: record$2(text, agentValue)
6861
6863
  }).optional()
6864
+ }),
6865
+ strictObject({
6866
+ kind: literal("workflow"),
6867
+ flowId: text,
6868
+ revisionId: text
6862
6869
  })
6863
6870
  ])
6864
6871
  });
@@ -6967,6 +6974,12 @@ var base = {
6967
6974
  timeoutMs: number().optional()
6968
6975
  };
6969
6976
  var node = union([
6977
+ strictObject({
6978
+ ...base,
6979
+ kind: literal("outputs"),
6980
+ outputDefs: array(port.strict()),
6981
+ outputMappings: inputs
6982
+ }).omit({ inputs: true }),
6970
6983
  object({
6971
6984
  ...base,
6972
6985
  inputs: record$2(text, never()),
@@ -6999,6 +7012,11 @@ var node = union([
6999
7012
  ...trigger,
7000
7013
  kind: literal("manual")
7001
7014
  }),
7015
+ strictObject({
7016
+ ...trigger,
7017
+ kind: literal("start"),
7018
+ inputDefs: workflowInputDefs
7019
+ }),
7002
7020
  strictObject({
7003
7021
  ...trigger,
7004
7022
  kind: literal("error"),
@@ -7063,7 +7081,7 @@ var module = object({
7063
7081
  imports: strings,
7064
7082
  source: text
7065
7083
  });
7066
- var document = preprocess(rejectRetiredDefinitions, object({
7084
+ var document = preprocess(normalizeDocument, object({
7067
7085
  bindings: record$2(text, binding),
7068
7086
  graph
7069
7087
  }));
@@ -7072,7 +7090,9 @@ object({
7072
7090
  literal(2),
7073
7091
  literal(4),
7074
7092
  literal(5),
7075
- literal(6)
7093
+ literal(6),
7094
+ literal(7),
7095
+ literal(8)
7076
7096
  ]),
7077
7097
  document,
7078
7098
  modules: record$2(text, module)
@@ -7080,13 +7100,19 @@ object({
7080
7100
  kind: literal("open-flow-flow-revision"),
7081
7101
  version: literal(1)
7082
7102
  });
7083
- function rejectRetiredDefinitions(value) {
7103
+ function normalizeDocument(value) {
7084
7104
  const candidate = record$1(value);
7085
7105
  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
7106
  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
7107
  const subflows = candidate.subflows;
7088
7108
  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
7109
  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.");
7110
+ if ([
7111
+ "inputDefs",
7112
+ "outputDefs",
7113
+ "outputMappings"
7114
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
7115
+ 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
7116
  return value;
7091
7117
  }
7092
7118
  function record$1(value) {