@voltro/plugin-ai-flows 0.84.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.
package/dist/index.js CHANGED
@@ -1,1743 +1,53 @@
1
- import { FLOW_RUN_WORKFLOW as e, HUMAN_RESPONSE_SIGNAL_PREFIX as t, flowRunWorkflow as n, humanResponseSignalName as r } from "./workflow.js";
2
- import { A as i, B as a, C as o, D as s, E as c, F as l, H as u, I as d, L as f, M as p, N as m, O as h, P as g, R as _, S as v, T as ee, V as y, _ as te, a as ne, b, c as re, d as x, f as S, g as C, h as ie, i as w, j as ae, k as oe, l as se, m as ce, n as le, o as T, p as ue, r as de, s as fe, t as pe, u as me, v as he, w as ge, x as _e, y as ve, z as ye } from "./ir-CdDUTf98.js";
3
- import { FlowBriefIncomplete as be, FlowCapabilityMissing as E, FlowDependencyError as xe, FlowNotAwaitingResponse as Se, FlowNotFound as Ce, FlowReviewDeliveryError as we, FlowRunNotFound as D, FlowValidationError as Te } from "./errors.js";
4
- import { n as Ee, t as De } from "./cadence-_9Izk_fL.js";
5
- import { Cause as Oe, Effect as O, Exit as ke, Schema as k } from "effect";
6
- import { WorkflowControlResultSchema as Ae, WorkflowRunHandleSchema as je, definePlugin as Me, pluginInstanceName as Ne } from "@voltro/protocol";
7
- import { and as Pe, boolean as Fe, eq as A, id as Ie, inSet as Le, integer as j, json as M, notInSet as Re, queryFor as N, registerRetention as ze, table as Be, text as P, timestamp as Ve } from "@voltro/database";
8
- import { tenant as He } from "@voltro/plugin-multitenancy/mixin";
9
- import { audit as Ue } from "@voltro/plugin-audit/mixin";
10
- import { softDelete as We } from "@voltro/plugin-soft-delete/mixin";
11
- import { SuspensionUnavailable as Ge, awaitSignalSuspending as Ke, step as F } from "@voltro/workflow";
12
- import { defineTool as qe, estimateCostUsd as Je, gatewayCostUsd as Ye, generateImage as Xe, generateObject as Ze, generateObjectJson as Qe, generateObjectWithTools as $e, generateSpeech as et, generateText as tt, generateVideo as nt, isMeteredUsage as rt } from "@voltro/ai";
13
- import { createHash as it } from "node:crypto";
14
- //#region src/registry.ts
15
- var I = /* @__PURE__ */ new Map(), at = (e) => {
16
- I.set(e.name, e);
17
- }, ot = (e) => I.get(e), st = () => [...I.values()], ct = () => I.clear(), L = Be("_voltro_ai_flows", {
18
- id: Ie({ prefix: "aifl" }),
19
- name: P(),
20
- description: P().nullable(),
21
- mode: P().default("deterministic"),
22
- status: P().default("draft"),
23
- visibility: P().default("private"),
24
- orchestratorModel: P().nullable(),
25
- orchestratorInstructions: P().nullable(),
26
- maxSteps: j().default(30),
27
- steps: M().nullable(),
28
- inputSchema: M().nullable(),
29
- chainTo: M().nullable(),
30
- cadence: M().nullable(),
31
- humanTimeoutMs: j().nullable(),
32
- isEnabled: Fe().default(!0),
33
- metadata: M().nullable(),
34
- icon: P().nullable(),
35
- color: P().nullable(),
36
- avatarUrl: P().nullable(),
37
- usageCount: j().default(0),
38
- ownerId: P().nullable()
39
- }).renamedFrom("ai_flows").with(He(), Ue(), We()).index(["status"]).index(["visibility"]), R = Be("_voltro_ai_flow_runs", {
40
- id: Ie({ prefix: "aifr" }),
41
- flowRef: P(),
42
- flowName: P().nullable(),
43
- mode: P().default("deterministic"),
44
- status: P().default("pending"),
45
- source: P().nullable(),
46
- requestId: P(),
47
- workflowStart: M().nullable(),
48
- input: M().nullable(),
49
- output: M().nullable(),
50
- steps: M().nullable(),
51
- currentStep: j().default(0),
52
- totalSteps: j().default(0),
53
- humanResponse: M().nullable(),
54
- chainPending: M().nullable(),
55
- chainRefusal: P().nullable(),
56
- costMicroUsd: j().default(0),
57
- costCompleteness: P().default("unknown"),
58
- durationMs: j().nullable(),
59
- error: P().nullable(),
60
- errorMessage: P().nullable(),
61
- startedAt: Ve().nullable(),
62
- completedAt: Ve().nullable(),
63
- cancelledAt: Ve().nullable(),
64
- sessionId: P().nullable(),
65
- sessionName: P().nullable(),
66
- ownerId: P().nullable(),
67
- metadata: M().nullable()
68
- }).renamedFrom("ai_flow_runs").with(He(), Ue()).index(["flowRef"]).index(["status"]).index(["requestId"]), lt = [L, R], ut = k.Struct({
69
- id: k.NonEmptyString,
70
- workflowName: k.Literal(e),
71
- status: k.Literal("queued")
72
- }), dt = (t) => ({
73
- id: t,
74
- workflowName: e,
75
- executionId: t,
76
- status: "running"
77
- }), ft = (e) => {
78
- let t = `flow start was not executed: ${e.reason}`;
79
- return e.incumbentExecutionId === null ? e.failureId === null ? t : `${t} (failure report ${e.failureId})` : `${t} (incumbent execution ${e.incumbentExecutionId})`;
80
- }, pt = async (e, t = {}) => {
81
- let n = e.workflows;
82
- if (!n) throw Error("workflow runtime unavailable; flow starts cannot be reconciled");
83
- if (n.startsDeferredUntilCommit === !0) return {
84
- examined: 0,
85
- accepted: 0,
86
- notExecuted: 0,
87
- pending: 0,
88
- failures: []
89
- };
90
- let r = t.take ?? 200, i = await e.store.query({
91
- table: R.tableName,
92
- predicate: A("status", "pending"),
93
- order: [],
94
- take: r,
95
- skip: void 0,
96
- projection: void 0
97
- }), a = {
98
- examined: 0,
99
- accepted: 0,
100
- notExecuted: 0,
101
- pending: 0,
102
- failures: []
103
- };
104
- for (let t of i) {
105
- let r = t.id;
106
- if (typeof r != "string") continue;
107
- let i = k.decodeUnknownOption(ut)(t.workflowStart);
108
- if (i._tag !== "None") {
109
- a.examined++;
110
- try {
111
- let t = await n.readStart({
112
- ...i.value,
113
- executionId: null
114
- });
115
- if (t.kind === "pending") {
116
- a.pending++;
117
- continue;
118
- }
119
- let o = (/* @__PURE__ */ new Date()).toISOString();
120
- if (t.kind === "accepted") {
121
- if (await e.store.update(R.tableName, r, { workflowStart: dt(t.executionId) }) === null) throw Error("flow run disappeared while recording its accepted start");
122
- a.accepted++;
123
- continue;
124
- }
125
- if (await e.store.update(R.tableName, r, {
126
- status: "failed",
127
- error: "FlowStartNotExecuted",
128
- errorMessage: ft(t),
129
- completedAt: o
130
- }) === null) throw Error("flow run disappeared while recording that its start will not execute");
131
- a.notExecuted++;
132
- } catch (e) {
133
- a.failures.push({
134
- runId: r,
135
- cause: e
136
- });
137
- }
138
- }
139
- }
140
- return a;
141
- }, mt = 168, ht = "VOLTRO_AI_FLOW_HUMAN_REVIEW_TIMEOUT_HOURS", gt = 2160, _t = "VOLTRO_AI_FLOW_RUNS_TTL_HOURS", vt = 5, yt = "VOLTRO_AI_FLOW_MAX_CHAIN_DEPTH", bt = { current: {} }, xt = (e) => {
142
- bt.current = e;
143
- }, St = () => bt.current, Ct = () => {
144
- bt.current = {};
145
- }, wt = (e, t) => {
146
- if (e === void 0 || e.trim() === "") return t * 36e5;
147
- let n = Number(e);
148
- return !Number.isFinite(n) || n < 0 ? t * 36e5 : n * 36e5;
149
- }, Tt = (e) => Number.isFinite(e) && e > 0 ? e : Infinity, Et = (e) => {
150
- let t = e.env ?? process.env;
151
- return Tt(e.step?.timeoutMs ?? e.flow?.humanTimeoutMs ?? e.deps?.humanReviewTimeoutMs ?? St().humanReviewTimeoutMs ?? wt(t.VOLTRO_AI_FLOW_HUMAN_REVIEW_TIMEOUT_HOURS, 168));
152
- }, Dt = (e) => {
153
- let t = e?.env ?? process.env, n = Number(t[yt]), r = e?.maxChainDepth ?? St().maxChainDepth ?? (Number.isFinite(n) && n >= 1 ? n : 5);
154
- return Number.isFinite(r) && r >= 1 ? r : 5;
155
- }, Ot = /\{\{\s*([\w.-]+)\s*\}\}/g, kt = (e) => {
156
- let t = [];
157
- for (let n of e.matchAll(Ot)) t.push(n[1]);
158
- return t;
159
- }, At = (e, t) => e.replace(Ot, (e, n) => {
160
- let r = t[n];
161
- return r == null ? "" : typeof r == "string" ? r : JSON.stringify(r);
162
- }), jt = (e, t) => {
163
- let n = /* @__PURE__ */ new Set();
164
- for (let r of kt(e)) t[r] == null && !n.has(r) && n.add(r);
165
- return [...n];
166
- }, Mt = (e) => {
167
- let t = [], n;
168
- if (e.forEach((e, r) => {
169
- let i = e.group;
170
- if (i !== void 0 && n !== void 0 && n.group === i) {
171
- n.steps.push({
172
- index: r,
173
- step: e
174
- });
175
- return;
176
- }
177
- n !== void 0 && t.push({
178
- ...n.group === void 0 ? {} : { group: n.group },
179
- steps: n.steps
180
- }), n = {
181
- ...i === void 0 ? {} : { group: i },
182
- steps: [{
183
- index: r,
184
- step: e
185
- }]
186
- };
187
- }), n !== void 0) {
188
- let e = n;
189
- t.push({
190
- ...e.group === void 0 ? {} : { group: e.group },
191
- steps: e.steps
192
- });
193
- }
194
- return t;
195
- }, Nt = (e) => {
196
- let t = /* @__PURE__ */ new Map();
197
- for (let n of e) n.group !== void 0 && t.set(n.group, (t.get(n.group) ?? 0) + 1);
198
- return [...t.entries()].filter(([, e]) => e > 1).map(([e]) => e).sort();
199
- }, z = k.suspend(() => k.Union(k.Null, k.Boolean, k.Finite, k.String, k.Array(z).pipe(k.mutable), k.Record({
200
- key: k.String,
201
- value: z
202
- }))), B = k.Record({
203
- key: k.String,
204
- value: k.Record({
205
- key: k.String,
206
- value: z
207
- })
208
- }), Pt = k.Struct({
209
- maxTokens: k.optionalWith(k.Int.pipe(k.positive(), k.lessThanOrEqualTo(2 ** 53 - 1)), { exact: !0 }),
210
- temperature: k.optionalWith(k.Finite.pipe(k.nonNegative()), { exact: !0 }),
211
- providerOptions: k.optionalWith(B, { exact: !0 })
212
- }), Ft = [
213
- "maxTokens",
214
- "temperature",
215
- "providerOptions"
216
- ], It = (e) => {
217
- if (typeof e != "object" || !e || Array.isArray(e)) return "params must be an object";
218
- let t = Object.keys(e), n = t.filter((e) => !Ft.includes(e)).sort(), r = t.filter((t) => Ft.includes(t) && k.decodeUnknownOption(Pt)({ [t]: e[t] })._tag === "None").sort();
219
- return [...n.length > 0 ? [`unsupported field${n.length === 1 ? "" : "s"}: ${n.join(", ")}`] : [], ...r.length > 0 ? [`invalid value for: ${r.join(", ")}`] : []].join("; ");
220
- }, Lt = (e) => O.try({
221
- try: () => k.decodeUnknownSync(Pt, { onExcessProperty: "error" })(e === void 0 ? {} : e),
222
- catch: () => `invalid text params (${It(e)}): expected maxTokens (positive safe integer), temperature (finite nonnegative number), and/or providerOptions (provider-keyed JSON object); other fields are not supported`
223
- }), V = k.String.pipe(k.filter((e) => {
224
- try {
225
- let t = new URL(e);
226
- return (t.protocol === "https:" || t.protocol === "http:") && t.username === "" && t.password === "";
227
- } catch {
228
- return !1;
229
- }
230
- })), Rt = k.Record({
231
- key: k.String,
232
- value: V
233
- }), zt = (e, t, n = {}) => O.try({
234
- try: () => {
235
- let r = k.decodeUnknownSync(v, { onExcessProperty: "error" })(e === void 0 ? {} : e), i = Object.fromEntries(Object.entries(r).map(([e, r]) => [e, r.from === "upload" ? r.url : r.artifact === void 0 ? Object.hasOwn(t, r.ref) ? t[r.ref] : void 0 : Object.hasOwn(n, r.ref) ? n[r.ref]?.[r.artifact]?.url : void 0]));
236
- return k.decodeUnknownSync(Rt)(i);
237
- },
238
- catch: () => "invalid or unresolved media input: each slot must resolve to an absolute HTTP(S) URL without embedded credentials"
239
- }), Bt = k.Struct({
240
- url: V,
241
- mediaType: k.NonEmptyString
242
- });
243
- k.Record({
244
- key: k.String,
245
- value: Bt
246
- });
247
- var Vt = (e, t = {}) => {
248
- let n = k.decodeUnknownOption(v)(e === void 0 ? {} : e);
249
- if (n._tag === "None") return {};
250
- let r = {};
251
- for (let [e, i] of Object.entries(n.value)) {
252
- if (i.from === "upload") {
253
- i.mediaType !== void 0 && k.is(V)(i.url) && (r[e] = {
254
- url: i.url,
255
- mediaType: i.mediaType
256
- });
257
- continue;
258
- }
259
- if (i.artifact === void 0 || !Object.hasOwn(t, i.ref)) continue;
260
- let n = t[i.ref]?.[i.artifact];
261
- n !== void 0 && k.is(V)(n.url) && (r[e] = {
262
- url: n.url,
263
- mediaType: n.mediaType
264
- });
265
- }
266
- return r;
267
- }, Ht = (e, t) => O.try({
268
- try: () => {
269
- let n = k.decodeUnknownSync(Rt)(t === void 0 ? {} : t), r = e === "image" ? ["referenceImageUrl", "maskImageUrl"] : e === "video" ? [
270
- "referenceImageUrl",
271
- "firstFrameImageUrl",
272
- "lastFrameImageUrl",
273
- "referenceVideoUrl"
274
- ] : [];
275
- if (Object.keys(n).some((e) => !r.includes(e))) throw Error("unsupported slot");
276
- if (e === "image" && n.maskImageUrl !== void 0 && n.referenceImageUrl === void 0) throw Error("mask requires reference");
277
- return n;
278
- },
279
- catch: () => `invalid or unsupported media input for ${e}; check the built-in adapter's slot contract`
280
- }), Ut = k.Struct({
281
- artifacts: b,
282
- costMicroUsd: k.optional(k.Finite.pipe(k.nonNegative())),
283
- costSource: k.optional(w),
284
- requestId: k.optional(k.NonEmptyString),
285
- usage: k.optional(m)
286
- }), Wt = (e) => O.try({
287
- try: () => k.decodeUnknownSync(Ut, { onExcessProperty: "error" })(e),
288
- catch: () => "invalid media result: expected artifacts with URL, mediaType and role, exactly one primary artifact, and optional storage references"
289
- }), H = (e) => e, Gt = (e) => e._tag === "FlowAgentUnavailable" ? e.publicMessage ?? "agent unavailable" : "agent not found", Kt = k.Struct({
290
- value: k.optional(k.Unknown),
291
- text: k.optional(k.String),
292
- url: k.optional(k.String),
293
- artifacts: k.optional(b),
294
- costMicroUsd: k.optional(k.Number),
295
- costSource: k.optional(w),
296
- requestId: k.optional(k.String),
297
- usage: k.optional(m),
298
- error: k.optional(k.String)
299
- }), qt = (e) => Wt(e).pipe(O.map((e) => {
300
- let t = e.artifacts.find((e) => e.role === "primary");
301
- return {
302
- value: t.url,
303
- url: t.url,
304
- artifacts: e.artifacts,
305
- ...e.requestId === void 0 ? {} : { requestId: e.requestId },
306
- ...e.costMicroUsd === void 0 ? {} : { costMicroUsd: e.costMicroUsd },
307
- ...e.costSource === void 0 ? {} : { costSource: e.costSource },
308
- ...e.usage === void 0 ? {} : { usage: e.usage }
309
- };
310
- }), O.catchAll((e) => O.succeed({ error: e }))), U = (e) => ({
311
- ...e.requestId ? { requestId: e.requestId } : {},
312
- ...e.costMicroUsd ? { costMicroUsd: e.costMicroUsd } : {},
313
- ...e.costSource === void 0 ? {} : { costSource: e.costSource },
314
- ...e.usage === void 0 ? {} : { usage: e.usage }
315
- }), W = () => (/* @__PURE__ */ new Date()).toISOString(), Jt = (e) => Math.round(e * 1e6), Yt = (e) => ({
316
- name: "gateway",
317
- model: e
318
- }), G = (e, t) => e.resolveModel?.(t) ?? Yt(t), Xt = (e, t, n, r) => O.gen(function* () {
319
- return t.maxSteps !== void 0 && (!Number.isSafeInteger(t.maxSteps) || t.maxSteps < 1) ? yield* O.fail(new E({
320
- capability: "resolveAgent",
321
- message: "agent maxSteps must be a positive safe integer"
322
- })) : yield* tt({
323
- ...r,
324
- system: t.system,
325
- prompt: n,
326
- provider: G(e, t.model),
327
- ...t.tools === void 0 ? {} : { tools: t.tools },
328
- ...t.maxSteps === void 0 ? {} : { maxSteps: t.maxSteps }
329
- });
330
- }), Zt = (e, t, n) => K(e, t, n).costMicroUsd, K = (e, t, n) => {
331
- let r = Ye(t);
332
- if (typeof r == "number") return {
333
- costMicroUsd: Jt(r),
334
- costSource: "gateway"
335
- };
336
- let i = Je(e, { model: n ?? "unknown" });
337
- return {
338
- costMicroUsd: i.costMicroUsd ?? 0,
339
- costSource: i.costSource ?? "unpriced"
340
- };
341
- }, q = (e) => {
342
- let t = e.filter((e) => (e.status === "succeeded" || e.status === "failed") && (e.costSource !== void 0 || e.costMicroUsd !== void 0));
343
- if (t.length === 0) return "unknown";
344
- let n = t.map((e) => e.costSource ?? "unpriced");
345
- return n.every((e) => e === "gateway") ? "actual" : n.some((e) => e === "unpriced") ? "incomplete" : "estimated";
346
- }, J = (e, t, n) => O.promise(() => e.store.update(R.tableName, t, n).then(() => void 0)).pipe(O.catchAllCause(() => O.void)), Qt = (e, t, n, r) => O.promise(async () => {
347
- let i = await e.store.query(N(R).where(A("id", t)).descriptor), a = i[0]?.[r];
348
- i[0] !== void 0 && a == null && await e.store.update(R.tableName, t, n);
349
- }).pipe(O.catchAllCause(() => O.void)), $t = (e, t) => O.promise(async () => {
350
- let n = (await e.store.query(N(R).where(A("id", t)).descriptor))[0]?.status;
351
- return n === "cancelling" || n === "cancelled";
352
- }).pipe(O.catchAllCause(() => O.succeed(!1))), en = (e, t) => O.promise(() => e.store.updateMany(R.tableName, {
353
- status: "cancelled",
354
- completedAt: W()
355
- }, { where: Pe(A("id", t), A("status", "cancelling")) }).then(() => void 0)).pipe(O.catchAllCause(() => O.void)), tn = (e, t) => O.gen(function* () {
356
- let n = ot(t);
357
- if (n) return n;
358
- let r = (yield* O.promise(() => e.store.query(N(L).where(A("id", t)).descriptor)))[0];
359
- return r ? d({
360
- name: r.name ?? t,
361
- mode: r.mode,
362
- steps: r.steps ?? [],
363
- maxSteps: r.maxSteps ?? null,
364
- brief: r.inputSchema ?? [],
365
- orchestratorModel: r.orchestratorModel ?? null,
366
- orchestratorInstructions: r.orchestratorInstructions ?? null,
367
- chain: r.chainTo ?? null,
368
- cadence: r.cadence ?? null,
369
- humanTimeoutMs: r.humanTimeoutMs ?? null
370
- }) : yield* O.fail(new Ce({
371
- flowRef: t,
372
- message: `no flow registered or stored for "${t}"`
373
- }));
374
- }), nn = (e, t, n, r, i, a) => O.gen(function* () {
375
- let e = At(n.prompt ?? "", r), o = yield* Lt(n.type === "agent" || n.type === "structured" || n.type === "generate" && (n.modality ?? "text") === "text" ? n.params : void 0).pipe(O.either);
376
- if (o._tag === "Left") return { error: `step "${n.id}": ${o.left}` };
377
- if (n.mediaInputs !== void 0 && (n.type !== "generate" || (n.modality ?? "text") === "text")) return { error: `step "${n.id}": media inputs require an image, video or audio generation step` };
378
- let s = jt(n.prompt ?? "", r);
379
- if (s.length > 0) return { error: new xe({
380
- stepId: n.id,
381
- unresolvedRef: s[0],
382
- message: `step "${n.id}" references unresolved {{${s[0]}}}`
383
- }).message };
384
- switch (n.type) {
385
- case "note": return {
386
- value: e,
387
- text: e,
388
- costMicroUsd: 0,
389
- costSource: "gateway"
390
- };
391
- case "agent": {
392
- if (!n.agentRef) return { error: "agent step missing agentRef" };
393
- if (!t.resolveAgent) return { error: new E({
394
- capability: "resolveAgent",
395
- message: "no agent resolver configured"
396
- }).message };
397
- let r = yield* H(t.resolveAgent(n.agentRef, i)).pipe(O.map((e) => ({
398
- ok: !0,
399
- a: e
400
- })), O.catchAll((e) => O.succeed({
401
- ok: !1,
402
- e
403
- })));
404
- if (!r.ok) return { error: r.e.message };
405
- let a = yield* Xt(t, r.a, e, o.right).pipe(O.map((e) => ({
406
- ok: !0,
407
- r: e
408
- })), O.catchAll((e) => O.succeed({
409
- ok: !1,
410
- e
411
- })));
412
- return a.ok ? {
413
- value: a.r.text,
414
- text: a.r.text,
415
- ...K(a.r.usage, a.r.providerMetadata, r.a.model)
416
- } : { error: String(a.e.message ?? a.e) };
417
- }
418
- case "structured": {
419
- if (n.schema === void 0) return { error: `step "${n.id}": structured step requires a JSON Schema` };
420
- let r = n.model ?? t.defaultModels?.text, i = yield* Qe({
421
- ...o.right,
422
- prompt: e,
423
- jsonSchema: n.schema,
424
- ...r ? { provider: G(t, r) } : {}
425
- }).pipe(O.map((e) => ({
426
- ok: !0,
427
- r: e
428
- })), O.catchAll((e) => O.succeed({
429
- ok: !1,
430
- e
431
- })));
432
- return i.ok ? {
433
- value: i.r.object,
434
- text: JSON.stringify(i.r.object, null, 2),
435
- ...K(i.r.usage, i.r.providerMetadata, r)
436
- } : { error: String(i.e.message ?? i.e) };
437
- }
438
- case "generate": {
439
- let s = n.modality ?? "text";
440
- if (s === "text") {
441
- let r = n.model ?? t.defaultModels?.text, i = yield* tt({
442
- ...o.right,
443
- prompt: e,
444
- ...r ? { provider: G(t, r) } : {}
445
- }).pipe(O.map((e) => ({
446
- ok: !0,
447
- r: e
448
- })), O.catchAll((e) => O.succeed({
449
- ok: !1,
450
- e
451
- })));
452
- return i.ok ? {
453
- value: i.r.text,
454
- text: i.r.text,
455
- ...K(i.r.usage, i.r.providerMetadata, r)
456
- } : { error: String(i.e.message ?? i.e) };
457
- }
458
- if (!t.generateMedia) return { error: new E({
459
- capability: `media:${s}`,
460
- message: `no media generator configured for ${s}`
461
- }).message };
462
- let c = yield* zt(n.mediaInputs, r, a).pipe(O.either);
463
- if (c._tag === "Left") return { error: `step "${n.id}": ${c.left}` };
464
- let l = Vt(n.mediaInputs, a), u = n.model ?? t.defaultModels?.[s], d = yield* H(t.generateMedia({
465
- modality: s,
466
- ...u ? { model: u } : {},
467
- prompt: e,
468
- ...n.params ? { params: n.params } : {},
469
- ...n.mediaInputs === void 0 ? {} : { inputs: c.right },
470
- ...Object.keys(l).length > 0 ? { inputRefs: l } : {},
471
- run: i
472
- })).pipe(O.map((e) => ({
473
- ok: !0,
474
- m: e
475
- })), O.catchAll((e) => O.succeed({
476
- ok: !1,
477
- e
478
- })));
479
- if (!d.ok) {
480
- let e = d.e.receipt;
481
- return {
482
- error: d.e.message,
483
- ...e === void 0 ? {} : e
484
- };
485
- }
486
- return yield* qt(d.m);
487
- }
488
- case "human": return { error: new E({
489
- capability: "human",
490
- message: "human step reached the step interpreter — it should have been parked by the deterministic executor (routing bug)"
491
- }).message };
492
- default: return { error: `unknown step type: ${String(n.type)}` };
493
- }
494
- }), rn = (e, t, n, i, o, s) => O.gen(function* () {
495
- let c = Object.assign(Object.create(null), o), l = Object.create(null), u = i.steps.map((e, t) => ({
496
- id: t,
497
- title: e.title ?? `Step ${t + 1}`,
498
- type: e.type,
499
- status: "pending",
500
- ...e.description ? { description: e.description } : {}
501
- })), d = 0;
502
- yield* Qt(e, n, {
503
- status: "running",
504
- steps: u,
505
- totalSteps: i.steps.length,
506
- currentStep: 0,
507
- startedAt: W()
508
- }, "startedAt");
509
- for (let o of Mt(i.steps)) {
510
- if (yield* $t(e, n)) return yield* en(e, n), {
511
- runId: n,
512
- status: "cancelled"
513
- };
514
- if (o.steps.length > 1) {
515
- let r = [];
516
- for (let { index: e, step: t } of o.steps) {
517
- if (t.when !== void 0 && !y(t.when, c)) {
518
- u[e] = {
519
- ...u[e],
520
- status: "skipped",
521
- completedAt: W(),
522
- skipReason: a(t.when)
523
- };
524
- continue;
525
- }
526
- r.push({
527
- index: e,
528
- step: t
529
- }), u[e] = {
530
- ...u[e],
531
- status: "running",
532
- startedAt: W()
533
- };
534
- }
535
- yield* J(e, n, {
536
- steps: u,
537
- currentStep: o.steps[0].index
538
- });
539
- let i = yield* O.all(r.map(({ index: r, step: i }) => F({
540
- name: `flow-${r}-${i.id}`,
541
- input: { index: r },
542
- success: Kt,
543
- execute: nn(e, t, i, c, {
544
- runId: n,
545
- tenantId: s.tenantId,
546
- ownerId: s.ownerId
547
- }, l)
548
- }).pipe(O.map((e) => ({
549
- index: r,
550
- step: i,
551
- result: e
552
- })))), { concurrency: "unbounded" }), f = i.find((e) => e.result.error);
553
- for (let { index: e, step: t, result: n } of i) {
554
- if (n.error) {
555
- d += n.costMicroUsd ?? 0, u[e] = {
556
- ...u[e],
557
- status: "failed",
558
- completedAt: W(),
559
- errorMessage: n.error,
560
- ...U(n)
561
- };
562
- continue;
563
- }
564
- t.outputKey && n.value !== void 0 && (c[t.outputKey] = n.value), t.outputKey && n.artifacts !== void 0 && (l[t.outputKey] = n.artifacts), d += n.costMicroUsd ?? 0, u[e] = {
565
- ...u[e],
566
- status: "succeeded",
567
- completedAt: W(),
568
- ...n.text ? { output: { text: n.text } } : {},
569
- ...n.url ? { url: n.url } : {},
570
- ...n.artifacts === void 0 ? {} : { artifacts: n.artifacts },
571
- ...U(n)
572
- };
573
- }
574
- if (f !== void 0) return yield* J(e, n, {
575
- steps: u,
576
- status: "failed",
577
- errorMessage: f.result.error,
578
- completedAt: W(),
579
- costMicroUsd: d,
580
- costCompleteness: q(u)
581
- }), {
582
- runId: n,
583
- status: "failed"
584
- };
585
- yield* J(e, n, {
586
- steps: u,
587
- currentStep: o.steps[o.steps.length - 1].index + 1,
588
- costMicroUsd: d,
589
- costCompleteness: q(u)
590
- });
591
- continue;
592
- }
593
- let { index: f, step: p } = o.steps[0];
594
- if (p.when !== void 0 && !y(p.when, c)) {
595
- u[f] = {
596
- ...u[f],
597
- status: "skipped",
598
- completedAt: W(),
599
- skipReason: a(p.when)
600
- }, yield* J(e, n, {
601
- steps: u,
602
- currentStep: f + 1
603
- });
604
- continue;
605
- }
606
- if (p.type === "human") {
607
- let a = {
608
- mode: p.reviewMode ?? "approve",
609
- ...p.options ? { options: p.options } : {},
610
- prompt: At(p.prompt ?? "", c)
611
- };
612
- u[f] = {
613
- ...u[f],
614
- status: "waiting",
615
- startedAt: W(),
616
- review: a
617
- }, yield* J(e, n, {
618
- steps: u,
619
- status: "waiting",
620
- currentStep: f
621
- }), t.onEvent && (yield* H(t.onEvent({
622
- kind: "review-needed",
623
- runId: n,
624
- flowName: i.name,
625
- ownerId: s.ownerId,
626
- source: s.source
627
- })).pipe(O.catchAllCause(() => O.void)));
628
- let o = Et({
629
- step: p,
630
- flow: i,
631
- deps: t
632
- }), l = yield* Ke(e, {
633
- name: r(f),
634
- schema: ce,
635
- timeoutMs: o
636
- }).pipe(O.map((e) => ({
637
- ok: !0,
638
- a: e
639
- })), O.catchAllCause((e) => Oe.isInterruptedOnly(e) ? O.failCause(e) : O.succeed({
640
- ok: !1,
641
- cause: e
642
- })));
643
- if (!l.ok) {
644
- let t = Number.isFinite(o) ? `human review timed out after ${o}ms` : "human review failed";
645
- return u[f] = {
646
- ...u[f],
647
- status: "failed",
648
- completedAt: W(),
649
- errorMessage: t
650
- }, yield* J(e, n, {
651
- steps: u,
652
- status: "failed",
653
- errorMessage: t,
654
- completedAt: W(),
655
- costMicroUsd: d,
656
- costCompleteness: q(u)
657
- }), {
658
- runId: n,
659
- status: "failed"
660
- };
661
- }
662
- let m = l.a;
663
- if (m.decision === "reject") return u[f] = {
664
- ...u[f],
665
- status: "failed",
666
- completedAt: W(),
667
- errorMessage: "rejected by reviewer"
668
- }, yield* J(e, n, {
669
- steps: u,
670
- status: "cancelled",
671
- humanResponse: m,
672
- completedAt: W(),
673
- costMicroUsd: d,
674
- costCompleteness: q(u)
675
- }), {
676
- runId: n,
677
- status: "cancelled"
678
- };
679
- p.outputKey && (c[p.outputKey] = m.value ?? m.text ?? m.decision ?? !0), u[f] = {
680
- ...u[f],
681
- status: "succeeded",
682
- completedAt: W(),
683
- output: { text: String(m.text ?? m.value ?? m.decision ?? "approved") }
684
- }, yield* J(e, n, {
685
- steps: u,
686
- status: "running",
687
- humanResponse: m,
688
- currentStep: f + 1
689
- });
690
- continue;
691
- }
692
- u[f] = {
693
- ...u[f],
694
- status: "running",
695
- startedAt: W()
696
- }, yield* J(e, n, {
697
- steps: u,
698
- currentStep: f
699
- });
700
- let m = yield* F({
701
- name: `flow-${f}-${p.id}`,
702
- input: { index: f },
703
- success: Kt,
704
- execute: nn(e, t, p, c, {
705
- runId: n,
706
- tenantId: s.tenantId,
707
- ownerId: s.ownerId
708
- }, l)
709
- });
710
- if (m.error) return d += m.costMicroUsd ?? 0, u[f] = {
711
- ...u[f],
712
- status: "failed",
713
- completedAt: W(),
714
- errorMessage: m.error,
715
- ...U(m)
716
- }, yield* J(e, n, {
717
- steps: u,
718
- status: "failed",
719
- errorMessage: m.error,
720
- completedAt: W(),
721
- costMicroUsd: d,
722
- costCompleteness: q(u)
723
- }), {
724
- runId: n,
725
- status: "failed"
726
- };
727
- p.outputKey && m.value !== void 0 && (c[p.outputKey] = m.value), p.outputKey && m.artifacts !== void 0 && (l[p.outputKey] = m.artifacts), d += m.costMicroUsd ?? 0, u[f] = {
728
- ...u[f],
729
- status: "succeeded",
730
- completedAt: W(),
731
- ...m.text ? { output: { text: m.text } } : {},
732
- ...m.url ? { url: m.url } : {},
733
- ...m.artifacts === void 0 ? {} : { artifacts: m.artifacts },
734
- ...U(m)
735
- }, yield* J(e, n, {
736
- steps: u,
737
- currentStep: f + 1,
738
- costMicroUsd: d,
739
- costCompleteness: q(u)
740
- });
741
- }
742
- let f = Object.create(null);
743
- for (let e of i.steps) e.outputKey && c[e.outputKey] !== void 0 && (f[e.outputKey] = c[e.outputKey]);
744
- return yield* J(e, n, {
745
- status: "succeeded",
746
- output: f,
747
- completedAt: W(),
748
- costMicroUsd: d
749
- }), {
750
- runId: n,
751
- status: "succeeded",
752
- output: f
753
- };
754
- }), an = (e, t, n, r, i, a, o) => O.gen(function* () {
755
- let s = n.chain;
756
- if (!s) return;
757
- let c = [...a.chainPath ?? [], a.flowRef];
758
- if (s.flowRef === n.name || s.flowRef === a.flowRef) return;
759
- if (c.includes(s.flowRef)) {
760
- yield* J(e, t, { chainRefusal: `chain to "${s.flowRef}" refused — it is already in this run's chain (${c.join(" → ")}), which would loop` });
761
- return;
762
- }
763
- let l = Dt(o);
764
- if (c.length >= l) {
765
- yield* J(e, t, { chainRefusal: `chain to "${s.flowRef}" refused — depth ${c.length} reached the limit of ${l} (${c.join(" → ")})` });
766
- return;
767
- }
768
- let u = {
769
- ...r,
770
- ...i
771
- }, d = {};
772
- for (let e of s.mappings) e.sourceKey in u && (d[e.targetKey] = u[e.sourceKey]);
773
- if (s.requireConfirmation) {
774
- yield* J(e, t, { chainPending: {
775
- flowRef: s.flowRef,
776
- input: d,
777
- status: "pending"
778
- } });
779
- return;
780
- }
781
- let f = e.workflows;
782
- if (!f) return;
783
- let p = `${t}--chain`, m = `${a.requestId}--chain`;
784
- yield* O.promise(async () => {
785
- try {
786
- await e.store.insert(R.tableName, {
787
- id: p,
788
- flowRef: s.flowRef,
789
- flowName: s.flowRef,
790
- status: "pending",
791
- source: a.source,
792
- requestId: m,
793
- input: d
794
- });
795
- } catch {}
796
- await f.child("flow.run", {
797
- runId: p,
798
- flowRef: s.flowRef,
799
- input: d,
800
- source: a.source,
801
- requestId: m,
802
- chainPath: c
803
- });
804
- }).pipe(O.catchAllCause(() => O.void));
805
- }), on = (e) => e.type === "agent" ? e.agentRef ? `agent step, agent "${e.agentRef}"` : "agent step" : e.type === "generate" ? `${e.modality ?? "media"} generation step` : `${e.type} step`, sn = (e) => e.steps.length === 0 ? "" : "Suggested plan (you MAY reorder, insert, or skip steps):\n" + e.steps.map((e, t) => `${t + 1}. ${e.title ?? e.id}${e.prompt ? `: ${e.prompt}` : ""} (${on(e)})`).join("\n"), cn = "an agentic flow runs its planner and every tool inside one durable step, which cannot park. Call the provider directly from the tool (generateImage, generateVideo, …), or give the work its own deterministic flow step", ln = k.optional(k.String.annotations({ description: "One short sentence: what this call is for. Shown to the user in the run timeline." })), un = (e) => e === void 0 || e.trim() === "" ? {} : { description: e.trim().slice(0, 200) }, dn = k.Struct({ json: k.String.annotations({ description: "The requested JSON object, serialized as a JSON string." }) }), fn = (e) => {
806
- try {
807
- let t = JSON.parse(e);
808
- return typeof t == "object" && t && !Array.isArray(t) ? t : void 0;
809
- } catch {
810
- return;
811
- }
812
- }, pn = (e) => {
813
- if (ke.isSuccess(e)) return "the tool returned without recording a result";
814
- if (Oe.isInterruptedOnly(e.cause)) return "interrupted before it finished — nothing waited for its result";
815
- let t = Oe.squash(e.cause);
816
- return t instanceof Error ? t.message : String(t);
817
- }, mn = (e) => {
818
- let t = Object.entries(e);
819
- return t.length === 0 ? "Execute the flow." : "Brief for this run:\n" + t.map(([e, t]) => `- ${e}: ${typeof t == "string" ? t : JSON.stringify(t)}`).join("\n");
820
- }, hn = (e) => [
821
- e.orchestrator?.instructions ?? "You are an orchestrator that uses the available tools to produce a bundled result.",
822
- sn(e),
823
- "When finished, emit a JSON object mapping each deliverable name (outputKey) to its value, serialized as a string in the json field."
824
- ].filter(Boolean).join("\n\n"), gn = k.Struct({
825
- object: k.Record({
826
- key: k.String,
827
- value: k.Unknown
828
- }),
829
- planCostMicroUsd: k.Number,
830
- planCostSource: k.optional(w),
831
- toolCostMicroUsd: k.Number,
832
- steps: k.Array(i),
833
- error: k.optional(k.String)
834
- }), _n = (e, t, n, r, i, a, o, s) => O.gen(function* () {
835
- yield* Qt(e, n, {
836
- status: "running",
837
- startedAt: W(),
838
- totalSteps: r.steps.length
839
- }, "startedAt");
840
- let c = yield* F({
841
- name: "flow-agentic",
842
- input: { flowRef: r.name },
843
- success: gn,
844
- execute: O.gen(function* () {
845
- let c = [], l = 0, u = (e) => {
846
- let t = c.length;
847
- return c.push({
848
- id: t,
849
- status: "running",
850
- startedAt: W(),
851
- ...e
852
- }), t;
853
- }, d = (e, t) => {
854
- c[e] = {
855
- ...c[e],
856
- completedAt: W(),
857
- ...t
858
- };
859
- }, f = () => J(e, n, {
860
- steps: c,
861
- currentStep: c.length,
862
- costMicroUsd: l
863
- }), p = (e, t) => O.suspend(() => {
864
- let n = u(e);
865
- return O.zipRight(f(), t(n)).pipe(O.onExit((e) => c[n]?.status === "running" ? (d(n, {
866
- status: "failed",
867
- errorMessage: pn(e)
868
- }), O.ignore(f())) : O.void));
869
- }), m = yield* (t.listAgents ? H(t.listAgents({
870
- runId: n,
871
- tenantId: o,
872
- ownerId: a
873
- })) : O.succeed(void 0)).pipe(O.either);
874
- if (m._tag === "Left") return yield* O.logWarning(`flow agent listing failed for run ${n}: ${m.left.message}`).pipe(O.annotateLogs({ scope: "voltro:ai-flows" })), {
875
- object: {},
876
- planCostMicroUsd: 0,
877
- toolCostMicroUsd: 0,
878
- steps: c,
879
- error: "flow agent listing failed"
880
- };
881
- let h = m.right, g = h ?? [...new Set(r.steps.flatMap((e) => e.type === "agent" && e.agentRef ? [e.agentRef] : []))].map((e) => ({ ref: e })), _ = g.map((e) => e.ref), v = _.length > 0 ? k.Literal(..._) : k.String, ee = qe({
882
- name: "run_agent",
883
- description: "Delegate a text task to an allowed sub-agent. Returns the agent's text." + (g.length > 0 ? ` Agents you may call: ${g.map((e) => e.description ? `${e.ref} (${e.description})` : e.ref).join("; ")}.` : ""),
884
- input: k.Struct({
885
- agentRef: v,
886
- prompt: k.String,
887
- purpose: ln
888
- }),
889
- execute: ({ agentRef: e, prompt: r, purpose: i }) => p({
890
- title: `agent:${e}`,
891
- type: "agent",
892
- agentRef: e,
893
- ...un(i)
894
- }, (i) => O.gen(function* () {
895
- if (!t.resolveAgent) return d(i, {
896
- status: "failed",
897
- errorMessage: "no agent resolver configured"
898
- }), yield* f(), "ERROR: no agent resolver configured";
899
- let s = yield* H(t.resolveAgent(e, {
900
- runId: n,
901
- tenantId: o,
902
- ownerId: a
903
- })).pipe(O.map((e) => ({
904
- ok: !0,
905
- a: e
906
- })), O.catchAll((e) => O.succeed({
907
- ok: !1,
908
- e
909
- })));
910
- if (!s.ok) return d(i, {
911
- status: "failed",
912
- errorMessage: s.e.message
913
- }), yield* f(), `ERROR: ${Gt(s.e)}`;
914
- let c = yield* Xt(t, s.a, r, {}).pipe(O.map((e) => ({
915
- ok: !0,
916
- r: e
917
- })), O.catchAll((e) => O.succeed({
918
- ok: !1,
919
- e
920
- })));
921
- if (!c.ok) {
922
- let e = String(c.e.message ?? c.e);
923
- return d(i, {
924
- status: "failed",
925
- errorMessage: e
926
- }), yield* f(), `ERROR: ${e}`;
927
- }
928
- let u = Zt(c.r.usage, c.r.providerMetadata, s.a.model);
929
- return l += u, d(i, {
930
- status: "succeeded",
931
- output: { text: c.r.text },
932
- costMicroUsd: u
933
- }), yield* f(), c.r.text;
934
- }))
935
- }), y = qe({
936
- name: "generate_media",
937
- description: "Generate image, video, or audio artifacts. Returns every artifact with its URL, role, media type and optional storage reference.",
938
- input: k.Struct({
939
- modality: k.Literal("image", "video", "audio"),
940
- prompt: k.String,
941
- purpose: ln,
942
- model: k.optional(k.String),
943
- inputs: k.optional(Rt),
944
- params: k.optional(k.Record({
945
- key: k.String,
946
- value: k.Unknown
947
- }))
948
- }),
949
- execute: ({ modality: e, prompt: r, purpose: i, model: s, inputs: c, params: u }) => p({
950
- title: `media:${e}`,
951
- type: "generate",
952
- modality: e,
953
- ...un(i)
954
- }, (i) => O.gen(function* () {
955
- if (!t.generateMedia) return d(i, {
956
- status: "failed",
957
- errorMessage: `no media generator for ${e}`
958
- }), yield* f(), `ERROR: no media generator configured for ${e}`;
959
- let p = yield* H(t.generateMedia({
960
- modality: e,
961
- prompt: r,
962
- ...s ? { model: s } : {},
963
- ...c === void 0 ? {} : { inputs: c },
964
- ...u === void 0 ? {} : { params: u },
965
- run: {
966
- runId: n,
967
- tenantId: o,
968
- ownerId: a
969
- }
970
- })).pipe(O.map((e) => ({
971
- ok: !0,
972
- r: e
973
- })), O.catchAll((e) => O.succeed({
974
- ok: !1,
975
- e
976
- })));
977
- if (!p.ok) return d(i, {
978
- status: "failed",
979
- errorMessage: p.e.message
980
- }), yield* f(), `ERROR: ${p.e.message}`;
981
- let m = yield* qt(p.r);
982
- return m.error ? (d(i, {
983
- status: "failed",
984
- errorMessage: m.error
985
- }), yield* f(), { error: m.error }) : (l += m.costMicroUsd ?? 0, d(i, {
986
- status: "succeeded",
987
- url: m.url,
988
- artifacts: m.artifacts,
989
- ...m.requestId ? { requestId: m.requestId } : {},
990
- costMicroUsd: m.costMicroUsd ?? 0,
991
- costSource: m.costSource ?? "unpriced"
992
- }), yield* f(), { artifacts: m.artifacts });
993
- }))
994
- }), te = qe({
995
- name: "pick_structured",
996
- description: "Produce a JSON object for a task. Returns the object.",
997
- input: k.Struct({
998
- prompt: k.String,
999
- purpose: ln,
1000
- model: k.optional(k.String)
1001
- }),
1002
- execute: ({ prompt: e, purpose: n, model: r }) => p({
1003
- title: "structured",
1004
- type: "structured",
1005
- ...un(n)
1006
- }, (n) => O.gen(function* () {
1007
- let i = yield* Ze({
1008
- prompt: `${e}\n\nReturn the JSON object serialized as a string in the \`json\` field.`,
1009
- schema: dn,
1010
- ...r ? { provider: G(t, r) } : {}
1011
- }).pipe(O.map((e) => ({
1012
- ok: !0,
1013
- r: e
1014
- })), O.catchAll((e) => O.succeed({
1015
- ok: !1,
1016
- e
1017
- })));
1018
- if (!i.ok) {
1019
- let e = String(i.e.message ?? i.e);
1020
- return d(n, {
1021
- status: "failed",
1022
- errorMessage: e
1023
- }), yield* f(), { error: e };
1024
- }
1025
- let a = Zt(i.r.usage, i.r.providerMetadata, r);
1026
- l += a;
1027
- let o = fn(i.r.object.json);
1028
- if (o === void 0) {
1029
- let e = "the model's `json` field is not a JSON object";
1030
- return d(n, {
1031
- status: "failed",
1032
- errorMessage: e,
1033
- costMicroUsd: a
1034
- }), yield* f(), { error: e };
1035
- }
1036
- return d(n, {
1037
- status: "succeeded",
1038
- output: { text: JSON.stringify(o) },
1039
- costMicroUsd: a
1040
- }), yield* f(), o;
1041
- }))
1042
- }), ne = {
1043
- run_agent: ee,
1044
- generate_media: y,
1045
- pick_structured: te
1046
- }, b = yield* (t.resolveTools ? H(t.resolveTools(s, {
1047
- runId: n,
1048
- tenantId: o,
1049
- ownerId: a
1050
- }, { provider: () => r.orchestrator?.model ? G(t, r.orchestrator.model) : void 0 })) : O.succeed({})).pipe(O.either);
1051
- if (b._tag === "Left") return yield* O.logWarning(`flow tool resolution failed for run ${n}: ${b.left.message}`).pipe(O.annotateLogs({ scope: "voltro:ai-flows" })), {
1052
- object: {},
1053
- planCostMicroUsd: 0,
1054
- toolCostMicroUsd: 0,
1055
- steps: c,
1056
- error: "flow tool resolution failed"
1057
- };
1058
- if (Object.keys(b.right).some((e) => Object.hasOwn(ne, e))) return {
1059
- object: {},
1060
- planCostMicroUsd: 0,
1061
- toolCostMicroUsd: 0,
1062
- steps: c,
1063
- error: "flow tools cannot replace reserved planner tools"
1064
- };
1065
- let re = t.memoryPrefix ? yield* H(t.memoryPrefix(a)).pipe(O.catchAll(() => O.succeed(""))) : "", x = re ? `${re}\n\n${hn(r)}` : hn(r), S = yield* $e({
1066
- system: x,
1067
- prompt: mn(i),
1068
- schema: dn,
1069
- tools: {
1070
- ...b.right,
1071
- ...h?.length === 0 ? {
1072
- generate_media: y,
1073
- pick_structured: te
1074
- } : ne
1075
- },
1076
- maxSteps: r.maxSteps,
1077
- ...r.orchestrator?.model ? { provider: G(t, r.orchestrator.model) } : {}
1078
- }).pipe(O.provideService(Ge, cn), O.map((e) => ({
1079
- ok: !0,
1080
- r: e
1081
- })), O.catchAll((e) => O.succeed({
1082
- ok: !1,
1083
- e
1084
- })));
1085
- for (let e of c) e.status === "running" && d(e.id, {
1086
- status: "failed",
1087
- errorMessage: "not finished — the run ended first"
1088
- });
1089
- if (!S.ok) return {
1090
- object: {},
1091
- planCostMicroUsd: 0,
1092
- toolCostMicroUsd: l,
1093
- steps: c,
1094
- error: String(S.e.message ?? S.e)
1095
- };
1096
- let C = fn(S.r.object.json);
1097
- return {
1098
- object: C ?? {},
1099
- ...C === void 0 ? { error: "the planner's `json` field is not a JSON object" } : {},
1100
- planCostMicroUsd: Zt(S.r.usage, S.r.providerMetadata, r.orchestrator?.model),
1101
- planCostSource: K(S.r.usage, S.r.providerMetadata, r.orchestrator?.model).costSource,
1102
- toolCostMicroUsd: l,
1103
- steps: c
1104
- };
1105
- })
1106
- }), l = c.planCostMicroUsd + c.toolCostMicroUsd, u = q([...c.steps, {
1107
- status: "succeeded",
1108
- costMicroUsd: c.planCostMicroUsd,
1109
- costSource: c.planCostSource ?? "unpriced"
1110
- }]);
1111
- return c.error ? (yield* J(e, n, {
1112
- status: "failed",
1113
- steps: c.steps,
1114
- errorMessage: c.error,
1115
- completedAt: W(),
1116
- costMicroUsd: l,
1117
- costCompleteness: u
1118
- }), {
1119
- runId: n,
1120
- status: "failed"
1121
- }) : (yield* J(e, n, {
1122
- status: "succeeded",
1123
- steps: c.steps,
1124
- output: c.object,
1125
- completedAt: W(),
1126
- costMicroUsd: l,
1127
- costCompleteness: u
1128
- }), {
1129
- runId: n,
1130
- status: "succeeded",
1131
- output: c.object
1132
- });
1133
- }), vn = (e, t = {}) => (n, r) => O.gen(function* () {
1134
- let { runId: r, flowRef: i, input: a } = n, o = yield* O.tryPromise(() => e.store.query(N(R).where(A("id", r)).descriptor)).pipe(O.flatMap(k.decodeUnknown(k.Tuple(k.Struct({
1135
- id: k.Literal(r),
1136
- tenantId: k.NullOr(k.NonEmptyString),
1137
- ownerId: k.optional(k.NullOr(k.String))
1138
- })))), O.either);
1139
- if (o._tag === "Left") return yield* J(e, r, {
1140
- status: "failed",
1141
- errorMessage: "flow run context unavailable: expected one matching run row with an explicit tenantId (string or null)",
1142
- completedAt: W()
1143
- }), {
1144
- runId: r,
1145
- status: "failed"
1146
- };
1147
- let { tenantId: s, ownerId: c = null } = o.right[0], l = yield* F({
1148
- name: "flow-0-resolve",
1149
- input: { flowRef: i },
1150
- success: k.Struct({
1151
- ir: k.Unknown,
1152
- error: k.optional(k.String)
1153
- }),
1154
- execute: tn(e, i).pipe(O.map((e) => ({ ir: e })), O.catchAll((e) => O.succeed({
1155
- ir: void 0,
1156
- error: e.message
1157
- })))
1158
- });
1159
- if (l.error || !l.ir) return yield* J(e, r, {
1160
- status: "failed",
1161
- errorMessage: l.error ?? "flow not found",
1162
- completedAt: W()
1163
- }), {
1164
- runId: r,
1165
- status: "failed"
1166
- };
1167
- let u = l.ir, d = u.mode === "agentic" ? yield* _n(e, t, r, u, a, c, s, i) : yield* rn(e, t, r, u, a, {
1168
- ownerId: c,
1169
- tenantId: s,
1170
- source: n.source
1171
- });
1172
- return d.status === "succeeded" && u.chain && (yield* an(e, r, u, a, d.output ?? {}, n, t)), t.onEvent && (d.status === "succeeded" || d.status === "failed") && (yield* H(t.onEvent({
1173
- kind: d.status,
1174
- runId: r,
1175
- flowName: u.name,
1176
- ownerId: c,
1177
- source: n.source
1178
- })).pipe(O.catchAllCause(() => O.void))), d;
1179
- }), yn = {
1180
- text: (e) => ({
1181
- type: "generate",
1182
- modality: "text",
1183
- ...e
1184
- }),
1185
- media: (e, t) => ({
1186
- type: "generate",
1187
- modality: e,
1188
- ...t
1189
- }),
1190
- agent: (e) => ({
1191
- type: "agent",
1192
- ...e
1193
- }),
1194
- structured: (e) => ({
1195
- type: "structured",
1196
- ...e
1197
- }),
1198
- note: (e) => ({
1199
- type: "note",
1200
- ...e
1201
- }),
1202
- human: (e) => ({
1203
- type: "human",
1204
- ...e
1205
- })
1206
- }, bn = (e) => e.map((e, t) => "id" in e && e.id ? e : {
1207
- id: `step-${t}`,
1208
- ...e
1209
- }), xn = (e) => {
1210
- let t = [], n = Mt(e.steps);
1211
- for (let e of Nt(n)) t.push(`group "${e}" is not contiguous — only CONSECUTIVE steps sharing a group run concurrently, so this would execute as two separate fan-outs`);
1212
- let r = new Set(e.brief.map((e) => e.key));
1213
- for (let e of n) {
1214
- for (let { step: n } of e.steps) {
1215
- n.type === "human" && n.group !== void 0 && t.push(`step "${n.id}" is a human review inside group "${n.group}" — a review SUSPENDS the whole run, which one branch of a fan-out cannot do`);
1216
- for (let i of kt(n.prompt ?? "")) r.has(i) || t.push(e.steps.length > 1 ? `step "${n.id}" references {{${i}}} which is produced inside its OWN group "${n.group}" or does not exist — grouped steps run concurrently, so they cannot read each other` : `step "${n.id}" references {{${i}}} which is not a brief field or a prior step outputKey`);
1217
- for (let [e, i] of Object.entries(n.mediaInputs ?? {})) i.from === "step" && !r.has(i.ref) && t.push(`step "${n.id}" media input "${e}" references "${i.ref}" which is not a brief field or an earlier segment's outputKey`);
1218
- n.when !== void 0 && !r.has(n.when.ref) && t.push(`step "${n.id}" has a when-condition on {{${n.when.ref}}} which is not a brief field or a prior step outputKey — it would never run`);
1219
- }
1220
- for (let { step: t } of e.steps) t.outputKey && r.add(f(t.outputKey));
1221
- }
1222
- if (t.length > 0) throw new Te({
1223
- flowRef: e.name,
1224
- message: `flow "${e.name}" has ${t.length} problem(s)`,
1225
- issues: t
1226
- });
1227
- }, Sn = (e) => {
1228
- let t = d({
1229
- name: e.name,
1230
- mode: e.mode,
1231
- steps: bn(e.steps),
1232
- maxSteps: e.maxSteps,
1233
- brief: e.brief,
1234
- orchestratorModel: e.orchestrator?.model,
1235
- orchestratorInstructions: e.orchestrator?.instructions,
1236
- chain: e.chain,
1237
- cadence: e.cadence,
1238
- humanTimeoutMs: e.humanTimeoutMs
1239
- });
1240
- return xn(t), at(t), t;
1241
- }, Cn = async (e, t, n) => {
1242
- let r = k.decodeUnknownSync(je.pipe(k.filter((e) => e.workflowName === "flow.run" && e.id.length > 0)))(n);
1243
- if (await e.store.update(R.tableName, t, { workflowStart: r }) === null) throw Error("flow start receipt could not be recorded; workflow submission may have succeeded");
1244
- return r;
1245
- }, wn = (e, t, n) => {
1246
- if (!Number.isFinite(t.getTime())) throw Error("cadence timestamp must be valid");
1247
- return `cron-${it("sha256").update(JSON.stringify([
1248
- n,
1249
- e,
1250
- Math.floor(t.getTime() / 6e4)
1251
- ])).digest("hex")}`;
1252
- }, Tn = async (e) => {
1253
- let t = [];
1254
- for (let n of st()) n.cadence && (n.cadence.repeats?.length ?? 0) > 0 && t.push({
1255
- tenantId: e.request.subject.tenantId,
1256
- flowRef: n.name,
1257
- cadence: n.cadence,
1258
- defaultInput: n.cadence.defaultInput ?? {}
1259
- });
1260
- let n = await e.store.select("_voltro_ai_flows").where("isEnabled", !0).all();
1261
- for (let r of n) r.id && r.cadence && (r.cadence.repeats?.length ?? 0) > 0 && t.push({
1262
- tenantId: r.tenantId ?? e.request.subject.tenantId,
1263
- flowRef: r.id,
1264
- cadence: r.cadence,
1265
- defaultInput: r.cadence.defaultInput ?? {}
1266
- });
1267
- return t;
1268
- }, En = async (e, t = /* @__PURE__ */ new Date()) => {
1269
- let r = [], i = 0, a = [], o = e.workflows ? await pt(e) : {
1270
- examined: 0,
1271
- accepted: 0,
1272
- notExecuted: 0,
1273
- pending: 0,
1274
- failures: []
1275
- };
1276
- a.push(...o.failures.map((e) => Error(`flow run ${e.runId}: start reconciliation failed`, { cause: e.cause })));
1277
- let s = await Tn(e);
1278
- for (let o of s) {
1279
- if (!De(o.cadence, t)) continue;
1280
- i += 1;
1281
- let s = wn(o.flowRef, t, o.tenantId), c = `run-${s}`;
1282
- try {
1283
- if (!e.workflows) throw Error("workflow runtime unavailable; no cadence start was submitted");
1284
- (await e.transaction(async (e) => {
1285
- let t = e.workflows;
1286
- if (!t) throw Error("workflow runtime unavailable in transaction; no cadence start was submitted");
1287
- await e.store.insertIgnoreWithOutcome("_voltro_ai_flow_runs", {
1288
- id: c,
1289
- flowRef: o.flowRef,
1290
- flowName: o.flowRef,
1291
- status: "pending",
1292
- source: "cron",
1293
- requestId: s,
1294
- input: o.defaultInput
1295
- }, { conflictColumns: ["id"] });
1296
- let r = await e.store.select("_voltro_ai_flow_runs").where("id", c).first();
1297
- if (!r) throw Error("cadence run is not readable after persistence");
1298
- let i = k.decodeUnknownSync(n.payloadSchema.pipe(k.filter((e) => e.runId === c && e.flowRef === o.flowRef && e.requestId === s && e.source === "cron")))({
1299
- ...r,
1300
- runId: r.id
1301
- });
1302
- return Cn(e, c, await t.start("flow.run", i));
1303
- }, o.tenantId === null ? void 0 : { tenantId: o.tenantId })).status === "running" && r.push(s);
1304
- } catch (e) {
1305
- a.push(e);
1306
- }
1307
- }
1308
- if (a.length > 0) throw AggregateError(a, `${a.length} cadence submission(s) failed`);
1309
- return {
1310
- matched: i,
1311
- started: r,
1312
- reconciled: o
1313
- };
1314
- }, Y = (e) => k.optionalWith(e, { exact: !0 }), Dn = k.Int.pipe(k.positive(), k.lessThanOrEqualTo(2 ** 53 - 1)), On = k.Int.pipe(k.between(-(2 ** 53 - 1), 2 ** 53 - 1)), kn = k.TemplateLiteral(k.Number, "x", k.Number).pipe(k.pattern(/^[1-9]\d*x[1-9]\d*$/)), An = k.TemplateLiteral(k.Number, ":", k.Number).pipe(k.pattern(/^[1-9]\d*:[1-9]\d*$/)), jn = k.Struct({
1315
- n: Y(Dn),
1316
- seed: Y(On),
1317
- size: Y(kn),
1318
- aspectRatio: Y(An),
1319
- providerOptions: Y(B)
1320
- }), Mn = k.Struct({
1321
- voice: Y(k.NonEmptyString),
1322
- outputFormat: Y(k.NonEmptyString),
1323
- instructions: Y(k.String),
1324
- speed: Y(k.Finite.pipe(k.positive())),
1325
- language: Y(k.NonEmptyString),
1326
- providerOptions: Y(B)
1327
- }), Nn = k.Struct({
1328
- aspectRatio: Y(An),
1329
- durationSeconds: Y(k.Finite.pipe(k.positive())),
1330
- resolution: Y(kn),
1331
- fps: Y(k.Finite.pipe(k.positive())),
1332
- seed: Y(On),
1333
- generateAudio: Y(k.Boolean),
1334
- maxInlineBytes: Y(Dn),
1335
- providerOptions: Y(B)
1336
- }), Pn = (e, t, n) => O.try({
1337
- try: () => k.decodeUnknownSync(e, { onExcessProperty: "error" })(t === void 0 ? {} : t),
1338
- catch: () => `invalid ${n} media params: check the built-in adapter's supported options and value ranges`
1339
- }), Fn = (e) => Pn(jn, e, "image"), In = (e) => Pn(Mn, e, "audio"), Ln = (e) => Pn(Nn, e, "video"), Rn = (e) => ({
1340
- name: "gateway",
1341
- model: e
1342
- }), zn = (e) => Math.round(e * 1e6), X = (e, t, n) => {
1343
- let r = Ye(t);
1344
- if (typeof r == "number") return {
1345
- costMicroUsd: zn(r),
1346
- costSource: "gateway"
1347
- };
1348
- if (e) {
1349
- let t = Je(e, { model: n ?? "unknown" });
1350
- return {
1351
- costMicroUsd: t.costMicroUsd ?? 0,
1352
- costSource: t.costSource ?? "unpriced"
1353
- };
1354
- }
1355
- return {
1356
- costMicroUsd: 0,
1357
- costSource: "unpriced"
1358
- };
1359
- }, Z = (e) => {
1360
- if (e === void 0) return { status: "unreported" };
1361
- let [t, n, r] = rt(e) ? [
1362
- e.unit,
1363
- e.input,
1364
- e.output
1365
- ] : [
1366
- "tokens",
1367
- e.inputTokens,
1368
- e.outputTokens
1369
- ];
1370
- return n === void 0 && r === void 0 ? { status: "unreported" } : {
1371
- status: "reported",
1372
- unit: t,
1373
- ...n === void 0 ? {} : { input: n },
1374
- ...r === void 0 ? {} : { output: r }
1375
- };
1376
- }, Q = (e, t, n) => ({
1377
- ...X(e, t, n),
1378
- usage: Z(e)
1379
- }), Bn = (e, t) => (n) => {
1380
- let r = n.model, i = (e) => t?.resolveModel?.(e) ?? Rn(e);
1381
- return O.gen(function* () {
1382
- let t = yield* Ht(n.modality, n.inputs).pipe(O.mapError((e) => new E({
1383
- capability: `media:${n.modality}`,
1384
- message: e
1385
- })));
1386
- if (n.modality === "image") {
1387
- let a = yield* Fn(n.params).pipe(O.mapError((e) => new E({
1388
- capability: "media:image",
1389
- message: e
1390
- }))), o = t.referenceImageUrl, s = t.maskImageUrl, c = yield* Xe({
1391
- ...a,
1392
- prompt: n.prompt,
1393
- ...o === void 0 ? {} : { inputs: {
1394
- images: [o],
1395
- ...s === void 0 ? {} : { mask: s }
1396
- } },
1397
- ...r ? { provider: i(r) } : {}
1398
- });
1399
- if (c.images.length === 0) return yield* O.fail(new E({
1400
- capability: "media:image",
1401
- message: "no image produced"
1402
- }));
1403
- let l = [];
1404
- for (let [t, i] of c.images.entries()) {
1405
- let a = yield* e.put({
1406
- data: i.data,
1407
- mediaType: i.mediaType,
1408
- run: n.run
1409
- }).pipe(O.mapError(() => new E({
1410
- capability: "media:image",
1411
- message: "media persistence failed",
1412
- receipt: Q(c.usage, c.providerMetadata, r)
1413
- })));
1414
- l.push({
1415
- url: a.url,
1416
- mediaType: i.mediaType,
1417
- role: t === 0 ? "primary" : "variant",
1418
- ...a.refId === void 0 ? {} : { storageRefId: a.refId },
1419
- ...i.providerMetadata === void 0 ? {} : { providerMetadata: i.providerMetadata }
1420
- });
1421
- }
1422
- return {
1423
- artifacts: l,
1424
- ...X(c.usage, c.providerMetadata, r),
1425
- usage: Z(c.usage)
1426
- };
1427
- }
1428
- if (n.modality === "audio") {
1429
- let t = yield* In(n.params).pipe(O.mapError((e) => new E({
1430
- capability: "media:audio",
1431
- message: e
1432
- }))), a = yield* et({
1433
- ...t,
1434
- text: n.prompt,
1435
- ...r ? { provider: i(r) } : {}
1436
- }), o = yield* e.put({
1437
- data: a.audio.data,
1438
- mediaType: a.audio.mediaType,
1439
- run: n.run
1440
- }).pipe(O.mapError(() => new E({
1441
- capability: "media:audio",
1442
- message: "media persistence failed",
1443
- receipt: Q(a.usage, a.providerMetadata, r)
1444
- })));
1445
- return {
1446
- artifacts: [{
1447
- url: o.url,
1448
- mediaType: a.audio.mediaType,
1449
- role: "primary",
1450
- ...o.refId === void 0 ? {} : { storageRefId: o.refId }
1451
- }],
1452
- ...X(a.usage, a.providerMetadata, r),
1453
- usage: Z(a.usage)
1454
- };
1455
- }
1456
- let { maxInlineBytes: a, providerOptions: o, ...s } = yield* Ln(n.params).pipe(O.mapError((e) => new E({
1457
- capability: "media:video",
1458
- message: e
1459
- }))), c = yield* nt({
1460
- prompt: n.prompt,
1461
- inputs: {
1462
- ...t.referenceImageUrl === void 0 ? {} : { image: t.referenceImageUrl },
1463
- ...t.referenceVideoUrl === void 0 ? {} : { references: [t.referenceVideoUrl] },
1464
- frameImages: [...t.firstFrameImageUrl === void 0 ? [] : [{
1465
- frameType: "first_frame",
1466
- image: t.firstFrameImageUrl
1467
- }], ...t.lastFrameImageUrl === void 0 ? [] : [{
1468
- frameType: "last_frame",
1469
- image: t.lastFrameImageUrl
1470
- }]]
1471
- },
1472
- ...r ? { provider: i(r) } : {},
1473
- params: s,
1474
- ...o === void 0 ? {} : { providerOptions: o },
1475
- ...a === void 0 ? {} : { maxInlineBytes: a }
1476
- }), l;
1477
- if (c.video.url) l = e.ingestUrl ? yield* e.ingestUrl(c.video.url, n.run).pipe(O.mapError(() => new E({
1478
- capability: "media:video",
1479
- message: "media persistence failed",
1480
- receipt: Q(c.usage, c.providerMetadata, r)
1481
- }))) : { url: c.video.url };
1482
- else if (c.video.data) l = yield* e.put({
1483
- data: c.video.data,
1484
- mediaType: c.video.mediaType,
1485
- run: n.run
1486
- }).pipe(O.mapError(() => new E({
1487
- capability: "media:video",
1488
- message: "media persistence failed",
1489
- receipt: Q(c.usage, c.providerMetadata, r)
1490
- })));
1491
- else return yield* O.fail(new E({
1492
- capability: "media:video",
1493
- message: "no video produced"
1494
- }));
1495
- return {
1496
- artifacts: [{
1497
- url: l.url,
1498
- mediaType: c.video.mediaType,
1499
- role: "primary",
1500
- ...l.refId === void 0 ? {} : { storageRefId: l.refId }
1501
- }],
1502
- ...X(c.usage, c.providerMetadata, r),
1503
- usage: Z(c.usage)
1504
- };
1505
- }).pipe(O.catchAll((e) => e instanceof E ? O.fail(e) : O.fail(new E({
1506
- capability: `media:${n.modality}`,
1507
- message: String(e.message ?? e)
1508
- }))));
1509
- }, Vn = () => globalThis.crypto?.randomUUID?.() ?? `req-${Date.now().toString(36)}`, Hn = (e) => e.request?.subject?.id ?? null, $ = (e, t) => O.promise(() => e.store.query(N(R).where(A("id", t)).descriptor)).pipe(O.map((e) => e[0])), Un = (e) => O.sync(() => {
1510
- let t = e.workflows;
1511
- if (!t) throw Error("workflow runtime unavailable; no flow start was submitted");
1512
- return t;
1513
- }), Wn = (t, n) => O.gen(function* () {
1514
- yield* Un(t);
1515
- let r = yield* tn(t, n.flowRef), i = n.input ?? {}, a = r.brief.filter((e) => e.required && e.type !== "boolean" && (i[e.key] === void 0 || i[e.key] === null || i[e.key] === "")).map((e) => e.key);
1516
- if (a.length > 0) return yield* O.fail(new be({
1517
- missing: a,
1518
- message: `missing required brief field(s): ${a.join(", ")}`
1519
- }));
1520
- let o = Vn(), s = `run-${o}`, c = n.source ?? "manual";
1521
- return yield* O.promise(() => t.transaction(async (t) => {
1522
- let a = t.workflows;
1523
- if (!a) throw Error("workflow runtime unavailable in transaction; no flow start was submitted");
1524
- await t.store.insert(R.tableName, {
1525
- id: s,
1526
- flowRef: n.flowRef,
1527
- flowName: r.name,
1528
- mode: r.mode,
1529
- status: "pending",
1530
- source: c,
1531
- requestId: o,
1532
- input: i,
1533
- ownerId: Hn(t)
1534
- });
1535
- let l = await Cn(t, s, await a.start(e, {
1536
- runId: s,
1537
- flowRef: n.flowRef,
1538
- input: i,
1539
- source: c,
1540
- requestId: o
1541
- }));
1542
- return x.make({
1543
- runId: s,
1544
- requestId: o,
1545
- admission: l
1546
- });
1547
- }));
1548
- }), Gn = (t, r) => O.gen(function* () {
1549
- return yield* Un(t), yield* O.tryPromise({
1550
- try: () => t.transaction(async (t) => {
1551
- let i = t.workflows;
1552
- if (!i) throw Error("workflow runtime unavailable in transaction; no flow start was submitted");
1553
- let a = (await t.store.query(N(R).where(A("id", r.runId)).descriptor))[0];
1554
- if (!a) throw new D({
1555
- runId: r.runId,
1556
- message: "run not found"
1557
- });
1558
- let o = a.requestId;
1559
- if (typeof o != "string" || o.length === 0) throw Error("stored flow run has no valid requestId; retry refused without changing the run");
1560
- let s = k.decodeUnknownEither(n.payloadSchema.pipe(k.filter((e) => e.runId === r.runId && e.flowRef.length > 0)))({
1561
- ...a,
1562
- runId: a.id
1563
- });
1564
- if (s._tag === "Left") throw Error("stored workflow payload is incomplete or invalid; retry refused without changing the run");
1565
- let c = await Cn(t, r.runId, await i.start(e, s.right));
1566
- return x.make({
1567
- runId: r.runId,
1568
- requestId: o,
1569
- admission: c
1570
- });
1571
- }),
1572
- catch: (e) => e
1573
- }).pipe(O.catchAll((e) => e instanceof D ? O.fail(e) : O.die(e)));
1574
- }), Kn = (t, r) => O.gen(function* () {
1575
- let i = yield* $(t, r.runId);
1576
- if (!i) return yield* O.fail(new D({
1577
- runId: r.runId,
1578
- message: "run not found"
1579
- }));
1580
- if (qn(i.status)) return T.make({
1581
- runId: r.runId,
1582
- status: i.status,
1583
- engine: "not-requested",
1584
- control: null
1585
- });
1586
- let a = (/* @__PURE__ */ new Date()).toISOString();
1587
- yield* O.promise(() => t.store.updateMany(R.tableName, {
1588
- status: "cancelling",
1589
- cancelledAt: a
1590
- }, { where: Pe(A("id", r.runId), Le("status", [
1591
- "pending",
1592
- "running",
1593
- "waiting"
1594
- ])) }));
1595
- let o = yield* $(t, r.runId);
1596
- if (!o) return yield* O.fail(new D({
1597
- runId: r.runId,
1598
- message: "run not found"
1599
- }));
1600
- if (qn(o.status)) return T.make({
1601
- runId: r.runId,
1602
- status: o.status,
1603
- engine: "not-requested",
1604
- control: null
1605
- });
1606
- let s = t.workflows, c = k.decodeUnknownOption(k.Struct({
1607
- runId: k.Literal(r.runId),
1608
- flowRef: k.NonEmptyString,
1609
- requestId: k.NonEmptyString,
1610
- input: k.Record({
1611
- key: k.String,
1612
- value: k.Unknown
1613
- }),
1614
- source: k.Literal("manual", "cron")
1615
- }))({
1616
- ...i,
1617
- runId: i.id
1618
- }), l = s === void 0 || c._tag === "None" ? null : yield* O.flatMap(n.executionId(c.value), (t) => O.tryPromise(async () => {
1619
- let n = k.decodeUnknownSync(Ae)(await s.cancel(e, t));
1620
- if (n.operation !== "cancel" || n.snapshot.workflowName !== "flow.run" || n.snapshot.executionId !== t) throw Error("workflow cancellation receipt does not match the flow execution");
1621
- return n;
1622
- })).pipe(O.catchAll(() => O.succeed(null))), u = l === null ? s === void 0 || c._tag === "None" ? "unreachable" : "unknown" : l.snapshot.status === "cancelled" && (l.kind === "confirmed" || l.kind === "already-terminal") ? "cancelled" : l.kind === "accepted" ? "accepted" : l.kind === "already-terminal" ? "already-terminal" : "unknown", d = Pe(A("id", r.runId), A("status", "cancelling"), A("cancelledAt", o.cancelledAt));
1623
- if (u === "cancelled") yield* O.promise(() => t.store.updateMany(R.tableName, {
1624
- status: "cancelled",
1625
- completedAt: o.completedAt ?? (/* @__PURE__ */ new Date()).toISOString()
1626
- }, { where: d }));
1627
- else if (l?.kind === "already-terminal") {
1628
- let e = k.decodeUnknownOption(n.successSchema)(l.snapshot.output), i = l.snapshot.status === "failed" ? "failed" : e._tag === "Some" && e.value.runId === r.runId && e.value.status !== "waiting" ? e.value.status : void 0;
1629
- i !== void 0 && (yield* O.promise(() => t.store.updateMany(R.tableName, {
1630
- status: i,
1631
- completedAt: o.completedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1632
- ...i === "cancelled" ? {} : { cancelledAt: null }
1633
- }, { where: d })));
1634
- }
1635
- let f = yield* $(t, r.runId);
1636
- return f ? yield* k.decodeUnknown(T)({
1637
- runId: r.runId,
1638
- status: f.status,
1639
- engine: u,
1640
- control: l
1641
- }).pipe(O.orDie) : yield* O.fail(new D({
1642
- runId: r.runId,
1643
- message: "run not found"
1644
- }));
1645
- }), qn = (e) => e === "succeeded" || e === "failed" || e === "cancelled", Jn = (e) => {
1646
- let t = e.steps?.filter((e) => e.status === "waiting"), n = t?.[0];
1647
- 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");
1648
- return n.id;
1649
- }, Yn = (t, i) => O.gen(function* () {
1650
- let a = (e, t) => new we({
1651
- runId: i.runId,
1652
- reason: e,
1653
- message: t
1654
- }), o = yield* k.decodeUnknown(se, { onExcessProperty: "error" })(i).pipe(O.mapError(() => a("invalid-response", "review response requires runId, displayed stepIndex and a valid response")));
1655
- if (o.response.decision === void 0 && o.response.text === void 0 && o.response.value === void 0) return yield* O.fail(a("invalid-response", "review response must contain a decision, text or value"));
1656
- let s = t.workflows;
1657
- if (!s) return yield* O.fail(a("runtime-unavailable", "workflow runtime unavailable; review was not sent"));
1658
- let c = yield* $(t, i.runId);
1659
- if (!c) return yield* O.fail(new D({
1660
- runId: i.runId,
1661
- message: "run not found"
1662
- }));
1663
- let l = c.status;
1664
- if (l !== "waiting") return yield* O.fail(new Se({
1665
- runId: i.runId,
1666
- status: l ?? "unknown",
1667
- message: `run is "${l}", not awaiting a response`
1668
- }));
1669
- let u = yield* O.try({
1670
- try: () => Jn(c),
1671
- catch: () => a("invalid-run", "stored run has no unambiguous waiting review")
1672
- });
1673
- if (u !== o.stepIndex) return yield* O.fail(new Se({
1674
- runId: i.runId,
1675
- status: l,
1676
- message: "this review is no longer waiting; reload the run before answering"
1677
- }));
1678
- let d = yield* k.decodeUnknown(k.Struct({
1679
- runId: k.Literal(i.runId),
1680
- flowRef: k.NonEmptyString,
1681
- requestId: k.NonEmptyString,
1682
- input: k.Record({
1683
- key: k.String,
1684
- value: k.Unknown
1685
- }),
1686
- source: k.Literal("manual", "cron")
1687
- }))({
1688
- ...c,
1689
- runId: c.id
1690
- }).pipe(O.mapError(() => a("invalid-run", "stored workflow payload is incomplete; review was not sent"))), f = yield* n.executionId(d), p = {
1691
- ...o.response,
1692
- respondedAt: (/* @__PURE__ */ new Date()).toISOString()
1693
- }, m = yield* O.tryPromise({
1694
- try: () => s.signal({
1695
- workflowName: e,
1696
- executionId: f
1697
- }, r(u), p),
1698
- catch: () => a("delivery-unknown", "review delivery was not confirmed; observe the run before retrying")
1699
- }), h = yield* k.decodeUnknown(k.Struct({ eventId: k.NonEmptyString }))(m).pipe(O.mapError(() => a("delivery-unknown", "workflow runtime returned no valid review delivery receipt")));
1700
- return yield* k.decodeUnknown(me)({
1701
- runId: i.runId,
1702
- stepIndex: u,
1703
- executionId: f,
1704
- eventId: h.eventId,
1705
- status: "accepted"
1706
- }).pipe(O.mapError(() => a("delivery-unknown", "workflow runtime returned no valid review delivery receipt")));
1707
- }), Xn = (e, t) => O.promise(() => e.store.query(N(L).where(A("id", t.id)).descriptor)).pipe(O.map((e) => e[0])), Zn = (e) => O.promise(() => e.store.query(N(L).descriptor)), Qn = (e, t) => O.promise(() => e.store.insert(L.tableName, {
1708
- id: t.id ?? `flow-${Vn()}`,
1709
- ...t
1710
- })), $n = (e, t) => O.promise(() => e.store.update(L.tableName, t.id, t.patch)), er = (e, t) => O.promise(() => e.store.delete(L.tableName, t.id)), tr = "aiFlows", nr = (e = {}) => {
1711
- let t = Ne({
1712
- base: tr,
1
+ import { clearRegistry as e, getRegisteredFlow as t, listRegisteredFlows as n, registerFlow as r } from "./registry.js";
2
+ import { aiFlowRunsTable as i, aiFlowsTable as a, aiFlowsTables as o } from "./table.js";
3
+ import { FLOW_RUN_WORKFLOW as s, HUMAN_RESPONSE_SIGNAL_PREFIX as c, humanResponseSignalName as l } from "./workflow.js";
4
+ import { admittedStartHandle as u, reconcileFlowStarts as d } from "./startReconcile.js";
5
+ import { FLOW_RUNS_TTL_ENV as f, FLOW_RUNS_TTL_HOURS_DEFAULT as p, HUMAN_REVIEW_TIMEOUT_ENV as m, HUMAN_REVIEW_TIMEOUT_HOURS_DEFAULT as h, MAX_CHAIN_DEPTH_DEFAULT as ee, MAX_CHAIN_DEPTH_ENV as te, getAiFlowsDefaults as ne, msFromHoursEnv as re, resetAiFlowsDefaults as ie, resolveHumanReviewTimeoutMs as g, resolveMaxChainDepth as _, setAiFlowsDefaults as v } from "./defaults.js";
6
+ import { ConditionOp as y, StepCondition as b, describeCondition as x, evaluateCondition as S, isTruthy as C } from "./condition.js";
7
+ import { BriefField as w, ChainPending as T, CostCompleteness as E, CostSource as D, FlowCadence as O, FlowCancelReceipt as k, FlowChain as A, FlowMode as j, FlowReviewInput as M, FlowReviewReceipt as N, FlowStartReceipt as P, FlowStatus as F, FlowStep as I, HumanResponse as L, Json as R, MAX_STEPS_DEFAULT as z, MAX_STEPS_MAX as B, MAX_STEPS_MIN as V, MediaArtifact as H, MediaArtifacts as U, MediaInputSlot as W, MediaInputs as G, MediaReceipt as K, Modality as q, ReviewMode as J, ReviewOption as Y, RunReview as ae, RunSource as oe, RunStatus as se, RunStep as ce, RunStepStatus as le, StepType as ue, StepUsage as de, Visibility as fe, clampMaxSteps as pe, normalizeFlow as me, sanitizeOutputKey as he } from "./ir.js";
8
+ import { collectRefs as ge, interpolate as _e, unresolvedRefs as ve } from "./interpolate.js";
9
+ import { flowSegments as ye, nonContiguousGroups as be } from "./segments.js";
10
+ import { buildFlowRunExecute as xe, resolveIr as Se } from "./engine.js";
11
+ import { defineFlow as Ce, flowStep as we, validateFlow as Te } from "./define.js";
12
+ import { cadenceMatches as Ee, nextRuns as De } from "./cadence.js";
13
+ import { cronRequestId as Oe, runCadenceTick as ke } from "./cadenceTick.js";
14
+ import { makeMediaGenerator as Ae } from "./mediaAdapter.js";
15
+ import { cancelFlow as je, createFlow as Me, deleteFlow as Ne, getFlow as Pe, launchFlow as Fe, listFlows as Ie, respondToFlow as Le, retryFlow as X, updateFlow as Re, waitingStepIndex as ze } from "./procedures.js";
16
+ import { Effect as Z } from "effect";
17
+ import { definePlugin as Be, pluginInstanceName as Ve } from "@voltro/protocol";
18
+ import { eq as Q, inSet as He, notInSet as Ue, queryFor as We, registerRetention as Ge } from "@voltro/database";
19
+ //#region src/index.ts
20
+ var $ = "aiFlows", Ke = (e = {}) => {
21
+ let t = Ve({
22
+ base: $,
1713
23
  alias: e.alias
1714
24
  });
1715
- xt(e.humanReviewTimeoutMs === void 0 ? {} : { humanReviewTimeoutMs: e.humanReviewTimeoutMs }), ze({
25
+ v(e.humanReviewTimeoutMs === void 0 ? {} : { humanReviewTimeoutMs: e.humanReviewTimeoutMs }), Ge({
1716
26
  source: "plugin",
1717
- table: R.tableName,
27
+ table: i.tableName,
1718
28
  timeColumn: "createdAt",
1719
- ttlMs: e.runsTtlMs ?? wt(process.env.VOLTRO_AI_FLOW_RUNS_TTL_HOURS, 2160),
1720
- envVar: _t,
29
+ ttlMs: e.runsTtlMs ?? re(process.env.VOLTRO_AI_FLOW_RUNS_TTL_HOURS, 2160),
30
+ envVar: f,
1721
31
  label: "ai flow runs",
1722
- where: Le("status", [
32
+ where: He("status", [
1723
33
  "succeeded",
1724
34
  "failed",
1725
35
  "cancelled"
1726
36
  ])
1727
37
  });
1728
- let n = Math.max(1, e.inspectPageMax ?? 200), r = { current: void 0 }, i = (e) => ({
38
+ let r = Math.max(1, e.inspectPageMax ?? 200), a = { current: void 0 }, s = (e) => ({
1729
39
  kind: "json",
1730
40
  data: e
1731
- }), a = (e, t) => ({
41
+ }), c = (e, t) => ({
1732
42
  kind: "json",
1733
43
  status: e,
1734
44
  data: { error: t }
1735
- }), o = (e, t, n) => O.promise(async () => {
1736
- let o = r.current;
1737
- if (!o) return a(503, "store not bound yet");
1738
- let s = await o.query({
45
+ }), l = (e, t, n) => Z.promise(async () => {
46
+ let r = a.current;
47
+ if (!r) return c(503, "store not bound yet");
48
+ let i = await r.query({
1739
49
  table: e,
1740
- predicate: n === void 0 ? void 0 : A("id", n),
50
+ predicate: n === void 0 ? void 0 : Q("id", n),
1741
51
  order: [{
1742
52
  column: "createdAt",
1743
53
  direction: "desc"
@@ -1762,30 +72,30 @@ var Vt = (e, t = {}) => {
1762
72
  "createdAt"
1763
73
  ] : void 0
1764
74
  });
1765
- return i({
1766
- count: s.length,
1767
- rows: s,
75
+ return s({
76
+ count: i.length,
77
+ rows: i,
1768
78
  take: t
1769
79
  });
1770
- }).pipe(O.catchAllCause(() => O.succeed(a(500, "query failed")))), s = (e, t) => {
1771
- let r = /[?&]take=(\d+)/.exec(e)?.[1], i = r === void 0 ? t : Number(r);
1772
- return Math.min(n, Math.max(1, Number.isFinite(i) ? i : t));
1773
- }, c = [{
80
+ }).pipe(Z.catchCause(() => Z.succeed(c(500, "query failed")))), d = (e, t) => {
81
+ let n = /[?&]take=(\d+)/.exec(e)?.[1], i = n === void 0 ? t : Number(n);
82
+ return Math.min(r, Math.max(1, Number.isFinite(i) ? i : t));
83
+ }, p = [{
1774
84
  method: "GET",
1775
85
  path: "/flows",
1776
86
  scope: "process",
1777
87
  description: "List flow definitions (`?take=` up to the configured max).",
1778
- handler: (e) => O.promise(async () => {
1779
- let t = r.current;
1780
- if (!t) return a(503, "store not bound yet");
1781
- let o = s(e.url, Math.min(200, n)), c = [...st()].sort((e, t) => e.name < t.name ? -1 : +(e.name > t.name)), l = c.slice(0, o).map((e) => ({
88
+ handler: (e) => Z.promise(async () => {
89
+ let t = a.current;
90
+ if (!t) return c(503, "store not bound yet");
91
+ let i = d(e.url, Math.min(200, r)), o = [...n()].sort((e, t) => e.name < t.name ? -1 : +(e.name > t.name)), l = o.slice(0, i).map((e) => ({
1782
92
  id: e.name,
1783
93
  name: e.name,
1784
94
  mode: e.mode,
1785
95
  definitionSource: "code"
1786
- })), u = l.length === o ? [] : await t.query({
96
+ })), u = l.length === i ? [] : await t.query({
1787
97
  table: "_voltro_ai_flows",
1788
- predicate: c.length === 0 ? void 0 : Re("id", c.map((e) => e.name)),
98
+ predicate: o.length === 0 ? void 0 : Ue("id", o.map((e) => e.name)),
1789
99
  order: [{
1790
100
  column: "createdAt",
1791
101
  direction: "desc"
@@ -1793,62 +103,62 @@ var Vt = (e, t = {}) => {
1793
103
  column: "id",
1794
104
  direction: "desc"
1795
105
  }],
1796
- take: o - l.length,
106
+ take: i - l.length,
1797
107
  skip: void 0,
1798
108
  projection: void 0
1799
- }), d = [...l, ...u.map((e) => ({
109
+ }), f = [...l, ...u.map((e) => ({
1800
110
  ...e,
1801
111
  definitionSource: "stored"
1802
112
  }))];
1803
- return i({
1804
- count: d.length,
1805
- rows: d,
1806
- take: o
113
+ return s({
114
+ count: f.length,
115
+ rows: f,
116
+ take: i
1807
117
  });
1808
- }).pipe(O.catchAllCause(() => O.succeed(a(500, "query failed"))))
118
+ }).pipe(Z.catchCause(() => Z.succeed(c(500, "query failed"))))
1809
119
  }, {
1810
120
  method: "GET",
1811
121
  path: "/runs",
1812
122
  scope: "process",
1813
123
  description: "List recent run summaries (`?take=` bounded); `?runId=` reads one run with payloads and steps.",
1814
- handler: (e) => o("_voltro_ai_flow_runs", s(e.url, Math.min(100, n)), new URL(e.url, "http://inspect.local").searchParams.get("runId") ?? void 0)
124
+ handler: (e) => l("_voltro_ai_flow_runs", d(e.url, Math.min(100, r)), new URL(e.url, "http://inspect.local").searchParams.get("runId") ?? void 0)
1815
125
  }];
1816
- return Me({
126
+ return Be({
1817
127
  name: t,
1818
- baseName: tr,
128
+ baseName: $,
1819
129
  description: "AI Flows — durable multi-step AI pipelines (deterministic + agentic) with human-in-the-loop, chaining, and cadence. Code-first (defineFlow) or data-driven.",
1820
130
  permissions: [
1821
131
  "store:write",
1822
132
  "inspect:read",
1823
133
  "store:changes:read"
1824
134
  ],
1825
- ...e.tables === !1 ? {} : { extendSchema: { tables: lt } },
1826
- inspectEndpoints: c,
135
+ ...e.tables === !1 ? {} : { extendSchema: { tables: o } },
136
+ inspectEndpoints: p,
1827
137
  bindDataStore: (e) => {
1828
- r.current = e;
138
+ a.current = e;
1829
139
  },
1830
- onChangeEvent: (e) => O.gen(function* () {
140
+ onChangeEvent: (e) => Z.gen(function* () {
1831
141
  if (e.table !== "_voltro_workflow_runs" || e.new === null || e.op !== "update" && e.op !== "insert") return;
1832
142
  let t = e.new;
1833
143
  if (t.tag !== "flow.run") return;
1834
- let n = r.current;
144
+ let n = a.current;
1835
145
  if (n === void 0) return;
1836
- let i = t.payload, a = (typeof i == "string" ? JSON.parse(i) : i)?.runId;
1837
- if (typeof a != "string") return;
1838
- let o = (yield* O.promise(() => n.query(N(R).where(A("id", a)).descriptor)))[0];
1839
- if (o === void 0) return;
1840
- let s = o.status, c = t.executionId, l = o.workflowStart;
1841
- s === "pending" && l?.status === "queued" && typeof c == "string" && c.length > 0 && (yield* O.promise(() => n.update(R.tableName, a, { workflowStart: dt(c) })));
1842
- let u = e.old?.status === "cancelled";
1843
- if (e.op !== "update" || t.status !== "cancelled" || u || s === "cancelled" || s === "succeeded" || s === "failed") return;
1844
- let d = (/* @__PURE__ */ new Date()).toISOString(), f = typeof o.cancelledAt == "string" ? o.cancelledAt : d;
1845
- yield* O.promise(() => n.update(R.tableName, a, {
146
+ let r = t.payload, o = (typeof r == "string" ? JSON.parse(r) : r)?.runId;
147
+ if (typeof o != "string") return;
148
+ let s = (yield* Z.promise(() => n.query(We(i).where(Q("id", o)).descriptor)))[0];
149
+ if (s === void 0) return;
150
+ let c = s.status, l = t.executionId, d = s.workflowStart;
151
+ c === "pending" && d?.status === "queued" && typeof l == "string" && l.length > 0 && (yield* Z.promise(() => n.update(i.tableName, o, { workflowStart: u(l) })));
152
+ let f = e.old?.status === "cancelled";
153
+ if (e.op !== "update" || t.status !== "cancelled" || f || c === "cancelled" || c === "succeeded" || c === "failed") return;
154
+ let p = (/* @__PURE__ */ new Date()).toISOString(), m = typeof s.cancelledAt == "string" ? s.cancelledAt : p;
155
+ yield* Z.promise(() => n.update(i.tableName, o, {
1846
156
  status: "cancelled",
1847
- cancelledAt: f,
1848
- completedAt: d
157
+ cancelledAt: m,
158
+ completedAt: p
1849
159
  }));
1850
- }).pipe(O.catchAllCause(() => O.void))
160
+ }).pipe(Z.catchCause(() => Z.void))
1851
161
  });
1852
162
  };
1853
163
  //#endregion
1854
- export { pe as BriefField, le as ChainPending, _ as ConditionOp, de as CostCompleteness, w as CostSource, _t as FLOW_RUNS_TTL_ENV, gt as FLOW_RUNS_TTL_HOURS_DEFAULT, e as FLOW_RUN_WORKFLOW, ne as FlowCadence, T as FlowCancelReceipt, fe as FlowChain, re as FlowMode, se as FlowReviewInput, me as FlowReviewReceipt, x as FlowStartReceipt, S as FlowStatus, ue as FlowStep, t as HUMAN_RESPONSE_SIGNAL_PREFIX, ht as HUMAN_REVIEW_TIMEOUT_ENV, mt as HUMAN_REVIEW_TIMEOUT_HOURS_DEFAULT, ce as HumanResponse, ie as Json, vt as MAX_CHAIN_DEPTH_DEFAULT, yt as MAX_CHAIN_DEPTH_ENV, C as MAX_STEPS_DEFAULT, te as MAX_STEPS_MAX, he as MAX_STEPS_MIN, ve as MediaArtifact, b as MediaArtifacts, _e as MediaInputSlot, v as MediaInputs, o as MediaReceipt, ge as Modality, ee as ReviewMode, c as ReviewOption, s as RunReview, h as RunSource, oe as RunStatus, i as RunStep, ae as RunStepStatus, ye as StepCondition, p as StepType, m as StepUsage, g as Visibility, dt as admittedStartHandle, R as aiFlowRunsTable, nr as aiFlowsPlugin, L as aiFlowsTable, lt as aiFlowsTables, vn as buildFlowRunExecute, De as cadenceMatches, Kn as cancelFlow, l as clampMaxSteps, ct as clearRegistry, kt as collectRefs, Qn as createFlow, wn as cronRequestId, Sn as defineFlow, er as deleteFlow, a as describeCondition, y as evaluateCondition, Mt as flowSegments, yn as flowStep, St as getAiFlowsDefaults, Xn as getFlow, ot as getRegisteredFlow, r as humanResponseSignalName, At as interpolate, u as isTruthy, Wn as launchFlow, Zn as listFlows, st as listRegisteredFlows, Bn as makeMediaGenerator, Ee as nextRuns, Nt as nonContiguousGroups, d as normalizeFlow, pt as reconcileFlowStarts, at as registerFlow, Ct as resetAiFlowsDefaults, Et as resolveHumanReviewTimeoutMs, tn as resolveIr, Dt as resolveMaxChainDepth, Yn as respondToFlow, Gn as retryFlow, En as runCadenceTick, f as sanitizeOutputKey, xt as setAiFlowsDefaults, jt as unresolvedRefs, $n as updateFlow, xn as validateFlow, Jn as waitingStepIndex };
164
+ export { w as BriefField, T as ChainPending, y as ConditionOp, E as CostCompleteness, D as CostSource, f as FLOW_RUNS_TTL_ENV, p as FLOW_RUNS_TTL_HOURS_DEFAULT, s as FLOW_RUN_WORKFLOW, O as FlowCadence, k as FlowCancelReceipt, A as FlowChain, j as FlowMode, M as FlowReviewInput, N as FlowReviewReceipt, P as FlowStartReceipt, F as FlowStatus, I as FlowStep, c as HUMAN_RESPONSE_SIGNAL_PREFIX, m as HUMAN_REVIEW_TIMEOUT_ENV, h as HUMAN_REVIEW_TIMEOUT_HOURS_DEFAULT, L as HumanResponse, R as Json, ee as MAX_CHAIN_DEPTH_DEFAULT, te as MAX_CHAIN_DEPTH_ENV, z as MAX_STEPS_DEFAULT, B as MAX_STEPS_MAX, V as MAX_STEPS_MIN, H as MediaArtifact, U as MediaArtifacts, W as MediaInputSlot, G as MediaInputs, K as MediaReceipt, q as Modality, J as ReviewMode, Y as ReviewOption, ae as RunReview, oe as RunSource, se as RunStatus, ce as RunStep, le as RunStepStatus, b as StepCondition, ue as StepType, de as StepUsage, fe as Visibility, u as admittedStartHandle, i as aiFlowRunsTable, Ke as aiFlowsPlugin, a as aiFlowsTable, o as aiFlowsTables, xe as buildFlowRunExecute, Ee as cadenceMatches, je as cancelFlow, pe as clampMaxSteps, e as clearRegistry, ge as collectRefs, Me as createFlow, Oe as cronRequestId, Ce as defineFlow, Ne as deleteFlow, x as describeCondition, S as evaluateCondition, ye as flowSegments, we as flowStep, ne as getAiFlowsDefaults, Pe as getFlow, t as getRegisteredFlow, l as humanResponseSignalName, _e as interpolate, C as isTruthy, Fe as launchFlow, Ie as listFlows, n as listRegisteredFlows, Ae as makeMediaGenerator, De as nextRuns, be as nonContiguousGroups, me as normalizeFlow, d as reconcileFlowStarts, r as registerFlow, ie as resetAiFlowsDefaults, g as resolveHumanReviewTimeoutMs, Se as resolveIr, _ as resolveMaxChainDepth, Le as respondToFlow, X as retryFlow, ke as runCadenceTick, he as sanitizeOutputKey, v as setAiFlowsDefaults, ve as unresolvedRefs, Re as updateFlow, Te as validateFlow, ze as waitingStepIndex };