@oomol-lab/open-flow 0.1.0-beta.76 → 0.1.0-beta.78
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.
- package/README.md +3 -0
- package/dist/browser/{ContentIcon-Cm1hbVzW.js → ContentIcon-CMn0c-kl.js} +99 -6
- package/dist/browser/{FlowCanvas-NzKtla_c.js → FlowCanvas-BQGBcfoL.js} +1709 -613
- package/dist/browser/{createResourceDialog-BgdedQqu.js → createResourceDialog-DCGxfKFM.js} +63 -57
- package/dist/browser/{dialog-aSElFFw2.js → dialog-WzR4CRFH.js} +76 -77
- package/dist/browser/{exportSvg-Dcz4HTo_.js → exportSvg-CYwyYiuH.js} +2 -2
- package/dist/browser/{flowChanges-NZyS7HSp.js → flowChanges-Bz4dbDN_.js} +6875 -11091
- package/dist/browser/{flowWorkspace-Bl0SDehy.js → flowWorkspace-BI6L6a4r.js} +1415 -3037
- package/dist/browser/licenses.md +1 -1
- package/dist/browser/preview.css +619 -462
- package/dist/browser/preview.js +9016 -14956
- package/dist/browser/theme.css +4 -2
- package/dist/browser/{tooltip-3XMK9jkr.js → tooltip-BDcVTNpu.js} +65 -2
- package/dist/browser/{typeScriptSession-C9sBGOKZ.js → typeScriptSession-CRoezJPN.js} +1 -1
- package/dist/browser/ui.css +112 -24
- package/dist/browser/ui.js +3 -2
- package/dist/browser/workbench.css +10020 -9842
- package/dist/browser/workbench.d.ts +5 -2
- package/dist/browser/workbench.js +2382 -2668
- package/dist/browser/{workbenchSelect-DBGP7Y4Z.js → workbenchSelect-DtAd0zc4.js} +2 -2
- package/dist/command/index.js +48 -48
- package/dist/common/authoring.d.ts +4 -4
- package/dist/common/authoringExamples.d.ts +3 -2
- package/dist/common/authoringSchema.d.ts +15 -4
- package/dist/common/control-api-conformance.js +155 -15
- package/dist/common/control-api-errors.d.ts +12 -0
- package/dist/common/control-api.d.ts +39 -2
- package/dist/common/control-api.js +180 -37
- package/dist/common/control-requests.d.ts +23 -3
- package/dist/common/control-requests.js +141 -14
- package/dist/common/engine-contract.d.ts +3 -2
- package/dist/common/flow-authoring.js +47 -7
- package/dist/common/flow-change-schema.d.ts +1 -1
- package/dist/common/flow-change.d.ts +2 -2
- package/dist/common/flow-change.js +48 -8
- package/dist/common/flow-encoding.js +47 -7
- package/dist/common/flow-semantics.js +86 -8
- package/dist/common/flow-state.d.ts +100 -0
- package/dist/common/flow-state.js +5794 -0
- package/dist/common/mcp.d.ts +96 -3
- package/dist/common/mcp.js +158 -13
- package/dist/common/run-events.js +19 -8
- package/dist/common/runtime-contract.d.ts +14 -0
- package/dist/common/runtime-contract.js +124 -17
- package/dist/common/runtime-nodejs-compat.js +11 -12
- package/dist/common/scheduler-node-execution.d.ts +1 -0
- package/dist/common/scheduler.d.ts +2 -1
- package/dist/common/scheduler.js +95 -40
- package/dist/common/state-conformance.d.ts +16 -0
- package/dist/common/tags.d.ts +4 -0
- package/dist/index.d.ts +11 -0
- package/package.json +5 -1
- package/src/control/common/api.ts +101 -11
- package/src/control/common/authoring.ts +7 -1
- package/src/control/common/authoringExamples.ts +9 -0
- package/src/control/common/authoringSchema.ts +18 -12
- package/src/control/common/errors.ts +6 -0
- package/src/control/common/flowDecoders.ts +1 -0
- package/src/control/common/mcp.ts +16 -0
- package/src/control/common/requests.ts +16 -2
- package/src/control/common/tags.ts +20 -0
- package/src/execution/common/events.ts +22 -7
- package/src/execution/common/node-execution.ts +3 -0
- package/src/execution/common/scheduler.ts +29 -13
- package/src/flow/common/change.ts +2 -1
- package/src/flow/common/changeSchema.ts +11 -1
- package/src/flow/common/errorHandling.ts +1 -1
- package/src/flow/common/semantics.ts +27 -1
- package/src/runtime/common/engineContract.ts +6 -3
- package/src/runtime/common/nodejsGuest.generated.json +11 -12
- package/src/runtime/common/runtime.ts +122 -7
- package/src/state/common/conformance.ts +81 -0
- package/src/state/common/state.ts +141 -0
- package/src/types/index.ts +11 -0
|
@@ -12473,6 +12473,63 @@ function httpRequestInputs(mappings, previous, next) {
|
|
|
12473
12473
|
const rename = candidate != null && ["query.", "header."].some((prefix) => candidate.every((name) => name.startsWith(prefix))) ? candidate : void 0;
|
|
12474
12474
|
return remapInputMappings(mappings, next.inputs, rename);
|
|
12475
12475
|
}
|
|
12476
|
+
strictObject({
|
|
12477
|
+
scope: _enum(["draft", "live"]),
|
|
12478
|
+
values: boolean().optional()
|
|
12479
|
+
});
|
|
12480
|
+
strictObject({
|
|
12481
|
+
scope: _enum(["draft", "live"]),
|
|
12482
|
+
key: string().min(1).refine((key) => new TextEncoder().encode(key).length <= 256).optional()
|
|
12483
|
+
});
|
|
12484
|
+
strictObject({
|
|
12485
|
+
scope: _enum(["draft", "live"]),
|
|
12486
|
+
space: string().regex(/^(flow|node:.+)$/)
|
|
12487
|
+
});
|
|
12488
|
+
var skipDuplicatesConfigSchema = strictObject({ fields: array(string().refine((field) => field.length > 0 && field.split(".").every((part) => part.length > 0), "Use a nonempty dot-separated field path.")).refine((fields) => new Set(fields).size === fields.length, "Identity fields must be distinct.").default([]) });
|
|
12489
|
+
var skipDuplicatesExecutorSchema = skipDuplicatesConfigSchema.extend({ kind: literal("skip-duplicates") });
|
|
12490
|
+
function skipDuplicatesTask(config = skipDuplicatesConfigSchema.parse({}), name = "Skip Duplicates") {
|
|
12491
|
+
return {
|
|
12492
|
+
name,
|
|
12493
|
+
executor: {
|
|
12494
|
+
...config,
|
|
12495
|
+
kind: "skip-duplicates"
|
|
12496
|
+
},
|
|
12497
|
+
inputs: [{
|
|
12498
|
+
handle: "items",
|
|
12499
|
+
jsonSchema: { type: "array" },
|
|
12500
|
+
nullable: false
|
|
12501
|
+
}],
|
|
12502
|
+
outputs: ["items", "duplicates"].map((handle) => ({
|
|
12503
|
+
handle,
|
|
12504
|
+
jsonSchema: { type: "array" },
|
|
12505
|
+
nullable: false
|
|
12506
|
+
}))
|
|
12507
|
+
};
|
|
12508
|
+
}
|
|
12509
|
+
object$1({
|
|
12510
|
+
version: literal(1),
|
|
12511
|
+
scope: _enum(["draft", "live"]),
|
|
12512
|
+
limits: object$1({
|
|
12513
|
+
maxValueBytes: number().positive(),
|
|
12514
|
+
maxValues: number().int().positive(),
|
|
12515
|
+
maxSpaces: number().int().positive(),
|
|
12516
|
+
maxIdentities: number().positive(),
|
|
12517
|
+
maxRunWrites: number().positive()
|
|
12518
|
+
}),
|
|
12519
|
+
values: array(object$1({
|
|
12520
|
+
key: string(),
|
|
12521
|
+
size: number().nonnegative(),
|
|
12522
|
+
updatedAt: number(),
|
|
12523
|
+
value: json$5().optional()
|
|
12524
|
+
})),
|
|
12525
|
+
spaces: array(object$1({
|
|
12526
|
+
space: string(),
|
|
12527
|
+
count: number().nonnegative(),
|
|
12528
|
+
pendingCount: number().nonnegative(),
|
|
12529
|
+
reservedCount: number().nonnegative(),
|
|
12530
|
+
updatedAt: number()
|
|
12531
|
+
}))
|
|
12532
|
+
});
|
|
12476
12533
|
function checkJsonDepth(value, depth = 0) {
|
|
12477
12534
|
if (depth > 64) throw new TypeError("Value exceeds the maximum JSON depth.");
|
|
12478
12535
|
if (value != null && typeof value == "object") for (const child of Object.values(value)) checkJsonDepth(child, depth + 1);
|
|
@@ -12792,7 +12849,8 @@ var managedFields = object$1({
|
|
|
12792
12849
|
flowId: text$1,
|
|
12793
12850
|
revisionId: text$1
|
|
12794
12851
|
}),
|
|
12795
|
-
httpRequestExecutorSchema
|
|
12852
|
+
httpRequestExecutorSchema,
|
|
12853
|
+
skipDuplicatesExecutorSchema
|
|
12796
12854
|
])
|
|
12797
12855
|
});
|
|
12798
12856
|
var managed = managedFields.transform(limitDecisionTask);
|
|
@@ -13062,7 +13120,8 @@ var revision = object$1({
|
|
|
13062
13120
|
literal(9),
|
|
13063
13121
|
literal(10),
|
|
13064
13122
|
literal(11),
|
|
13065
|
-
literal(12)
|
|
13123
|
+
literal(12),
|
|
13124
|
+
literal(13)
|
|
13066
13125
|
]),
|
|
13067
13126
|
document,
|
|
13068
13127
|
modules: record$3(text$1, module)
|
|
@@ -13287,6 +13346,7 @@ function changeOperationsSchema(kind) {
|
|
|
13287
13346
|
return toJSONSchema(schema, { io: "input" });
|
|
13288
13347
|
}
|
|
13289
13348
|
function checkModelVersion(content) {
|
|
13349
|
+
if (content.modelVersion < 13 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind === "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind === "skip-duplicates")) throw new Error("Skip Duplicates requires Flow model v13.");
|
|
13290
13350
|
if (content.modelVersion < 12 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "moduleId" in candidateNode.task && candidateNode.task.capabilities?.some((item) => item.kind == "http"))) throw new TypeError("Code HTTP access requires Flow model version 12.");
|
|
13291
13351
|
if (content.modelVersion < 11 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind == "http-request")) throw new TypeError("HTTP Request requires Flow model version 11.");
|
|
13292
13352
|
if (content.modelVersion < 11 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && ("moduleId" in candidateNode.task ? candidateNode.task.capabilities?.some((item) => item.kind == "workflow") : candidateNode.task.executor.kind == "agent" && candidateNode.task.executor.tools.some((item) => item.kind == "workflow")))) throw new TypeError("Workflow tools require Flow model version 11.");
|
|
@@ -13308,8 +13368,8 @@ function assertDocumentHttpAuthBindings(content) {
|
|
|
13308
13368
|
}
|
|
13309
13369
|
//#endregion
|
|
13310
13370
|
//#region src/runtime/common/engineContract.ts
|
|
13311
|
-
/**
|
|
13312
|
-
var currentEngineContract = "open-flow-engine/
|
|
13371
|
+
/** v10 adds persistent Flow State to the published v9 Node compatibility and fetch contract. */
|
|
13372
|
+
var currentEngineContract = "open-flow-engine/v10";
|
|
13313
13373
|
/** The published v8 Node compatibility contract, retained for existing Publications and Runs. */
|
|
13314
13374
|
var nodejsEngineContract = "open-flow-engine/v8/nodejs-compat-v1";
|
|
13315
13375
|
var platformSource = (contract) => `export const engineContract = ${JSON.stringify(contract)}
|
|
@@ -13354,13 +13414,19 @@ var nodejsContract = {
|
|
|
13354
13414
|
].flatMap((name) => [name, `node:${name}`])),
|
|
13355
13415
|
platformSource: platformSource(nodejsEngineContract)
|
|
13356
13416
|
};
|
|
13357
|
-
var
|
|
13417
|
+
var v9Contract = {
|
|
13358
13418
|
...nodejsContract,
|
|
13359
13419
|
codeFetch: true,
|
|
13420
|
+
platformSource: platformSource("open-flow-engine/v9")
|
|
13421
|
+
};
|
|
13422
|
+
var currentContract = {
|
|
13423
|
+
...v9Contract,
|
|
13424
|
+
flowState: true,
|
|
13360
13425
|
platformSource: platformSource(currentEngineContract)
|
|
13361
13426
|
};
|
|
13362
13427
|
function findEngineContract(contract) {
|
|
13363
|
-
if (contract == "open-flow-engine/
|
|
13428
|
+
if (contract == "open-flow-engine/v10") return currentContract;
|
|
13429
|
+
if (contract == "open-flow-engine/v9") return v9Contract;
|
|
13364
13430
|
if (contract == "open-flow-engine/v8") return v8Contract;
|
|
13365
13431
|
if (contract == "open-flow-engine/v8/nodejs-compat-v1") return nodejsContract;
|
|
13366
13432
|
if (contract == "open-flow-engine/v7" || contract == "open-flow-engine/v7/nodejs-compat-v1") return {
|
|
@@ -13965,6 +14031,7 @@ var authoringTypes = [
|
|
|
13965
14031
|
"decision",
|
|
13966
14032
|
"openapi",
|
|
13967
14033
|
"http-request",
|
|
14034
|
+
"skip-duplicates",
|
|
13968
14035
|
"condition",
|
|
13969
14036
|
"value",
|
|
13970
14037
|
"wait",
|
|
@@ -14096,6 +14163,7 @@ var authoringConfigurations = {
|
|
|
14096
14163
|
"connector": authoringDefinitionSchemas.connector.omit({ outputMode: true }).strict(),
|
|
14097
14164
|
"openapi": authoringOpenApiSchema,
|
|
14098
14165
|
"http-request": httpRequestConfigSchema,
|
|
14166
|
+
"skip-duplicates": skipDuplicatesConfigSchema,
|
|
14099
14167
|
"agent": authoringDefinitionSchemas.agent.omit({
|
|
14100
14168
|
prompt: true,
|
|
14101
14169
|
tools: true
|
|
@@ -14315,7 +14383,7 @@ function authoringSchema(kind) {
|
|
|
14315
14383
|
guidance: "Read a node type schema before creating or configuring it. Use $alias to reference a preceding node.add in the same batch. Read returns stable node references. Long code and prompt fields use text reads and edits. Changes use the observed baseRevision and a stable requestId."
|
|
14316
14384
|
} : {
|
|
14317
14385
|
type: kind,
|
|
14318
|
-
onError: retryNodeTypes.some((nodeType) => nodeType == kind) ? { enum: ["stop", "error"] } : false,
|
|
14386
|
+
onError: kind == "skip-duplicates" || retryNodeTypes.some((nodeType) => nodeType == kind) ? { enum: ["stop", "error"] } : false,
|
|
14319
14387
|
retry: retryNodeTypes.some((nodeType) => nodeType == kind) ? toJSONSchema(retryConfigurationSchema) : false,
|
|
14320
14388
|
inputSources: ["poll", "integration"].includes(kind) ? [
|
|
14321
14389
|
"value",
|
|
@@ -14345,7 +14413,7 @@ function authoringSchema(kind) {
|
|
|
14345
14413
|
"wait",
|
|
14346
14414
|
"approval"
|
|
14347
14415
|
].includes(kind),
|
|
14348
|
-
guidance: kind == "webhook-response" ? "Prepare an HTTP response using fixed inputs body (any JSON, default empty text), statusCode (number, default 200) and headers (scalar-valued object, default {}). Select this node in Webhook options.responseBody as {kind: \"webhook-response\", nodeId: \"node reference\", timeoutMs: 30000}. Its first completion responds immediately while the Run continues. It has no business outputs. Multiple response nodes are allowed; each Webhook selects one reachable node." : kind == "outputs" ? "Declare output fields through config.outputDefs. Set their values through node.add.inputs or input.set. Outputs is a singleton execution sink; it waits for its predecessors and produces workflow business outputs independently of node logs. No downstream edges or data references to Outputs are allowed." : kind == "webhook" ? "Use options.responseBody: {kind: \"webhook-response\", nodeId: \"node ID or $alias\", timeoutMs: 30000} to respond on the selected node’s first completion while the Run continues. Body, statusCode and headers come exclusively from that node; clear workflow-output-only status/header references when switching. Alternatively configure options.responseBody as {kind: \"workflow-outputs\", output?: \"top-level output name\", timeoutMs?: 30000} to respond after the Run succeeds. Omit output for the complete object. Connect Webhook to Outputs. Timeout is 1000–60000 ms; HTTP timeout does not cancel the Run. Strings return text; other values return JSON. Only in this mode, options.responseStatusCodeOutput can select a numeric top-level workflow output as the HTTP status, overriding the preserved fixed responseStatusCode (default 200). Its runtime value must be an integer from 200 to 599, excluding 204, 205, 304; missing or invalid values return 500. Use responseHeaders for fixed text headers. In workflow-output mode, responseHeaderOutputs maps header names to top-level output names; values can be string, number or boolean and are converted to text. Alternatively responseHeadersSource: {kind: \"workflow-outputs\", output?: \"object field\"} replaces the entire header object (omit output for all outputs), preserving but ignoring per-header settings. Missing, null, complex or invalid header values return 500 without fallback. Header restrictions and Content-Type policy still apply. Omit responseBody for immediate responseData. Clear options.responseBody, options.responseStatusCodeOutput, options.responseHeadersSource and options.responseHeaderOutputs explicitly to switch back." : kind == "start" ? "Declare workflow inputs through config.inputDefs; read them in Start node details. REST calls and manual runs supply them as trigger.outputs. Downstream nodes bind these parameters as Start outputs. Start has no input sources or defaults; non-nullable parameters are required, and omitted nullable parameters become null." : kind == "condition" ? "Edit branch operands through config.branches. A branch can test one expression, all expressions, or any alternatives. Unmatched execution uses branch otherwise." : ["poll", "integration"].includes(kind) ? "Configure static parameters with node.add.inputs or input.set. Definitions come from the selected Trigger key; execution output and variable sources are unavailable." : kind == "llm" ? "Configure model settings, message templates and history as defaults. Input bindings with the same names override these defaults; named business inputs can be bound directly. Template strings interpolate {{name}}." : kind == "http-request" ? "Configure method, query/headers modes and names, bodyFormat, authentication, responseFormat and statusPolicy. Bind url, query.<name>/header.<name> or whole query/headers objects, body and auth.token (Basic: auth.username/auth.password). Credentials accept variables or upstream outputs only. Outputs: body, statusCode, headers. Authentication is replaced as a complete choice." : kind == "openapi" ? "Select an operation; the tool resolves its ports and authentication. Read authenticationChoices from node details. authentication is replaced as a complete choice. Bind advertised credentials through inputs." : kind == "workflow" ? "Select another workflow with config.flowId. A workflow cannot call itself, including in a disconnected node. Owned unpublished or unavailable targets may be saved as incomplete drafts. Use node.refresh to load the current published interface." : kind == "agent" ? "Tools accept Connector Actions or {kind: \"workflow\", flowId, name, description, approval, inputs}. Workflow parameter sources use model, input or value. The platform derives the interface. Refresh a workflow tool with node.refresh and tool: its name." : kind == "code" ? codeGuidance : "Supply business configuration and input data. Fixed definitions are assembled by the tool. Existing constraints and defaults are preserved on partial updates.",
|
|
14416
|
+
guidance: kind == "webhook-response" ? "Prepare an HTTP response using fixed inputs body (any JSON, default empty text), statusCode (number, default 200) and headers (scalar-valued object, default {}). Select this node in Webhook options.responseBody as {kind: \"webhook-response\", nodeId: \"node reference\", timeoutMs: 30000}. Its first completion responds immediately while the Run continues. It has no business outputs. Multiple response nodes are allowed; each Webhook selects one reachable node." : kind == "outputs" ? "Declare output fields through config.outputDefs. Set their values through node.add.inputs or input.set. Outputs is a singleton execution sink; it waits for its predecessors and produces workflow business outputs independently of node logs. No downstream edges or data references to Outputs are allowed." : kind == "webhook" ? "Use options.responseBody: {kind: \"webhook-response\", nodeId: \"node ID or $alias\", timeoutMs: 30000} to respond on the selected node’s first completion while the Run continues. Body, statusCode and headers come exclusively from that node; clear workflow-output-only status/header references when switching. Alternatively configure options.responseBody as {kind: \"workflow-outputs\", output?: \"top-level output name\", timeoutMs?: 30000} to respond after the Run succeeds. Omit output for the complete object. Connect Webhook to Outputs. Timeout is 1000–60000 ms; HTTP timeout does not cancel the Run. Strings return text; other values return JSON. Only in this mode, options.responseStatusCodeOutput can select a numeric top-level workflow output as the HTTP status, overriding the preserved fixed responseStatusCode (default 200). Its runtime value must be an integer from 200 to 599, excluding 204, 205, 304; missing or invalid values return 500. Use responseHeaders for fixed text headers. In workflow-output mode, responseHeaderOutputs maps header names to top-level output names; values can be string, number or boolean and are converted to text. Alternatively responseHeadersSource: {kind: \"workflow-outputs\", output?: \"object field\"} replaces the entire header object (omit output for all outputs), preserving but ignoring per-header settings. Missing, null, complex or invalid header values return 500 without fallback. Header restrictions and Content-Type policy still apply. Omit responseBody for immediate responseData. Clear options.responseBody, options.responseStatusCodeOutput, options.responseHeadersSource and options.responseHeaderOutputs explicitly to switch back." : kind == "start" ? "Declare workflow inputs through config.inputDefs; read them in Start node details. REST calls and manual runs supply them as trigger.outputs. Downstream nodes bind these parameters as Start outputs. Start has no input sources or defaults; non-nullable parameters are required, and omitted nullable parameters become null." : kind == "condition" ? "Edit branch operands through config.branches. A branch can test one expression, all expressions, or any alternatives. Unmatched execution uses branch otherwise." : ["poll", "integration"].includes(kind) ? "Configure static parameters with node.add.inputs or input.set. Definitions come from the selected Trigger key; execution output and variable sources are unavailable." : kind == "llm" ? "Configure model settings, message templates and history as defaults. Input bindings with the same names override these defaults; named business inputs can be bound directly. Template strings interpolate {{name}}." : kind == "skip-duplicates" ? "Bind an items array. Configure fields as dot-separated identity paths; an empty list uses each scalar item. Outputs are items and duplicates. History belongs to this node and commits only when the Run completes successfully. Fields accept strings or finite numbers; missing or complex values reject the batch." : kind == "http-request" ? "Configure method, query/headers modes and names, bodyFormat, authentication, responseFormat and statusPolicy. Bind url, query.<name>/header.<name> or whole query/headers objects, body and auth.token (Basic: auth.username/auth.password). Credentials accept variables or upstream outputs only. Outputs: body, statusCode, headers. Authentication is replaced as a complete choice." : kind == "openapi" ? "Select an operation; the tool resolves its ports and authentication. Read authenticationChoices from node details. authentication is replaced as a complete choice. Bind advertised credentials through inputs." : kind == "workflow" ? "Select another workflow with config.flowId. A workflow cannot call itself, including in a disconnected node. Owned unpublished or unavailable targets may be saved as incomplete drafts. Use node.refresh to load the current published interface." : kind == "agent" ? "Tools accept Connector Actions or {kind: \"workflow\", flowId, name, description, approval, inputs}. Workflow parameter sources use model, input or value. The platform derives the interface. Refresh a workflow tool with node.refresh and tool: its name." : kind == "code" ? codeGuidance : "Supply business configuration and input data. Fixed definitions are assembled by the tool. Existing constraints and defaults are preserved on partial updates.",
|
|
14349
14417
|
example: {
|
|
14350
14418
|
op: "node.add",
|
|
14351
14419
|
as: "step",
|
|
@@ -14368,6 +14436,13 @@ function authoringSchema(kind) {
|
|
|
14368
14436
|
}]
|
|
14369
14437
|
} },
|
|
14370
14438
|
"integration": { config: { key: "<Trigger key>" } },
|
|
14439
|
+
"skip-duplicates": {
|
|
14440
|
+
config: { fields: ["id"] },
|
|
14441
|
+
inputs: { items: {
|
|
14442
|
+
kind: "value",
|
|
14443
|
+
value: [{ id: "a" }, { id: "b" }]
|
|
14444
|
+
} }
|
|
14445
|
+
},
|
|
14371
14446
|
"http-request": {
|
|
14372
14447
|
config: {},
|
|
14373
14448
|
inputs: { url: {
|
|
@@ -14627,7 +14702,7 @@ var nodeErrorSchema = {
|
|
|
14627
14702
|
}
|
|
14628
14703
|
};
|
|
14629
14704
|
function supportsNodeErrorHandling(node) {
|
|
14630
|
-
return supportsNodeRetry(node);
|
|
14705
|
+
return supportsNodeRetry(node) || node.kind === "task" && "executor" in node.task && node.task.executor.kind === "skip-duplicates";
|
|
14631
14706
|
}
|
|
14632
14707
|
function nodeSystemOutputPorts(node) {
|
|
14633
14708
|
return supportsNodeErrorHandling(node) && node.onError == "error" ? { error: {
|
|
@@ -14802,10 +14877,10 @@ function upgradeRevisionContent(content) {
|
|
|
14802
14877
|
function upgradeDecodedRevisionContent(content) {
|
|
14803
14878
|
const graph = content.document.graph;
|
|
14804
14879
|
const hasManual = Object.values(graph.nodes).some((node) => node.kind == "manual");
|
|
14805
|
-
if (!hasManual && content.modelVersion ==
|
|
14880
|
+
if (!hasManual && content.modelVersion == 13) return content;
|
|
14806
14881
|
return {
|
|
14807
14882
|
...content,
|
|
14808
|
-
modelVersion:
|
|
14883
|
+
modelVersion: 13,
|
|
14809
14884
|
document: {
|
|
14810
14885
|
...content.document,
|
|
14811
14886
|
graph: hasManual ? {
|
|
@@ -14840,7 +14915,7 @@ function invalid(message) {
|
|
|
14840
14915
|
throw new FlowChangeError(message);
|
|
14841
14916
|
}
|
|
14842
14917
|
function applyFlowChanges(content, operations) {
|
|
14843
|
-
const source = content.modelVersion !=
|
|
14918
|
+
const source = content.modelVersion != 13 || Object.values(content.document.graph.nodes).some((node) => node.kind == "manual") ? decodeRevisionContent(content) : content;
|
|
14844
14919
|
const document = { ...source.document };
|
|
14845
14920
|
const modules = { ...source.modules };
|
|
14846
14921
|
for (const operation of operations) switch (operation.kind) {
|
|
@@ -15288,7 +15363,7 @@ function applyFlowChanges(content, operations) {
|
|
|
15288
15363
|
assertDocumentHttpAuthBindings(document);
|
|
15289
15364
|
return upgradeDecodedRevisionContent({
|
|
15290
15365
|
document,
|
|
15291
|
-
modelVersion:
|
|
15366
|
+
modelVersion: 13,
|
|
15292
15367
|
modules
|
|
15293
15368
|
});
|
|
15294
15369
|
}
|
|
@@ -16513,7 +16588,7 @@ function authoringNode(content, ref) {
|
|
|
16513
16588
|
inputs: fieldsView([...task.inputs, ...node.kind == "task" ? node.additionalInputs ?? [] : []].filter((port) => !("handle" in port) || !llmReservedInputs.includes(port.handle)))
|
|
16514
16589
|
};
|
|
16515
16590
|
else if (task.executor.kind == "workflow") config = { flowId: task.executor.flowId };
|
|
16516
|
-
else if (task.executor.kind == "http-request") {
|
|
16591
|
+
else if (task.executor.kind == "http-request" || task.executor.kind == "skip-duplicates") {
|
|
16517
16592
|
const { kind: _kind, ...settings } = task.executor;
|
|
16518
16593
|
config = settings;
|
|
16519
16594
|
} else if (task.executor.kind == "openapi") config = { ...openApiConfigView(task.executor) };
|
|
@@ -16903,6 +16978,14 @@ async function compileAuthoring(base, request, host) {
|
|
|
16903
16978
|
};
|
|
16904
16979
|
} else task = await connectorTask(config, String(update.name));
|
|
16905
16980
|
} else if (type == "decision") task = decisionTask(config.questions, String(update.name));
|
|
16981
|
+
else if (type == "skip-duplicates") task = {
|
|
16982
|
+
...before,
|
|
16983
|
+
name: String(update.name),
|
|
16984
|
+
executor: {
|
|
16985
|
+
kind: "skip-duplicates",
|
|
16986
|
+
...skipDuplicatesConfigSchema.parse(config)
|
|
16987
|
+
}
|
|
16988
|
+
};
|
|
16906
16989
|
else if (type == "http-request") {
|
|
16907
16990
|
task = httpRequestTask(httpRequestConfigSchema.parse(config), String(update.name), before);
|
|
16908
16991
|
next = {
|
|
@@ -17250,6 +17333,9 @@ async function compileAuthoring(base, request, host) {
|
|
|
17250
17333
|
case "connector":
|
|
17251
17334
|
changes = createManagedTask(identity, await connectorTask(config, name));
|
|
17252
17335
|
break;
|
|
17336
|
+
case "skip-duplicates":
|
|
17337
|
+
changes = createManagedTask(identity, skipDuplicatesTask(skipDuplicatesConfigSchema.parse(config), name));
|
|
17338
|
+
break;
|
|
17253
17339
|
case "http-request":
|
|
17254
17340
|
changes = createManagedTask(identity, httpRequestTask(httpRequestConfigSchema.parse(config), name));
|
|
17255
17341
|
break;
|
|
@@ -17471,6 +17557,7 @@ var descriptions = {
|
|
|
17471
17557
|
"poll": "Gmail polling by key; replace CONNECTION_ID with an active Gmail connection.",
|
|
17472
17558
|
"integration": "Telegram webhook integration by key; replace CONNECTION_ID with an active Telegram connection.",
|
|
17473
17559
|
"decision": "AI Decision evaluates named questions against target and returns a complete answer object per output. Configure target before running.",
|
|
17560
|
+
"skip-duplicates": "Skip items already recorded by successful Runs. Configure identity fields; an empty list uses each string or numeric item. History is private to the node and only commits after Run success.",
|
|
17474
17561
|
"http-request": "A single HTTP request. Bind url and request inputs; outputs are body, statusCode and headers.",
|
|
17475
17562
|
"openapi": "A fixed JSON API operation. Replace the example document and URL before running.",
|
|
17476
17563
|
"connector": "A Connector Task and its node. Replace ACTION_ID, CONNECTION_ID and port definitions using connector_get / connector show. Set connectionId to an empty string to defer account configuration; execution will require an account.",
|
|
@@ -17515,6 +17602,21 @@ function authoringExample(name) {
|
|
|
17515
17602
|
instructions: "Does the customer need support?"
|
|
17516
17603
|
}]);
|
|
17517
17604
|
break;
|
|
17605
|
+
case "skip-duplicates":
|
|
17606
|
+
operations = [...createManagedTask({ nodeId: "skip-duplicates" }, skipDuplicatesTask()), {
|
|
17607
|
+
kind: "graph.node.input.set",
|
|
17608
|
+
nodeId: "skip-duplicates",
|
|
17609
|
+
handle: "items",
|
|
17610
|
+
value: {
|
|
17611
|
+
kind: "value",
|
|
17612
|
+
value: [
|
|
17613
|
+
"a",
|
|
17614
|
+
"b",
|
|
17615
|
+
"a"
|
|
17616
|
+
]
|
|
17617
|
+
}
|
|
17618
|
+
}];
|
|
17619
|
+
break;
|
|
17518
17620
|
case "http-request":
|
|
17519
17621
|
operations = [...createManagedTask({ nodeId: "http" }, httpRequestTask()), {
|
|
17520
17622
|
kind: "graph.node.input.set",
|
|
@@ -17758,6 +17860,8 @@ var json = json$5();
|
|
|
17758
17860
|
var id = string().min(1);
|
|
17759
17861
|
var version = literal(1);
|
|
17760
17862
|
var flowName = id.refine((value) => value == value.trim() && resourceNameIssue(value) == null, "Flow name is invalid.");
|
|
17863
|
+
var tagIds = array(id).transform((ids) => [...new Set(ids)].toSorted());
|
|
17864
|
+
var tagName = id.transform((name) => name.trim()).refine((name) => resourceNameIssue(name) == null, "Tag name is invalid.");
|
|
17761
17865
|
var inputs = record$3(string(), record$3(string(), json));
|
|
17762
17866
|
var trigger = strictObject({
|
|
17763
17867
|
nodeId: id,
|
|
@@ -17784,13 +17888,33 @@ var schemas = {
|
|
|
17784
17888
|
file: json,
|
|
17785
17889
|
name: flowName.optional(),
|
|
17786
17890
|
teamId: id.optional(),
|
|
17891
|
+
tagIds: tagIds.optional(),
|
|
17787
17892
|
version
|
|
17788
17893
|
}),
|
|
17789
17894
|
createFlow: strictObject({
|
|
17790
17895
|
name: flowName,
|
|
17791
17896
|
teamId: id.optional(),
|
|
17897
|
+
tagIds: tagIds.optional(),
|
|
17898
|
+
presentation: record$3(string(), json).optional(),
|
|
17899
|
+
version
|
|
17900
|
+
}),
|
|
17901
|
+
saveTag: strictObject({
|
|
17902
|
+
name: tagName,
|
|
17903
|
+
version
|
|
17904
|
+
}),
|
|
17905
|
+
setFlowTags: strictObject({
|
|
17906
|
+
tagIds,
|
|
17792
17907
|
version
|
|
17793
17908
|
}),
|
|
17909
|
+
updateFlow: union([strictObject({
|
|
17910
|
+
name: flowName,
|
|
17911
|
+
tagIds: tagIds.optional(),
|
|
17912
|
+
version
|
|
17913
|
+
}), strictObject({
|
|
17914
|
+
name: flowName.optional(),
|
|
17915
|
+
tagIds,
|
|
17916
|
+
version
|
|
17917
|
+
})]),
|
|
17794
17918
|
renameFlow: strictObject({
|
|
17795
17919
|
name: flowName,
|
|
17796
17920
|
version
|
|
@@ -17895,6 +18019,9 @@ var controlRequests = {
|
|
|
17895
18019
|
eventSourceRevision: decoder(schemas.eventSourceRevision),
|
|
17896
18020
|
importFlow: decoder(schemas.importFlow),
|
|
17897
18021
|
createFlow: decoder(schemas.createFlow),
|
|
18022
|
+
saveTag: decoder(schemas.saveTag),
|
|
18023
|
+
setFlowTags: decoder(schemas.setFlowTags),
|
|
18024
|
+
updateFlow: decoder(schemas.updateFlow),
|
|
17898
18025
|
renameFlow: decoder(schemas.renameFlow),
|
|
17899
18026
|
changeDraft(value) {
|
|
17900
18027
|
const body = schemas.changeDraft.parse(value);
|
|
@@ -9,9 +9,10 @@ export interface EngineContract {
|
|
|
9
9
|
readonly httpRequests?: boolean;
|
|
10
10
|
/** Code may call `context.fetch` for hosts declared by its `http` Capability. */
|
|
11
11
|
readonly codeFetch?: boolean;
|
|
12
|
+
readonly flowState?: boolean;
|
|
12
13
|
}
|
|
13
|
-
/**
|
|
14
|
-
export declare const currentEngineContract = "open-flow-engine/
|
|
14
|
+
/** v10 adds persistent Flow State to the published v9 Node compatibility and fetch contract. */
|
|
15
|
+
export declare const currentEngineContract = "open-flow-engine/v10";
|
|
15
16
|
/** The published v8 Node compatibility contract, retained for existing Publications and Runs. */
|
|
16
17
|
export declare const nodejsEngineContract = "open-flow-engine/v8/nodejs-compat-v1";
|
|
17
18
|
export declare function findEngineContract(contract: string): EngineContract | undefined;
|
|
@@ -8760,6 +8760,43 @@ var httpRequestExecutorSchema = strictObject({
|
|
|
8760
8760
|
]).default("auto"),
|
|
8761
8761
|
statusPolicy: _enum(["success", "all"]).default("success")
|
|
8762
8762
|
}).extend({ kind: literal("http-request") });
|
|
8763
|
+
strictObject({
|
|
8764
|
+
scope: _enum(["draft", "live"]),
|
|
8765
|
+
values: boolean().optional()
|
|
8766
|
+
});
|
|
8767
|
+
strictObject({
|
|
8768
|
+
scope: _enum(["draft", "live"]),
|
|
8769
|
+
key: string().min(1).refine((key) => new TextEncoder().encode(key).length <= 256).optional()
|
|
8770
|
+
});
|
|
8771
|
+
strictObject({
|
|
8772
|
+
scope: _enum(["draft", "live"]),
|
|
8773
|
+
space: string().regex(/^(flow|node:.+)$/)
|
|
8774
|
+
});
|
|
8775
|
+
var skipDuplicatesExecutorSchema = strictObject({ fields: array(string().refine((field) => field.length > 0 && field.split(".").every((part) => part.length > 0), "Use a nonempty dot-separated field path.")).refine((fields) => new Set(fields).size === fields.length, "Identity fields must be distinct.").default([]) }).extend({ kind: literal("skip-duplicates") });
|
|
8776
|
+
object({
|
|
8777
|
+
version: literal(1),
|
|
8778
|
+
scope: _enum(["draft", "live"]),
|
|
8779
|
+
limits: object({
|
|
8780
|
+
maxValueBytes: number().positive(),
|
|
8781
|
+
maxValues: number().int().positive(),
|
|
8782
|
+
maxSpaces: number().int().positive(),
|
|
8783
|
+
maxIdentities: number().positive(),
|
|
8784
|
+
maxRunWrites: number().positive()
|
|
8785
|
+
}),
|
|
8786
|
+
values: array(object({
|
|
8787
|
+
key: string(),
|
|
8788
|
+
size: number().nonnegative(),
|
|
8789
|
+
updatedAt: number(),
|
|
8790
|
+
value: json$1().optional()
|
|
8791
|
+
})),
|
|
8792
|
+
spaces: array(object({
|
|
8793
|
+
space: string(),
|
|
8794
|
+
count: number().nonnegative(),
|
|
8795
|
+
pendingCount: number().nonnegative(),
|
|
8796
|
+
reservedCount: number().nonnegative(),
|
|
8797
|
+
updatedAt: number()
|
|
8798
|
+
}))
|
|
8799
|
+
});
|
|
8763
8800
|
function checkJsonDepth(value, depth = 0) {
|
|
8764
8801
|
if (depth > 64) throw new TypeError("Value exceeds the maximum JSON depth.");
|
|
8765
8802
|
if (value != null && typeof value == "object") for (const child of Object.values(value)) checkJsonDepth(child, depth + 1);
|
|
@@ -9055,7 +9092,8 @@ var managedFields = object({
|
|
|
9055
9092
|
flowId: text,
|
|
9056
9093
|
revisionId: text
|
|
9057
9094
|
}),
|
|
9058
|
-
httpRequestExecutorSchema
|
|
9095
|
+
httpRequestExecutorSchema,
|
|
9096
|
+
skipDuplicatesExecutorSchema
|
|
9059
9097
|
])
|
|
9060
9098
|
});
|
|
9061
9099
|
var managed = managedFields.transform(limitDecisionTask);
|
|
@@ -9325,7 +9363,8 @@ var revision = object({
|
|
|
9325
9363
|
literal(9),
|
|
9326
9364
|
literal(10),
|
|
9327
9365
|
literal(11),
|
|
9328
|
-
literal(12)
|
|
9366
|
+
literal(12),
|
|
9367
|
+
literal(13)
|
|
9329
9368
|
]),
|
|
9330
9369
|
document,
|
|
9331
9370
|
modules: record$1(text, module)
|
|
@@ -9526,6 +9565,7 @@ array(union([...new Map(Object.entries(shapes).map(([kind, shape]) => [kind, sha
|
|
|
9526
9565
|
...shape
|
|
9527
9566
|
})])).values()])).min(1);
|
|
9528
9567
|
function checkModelVersion(content) {
|
|
9568
|
+
if (content.modelVersion < 13 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind === "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind === "skip-duplicates")) throw new Error("Skip Duplicates requires Flow model v13.");
|
|
9529
9569
|
if (content.modelVersion < 12 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "moduleId" in candidateNode.task && candidateNode.task.capabilities?.some((item) => item.kind == "http"))) throw new TypeError("Code HTTP access requires Flow model version 12.");
|
|
9530
9570
|
if (content.modelVersion < 11 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind == "http-request")) throw new TypeError("HTTP Request requires Flow model version 11.");
|
|
9531
9571
|
if (content.modelVersion < 11 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && ("moduleId" in candidateNode.task ? candidateNode.task.capabilities?.some((item) => item.kind == "workflow") : candidateNode.task.executor.kind == "agent" && candidateNode.task.executor.tools.some((item) => item.kind == "workflow")))) throw new TypeError("Workflow tools require Flow model version 11.");
|
|
@@ -9604,7 +9644,7 @@ function setConditionInput(node, handle, mapping) {
|
|
|
9604
9644
|
//#endregion
|
|
9605
9645
|
//#region src/flow/common/errorHandling.ts
|
|
9606
9646
|
function supportsNodeErrorHandling(node) {
|
|
9607
|
-
return supportsNodeRetry(node);
|
|
9647
|
+
return supportsNodeRetry(node) || node.kind === "task" && "executor" in node.task && node.task.executor.kind === "skip-duplicates";
|
|
9608
9648
|
}
|
|
9609
9649
|
//#endregion
|
|
9610
9650
|
//#region src/flow/common/change.ts
|
|
@@ -9755,10 +9795,10 @@ function isTriggerNode(node) {
|
|
|
9755
9795
|
function upgradeDecodedRevisionContent(content) {
|
|
9756
9796
|
const graph = content.document.graph;
|
|
9757
9797
|
const hasManual = Object.values(graph.nodes).some((node) => node.kind == "manual");
|
|
9758
|
-
if (!hasManual && content.modelVersion ==
|
|
9798
|
+
if (!hasManual && content.modelVersion == 13) return content;
|
|
9759
9799
|
return {
|
|
9760
9800
|
...content,
|
|
9761
|
-
modelVersion:
|
|
9801
|
+
modelVersion: 13,
|
|
9762
9802
|
document: {
|
|
9763
9803
|
...content.document,
|
|
9764
9804
|
graph: hasManual ? {
|
|
@@ -9793,7 +9833,7 @@ function invalid(message) {
|
|
|
9793
9833
|
throw new FlowChangeError(message);
|
|
9794
9834
|
}
|
|
9795
9835
|
function applyFlowChanges(content, operations) {
|
|
9796
|
-
const source = content.modelVersion !=
|
|
9836
|
+
const source = content.modelVersion != 13 || Object.values(content.document.graph.nodes).some((node) => node.kind == "manual") ? decodeRevisionContent(content) : content;
|
|
9797
9837
|
const document = { ...source.document };
|
|
9798
9838
|
const modules = { ...source.modules };
|
|
9799
9839
|
for (const operation of operations) switch (operation.kind) {
|
|
@@ -10241,7 +10281,7 @@ function applyFlowChanges(content, operations) {
|
|
|
10241
10281
|
assertDocumentHttpAuthBindings(document);
|
|
10242
10282
|
return upgradeDecodedRevisionContent({
|
|
10243
10283
|
document,
|
|
10244
|
-
modelVersion:
|
|
10284
|
+
modelVersion: 13,
|
|
10245
10285
|
modules
|
|
10246
10286
|
});
|
|
10247
10287
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ChangeOperation, FlowDocument, JsonValue, RevisionContent } from './flow-change.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
export declare const currentFlowModelVersion =
|
|
3
|
+
export declare const currentFlowModelVersion = 13;
|
|
4
4
|
export declare const connectorCapabilitySchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
5
5
|
kind: z.ZodLiteral<"connector">;
|
|
6
6
|
action: z.ZodString;
|
|
@@ -71,7 +71,7 @@ export interface ConditionNode extends GraphNodeBase {
|
|
|
71
71
|
readonly matchMode: 'first' | 'all';
|
|
72
72
|
readonly kind: 'condition';
|
|
73
73
|
}
|
|
74
|
-
export type ManagedTaskExecutor = import('./http-request.js').HttpRequestExecutor | WorkflowExecutor | import('./decision.js').DecisionExecutor | import('./openapi.js').OpenApiExecutor | {
|
|
74
|
+
export type ManagedTaskExecutor = import('./http-request.js').HttpRequestExecutor | import('./flow-state.js').SkipDuplicatesExecutor | WorkflowExecutor | import('./decision.js').DecisionExecutor | import('./openapi.js').OpenApiExecutor | {
|
|
75
75
|
readonly kind: 'connector';
|
|
76
76
|
readonly action: string;
|
|
77
77
|
readonly connectionId?: string;
|
|
@@ -160,7 +160,7 @@ export interface FlowDocument {
|
|
|
160
160
|
}
|
|
161
161
|
export interface RevisionContent {
|
|
162
162
|
readonly document: FlowDocument;
|
|
163
|
-
readonly modelVersion: 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | typeof currentFlowModelVersion;
|
|
163
|
+
readonly modelVersion: 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | typeof currentFlowModelVersion;
|
|
164
164
|
readonly modules: Readonly<Record<string, CodeModule>>;
|
|
165
165
|
}
|
|
166
166
|
export interface GraphEdge {
|
|
@@ -8833,6 +8833,43 @@ var httpRequestExecutorSchema = strictObject({
|
|
|
8833
8833
|
]).default("auto"),
|
|
8834
8834
|
statusPolicy: _enum(["success", "all"]).default("success")
|
|
8835
8835
|
}).extend({ kind: literal("http-request") });
|
|
8836
|
+
strictObject({
|
|
8837
|
+
scope: _enum(["draft", "live"]),
|
|
8838
|
+
values: boolean().optional()
|
|
8839
|
+
});
|
|
8840
|
+
strictObject({
|
|
8841
|
+
scope: _enum(["draft", "live"]),
|
|
8842
|
+
key: string().min(1).refine((key) => new TextEncoder().encode(key).length <= 256).optional()
|
|
8843
|
+
});
|
|
8844
|
+
strictObject({
|
|
8845
|
+
scope: _enum(["draft", "live"]),
|
|
8846
|
+
space: string().regex(/^(flow|node:.+)$/)
|
|
8847
|
+
});
|
|
8848
|
+
var skipDuplicatesExecutorSchema = strictObject({ fields: array(string().refine((field) => field.length > 0 && field.split(".").every((part) => part.length > 0), "Use a nonempty dot-separated field path.")).refine((fields) => new Set(fields).size === fields.length, "Identity fields must be distinct.").default([]) }).extend({ kind: literal("skip-duplicates") });
|
|
8849
|
+
object({
|
|
8850
|
+
version: literal(1),
|
|
8851
|
+
scope: _enum(["draft", "live"]),
|
|
8852
|
+
limits: object({
|
|
8853
|
+
maxValueBytes: number().positive(),
|
|
8854
|
+
maxValues: number().int().positive(),
|
|
8855
|
+
maxSpaces: number().int().positive(),
|
|
8856
|
+
maxIdentities: number().positive(),
|
|
8857
|
+
maxRunWrites: number().positive()
|
|
8858
|
+
}),
|
|
8859
|
+
values: array(object({
|
|
8860
|
+
key: string(),
|
|
8861
|
+
size: number().nonnegative(),
|
|
8862
|
+
updatedAt: number(),
|
|
8863
|
+
value: json$1().optional()
|
|
8864
|
+
})),
|
|
8865
|
+
spaces: array(object({
|
|
8866
|
+
space: string(),
|
|
8867
|
+
count: number().nonnegative(),
|
|
8868
|
+
pendingCount: number().nonnegative(),
|
|
8869
|
+
reservedCount: number().nonnegative(),
|
|
8870
|
+
updatedAt: number()
|
|
8871
|
+
}))
|
|
8872
|
+
});
|
|
8836
8873
|
function checkJsonDepth(value, depth = 0) {
|
|
8837
8874
|
if (depth > 64) throw new TypeError("Value exceeds the maximum JSON depth.");
|
|
8838
8875
|
if (value != null && typeof value == "object") for (const child of Object.values(value)) checkJsonDepth(child, depth + 1);
|
|
@@ -8933,7 +8970,7 @@ var webhookResponseTimeout = {
|
|
|
8933
8970
|
}).jsonSchema;
|
|
8934
8971
|
//#endregion
|
|
8935
8972
|
//#region src/flow/common/changeSchema.ts
|
|
8936
|
-
var currentFlowModelVersion =
|
|
8973
|
+
var currentFlowModelVersion = 13;
|
|
8937
8974
|
var text = string();
|
|
8938
8975
|
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.");
|
|
8939
8976
|
var json = json$1();
|
|
@@ -9131,7 +9168,8 @@ var managedFields = object({
|
|
|
9131
9168
|
flowId: text,
|
|
9132
9169
|
revisionId: text
|
|
9133
9170
|
}),
|
|
9134
|
-
httpRequestExecutorSchema
|
|
9171
|
+
httpRequestExecutorSchema,
|
|
9172
|
+
skipDuplicatesExecutorSchema
|
|
9135
9173
|
])
|
|
9136
9174
|
});
|
|
9137
9175
|
var managed = managedFields.transform(limitDecisionTask);
|
|
@@ -9401,7 +9439,8 @@ var revision = object({
|
|
|
9401
9439
|
literal(9),
|
|
9402
9440
|
literal(10),
|
|
9403
9441
|
literal(11),
|
|
9404
|
-
literal(12)
|
|
9442
|
+
literal(12),
|
|
9443
|
+
literal(13)
|
|
9405
9444
|
]),
|
|
9406
9445
|
document,
|
|
9407
9446
|
modules: record$1(text, module)
|
|
@@ -9626,6 +9665,7 @@ function changeOperationsSchema(kind) {
|
|
|
9626
9665
|
return toJSONSchema(schema, { io: "input" });
|
|
9627
9666
|
}
|
|
9628
9667
|
function checkModelVersion(content) {
|
|
9668
|
+
if (content.modelVersion < 13 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind === "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind === "skip-duplicates")) throw new Error("Skip Duplicates requires Flow model v13.");
|
|
9629
9669
|
if (content.modelVersion < 12 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "moduleId" in candidateNode.task && candidateNode.task.capabilities?.some((item) => item.kind == "http"))) throw new TypeError("Code HTTP access requires Flow model version 12.");
|
|
9630
9670
|
if (content.modelVersion < 11 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind == "http-request")) throw new TypeError("HTTP Request requires Flow model version 11.");
|
|
9631
9671
|
if (content.modelVersion < 11 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && ("moduleId" in candidateNode.task ? candidateNode.task.capabilities?.some((item) => item.kind == "workflow") : candidateNode.task.executor.kind == "agent" && candidateNode.task.executor.tools.some((item) => item.kind == "workflow")))) throw new TypeError("Workflow tools require Flow model version 11.");
|
|
@@ -9724,7 +9764,7 @@ var nodeErrorSchema = {
|
|
|
9724
9764
|
}
|
|
9725
9765
|
};
|
|
9726
9766
|
function supportsNodeErrorHandling(node) {
|
|
9727
|
-
return supportsNodeRetry(node);
|
|
9767
|
+
return supportsNodeRetry(node) || node.kind === "task" && "executor" in node.task && node.task.executor.kind === "skip-duplicates";
|
|
9728
9768
|
}
|
|
9729
9769
|
function nodeSystemOutputPorts(node) {
|
|
9730
9770
|
return supportsNodeErrorHandling(node) && node.onError == "error" ? { error: {
|
|
@@ -9905,10 +9945,10 @@ function upgradeRevisionContent(content) {
|
|
|
9905
9945
|
function upgradeDecodedRevisionContent(content) {
|
|
9906
9946
|
const graph = content.document.graph;
|
|
9907
9947
|
const hasManual = Object.values(graph.nodes).some((node) => node.kind == "manual");
|
|
9908
|
-
if (!hasManual && content.modelVersion ==
|
|
9948
|
+
if (!hasManual && content.modelVersion == 13) return content;
|
|
9909
9949
|
return {
|
|
9910
9950
|
...content,
|
|
9911
|
-
modelVersion:
|
|
9951
|
+
modelVersion: 13,
|
|
9912
9952
|
document: {
|
|
9913
9953
|
...content.document,
|
|
9914
9954
|
graph: hasManual ? {
|
|
@@ -9955,7 +9995,7 @@ function invalid(message) {
|
|
|
9955
9995
|
throw new FlowChangeError(message);
|
|
9956
9996
|
}
|
|
9957
9997
|
function applyFlowChanges(content, operations) {
|
|
9958
|
-
const source = content.modelVersion !=
|
|
9998
|
+
const source = content.modelVersion != 13 || Object.values(content.document.graph.nodes).some((node) => node.kind == "manual") ? decodeRevisionContent(content) : content;
|
|
9959
9999
|
const document = { ...source.document };
|
|
9960
10000
|
const modules = { ...source.modules };
|
|
9961
10001
|
for (const operation of operations) switch (operation.kind) {
|
|
@@ -10403,7 +10443,7 @@ function applyFlowChanges(content, operations) {
|
|
|
10403
10443
|
assertDocumentHttpAuthBindings(document);
|
|
10404
10444
|
return upgradeDecodedRevisionContent({
|
|
10405
10445
|
document,
|
|
10406
|
-
modelVersion:
|
|
10446
|
+
modelVersion: 13,
|
|
10407
10447
|
modules
|
|
10408
10448
|
});
|
|
10409
10449
|
}
|