@voltro/plugin-ai-flows 0.85.0 → 0.86.0

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.
@@ -0,0 +1,208 @@
1
+ import { aiFlowRunsTable as e, aiFlowsTable as t } from "./table.js";
2
+ import { FLOW_RUN_WORKFLOW as n, flowRunWorkflow as r, humanResponseSignalName as i } from "./workflow.js";
3
+ import { FlowCancelReceipt as a, FlowReviewInput as o, FlowReviewReceipt as s, FlowStartReceipt as c } from "./ir.js";
4
+ import { FlowBriefIncomplete as l, FlowNotAwaitingResponse as u, FlowReviewDeliveryError as d, FlowRunNotFound as f } from "./errors.js";
5
+ import { resolveIr as p } from "./engine.js";
6
+ import { recordFlowStartReceipt as m } from "./startReceipt.js";
7
+ import { Effect as h, Result as g, Schema as _ } from "effect";
8
+ import { WorkflowControlResultSchema as v } from "@voltro/protocol";
9
+ import { and as y, eq as b, inSet as x, queryFor as S } from "@voltro/database";
10
+ //#region src/procedures.ts
11
+ var C = () => globalThis.crypto?.randomUUID?.() ?? `req-${Date.now().toString(36)}`, w = (e) => e.request?.subject?.id ?? null, T = (t, n) => h.promise(() => t.store.query(S(e).where(b("id", n)).descriptor)).pipe(h.map((e) => e[0])), E = (e) => h.sync(() => {
12
+ let t = e.workflows;
13
+ if (!t) throw Error("workflow runtime unavailable; no flow start was submitted");
14
+ return t;
15
+ }), D = (t, r) => h.gen(function* () {
16
+ yield* E(t);
17
+ let i = yield* p(t, r.flowRef), a = r.input ?? {}, o = i.brief.filter((e) => e.required && e.type !== "boolean" && (a[e.key] === void 0 || a[e.key] === null || a[e.key] === "")).map((e) => e.key);
18
+ if (o.length > 0) return yield* h.fail(new l({
19
+ missing: o,
20
+ message: `missing required brief field(s): ${o.join(", ")}`
21
+ }));
22
+ let s = C(), u = `run-${s}`, d = r.source ?? "manual";
23
+ return yield* h.promise(() => t.transaction(async (t) => {
24
+ let o = t.workflows;
25
+ if (!o) throw Error("workflow runtime unavailable in transaction; no flow start was submitted");
26
+ await t.store.insert(e.tableName, {
27
+ id: u,
28
+ flowRef: r.flowRef,
29
+ flowName: i.name,
30
+ mode: i.mode,
31
+ status: "pending",
32
+ source: d,
33
+ requestId: s,
34
+ input: a,
35
+ ownerId: w(t)
36
+ });
37
+ let l = await m(t, u, await o.start(n, {
38
+ runId: u,
39
+ flowRef: r.flowRef,
40
+ input: a,
41
+ source: d,
42
+ requestId: s
43
+ }));
44
+ return c.make({
45
+ runId: u,
46
+ requestId: s,
47
+ admission: l
48
+ });
49
+ }));
50
+ }), O = (t, i) => h.gen(function* () {
51
+ return yield* E(t), yield* h.tryPromise({
52
+ try: () => t.transaction(async (t) => {
53
+ let a = t.workflows;
54
+ if (!a) throw Error("workflow runtime unavailable in transaction; no flow start was submitted");
55
+ let o = (await t.store.query(S(e).where(b("id", i.runId)).descriptor))[0];
56
+ if (!o) throw new f({
57
+ runId: i.runId,
58
+ message: "run not found"
59
+ });
60
+ let s = o.requestId;
61
+ if (typeof s != "string" || s.length === 0) throw Error("stored flow run has no valid requestId; retry refused without changing the run");
62
+ let l = _.decodeUnknownResult(r.payloadSchema.pipe(_.check(_.makeFilter((e) => e.runId === i.runId && e.flowRef.length > 0))))({
63
+ ...o,
64
+ runId: o.id
65
+ });
66
+ if (g.isFailure(l)) throw Error("stored workflow payload is incomplete or invalid; retry refused without changing the run");
67
+ let u = await m(t, i.runId, await a.start(n, l.success));
68
+ return c.make({
69
+ runId: i.runId,
70
+ requestId: s,
71
+ admission: u
72
+ });
73
+ }),
74
+ catch: (e) => e
75
+ }).pipe(h.catch((e) => e instanceof f ? h.fail(e) : h.die(e)));
76
+ }), k = (t, i) => h.gen(function* () {
77
+ let o = yield* T(t, i.runId);
78
+ if (!o) return yield* h.fail(new f({
79
+ runId: i.runId,
80
+ message: "run not found"
81
+ }));
82
+ if (A(o.status)) return a.make({
83
+ runId: i.runId,
84
+ status: o.status,
85
+ engine: "not-requested",
86
+ control: null
87
+ });
88
+ let s = (/* @__PURE__ */ new Date()).toISOString();
89
+ yield* h.promise(() => t.store.updateMany(e.tableName, {
90
+ status: "cancelling",
91
+ cancelledAt: s
92
+ }, { where: y(b("id", i.runId), x("status", [
93
+ "pending",
94
+ "running",
95
+ "waiting"
96
+ ])) }));
97
+ let c = yield* T(t, i.runId);
98
+ if (!c) return yield* h.fail(new f({
99
+ runId: i.runId,
100
+ message: "run not found"
101
+ }));
102
+ if (A(c.status)) return a.make({
103
+ runId: i.runId,
104
+ status: c.status,
105
+ engine: "not-requested",
106
+ control: null
107
+ });
108
+ let l = t.workflows, u = _.decodeUnknownOption(_.Struct({
109
+ runId: _.Literal(i.runId),
110
+ flowRef: _.NonEmptyString,
111
+ requestId: _.NonEmptyString,
112
+ input: _.Record(_.String, _.Unknown),
113
+ source: _.Literals(["manual", "cron"])
114
+ }))({
115
+ ...o,
116
+ runId: o.id
117
+ }), d = l === void 0 || u._tag === "None" ? null : yield* h.flatMap(r.executionId(u.value), (e) => h.tryPromise(async () => {
118
+ let t = _.decodeUnknownSync(v)(await l.cancel(n, e));
119
+ if (t.operation !== "cancel" || t.snapshot.workflowName !== "flow.run" || t.snapshot.executionId !== e) throw Error("workflow cancellation receipt does not match the flow execution");
120
+ return t;
121
+ })).pipe(h.catch(() => h.succeed(null))), p = d === null ? l === void 0 || u._tag === "None" ? "unreachable" : "unknown" : d.snapshot.status === "cancelled" && (d.kind === "confirmed" || d.kind === "already-terminal") ? "cancelled" : d.kind === "accepted" ? "accepted" : d.kind === "already-terminal" ? "already-terminal" : "unknown", m = y(b("id", i.runId), b("status", "cancelling"), b("cancelledAt", c.cancelledAt));
122
+ if (p === "cancelled") yield* h.promise(() => t.store.updateMany(e.tableName, {
123
+ status: "cancelled",
124
+ completedAt: c.completedAt ?? (/* @__PURE__ */ new Date()).toISOString()
125
+ }, { where: m }));
126
+ else if (d?.kind === "already-terminal") {
127
+ let n = _.decodeUnknownOption(r.successSchema)(d.snapshot.output), a = d.snapshot.status === "failed" ? "failed" : n._tag === "Some" && n.value.runId === i.runId && n.value.status !== "waiting" ? n.value.status : void 0;
128
+ a !== void 0 && (yield* h.promise(() => t.store.updateMany(e.tableName, {
129
+ status: a,
130
+ completedAt: c.completedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
131
+ ...a === "cancelled" ? {} : { cancelledAt: null }
132
+ }, { where: m })));
133
+ }
134
+ let g = yield* T(t, i.runId);
135
+ return g ? yield* _.decodeUnknownEffect(a)({
136
+ runId: i.runId,
137
+ status: g.status,
138
+ engine: p,
139
+ control: d
140
+ }).pipe(h.orDie) : yield* h.fail(new f({
141
+ runId: i.runId,
142
+ message: "run not found"
143
+ }));
144
+ }), A = (e) => e === "succeeded" || e === "failed" || e === "cancelled", j = (e) => {
145
+ let t = e.steps?.filter((e) => e.status === "waiting"), n = t?.[0];
146
+ if (t?.length !== 1 || n?.type !== "human" || !Number.isSafeInteger(n.id) || n.id < 0) throw Error("expected exactly one waiting human step with a nonnegative integer index");
147
+ return n.id;
148
+ }, M = (e, t) => h.gen(function* () {
149
+ let a = (e, n) => new d({
150
+ runId: t.runId,
151
+ reason: e,
152
+ message: n
153
+ }), c = yield* _.decodeUnknownEffect(o, { onExcessProperty: "error" })(t).pipe(h.mapError(() => a("invalid-response", "review response requires runId, displayed stepIndex and a valid response")));
154
+ if (c.response.decision === void 0 && c.response.text === void 0 && c.response.value === void 0) return yield* h.fail(a("invalid-response", "review response must contain a decision, text or value"));
155
+ let l = e.workflows;
156
+ if (!l) return yield* h.fail(a("runtime-unavailable", "workflow runtime unavailable; review was not sent"));
157
+ let p = yield* T(e, t.runId);
158
+ if (!p) return yield* h.fail(new f({
159
+ runId: t.runId,
160
+ message: "run not found"
161
+ }));
162
+ let m = p.status;
163
+ if (m !== "waiting") return yield* h.fail(new u({
164
+ runId: t.runId,
165
+ status: m ?? "unknown",
166
+ message: `run is "${m}", not awaiting a response`
167
+ }));
168
+ let g = yield* h.try({
169
+ try: () => j(p),
170
+ catch: () => a("invalid-run", "stored run has no unambiguous waiting review")
171
+ });
172
+ if (g !== c.stepIndex) return yield* h.fail(new u({
173
+ runId: t.runId,
174
+ status: m,
175
+ message: "this review is no longer waiting; reload the run before answering"
176
+ }));
177
+ let v = yield* _.decodeUnknownEffect(_.Struct({
178
+ runId: _.Literal(t.runId),
179
+ flowRef: _.NonEmptyString,
180
+ requestId: _.NonEmptyString,
181
+ input: _.Record(_.String, _.Unknown),
182
+ source: _.Literals(["manual", "cron"])
183
+ }))({
184
+ ...p,
185
+ runId: p.id
186
+ }).pipe(h.mapError(() => a("invalid-run", "stored workflow payload is incomplete; review was not sent"))), y = yield* r.executionId(v), b = {
187
+ ...c.response,
188
+ respondedAt: (/* @__PURE__ */ new Date()).toISOString()
189
+ }, x = yield* h.tryPromise({
190
+ try: () => l.signal({
191
+ workflowName: n,
192
+ executionId: y
193
+ }, i(g), b),
194
+ catch: () => a("delivery-unknown", "review delivery was not confirmed; observe the run before retrying")
195
+ }), S = yield* _.decodeUnknownEffect(_.Struct({ eventId: _.NonEmptyString }))(x).pipe(h.mapError(() => a("delivery-unknown", "workflow runtime returned no valid review delivery receipt")));
196
+ return yield* _.decodeUnknownEffect(s)({
197
+ runId: t.runId,
198
+ stepIndex: g,
199
+ executionId: y,
200
+ eventId: S.eventId,
201
+ status: "accepted"
202
+ }).pipe(h.mapError(() => a("delivery-unknown", "workflow runtime returned no valid review delivery receipt")));
203
+ }), N = (e, n) => h.promise(() => e.store.query(S(t).where(b("id", n.id)).descriptor)).pipe(h.map((e) => e[0])), P = (e) => h.promise(() => e.store.query(S(t).descriptor)), F = (e, n) => h.promise(() => e.store.insert(t.tableName, {
204
+ id: n.id ?? `flow-${C()}`,
205
+ ...n
206
+ })), I = (e, n) => h.promise(() => e.store.update(t.tableName, n.id, n.patch)), L = (e, n) => h.promise(() => e.store.delete(t.tableName, n.id));
207
+ //#endregion
208
+ export { k as cancelFlow, F as createFlow, L as deleteFlow, N as getFlow, i as humanResponseSignalName, D as launchFlow, P as listFlows, M as respondToFlow, O as retryFlow, I as updateFlow, j as waitingStepIndex };
@@ -0,0 +1,6 @@
1
+ //#region src/registry.ts
2
+ var e = /* @__PURE__ */ new Map(), t = (t) => {
3
+ e.set(t.name, t);
4
+ }, n = (t) => e.get(t), r = () => [...e.values()], i = () => e.clear();
5
+ //#endregion
6
+ export { i as clearRegistry, n as getRegisteredFlow, r as listRegisteredFlows, t as registerFlow };
@@ -0,0 +1,33 @@
1
+ //#region src/segments.ts
2
+ var e = (e) => {
3
+ let t = [], n;
4
+ if (e.forEach((e, r) => {
5
+ let i = e.group;
6
+ i !== void 0 && n !== void 0 && n.group === i ? n.steps.push({
7
+ index: r,
8
+ step: e
9
+ }) : (n !== void 0 && t.push({
10
+ ...n.group === void 0 ? {} : { group: n.group },
11
+ steps: n.steps
12
+ }), n = {
13
+ ...i === void 0 ? {} : { group: i },
14
+ steps: [{
15
+ index: r,
16
+ step: e
17
+ }]
18
+ });
19
+ }), n !== void 0) {
20
+ let e = n;
21
+ t.push({
22
+ ...e.group === void 0 ? {} : { group: e.group },
23
+ steps: e.steps
24
+ });
25
+ }
26
+ return t;
27
+ }, t = (e) => {
28
+ let t = /* @__PURE__ */ new Map();
29
+ for (let n of e) n.group !== void 0 && t.set(n.group, (t.get(n.group) ?? 0) + 1);
30
+ return [...t.entries()].filter(([, e]) => e > 1).map(([e]) => e).sort();
31
+ };
32
+ //#endregion
33
+ export { e as flowSegments, t as nonContiguousGroups };
@@ -0,0 +1,12 @@
1
+ import { aiFlowRunsTable as e } from "./table.js";
2
+ import "./workflow.js";
3
+ import { Schema as t } from "effect";
4
+ import { WorkflowRunHandleSchema as n } from "@voltro/protocol";
5
+ //#region src/startReceipt.ts
6
+ var r = async (r, i, a) => {
7
+ let o = t.decodeUnknownSync(n.pipe(t.check(t.makeFilter((e) => e.workflowName === "flow.run" && e.id.length > 0))))(a);
8
+ if (await r.store.update(e.tableName, i, { workflowStart: o }) === null) throw Error("flow start receipt could not be recorded; workflow submission may have succeeded");
9
+ return o;
10
+ };
11
+ //#endregion
12
+ export { r as recordFlowStartReceipt };
@@ -0,0 +1,81 @@
1
+ import { aiFlowRunsTable as e } from "./table.js";
2
+ import { FLOW_RUN_WORKFLOW as t } from "./workflow.js";
3
+ import { Schema as n } from "effect";
4
+ import { eq as r } from "@voltro/database";
5
+ //#region src/startReconcile.ts
6
+ var i = n.Struct({
7
+ id: n.NonEmptyString,
8
+ workflowName: n.Literal(t),
9
+ status: n.Literal("queued")
10
+ }), a = (e) => ({
11
+ id: e,
12
+ workflowName: t,
13
+ executionId: e,
14
+ status: "running"
15
+ }), o = (e) => {
16
+ let t = `flow start was not executed: ${e.reason}`;
17
+ return e.incumbentExecutionId === null ? e.failureId === null ? t : `${t} (failure report ${e.failureId})` : `${t} (incumbent execution ${e.incumbentExecutionId})`;
18
+ }, s = async (t, s = {}) => {
19
+ let c = t.workflows;
20
+ if (!c) throw Error("workflow runtime unavailable; flow starts cannot be reconciled");
21
+ if (c.startsDeferredUntilCommit === !0) return {
22
+ examined: 0,
23
+ accepted: 0,
24
+ notExecuted: 0,
25
+ pending: 0,
26
+ failures: []
27
+ };
28
+ let l = s.take ?? 200, u = await t.store.query({
29
+ table: e.tableName,
30
+ predicate: r("status", "pending"),
31
+ order: [],
32
+ take: l,
33
+ skip: void 0,
34
+ projection: void 0
35
+ }), d = {
36
+ examined: 0,
37
+ accepted: 0,
38
+ notExecuted: 0,
39
+ pending: 0,
40
+ failures: []
41
+ };
42
+ for (let r of u) {
43
+ let s = r.id;
44
+ if (typeof s != "string") continue;
45
+ let l = n.decodeUnknownOption(i)(r.workflowStart);
46
+ if (l._tag !== "None") {
47
+ d.examined++;
48
+ try {
49
+ let n = await c.readStart({
50
+ ...l.value,
51
+ executionId: null
52
+ });
53
+ if (n.kind === "pending") {
54
+ d.pending++;
55
+ continue;
56
+ }
57
+ let r = (/* @__PURE__ */ new Date()).toISOString();
58
+ if (n.kind === "accepted") {
59
+ if (await t.store.update(e.tableName, s, { workflowStart: a(n.executionId) }) === null) throw Error("flow run disappeared while recording its accepted start");
60
+ d.accepted++;
61
+ continue;
62
+ }
63
+ if (await t.store.update(e.tableName, s, {
64
+ status: "failed",
65
+ error: "FlowStartNotExecuted",
66
+ errorMessage: o(n),
67
+ completedAt: r
68
+ }) === null) throw Error("flow run disappeared while recording that its start will not execute");
69
+ d.notExecuted++;
70
+ } catch (e) {
71
+ d.failures.push({
72
+ runId: s,
73
+ cause: e
74
+ });
75
+ }
76
+ }
77
+ }
78
+ return d;
79
+ };
80
+ //#endregion
81
+ export { a as admittedStartHandle, s as reconcileFlowStarts };
package/dist/table.js ADDED
@@ -0,0 +1,59 @@
1
+ import { boolean as e, id as t, integer as n, json as r, table as i, text as a, timestamp as o } from "@voltro/database";
2
+ import { tenant as s } from "@voltro/plugin-multitenancy/mixin";
3
+ import { audit as c } from "@voltro/plugin-audit/mixin";
4
+ import { softDelete as l } from "@voltro/plugin-soft-delete/mixin";
5
+ //#region src/table.ts
6
+ var u = i("_voltro_ai_flows", {
7
+ id: t({ prefix: "aifl" }),
8
+ name: a(),
9
+ description: a().nullable(),
10
+ mode: a().default("deterministic"),
11
+ status: a().default("draft"),
12
+ visibility: a().default("private"),
13
+ orchestratorModel: a().nullable(),
14
+ orchestratorInstructions: a().nullable(),
15
+ maxSteps: n().default(30),
16
+ steps: r().nullable(),
17
+ inputSchema: r().nullable(),
18
+ chainTo: r().nullable(),
19
+ cadence: r().nullable(),
20
+ humanTimeoutMs: n().nullable(),
21
+ isEnabled: e().default(!0),
22
+ metadata: r().nullable(),
23
+ icon: a().nullable(),
24
+ color: a().nullable(),
25
+ avatarUrl: a().nullable(),
26
+ usageCount: n().default(0),
27
+ ownerId: a().nullable()
28
+ }).renamedFrom("ai_flows").with(s(), c(), l()).index(["status"]).index(["visibility"]), d = i("_voltro_ai_flow_runs", {
29
+ id: t({ prefix: "aifr" }),
30
+ flowRef: a(),
31
+ flowName: a().nullable(),
32
+ mode: a().default("deterministic"),
33
+ status: a().default("pending"),
34
+ source: a().nullable(),
35
+ requestId: a(),
36
+ workflowStart: r().nullable(),
37
+ input: r().nullable(),
38
+ output: r().nullable(),
39
+ steps: r().nullable(),
40
+ currentStep: n().default(0),
41
+ totalSteps: n().default(0),
42
+ humanResponse: r().nullable(),
43
+ chainPending: r().nullable(),
44
+ chainRefusal: a().nullable(),
45
+ costMicroUsd: n().default(0),
46
+ costCompleteness: a().default("unknown"),
47
+ durationMs: n().nullable(),
48
+ error: a().nullable(),
49
+ errorMessage: a().nullable(),
50
+ startedAt: o().nullable(),
51
+ completedAt: o().nullable(),
52
+ cancelledAt: o().nullable(),
53
+ sessionId: a().nullable(),
54
+ sessionName: a().nullable(),
55
+ ownerId: a().nullable(),
56
+ metadata: r().nullable()
57
+ }).renamedFrom("ai_flow_runs").with(s(), c()).index(["flowRef"]).index(["status"]).index(["requestId"]), f = [u, d];
58
+ //#endregion
59
+ export { d as aiFlowRunsTable, u as aiFlowsTable, f as aiFlowsTables };
@@ -0,0 +1,21 @@
1
+ import { ProviderOptions as e } from "./jsonParams.js";
2
+ import { Effect as t, Schema as n } from "effect";
3
+ //#region src/textParams.ts
4
+ var r = n.Struct({
5
+ maxTokens: n.optionalKey(n.Int.pipe(n.check(n.isGreaterThan(0)), n.check(n.isLessThanOrEqualTo(2 ** 53 - 1)))),
6
+ temperature: n.optionalKey(n.Finite.pipe(n.check(n.isGreaterThanOrEqualTo(0)))),
7
+ providerOptions: n.optionalKey(e)
8
+ }), i = [
9
+ "maxTokens",
10
+ "temperature",
11
+ "providerOptions"
12
+ ], a = (e) => {
13
+ if (typeof e != "object" || !e || Array.isArray(e)) return "params must be an object";
14
+ let t = Object.keys(e), a = t.filter((e) => !i.includes(e)).sort(), o = t.filter((t) => i.includes(t) && n.decodeUnknownOption(r)({ [t]: e[t] })._tag === "None").sort();
15
+ return [...a.length > 0 ? [`unsupported field${a.length === 1 ? "" : "s"}: ${a.join(", ")}`] : [], ...o.length > 0 ? [`invalid value for: ${o.join(", ")}`] : []].join("; ");
16
+ }, o = (e) => t.try({
17
+ try: () => n.decodeUnknownSync(r, { onExcessProperty: "error" })(e === void 0 ? {} : e),
18
+ catch: () => `invalid text params (${a(e)}): expected maxTokens (positive safe integer), temperature (finite nonnegative number), and/or providerOptions (provider-keyed JSON object); other fields are not supported`
19
+ });
20
+ //#endregion
21
+ export { o as decodeTextParams };
package/dist/web.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as e, t } from "./cadence-_9Izk_fL.js";
1
+ import { cadenceMatches as e, nextRuns as t } from "./cadence.js";
2
2
  import { useAction as n, useSubscription as r } from "@voltro/client";
