@oomol-lab/open-flow 0.1.0-beta.77 → 0.1.0-beta.79
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 +2 -0
- package/dist/browser/{ContentIcon-VZQO8VZU.js → ContentIcon-CMn0c-kl.js} +93 -3
- package/dist/browser/{FlowCanvas-BNGDMaWr.js → FlowCanvas-BQGBcfoL.js} +1675 -591
- package/dist/browser/{createResourceDialog-BmtakfVg.js → createResourceDialog-DkovGogv.js} +3 -3
- package/dist/browser/{dialog-BcFBfRB1.js → dialog-CFFuRM8s.js} +37 -86
- package/dist/browser/{exportSvg-CG8hEUNk.js → exportSvg-CYwyYiuH.js} +2 -2
- package/dist/browser/{flowChanges-BGo_4Ypo.js → flowChanges-CN2R-m1M.js} +1258 -422
- package/dist/browser/{flowWorkspace-BFHGev7s.js → flowWorkspace-CXVL1FNv.js} +634 -628
- package/dist/browser/licenses.md +1 -1
- package/dist/browser/preview.css +512 -462
- package/dist/browser/preview.js +8183 -6384
- package/dist/browser/{tooltip-BAWSUexx.js → tooltip-BDcVTNpu.js} +65 -2
- package/dist/browser/{typeScriptSession-CRoezJPN.js → typeScriptSession-CoEIptNC.js} +1 -1
- package/dist/browser/ui.css +5 -24
- package/dist/browser/workbench.css +512 -462
- package/dist/browser/workbench.d.ts +2 -3
- package/dist/browser/workbench.js +65 -690
- package/dist/browser/{workbenchSelect-CjK-xdm3.js → workbenchSelect-CkOS95gX.js} +2 -2
- package/dist/command/index.js +31 -31
- package/dist/common/authoring.d.ts +3 -3
- package/dist/common/authoringExamples.d.ts +3 -3
- package/dist/common/authoringSchema.d.ts +14 -22
- package/dist/common/control-api-conformance.js +91 -25
- package/dist/common/control-api.d.ts +8 -3
- package/dist/common/control-api.js +51 -25
- package/dist/common/control-requests.d.ts +9 -3
- package/dist/common/control-requests.js +54 -42
- package/dist/common/flow-authoring.js +32 -19
- package/dist/common/flow-change.d.ts +1 -1
- package/dist/common/flow-change.js +32 -19
- package/dist/common/flow-encoding.js +31 -18
- package/dist/common/flow-semantics.js +41 -26
- package/dist/common/flow-state.d.ts +49 -43
- package/dist/common/flow-state.js +95 -110
- package/dist/common/mcp.d.ts +35 -4
- package/dist/common/mcp.js +51 -26
- package/dist/common/run-events.js +19 -9
- package/dist/common/runtime-contract.d.ts +4 -1
- package/dist/common/runtime-contract.js +66 -17
- package/dist/common/runtime-nodejs-compat.js +11 -12
- package/dist/common/scheduler.d.ts +2 -1
- package/dist/common/scheduler.js +82 -55
- package/dist/common/state-conformance.d.ts +3 -3
- package/dist/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/control/common/api.ts +36 -7
- package/src/control/common/authoring.ts +6 -5
- package/src/control/common/authoringExamples.ts +6 -5
- package/src/control/common/authoringSchema.ts +7 -7
- package/src/control/common/conformance.ts +31 -0
- package/src/control/common/mcp.ts +7 -2
- package/src/control/common/requests.ts +10 -1
- package/src/execution/common/events.ts +22 -10
- package/src/execution/common/node-execution.ts +1 -1
- package/src/execution/common/scheduler.ts +28 -14
- package/src/flow/common/change.ts +1 -1
- package/src/flow/common/changeSchema.ts +4 -4
- package/src/flow/common/errorHandling.ts +1 -1
- package/src/flow/common/semantics.ts +12 -6
- package/src/runtime/common/nodejsGuest.generated.json +11 -12
- package/src/runtime/common/runtime.ts +45 -12
- package/src/state/common/conformance.ts +32 -21
- package/src/state/common/state.ts +85 -80
- package/src/types/index.ts +1 -0
|
@@ -5604,44 +5604,58 @@ function dequal(foo, bar) {
|
|
|
5604
5604
|
//#region src/state/common/conformance.ts
|
|
5605
5605
|
var stateConformanceCases = [
|
|
5606
5606
|
{
|
|
5607
|
-
name: "
|
|
5607
|
+
name: "reads selected State keys in input order with missing, falsy and independent values",
|
|
5608
5608
|
async verify(harness) {
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
}
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5609
|
+
if (!dequal(await harness.run(`export default async (_, context) => {
|
|
5610
|
+
await context.state.set('object', { nested: [1] });
|
|
5611
|
+
await context.state.set('zero', 0);
|
|
5612
|
+
await context.state.set('false', false);
|
|
5613
|
+
await context.state.set('empty', '');
|
|
5614
|
+
const values = await context.state.get(['false', 'missing', 'object', 'zero', 'empty']);
|
|
5615
|
+
values[2].nested.push(2);
|
|
5616
|
+
return {result: {values, retained: await context.state.get('object'), zero: await context.state.get('zero')}};
|
|
5617
|
+
}`), {
|
|
5618
|
+
values: [
|
|
5619
|
+
false,
|
|
5620
|
+
null,
|
|
5621
|
+
{ nested: [1, 2] },
|
|
5622
|
+
0,
|
|
5623
|
+
""
|
|
5624
|
+
],
|
|
5625
|
+
retained: { nested: [1] },
|
|
5626
|
+
zero: 0
|
|
5627
|
+
})) throw new Error("State batch reads must preserve order, missing keys and independent JSON values.");
|
|
5628
|
+
}
|
|
5629
|
+
},
|
|
5630
|
+
{
|
|
5631
|
+
name: "skips composite identities across successful Runs without depending on field order",
|
|
5632
|
+
async verify(harness) {
|
|
5633
|
+
const items = [
|
|
5634
|
+
{
|
|
5635
|
+
company: "a",
|
|
5636
|
+
id: 1
|
|
5637
|
+
},
|
|
5638
|
+
{
|
|
5639
|
+
company: "b",
|
|
5640
|
+
id: 1
|
|
5641
|
+
},
|
|
5642
|
+
{
|
|
5643
|
+
company: "a",
|
|
5644
|
+
id: 1
|
|
5645
|
+
}
|
|
5646
|
+
];
|
|
5647
|
+
if (!dequal(await harness.skipDuplicates({ fields: ["company", "id"] }, items), {
|
|
5648
|
+
items: items.slice(0, 2),
|
|
5649
|
+
duplicates: [items[2]]
|
|
5650
|
+
})) throw new Error("Composite identities must retain the first item in input order.");
|
|
5651
|
+
if (!dequal(await harness.skipDuplicates({ fields: ["id", "company"] }, items), {
|
|
5652
|
+
items: [],
|
|
5653
|
+
duplicates: items
|
|
5654
|
+
})) throw new Error("Successful Run history must persist independently of field order.");
|
|
5655
|
+
if (!dequal(await harness.skipDuplicates({ fields: ["id"] }, items), {
|
|
5656
|
+
items: [items[0]],
|
|
5657
|
+
duplicates: items.slice(1)
|
|
5658
|
+
})) throw new Error("The field definition must participate in identity.");
|
|
5645
5659
|
}
|
|
5646
5660
|
},
|
|
5647
5661
|
{
|
|
@@ -5710,30 +5724,35 @@ var stateConformanceCases = [
|
|
|
5710
5724
|
];
|
|
5711
5725
|
//#endregion
|
|
5712
5726
|
//#region src/state/common/state.ts
|
|
5727
|
+
var stateReadLimits = {
|
|
5728
|
+
maxKeys: 16,
|
|
5729
|
+
maxBytes: 1048576
|
|
5730
|
+
};
|
|
5731
|
+
var keySchema = string().min(1).refine((value) => new TextEncoder().encode(value).length <= 256);
|
|
5713
5732
|
var stateQuerySchema = strictObject({
|
|
5714
5733
|
scope: _enum(["draft", "live"]),
|
|
5715
|
-
values:
|
|
5734
|
+
values: literal(false).optional()
|
|
5735
|
+
});
|
|
5736
|
+
var stateReadSchema = strictObject({
|
|
5737
|
+
scope: _enum(["draft", "live"]),
|
|
5738
|
+
keys: array(keySchema).min(1).max(stateReadLimits.maxKeys).refine((keys) => new Set(keys).size === keys.length, "State keys must be distinct.")
|
|
5716
5739
|
});
|
|
5717
5740
|
var stateClearSchema = strictObject({
|
|
5718
5741
|
scope: _enum(["draft", "live"]),
|
|
5719
|
-
key:
|
|
5742
|
+
key: keySchema.optional()
|
|
5720
5743
|
});
|
|
5721
5744
|
var dedupeClearSchema = strictObject({
|
|
5722
5745
|
scope: _enum(["draft", "live"]),
|
|
5723
5746
|
space: string().regex(/^(flow|node:.+)$/)
|
|
5724
5747
|
});
|
|
5725
|
-
var
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
space: _enum(["node", "flow"]).default("node")
|
|
5729
|
-
});
|
|
5730
|
-
var dedupeExecutorSchema = dedupeConfigSchema.extend({ kind: literal("dedupe") });
|
|
5731
|
-
function dedupeTask(config = dedupeConfigSchema.parse({}), name = "Remove Duplicates") {
|
|
5748
|
+
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([]) });
|
|
5749
|
+
var skipDuplicatesExecutorSchema = skipDuplicatesConfigSchema.extend({ kind: literal("skip-duplicates") });
|
|
5750
|
+
function skipDuplicatesTask(config = skipDuplicatesConfigSchema.parse({}), name = "Skip Duplicates") {
|
|
5732
5751
|
return {
|
|
5733
5752
|
name,
|
|
5734
5753
|
executor: {
|
|
5735
5754
|
...config,
|
|
5736
|
-
kind: "
|
|
5755
|
+
kind: "skip-duplicates"
|
|
5737
5756
|
},
|
|
5738
5757
|
inputs: [{
|
|
5739
5758
|
handle: "items",
|
|
@@ -5753,7 +5772,7 @@ var StateError = class extends Error {
|
|
|
5753
5772
|
this.retryable = false;
|
|
5754
5773
|
this.name = "StateError";
|
|
5755
5774
|
this.code = code;
|
|
5756
|
-
this.catchable = code === "dedupe.full";
|
|
5775
|
+
this.catchable = code === "dedupe.full" || code === "node.input-invalid";
|
|
5757
5776
|
}
|
|
5758
5777
|
};
|
|
5759
5778
|
function stateKey(key) {
|
|
@@ -5767,58 +5786,18 @@ function dedupeIdentities(value) {
|
|
|
5767
5786
|
async function hashIdentities(ids) {
|
|
5768
5787
|
return Promise.all(ids.map(async (id) => new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`${typeof id}:${String(id)}`))).slice(0, 16)));
|
|
5769
5788
|
}
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
31,
|
|
5783
|
-
30,
|
|
5784
|
-
31,
|
|
5785
|
-
30,
|
|
5786
|
-
31,
|
|
5787
|
-
31,
|
|
5788
|
-
30,
|
|
5789
|
-
31,
|
|
5790
|
-
30,
|
|
5791
|
-
31
|
|
5792
|
-
][Number(month) - 1] ?? 0;
|
|
5793
|
-
const result = Date.parse(id);
|
|
5794
|
-
if (Number(month) < 1 || Number(month) > 12 || Number(day) < 1 || Number(day) > days || Number(hour) > 23 || Number(minute) > 59 || Number(second) > 59 || zone !== "Z" && (Number(zone.slice(1, 3)) > 23 || Number(zone.slice(4)) > 59) || !Number.isFinite(result)) throw new StateError("capability.invalid", "Watermarks require valid calendar timestamps.");
|
|
5795
|
-
return result;
|
|
5796
|
-
}
|
|
5797
|
-
function increasingIdentities(ids, watermark) {
|
|
5798
|
-
const type = typeof (watermark ?? ids[0]);
|
|
5799
|
-
if (ids.some((id) => typeof id !== type)) throw new StateError("capability.invalid", "Watermark types must not be mixed.");
|
|
5800
|
-
const initial = watermark == null ? -Infinity : watermarkValue(watermark);
|
|
5801
|
-
const seen = /* @__PURE__ */ new Set();
|
|
5802
|
-
let maximum = initial;
|
|
5803
|
-
let next = watermark;
|
|
5804
|
-
return {
|
|
5805
|
-
inserted: ids.map((id) => {
|
|
5806
|
-
const value = watermarkValue(id);
|
|
5807
|
-
const fresh = value > initial && !seen.has(value);
|
|
5808
|
-
seen.add(value);
|
|
5809
|
-
if (value > maximum) {
|
|
5810
|
-
maximum = value;
|
|
5811
|
-
next = id;
|
|
5812
|
-
}
|
|
5813
|
-
return fresh;
|
|
5814
|
-
}),
|
|
5815
|
-
watermark: next
|
|
5816
|
-
};
|
|
5817
|
-
}
|
|
5818
|
-
function itemIdentities(items, field) {
|
|
5819
|
-
if (!Array.isArray(items)) throw new StateError("capability.invalid", "Deduplication requires an array of items.");
|
|
5820
|
-
const path = field === "" ? [] : field.split(".");
|
|
5821
|
-
return dedupeIdentities(items.map((item) => path.reduce((value, key) => value != null && typeof value === "object" && Object.hasOwn(value, key) ? value[key] : void 0, item)));
|
|
5789
|
+
/** Canonical identities include the field definition and preserve scalar types. */
|
|
5790
|
+
function skipDuplicatesIdentities(items, fields) {
|
|
5791
|
+
if (!Array.isArray(items)) throw new StateError("node.input-invalid", "Skip Duplicates requires an array of items.");
|
|
5792
|
+
const paths = fields.toSorted();
|
|
5793
|
+
return items.map((item, index) => {
|
|
5794
|
+
const values = (paths.length === 0 ? [""] : paths).map((field) => {
|
|
5795
|
+
const value = field === "" ? item : field.split(".").reduce((current, key) => current != null && typeof current === "object" && Object.hasOwn(current, key) ? current[key] : void 0, item);
|
|
5796
|
+
if (typeof value !== "string" && !(typeof value === "number" && Number.isFinite(value))) throw new StateError("node.input-invalid", `Item ${index + 1}, ${field === "" ? "the item itself" : `field ${JSON.stringify(field)}`} must be a string or finite number.`);
|
|
5797
|
+
return value;
|
|
5798
|
+
});
|
|
5799
|
+
return JSON.stringify([paths, values]);
|
|
5800
|
+
});
|
|
5822
5801
|
}
|
|
5823
5802
|
var flowStateViewSchema = object({
|
|
5824
5803
|
version: literal(1),
|
|
@@ -5830,23 +5809,29 @@ var flowStateViewSchema = object({
|
|
|
5830
5809
|
maxIdentities: number().positive(),
|
|
5831
5810
|
maxRunWrites: number().positive()
|
|
5832
5811
|
}),
|
|
5833
|
-
values: array(
|
|
5812
|
+
values: array(strictObject({
|
|
5834
5813
|
key: string(),
|
|
5835
5814
|
size: number().nonnegative(),
|
|
5836
|
-
updatedAt: number()
|
|
5837
|
-
value: json().optional()
|
|
5815
|
+
updatedAt: number()
|
|
5838
5816
|
})),
|
|
5839
5817
|
spaces: array(object({
|
|
5840
5818
|
space: string(),
|
|
5841
|
-
mode: _enum(["new", "increasing"]),
|
|
5842
5819
|
count: number().nonnegative(),
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
number(),
|
|
5846
|
-
_null()
|
|
5847
|
-
]),
|
|
5820
|
+
pendingCount: number().nonnegative(),
|
|
5821
|
+
reservedCount: number().nonnegative(),
|
|
5848
5822
|
updatedAt: number()
|
|
5849
5823
|
}))
|
|
5850
5824
|
});
|
|
5825
|
+
var flowStateValuesSchema = object({
|
|
5826
|
+
version: literal(1),
|
|
5827
|
+
scope: _enum(["draft", "live"]),
|
|
5828
|
+
values: array(strictObject({
|
|
5829
|
+
key: keySchema,
|
|
5830
|
+
value: json()
|
|
5831
|
+
})).min(1).max(stateReadLimits.maxKeys)
|
|
5832
|
+
}).refine((response) => {
|
|
5833
|
+
const encoder = new TextEncoder();
|
|
5834
|
+
return response.values.reduce((bytes, item) => bytes + (item.value === null ? 0 : encoder.encode(JSON.stringify(item.value)).byteLength), 0) <= stateReadLimits.maxBytes;
|
|
5835
|
+
}, "State values exceed the 1 MiB read limit.");
|
|
5851
5836
|
//#endregion
|
|
5852
|
-
export { StateError, dedupeClearSchema,
|
|
5837
|
+
export { StateError, dedupeClearSchema, dedupeIdentities, flowStateValuesSchema, flowStateViewSchema, hashIdentities, skipDuplicatesConfigSchema, skipDuplicatesExecutorSchema, skipDuplicatesIdentities, skipDuplicatesTask, stateClearSchema, stateConformanceCases, stateKey, stateQuerySchema, stateReadLimits, stateReadSchema };
|
package/dist/common/mcp.d.ts
CHANGED
|
@@ -22,7 +22,38 @@ export declare const mcpTools: {
|
|
|
22
22
|
validate(value: unknown): {
|
|
23
23
|
value: {
|
|
24
24
|
scope: "draft" | "live";
|
|
25
|
-
values?:
|
|
25
|
+
values?: false | undefined;
|
|
26
|
+
flowId: string;
|
|
27
|
+
};
|
|
28
|
+
} | {
|
|
29
|
+
issues: {
|
|
30
|
+
message: string;
|
|
31
|
+
path: string[];
|
|
32
|
+
}[];
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
flow_state_read: {
|
|
38
|
+
description: string;
|
|
39
|
+
annotations: {
|
|
40
|
+
readOnlyHint: boolean;
|
|
41
|
+
destructiveHint: boolean;
|
|
42
|
+
idempotentHint: boolean;
|
|
43
|
+
openWorldHint: boolean;
|
|
44
|
+
};
|
|
45
|
+
inputSchema: {
|
|
46
|
+
'~standard': {
|
|
47
|
+
version: 1;
|
|
48
|
+
vendor: string;
|
|
49
|
+
jsonSchema: {
|
|
50
|
+
input: () => Record<string, unknown>;
|
|
51
|
+
output: () => Record<string, unknown>;
|
|
52
|
+
};
|
|
53
|
+
validate(value: unknown): {
|
|
54
|
+
value: {
|
|
55
|
+
scope: "draft" | "live";
|
|
56
|
+
keys: string[];
|
|
26
57
|
flowId: string;
|
|
27
58
|
};
|
|
28
59
|
} | {
|
|
@@ -254,7 +285,7 @@ export declare const mcpTools: {
|
|
|
254
285
|
value: {
|
|
255
286
|
revision?: string | undefined;
|
|
256
287
|
query: string;
|
|
257
|
-
type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "
|
|
288
|
+
type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "skip-duplicates" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow" | undefined;
|
|
258
289
|
offset: number;
|
|
259
290
|
limit: number;
|
|
260
291
|
flowId: string;
|
|
@@ -286,7 +317,7 @@ export declare const mcpTools: {
|
|
|
286
317
|
};
|
|
287
318
|
validate(value: unknown): {
|
|
288
319
|
value: {
|
|
289
|
-
type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "
|
|
320
|
+
type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "skip-duplicates" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow" | undefined;
|
|
290
321
|
action?: string | undefined;
|
|
291
322
|
flowId?: string | undefined;
|
|
292
323
|
};
|
|
@@ -414,7 +445,7 @@ export declare const mcpTools: {
|
|
|
414
445
|
edits: ({
|
|
415
446
|
op: "node.add";
|
|
416
447
|
as: string;
|
|
417
|
-
type: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "
|
|
448
|
+
type: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "skip-duplicates" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow";
|
|
418
449
|
name: string;
|
|
419
450
|
onError?: "error" | "stop" | undefined;
|
|
420
451
|
retry?: {
|
package/dist/common/mcp.js
CHANGED
|
@@ -8848,24 +8848,29 @@ var httpRequestConfigSchema = strictObject({
|
|
|
8848
8848
|
var httpRequestExecutorSchema = httpRequestConfigSchema.extend({ kind: literal("http-request") });
|
|
8849
8849
|
//#endregion
|
|
8850
8850
|
//#region src/state/common/state.ts
|
|
8851
|
+
var stateReadLimits = {
|
|
8852
|
+
maxKeys: 16,
|
|
8853
|
+
maxBytes: 1048576
|
|
8854
|
+
};
|
|
8855
|
+
var keySchema = string$1().min(1).refine((value) => new TextEncoder().encode(value).length <= 256);
|
|
8851
8856
|
var stateQuerySchema = strictObject({
|
|
8852
8857
|
scope: _enum(["draft", "live"]),
|
|
8853
|
-
values:
|
|
8858
|
+
values: literal(false).optional()
|
|
8859
|
+
});
|
|
8860
|
+
var stateReadSchema = strictObject({
|
|
8861
|
+
scope: _enum(["draft", "live"]),
|
|
8862
|
+
keys: array(keySchema).min(1).max(stateReadLimits.maxKeys).refine((keys) => new Set(keys).size === keys.length, "State keys must be distinct.")
|
|
8854
8863
|
});
|
|
8855
8864
|
var stateClearSchema = strictObject({
|
|
8856
8865
|
scope: _enum(["draft", "live"]),
|
|
8857
|
-
key:
|
|
8866
|
+
key: keySchema.optional()
|
|
8858
8867
|
});
|
|
8859
8868
|
var dedupeClearSchema = strictObject({
|
|
8860
8869
|
scope: _enum(["draft", "live"]),
|
|
8861
8870
|
space: string$1().regex(/^(flow|node:.+)$/)
|
|
8862
8871
|
});
|
|
8863
|
-
var
|
|
8864
|
-
|
|
8865
|
-
mode: _enum(["new", "increasing"]).default("new"),
|
|
8866
|
-
space: _enum(["node", "flow"]).default("node")
|
|
8867
|
-
});
|
|
8868
|
-
var dedupeExecutorSchema = dedupeConfigSchema.extend({ kind: literal("dedupe") });
|
|
8872
|
+
var skipDuplicatesConfigSchema = strictObject({ fields: array(string$1().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([]) });
|
|
8873
|
+
var skipDuplicatesExecutorSchema = skipDuplicatesConfigSchema.extend({ kind: literal("skip-duplicates") });
|
|
8869
8874
|
var flowStateViewSchema = object({
|
|
8870
8875
|
version: literal(1),
|
|
8871
8876
|
scope: _enum(["draft", "live"]),
|
|
@@ -8876,24 +8881,30 @@ var flowStateViewSchema = object({
|
|
|
8876
8881
|
maxIdentities: number().positive(),
|
|
8877
8882
|
maxRunWrites: number().positive()
|
|
8878
8883
|
}),
|
|
8879
|
-
values: array(
|
|
8884
|
+
values: array(strictObject({
|
|
8880
8885
|
key: string$1(),
|
|
8881
8886
|
size: number().nonnegative(),
|
|
8882
|
-
updatedAt: number()
|
|
8883
|
-
value: json$4().optional()
|
|
8887
|
+
updatedAt: number()
|
|
8884
8888
|
})),
|
|
8885
8889
|
spaces: array(object({
|
|
8886
8890
|
space: string$1(),
|
|
8887
|
-
mode: _enum(["new", "increasing"]),
|
|
8888
8891
|
count: number().nonnegative(),
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
number(),
|
|
8892
|
-
_null()
|
|
8893
|
-
]),
|
|
8892
|
+
pendingCount: number().nonnegative(),
|
|
8893
|
+
reservedCount: number().nonnegative(),
|
|
8894
8894
|
updatedAt: number()
|
|
8895
8895
|
}))
|
|
8896
8896
|
});
|
|
8897
|
+
var flowStateValuesSchema = object({
|
|
8898
|
+
version: literal(1),
|
|
8899
|
+
scope: _enum(["draft", "live"]),
|
|
8900
|
+
values: array(strictObject({
|
|
8901
|
+
key: keySchema,
|
|
8902
|
+
value: json$4()
|
|
8903
|
+
})).min(1).max(stateReadLimits.maxKeys)
|
|
8904
|
+
}).refine((response) => {
|
|
8905
|
+
const encoder = new TextEncoder();
|
|
8906
|
+
return response.values.reduce((bytes, item) => bytes + (item.value === null ? 0 : encoder.encode(JSON.stringify(item.value)).byteLength), 0) <= stateReadLimits.maxBytes;
|
|
8907
|
+
}, "State values exceed the 1 MiB read limit.");
|
|
8897
8908
|
function checkJsonDepth(value, depth = 0) {
|
|
8898
8909
|
if (depth > 64) throw new TypeError("Value exceeds the maximum JSON depth.");
|
|
8899
8910
|
if (value != null && typeof value == "object") for (const child of Object.values(value)) checkJsonDepth(child, depth + 1);
|
|
@@ -9183,7 +9194,7 @@ var managedFields = object({
|
|
|
9183
9194
|
revisionId: text
|
|
9184
9195
|
}),
|
|
9185
9196
|
httpRequestExecutorSchema,
|
|
9186
|
-
|
|
9197
|
+
skipDuplicatesExecutorSchema
|
|
9187
9198
|
])
|
|
9188
9199
|
});
|
|
9189
9200
|
var managed = managedFields.transform(limitDecisionTask);
|
|
@@ -9655,7 +9666,7 @@ array(union([...new Map(Object.entries(shapes).map(([kind, shape]) => [kind, sha
|
|
|
9655
9666
|
...shape
|
|
9656
9667
|
})])).values()])).min(1);
|
|
9657
9668
|
function checkModelVersion(content) {
|
|
9658
|
-
if (content.modelVersion < 13 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind === "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind === "
|
|
9669
|
+
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.");
|
|
9659
9670
|
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.");
|
|
9660
9671
|
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.");
|
|
9661
9672
|
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.");
|
|
@@ -9812,7 +9823,7 @@ var type = _enum([
|
|
|
9812
9823
|
"decision",
|
|
9813
9824
|
"openapi",
|
|
9814
9825
|
"http-request",
|
|
9815
|
-
"
|
|
9826
|
+
"skip-duplicates",
|
|
9816
9827
|
"condition",
|
|
9817
9828
|
"value",
|
|
9818
9829
|
"wait",
|
|
@@ -9943,7 +9954,7 @@ var authoringConfigurations = {
|
|
|
9943
9954
|
"connector": authoringDefinitionSchemas.connector.omit({ outputMode: true }).strict(),
|
|
9944
9955
|
"openapi": authoringOpenApiSchema,
|
|
9945
9956
|
"http-request": httpRequestConfigSchema,
|
|
9946
|
-
"
|
|
9957
|
+
"skip-duplicates": skipDuplicatesConfigSchema,
|
|
9947
9958
|
"agent": authoringDefinitionSchemas.agent.omit({
|
|
9948
9959
|
prompt: true,
|
|
9949
9960
|
tools: true
|
|
@@ -12057,7 +12068,7 @@ function decodeRunEvent(value) {
|
|
|
12057
12068
|
switch (kind) {
|
|
12058
12069
|
case "node.started": {
|
|
12059
12070
|
const nodeKind = payload.nodeKind;
|
|
12060
|
-
if (nodeKind !== void 0 && nodeKind !== "approval" && nodeKind !== "condition" && nodeKind !== "connector" && nodeKind !== "javascript" && nodeKind !== "decision" && nodeKind !== "openapi" && nodeKind !== "http-request" && nodeKind !== "
|
|
12071
|
+
if (nodeKind !== void 0 && nodeKind !== "approval" && nodeKind !== "condition" && nodeKind !== "connector" && nodeKind !== "javascript" && nodeKind !== "decision" && nodeKind !== "openapi" && nodeKind !== "http-request" && nodeKind !== "skip-duplicates" && nodeKind !== "llm" && nodeKind !== "agent" && nodeKind !== "value" && nodeKind !== "outputs" && nodeKind !== "webhook-response" && nodeKind !== "workflow" && nodeKind !== "wait") return invalidResponse();
|
|
12061
12072
|
return {
|
|
12062
12073
|
...base,
|
|
12063
12074
|
kind,
|
|
@@ -12282,12 +12293,13 @@ var ControlClient = class {
|
|
|
12282
12293
|
})
|
|
12283
12294
|
}));
|
|
12284
12295
|
}
|
|
12285
|
-
async createFlow(name, idempotencyKey = `flow-${randomId()}`, teamId, tagIds) {
|
|
12296
|
+
async createFlow(name, idempotencyKey = `flow-${randomId()}`, teamId, tagIds, initialPresentation) {
|
|
12286
12297
|
return flow$1(await this.request("/v1/flows", {
|
|
12287
12298
|
body: JSON.stringify({
|
|
12288
12299
|
name,
|
|
12289
12300
|
...teamId == null ? {} : { teamId },
|
|
12290
12301
|
...tagIds == null ? {} : { tagIds },
|
|
12302
|
+
...initialPresentation == null ? {} : { presentation: initialPresentation },
|
|
12291
12303
|
version: 1
|
|
12292
12304
|
}),
|
|
12293
12305
|
headers: { "idempotency-key": idempotencyKey },
|
|
@@ -12369,10 +12381,22 @@ var ControlClient = class {
|
|
|
12369
12381
|
})
|
|
12370
12382
|
}));
|
|
12371
12383
|
}
|
|
12372
|
-
async getFlowState(flowId, scope
|
|
12373
|
-
const result = flowStateViewSchema.safeParse(await this.request(`/v1/flows/${segment(flowId)}/state?scope=${scope}
|
|
12384
|
+
async getFlowState(flowId, scope) {
|
|
12385
|
+
const result = flowStateViewSchema.safeParse(await this.request(`/v1/flows/${segment(flowId)}/state?scope=${scope}`));
|
|
12374
12386
|
return result.success && result.data.scope === scope ? result.data : invalidResponse();
|
|
12375
12387
|
}
|
|
12388
|
+
async getFlowStateValues(flowId, scope, keys, signal) {
|
|
12389
|
+
const result = flowStateValuesSchema.safeParse(await this.request(`/v1/flows/${segment(flowId)}/state/read`, {
|
|
12390
|
+
method: "POST",
|
|
12391
|
+
body: JSON.stringify({
|
|
12392
|
+
version: 1,
|
|
12393
|
+
scope,
|
|
12394
|
+
keys
|
|
12395
|
+
}),
|
|
12396
|
+
signal
|
|
12397
|
+
}));
|
|
12398
|
+
return result.success && result.data.scope === scope && result.data.values.length === keys.length && result.data.values.every((item, index) => item.key === keys[index]) ? result.data : invalidResponse();
|
|
12399
|
+
}
|
|
12376
12400
|
async clearFlowState(flowId, scope, key) {
|
|
12377
12401
|
const source = record(await this.request(`/v1/flows/${segment(flowId)}/state?scope=${scope}${key == null ? "" : `&key=${encodeURIComponent(key)}`}`, { method: "DELETE" }));
|
|
12378
12402
|
if (source.version !== 1 || source.cleared !== true) invalidResponse();
|
|
@@ -13135,7 +13159,8 @@ function tool(description, schema, readOnly, idempotent = true) {
|
|
|
13135
13159
|
};
|
|
13136
13160
|
}
|
|
13137
13161
|
var mcpTools = {
|
|
13138
|
-
flow_state: tool("Inspect Flow state usage, business
|
|
13162
|
+
flow_state: tool("Inspect Flow state usage, business key metadata and deduplication spaces. Never returns values. Scope is required.", stateQuerySchema.extend({ flowId: flow }), true),
|
|
13163
|
+
flow_state_read: tool("Read values for 1–16 distinct named State keys in one explicit scope. Values are returned in request order; missing keys return null. The combined stored JSON limit is 1 MiB; oversized reads fail without partial results.", stateReadSchema.extend({ flowId: flow }), true),
|
|
13139
13164
|
flow_state_clear: tool("Delete one business state key or clear all business values. Explicit draft/live scope is required; live changes production state immediately.", stateClearSchema.extend({ flowId: flow }), false),
|
|
13140
13165
|
flow_dedupe_clear: tool("Clear one deduplication space (flow or node:<id>). Explicit draft/live scope is required; live changes production history immediately.", dedupeClearSchema.extend({ flowId: flow }), false),
|
|
13141
13166
|
flow_canvas: tool("Broadcast a transient canvas command to connected Workbenches viewing this Flow. Success only confirms Server broadcast, not delivery or execution. No replay, session selection or Presentation save. Pan uses screen pixels (positive right/down); zoom is an absolute ratio (0.1–3); fit includes all nodes. Repeating pan moves again.", strictObject({
|
|
@@ -54,7 +54,7 @@ var nodeKinds = /* @__PURE__ */ new Set([
|
|
|
54
54
|
"javascript",
|
|
55
55
|
"openapi",
|
|
56
56
|
"http-request",
|
|
57
|
-
"
|
|
57
|
+
"skip-duplicates",
|
|
58
58
|
"llm",
|
|
59
59
|
"value",
|
|
60
60
|
"wait",
|
|
@@ -81,12 +81,12 @@ function nodeKind(value) {
|
|
|
81
81
|
function runId(event) {
|
|
82
82
|
return string(event.runId, "Runtime event runId");
|
|
83
83
|
}
|
|
84
|
-
function nodeContext(event, flows, platformRunId) {
|
|
84
|
+
function nodeContext(event, flows, platformRunId, identify) {
|
|
85
85
|
const rawRunId = runId(event);
|
|
86
86
|
const flowId = flows.get(rawRunId);
|
|
87
87
|
if (flowId == null) throw new TypeError("Runtime node event preceded its run.started event.");
|
|
88
88
|
return {
|
|
89
|
-
executionId:
|
|
89
|
+
executionId: identify("execution", platformRunId, rawRunId, string(event.jobId, "Runtime node event jobId")),
|
|
90
90
|
flowId,
|
|
91
91
|
nodeId: string(event.nodeId, "Runtime node event nodeId"),
|
|
92
92
|
rawRunId
|
|
@@ -139,6 +139,16 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
|
|
|
139
139
|
const jobs = /* @__PURE__ */ new Map();
|
|
140
140
|
const nodeProgressBuckets = /* @__PURE__ */ new Map();
|
|
141
141
|
const runProgressBuckets = /* @__PURE__ */ new Map();
|
|
142
|
+
const identities = /* @__PURE__ */ new Map();
|
|
143
|
+
const identify = (prefix, ...parts) => {
|
|
144
|
+
const key = JSON.stringify([prefix, ...parts]);
|
|
145
|
+
let identity = identities.get(key);
|
|
146
|
+
if (identity == null) {
|
|
147
|
+
identity = opaqueId(prefix, ...parts);
|
|
148
|
+
identities.set(key, identity);
|
|
149
|
+
}
|
|
150
|
+
return identity;
|
|
151
|
+
};
|
|
142
152
|
return async (value) => {
|
|
143
153
|
const event = object(value, "Runtime event");
|
|
144
154
|
const type = string(event.type, "Runtime event type");
|
|
@@ -157,8 +167,8 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
|
|
|
157
167
|
kind: "run.started",
|
|
158
168
|
payload: {
|
|
159
169
|
flowId,
|
|
160
|
-
...parentRunId === void 0 ? {} : { parentScopeId: await
|
|
161
|
-
scopeId: await
|
|
170
|
+
...parentRunId === void 0 ? {} : { parentScopeId: await identify("scope", platformRunId, parentRunId) },
|
|
171
|
+
scopeId: await identify("scope", platformRunId, rawRunId)
|
|
162
172
|
}
|
|
163
173
|
};
|
|
164
174
|
}
|
|
@@ -175,7 +185,7 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
|
|
|
175
185
|
payload: {
|
|
176
186
|
flowId,
|
|
177
187
|
progress: event.progress,
|
|
178
|
-
scopeId: await
|
|
188
|
+
scopeId: await identify("scope", platformRunId, rawRunId)
|
|
179
189
|
}
|
|
180
190
|
};
|
|
181
191
|
}
|
|
@@ -183,7 +193,7 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
|
|
|
183
193
|
const rawRunId = runId(event);
|
|
184
194
|
if (type == "run.failed" && rawRunId == platformRunId && event.failure != null) {
|
|
185
195
|
const failure = object(event.failure, "Runtime terminal failure");
|
|
186
|
-
const context = nodeContext(failure, flows, platformRunId);
|
|
196
|
+
const context = nodeContext(failure, flows, platformRunId, identify);
|
|
187
197
|
return {
|
|
188
198
|
kind: "node.failed",
|
|
189
199
|
payload: {
|
|
@@ -201,13 +211,13 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
|
|
|
201
211
|
return;
|
|
202
212
|
}
|
|
203
213
|
if (type == "node.started" || type == "node.progress" || type == "node.artifact" || type == "node.log" || type == "node.completed" || type == "node.failed") {
|
|
204
|
-
const context = nodeContext(event, flows, platformRunId);
|
|
214
|
+
const context = nodeContext(event, flows, platformRunId, identify);
|
|
205
215
|
const executionId = await context.executionId;
|
|
206
216
|
const payload = {
|
|
207
217
|
executionId,
|
|
208
218
|
flowId: context.flowId,
|
|
209
219
|
nodeId: context.nodeId,
|
|
210
|
-
scopeId: await
|
|
220
|
+
scopeId: await identify("scope", platformRunId, context.rawRunId),
|
|
211
221
|
...event.systemOutputs === void 0 ? {} : { systemOutputs: object(event.systemOutputs, "Runtime system outputs") },
|
|
212
222
|
...event.handled === true ? { handled: true } : {}
|
|
213
223
|
};
|
|
@@ -3,7 +3,10 @@ export { currentEngineContract, nodejsEngineContract, findEngineContract, type E
|
|
|
3
3
|
/** Serialized into the guest; keep validation and helpers self-contained. */
|
|
4
4
|
export declare function createState(invoke: (kind: string, payload: JsonValue) => Promise<RuntimeCapabilityResponse>): {
|
|
5
5
|
state: Readonly<{
|
|
6
|
-
get
|
|
6
|
+
get: {
|
|
7
|
+
(key: string): Promise<JsonValue>;
|
|
8
|
+
(keys: readonly string[]): Promise<JsonValue[]>;
|
|
9
|
+
};
|
|
7
10
|
set(key: unknown, value: unknown): Promise<void>;
|
|
8
11
|
insert(key: unknown, value: unknown): Promise<boolean>;
|
|
9
12
|
delete(key: unknown): Promise<void>;
|