3
3
  //#region src/web.ts
4
4
  var i = {
@@ -96,4 +96,4 @@ var i = {
96
96
  };
97
97
  };
98
98
  //#endregion
99
- export { i as DEFAULT_FLOW_RPC_TAGS, t as cadenceMatches, e as nextRuns, p as useCancelFlow, h as useFlowReview, c as useFlowRun, l as useFlowRuns, u as useFlows, d as useLaunchFlow, m as useRespondToFlow, f as useRetryFlow };
99
+ export { i as DEFAULT_FLOW_RPC_TAGS, e as cadenceMatches, t as nextRuns, p as useCancelFlow, h as useFlowReview, c as useFlowRun, l as useFlowRuns, u as useFlows, d as useLaunchFlow, m as useRespondToFlow, f as useRetryFlow };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/plugin-ai-flows",
3
- "version": "0.85.0",
3
+ "version": "0.86.0",
4
4
  "description": "AI Flows — durable multi-step AI pipelines (deterministic + agentic) with human-in-the-loop, chaining, and cadence. Author flows in code (defineFlow) or as data (visual editor rows); one engine runs both on @voltro/workflow durability, @voltro/ai generation, storage artifacts, and notifications.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -58,16 +58,16 @@
58
58
  "node": ">=24.0.0"
59
59
  },
60
60
  "dependencies": {
61
- "@voltro/ai": "0.85.0",
62
- "@voltro/client": "0.85.0",
63
- "@voltro/database": "0.85.0",
64
- "@voltro/env": "0.85.0",
65
- "@voltro/plugin-audit": "0.85.0",
66
- "@voltro/plugin-multitenancy": "0.85.0",
67
- "@voltro/plugin-soft-delete": "0.85.0",
68
- "@voltro/protocol": "0.85.0",
69
- "@voltro/runtime": "0.85.0",
70
- "@voltro/workflow": "0.85.0"
61
+ "@voltro/ai": "0.86.0",
62
+ "@voltro/client": "0.86.0",
63
+ "@voltro/database": "0.86.0",
64
+ "@voltro/env": "0.86.0",
65
+ "@voltro/plugin-audit": "0.86.0",
66
+ "@voltro/plugin-multitenancy": "0.86.0",
67
+ "@voltro/plugin-soft-delete": "0.86.0",
68
+ "@voltro/protocol": "0.86.0",
69
+ "@voltro/runtime": "0.86.0",
70
+ "@voltro/workflow": "0.86.0"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "effect": "4.0.1"