@voltro/ai 0.57.0 → 0.59.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.
@@ -171,7 +171,7 @@ var u = [], d = (...e) => {
171
171
  e.close();
172
172
  } }) };
173
173
  }
174
- }), T = "iVBORw0KGgo=", E = "SUQzBAAAAAAAAA==", D = "video/mp4", O = (e, t) => ({
174
+ }), T = "iVBORw0KGgo=", E = "SUQzBAAAAAAAAA==", D = "video/mp4", O = "mock transcript", k = (e, t) => ({
175
175
  specificationVersion: "v4",
176
176
  provider: "mock",
177
177
  modelId: e,
@@ -190,7 +190,7 @@ var u = [], d = (...e) => {
190
190
  totalTokens: 0
191
191
  }
192
192
  })
193
- }), k = (e, t, n) => ({
193
+ }), A = (e, t, n) => ({
194
194
  specificationVersion: "v4",
195
195
  provider: "mock",
196
196
  modelId: e,
@@ -203,7 +203,25 @@ var u = [], d = (...e) => {
203
203
  },
204
204
  ...n === void 0 ? {} : { providerMetadata: n }
205
205
  })
206
- }), A = (e, t, n) => ({
206
+ }), j = (e, t, n) => ({
207
+ specificationVersion: "v4",
208
+ provider: "mock",
209
+ modelId: e,
210
+ doGenerate: async () => ({
211
+ text: t,
212
+ segments: [],
213
+ language: "en",
214
+ durationInSeconds: 1,
215
+ warnings: [],
216
+ response: {
217
+ timestamp: /* @__PURE__ */ new Date(),
218
+ modelId: e,
219
+ headers: {},
220
+ body: void 0
221
+ },
222
+ ...n === void 0 ? {} : { providerMetadata: n }
223
+ })
224
+ }), M = (e, t, n) => ({
207
225
  specificationVersion: "v4",
208
226
  provider: "mock",
209
227
  modelId: e,
@@ -218,31 +236,38 @@ var u = [], d = (...e) => {
218
236
  },
219
237
  ...n === void 0 ? {} : { providerMetadata: n }
220
238
  })
221
- }), j = (e) => e.apiKey !== void 0 || e.baseURL !== void 0, M = (e) => ({
239
+ }), N = (e) => e.apiKey !== void 0 || e.baseURL !== void 0, P = (e) => ({
222
240
  ...e.apiKey === void 0 ? {} : { apiKey: e.apiKey },
223
241
  ...e.baseURL === void 0 ? {} : { baseURL: e.baseURL }
224
- }), N = (o, s) => m((() => {
242
+ }), F = (o, s) => m((() => {
225
243
  switch (o.name) {
226
244
  case "mock": return w(o.model ?? "mock", o.mockText, o.script, o.providerMetadata);
227
- case "anthropic": return j(o) ? t(M(o))(o.model) : e(o.model);
228
- case "openai": return j(o) ? n(M(o))(o.model) : r(o.model);
229
- case "gateway": return j(o) ? i(M(o))(o.model) : a(o.model);
245
+ case "anthropic": return N(o) ? t(P(o))(o.model) : e(o.model);
246
+ case "openai": return N(o) ? n(P(o))(o.model) : r(o.model);
247
+ case "gateway": return N(o) ? i(P(o))(o.model) : a(o.model);
230
248
  }
231
- })(), s), P = (e) => {
249
+ })(), s), I = (e) => {
232
250
  switch (e.name) {
233
- case "mock": return O(e.model ?? "mock", e.mockMedia?.imageBase64 ?? T);
234
- case "openai": return j(e) ? n(M(e)).image(e.model) : r.image(e.model);
235
- case "gateway": return j(e) ? i(M(e)).image(e.model) : a.image(e.model);
251
+ case "mock": return k(e.model ?? "mock", e.mockMedia?.imageBase64 ?? T);
252
+ case "openai": return N(e) ? n(P(e)).image(e.model) : r.image(e.model);
253
+ case "gateway": return N(e) ? i(P(e)).image(e.model) : a.image(e.model);
236
254
  case "anthropic": throw Error("Provider 'anthropic' does not support image generation. Use 'openai' or 'gateway'.");
237
255
  }
238
- }, F = (e) => {
256
+ }, L = (e) => {
239
257
  switch (e.name) {
240
- case "mock": return k(e.model ?? "mock", e.mockMedia?.audioBase64 ?? E, e.providerMetadata);
241
- case "openai": return j(e) ? n(M(e)).speech(e.model) : r.speech(e.model);
242
- case "gateway": return j(e) ? i(M(e)).speech(e.model) : a.speech(e.model);
258
+ case "mock": return A(e.model ?? "mock", e.mockMedia?.audioBase64 ?? E, e.providerMetadata);
259
+ case "openai": return N(e) ? n(P(e)).speech(e.model) : r.speech(e.model);
260
+ case "gateway": return N(e) ? i(P(e)).speech(e.model) : a.speech(e.model);
243
261
  case "anthropic": throw Error("Provider 'anthropic' does not support speech generation. Use 'openai' or 'gateway'.");
244
262
  }
245
- }, I = (e) => {
263
+ }, R = (e) => {
264
+ switch (e.name) {
265
+ case "mock": return j(e.model ?? "mock", e.mockMedia?.transcript ?? O, e.providerMetadata);
266
+ case "openai": return N(e) ? n(P(e)).transcription(e.model) : r.transcription(e.model);
267
+ case "gateway": return N(e) ? i(P(e)).transcription(e.model) : a.transcription(e.model);
268
+ case "anthropic": throw Error("Provider 'anthropic' does not support transcription. Use 'openai' or 'gateway'.");
269
+ }
270
+ }, z = (e) => {
246
271
  switch (e.name) {
247
272
  case "mock": {
248
273
  let t = e.mockMedia, n = t?.videoBase64 === void 0 ? {
@@ -254,17 +279,17 @@ var u = [], d = (...e) => {
254
279
  data: t.videoBase64,
255
280
  mediaType: D
256
281
  };
257
- return A(e.model ?? "mock", n, e.providerMetadata);
282
+ return M(e.model ?? "mock", n, e.providerMetadata);
258
283
  }
259
- case "gateway": return j(e) ? i(M(e)).video(e.model) : a.video(e.model);
284
+ case "gateway": return N(e) ? i(P(e)).video(e.model) : a.video(e.model);
260
285
  case "openai": throw Error("Provider 'openai' does not support video generation. Use 'gateway'.");
261
286
  case "anthropic": throw Error("Provider 'anthropic' does not support video generation. Use 'gateway'.");
262
287
  }
263
- }, L = null, R = (e) => {
264
- let t = L;
265
- return L = e, t;
266
- }, z = () => L, B = (e = process.env) => {
267
- if (L) return L;
288
+ }, B = null, V = (e) => {
289
+ let t = B;
290
+ return B = e, t;
291
+ }, H = () => B, U = (e = process.env) => {
292
+ if (B) return B;
268
293
  let t = (e.AI_PROVIDER ?? "mock").toLowerCase(), n = e.AI_MODEL;
269
294
  switch (t) {
270
295
  case "mock": return {
@@ -291,4 +316,4 @@ var u = [], d = (...e) => {
291
316
  }
292
317
  };
293
318
  //#endregion
294
- export { N as a, R as c, o as d, s as f, c as g, d as h, P as i, m as l, h as m, z as n, F as o, f as p, B as r, I as s, v as t, p as u };
319
+ export { c as _, F as a, z as c, p as d, o as f, d as g, h, I as i, V as l, f as m, H as n, L as o, s as p, U as r, R as s, v as t, m as u };
package/dist/test.js CHANGED
@@ -1,4 +1,4 @@
1
- import { c as e, t } from "./provider-BOC5wBxx.js";
1
+ import { l as e, t } from "./provider-BOgeCRkg.js";
2
2
  //#region src/test/index.ts
3
3
  var n = (e) => e.turns && e.turns.length > 0 ? e.turns : e.stream && e.stream.length > 0 ? [{ text: e.stream.join("") }] : e.generate ? [{ text: e.generate.text }] : [{ text: "" }], r = (e) => {
4
4
  let r = new t(n(e));
@@ -34,18 +34,6 @@ declare type AiJsonValue = null | boolean | number | string | {
34
34
  [key: string]: AiJsonValue;
35
35
  } | AiJsonValue[];
36
36
 
37
- /**
38
- * A schema-constrained completion as a durable step.
39
- *
40
- * The schema is the step's success schema too, so the journaled value is
41
- * decoded on replay exactly as it was on the first run — a structured result
42
- * that only validated the first time through would be the worst kind of replay
43
- * bug.
44
- *
45
- * Offloaded, the schema is rendered to JSON Schema for the dispatcher (a
46
- * JavaScript Schema cannot be journaled) and the DECODE still happens here,
47
- * where the real schema exists.
48
- */
49
37
  export declare const aiObjectStep: <A, I>(options: AiObjectStepOptions<A, I>) => Effect.Effect<A, unknown>;
50
38
 
51
39
  export declare interface AiObjectStepOptions<A, I> extends AiStepBaseOptions {
@@ -394,6 +382,9 @@ declare type ProviderConfig = {
394
382
  /** base64 the mock video model yields INSTEAD of a URL — exercises the
395
383
  * bytes branch of `generateVideo`. Takes precedence over `videoUrl`. */
396
384
  readonly videoBase64?: string;
385
+ /** The text the mock transcription model returns. Lets a test assert on
386
+ * an exact transcript without a provider. */
387
+ readonly transcript?: string;
397
388
  };
398
389
  } | {
399
390
  readonly name: 'anthropic';
@@ -452,4 +443,70 @@ export declare const resolveStepPrompt: (options: Pick<AiStepBaseOptions, "promp
452
443
  readonly rendered: RenderedPrompt | undefined;
453
444
  };
454
445
 
446
+ /**
447
+ * Transcription as a durable step — with `offload`, which is the point.
448
+ *
449
+ * A ninety-minute recording is not a request. Without offloading, a worker holds
450
+ * a connection for the whole call; `aiStep` and `aiObjectStep` have had
451
+ * `offload: true` all along and transcription — the modality that runs LONGEST —
452
+ * did not. The queue row carries the SOURCE, never the bytes: putting the audio
453
+ * in the row would reintroduce exactly the cost offloading exists to remove.
454
+ */
455
+ export declare const transcribeStep: (options: TranscribeStepOptions) => Effect.Effect<{
456
+ readonly text: string;
457
+ readonly language?: string;
458
+ readonly durationSec?: number;
459
+ }, unknown>;
460
+
461
+ export declare interface TranscribeStepOptions extends Omit<AiStepBaseOptions, 'prompt' | 'system' | 'promptTemplate' | 'promptVars'> {
462
+ readonly source: TranscriptionSource;
463
+ readonly language?: string;
464
+ readonly timestamps?: TranscriptionTimestamps;
465
+ readonly diarize?: boolean;
466
+ readonly translateToEnglish?: boolean;
467
+ /** Resolve a `storageRef`. Required only for a ref source — and for an
468
+ * OFFLOADED one it must be wired on the dispatcher too, since that is the
469
+ * process that will do the read. */
470
+ readonly resolveRef?: (ref: string) => Promise<{
471
+ bytes: Uint8Array;
472
+ mediaType: string;
473
+ }>;
474
+ }
475
+
476
+ /**
477
+ * Where the audio is.
478
+ *
479
+ * `storageRef` is the one to reach for: the file is already in the app's
480
+ * storage, and resolving it there keeps tenancy, signing and lifetime with the
481
+ * component that owns them. The resolver is injected rather than imported so
482
+ * this module stays free of a storage dependency — `@voltro/ai` must not learn
483
+ * about buckets to transcribe a file.
484
+ */
485
+ declare type TranscriptionSource =
486
+ /** Resolved by the app's own storage — the case to reach for. */
487
+ {
488
+ readonly storageRef: string;
489
+ }
490
+ /** Fetched by this function. Convenient, but the bytes do pass through this
491
+ * process: the SDK takes bytes or base64 and never a location. */
492
+ | {
493
+ readonly url: string;
494
+ }
495
+ /** Already in hand. The one that costs memory by construction. */
496
+ | {
497
+ readonly bytes: Uint8Array;
498
+ readonly mediaType: string;
499
+ };
500
+
501
+ /** What a `transcribeStep` journals. Structural, because a durable step's
502
+ * success schema is what a replay decodes through — see `AiStepText`. */
503
+ export declare const TranscriptionStepResult: Schema.Struct<{
504
+ text: typeof Schema.String;
505
+ language: Schema.optional<typeof Schema.String>;
506
+ durationSec: Schema.optional<typeof Schema.Number>;
507
+ }>;
508
+
509
+ /** How much timestamp detail to ask for. Providers charge for it. */
510
+ declare type TranscriptionTimestamps = 'none' | 'segment' | 'word';
511
+
455
512
  export { }
package/dist/workflow.js CHANGED
@@ -1,17 +1,17 @@
1
- import { r as e } from "./provider-BOC5wBxx.js";
2
- import { C as t, D as n, E as r, H as i, U as a, m as o, o as s, p as c, s as l, t as u, y as d, z as f } from "./inferenceQueue-CJZ4xw3R.js";
3
- import { Effect as p, Schema as m } from "effect";
4
- import { eq as h } from "@voltro/database";
5
- import { CurrentWorkflowExecutionId as g, awaitSignalSuspending as _, step as v, suspendForBudget as y } from "@voltro/workflow";
1
+ import { r as e } from "./provider-BOgeCRkg.js";
2
+ import { B as t, D as n, G as r, K as i, O as a, b as o, m as s, o as c, p as l, s as u, t as d, w as f, y as p } from "./inferenceQueue-CS1VouiW.js";
3
+ import { Effect as m, Schema as h } from "effect";
4
+ import { eq as g } from "@voltro/database";
5
+ import { CurrentWorkflowExecutionId as _, awaitSignalSuspending as v, step as y, suspendForBudget as b } from "@voltro/workflow";
6
6
  //#region src/inferStep.ts
7
- var b = {
7
+ var x = {
8
8
  maxAttempts: 4,
9
9
  strategy: "exponential",
10
10
  baseDelay: "1 second",
11
11
  maxDelay: "30 seconds",
12
12
  jitter: !0,
13
13
  respectRetryAfter: !0
14
- }, x = 36e5, S = "ai-usd", C = (e, t, n, r) => {
14
+ }, S = 36e5, C = "ai-usd", w = (e, t, n, r) => {
15
15
  let i = r === void 0 ? {} : {
16
16
  promptId: r.promptId,
17
17
  promptVersion: r.digest,
@@ -24,14 +24,14 @@ var b = {
24
24
  ...t === void 0 ? {} : { system: t }
25
25
  } : {
26
26
  ...i,
27
- promptDigest: o(e),
27
+ promptDigest: s(e),
28
28
  promptChars: e.length,
29
29
  ...t === void 0 ? {} : {
30
- systemDigest: o(t),
30
+ systemDigest: s(t),
31
31
  systemChars: t.length
32
32
  }
33
33
  };
34
- }, w = (e) => c(e.prompt) ? {
34
+ }, T = (e) => l(e.prompt) ? {
35
35
  text: e.prompt.prompt,
36
36
  system: e.system ?? e.prompt.system,
37
37
  rendered: e.prompt
@@ -39,68 +39,68 @@ var b = {
39
39
  text: e.prompt,
40
40
  system: e.system,
41
41
  rendered: void 0
42
- }, T = (e) => ({
42
+ }, E = (e) => ({
43
43
  provider: String(e.provider ?? "unknown"),
44
44
  model: String(e.model ?? "unknown")
45
- }), E = (e, t, n, r, a) => {
46
- let o = e.store;
47
- if (o === void 0) return p.void;
48
- let { provider: s, model: c } = T(t), l = f(r.providerMetadata);
49
- return i(o, {
50
- provider: s,
51
- model: c,
52
- operation: n,
45
+ }), D = (e, n, i, a, o) => {
46
+ let s = e.store;
47
+ if (s === void 0) return m.void;
48
+ let { provider: c, model: l } = E(n), u = t(a.providerMetadata);
49
+ return r(s, {
50
+ provider: c,
51
+ model: l,
52
+ operation: i,
53
53
  agent: e.name,
54
- usage: r.usage,
54
+ usage: a.usage,
55
55
  ...e.tenantId === void 0 ? {} : { tenantId: e.tenantId },
56
- ...l === void 0 ? {} : { actualCostUsd: l },
57
- ...a === void 0 ? {} : { prompt: a }
58
- }).pipe(p.asVoid, p.catchAllCause(() => p.void));
59
- }, D = (e, t) => {
56
+ ...u === void 0 ? {} : { actualCostUsd: u },
57
+ ...o === void 0 ? {} : { prompt: o }
58
+ }).pipe(m.asVoid, m.catchAllCause(() => m.void));
59
+ }, O = (e, t) => {
60
60
  let n = e.store;
61
- return n === void 0 || t === void 0 ? p.void : d(n, {
61
+ return n === void 0 || t === void 0 ? m.void : p(n, {
62
62
  ...t.definition,
63
63
  digest: t.digest
64
- }).pipe(p.asVoid, p.catchAllCause(() => p.void));
65
- }, O = m.Struct({
66
- text: m.String,
67
- inputTokens: m.NullOr(m.Number),
68
- outputTokens: m.NullOr(m.Number),
69
- totalTokens: m.NullOr(m.Number)
70
- }), k = (e) => typeof e == "object" && !!e && e.__voltro_ai_error === !0, A = class extends Error {
64
+ }).pipe(m.asVoid, m.catchAllCause(() => m.void));
65
+ }, k = h.Struct({
66
+ text: h.String,
67
+ inputTokens: h.NullOr(h.Number),
68
+ outputTokens: h.NullOr(h.Number),
69
+ totalTokens: h.NullOr(h.Number)
70
+ }), A = (e) => typeof e == "object" && !!e && e.__voltro_ai_error === !0, j = class extends Error {
71
71
  attempts;
72
72
  constructor(e, t, n) {
73
73
  super(`aiStep('${e}'): the offloaded model call gave up after ${n} attempt(s): ${t}. The queued call is in _voltro_ai_inferences with status 'failed' — the Flow tab shows it with the provider's own message.`), this.name = "AiOffloadError", this.attempts = n;
74
74
  }
75
- }, j = class extends Error {
75
+ }, M = class extends Error {
76
76
  constructor(e) {
77
77
  super(`aiStep('${e}'): offload: true needs \`store\` — the queued call lives in a table and the dispatcher reads it from there. Pass ctx.store.`), this.name = "AiOffloadMisuseError";
78
78
  }
79
- }, M = (e, t, n, r, i) => p.gen(function* () {
80
- let a = e.store;
81
- if (a === void 0) return yield* p.die(new j(e.name));
82
- let o = yield* g;
83
- if (o === void 0) return yield* p.die(/* @__PURE__ */ Error(`aiStep('${e.name}'): offload: true is only valid inside a workflow body — there is no execution to suspend here.`));
84
- let { provider: c, model: d } = T(t), f = l(o, e.name), m = yield* p.promise(() => a.query({
79
+ }, N = (e, t, n, r, i, a) => m.gen(function* () {
80
+ let o = e.store;
81
+ if (o === void 0) return yield* m.die(new M(e.name));
82
+ let s = yield* _;
83
+ if (s === void 0) return yield* m.die(/* @__PURE__ */ Error(`aiStep('${e.name}'): offload: true is only valid inside a workflow body — there is no execution to suspend here.`));
84
+ let { provider: l, model: f } = E(t), p = u(s, e.name), h = yield* m.promise(() => o.query({
85
85
  table: "_voltro_workflow_runs",
86
- predicate: h("executionId", o),
86
+ predicate: g("executionId", s),
87
87
  order: [],
88
88
  take: 1,
89
89
  skip: void 0,
90
90
  projection: void 0
91
- })), _ = String(m[0]?.tag ?? ""), v = m[0]?.id;
92
- return yield* p.promise(() => a.insertIgnore(u, {
93
- id: f,
91
+ })), v = String(h[0]?.tag ?? ""), y = h[0]?.id;
92
+ return yield* m.promise(() => o.insertIgnore(d, {
93
+ id: p,
94
94
  tenantId: e.tenantId ?? null,
95
- executionId: o,
96
- workflowName: _,
97
- runId: typeof v == "string" ? v : null,
98
- signalName: s(f),
95
+ executionId: s,
96
+ workflowName: v,
97
+ runId: typeof y == "string" ? y : null,
98
+ signalName: c(p),
99
99
  stepName: e.name,
100
100
  status: "pending",
101
101
  kind: n,
102
- provider: c,
103
- model: d,
102
+ provider: l,
103
+ model: f,
104
104
  prompt: i.text,
105
105
  system: i.system ?? null,
106
106
  promptId: i.rendered?.promptId ?? null,
@@ -109,120 +109,156 @@ var b = {
109
109
  maxTokens: e.maxTokens ?? null,
110
110
  providerOptions: e.providerOptions ?? null,
111
111
  jsonSchema: r,
112
+ ...a === void 0 ? {} : { transcription: a },
112
113
  attempts: 0,
113
114
  enqueuedAt: /* @__PURE__ */ new Date()
114
- }, { conflictColumns: ["id"] })), f;
115
- }), N = (e, t, n, r, i, a) => p.gen(function* () {
116
- let o = yield* v({
115
+ }, { conflictColumns: ["id"] })), p;
116
+ }), P = (e, t, n, r, i, a, o) => m.gen(function* () {
117
+ let s = yield* y({
117
118
  name: `${e.name}:enqueue`,
118
- success: m.String,
119
+ success: h.String,
119
120
  input: i,
120
- execute: M(e, t, n, r, a)
121
+ execute: N(e, t, n, r, a, o)
121
122
  });
122
- yield* D(e, a.rendered);
123
- let c = yield* _({ store: e.store }, {
124
- name: s(o),
125
- schema: m.Unknown,
123
+ yield* O(e, a.rendered);
124
+ let l = yield* v({ store: e.store }, {
125
+ name: c(s),
126
+ schema: h.Unknown,
126
127
  timeoutMs: e.offloadTimeoutMs ?? 36e5
127
128
  });
128
- return k(c) ? yield* p.die(new A(e.name, c.message, c.attempts)) : c;
129
- }), P = class extends Error {
129
+ return A(l) ? yield* m.die(new j(e.name, l.message, l.attempts)) : l;
130
+ }), F = class extends Error {
130
131
  constructor(e) {
131
132
  super(`aiStep('${e}'): budget needs \`store\` — the reservation counter and the hold both live in tables. Pass ctx.store.`), this.name = "AiBudgetMisuseError";
132
133
  }
133
- }, F = (e) => p.gen(function* () {
134
+ }, I = (e) => m.gen(function* () {
134
135
  let t = e.budget;
135
136
  if (t === void 0) return;
136
137
  let n = e.store;
137
- if (n === void 0) return yield* p.die(new P(e.name));
138
- let r = e.tenantId ?? null, i = t.name ?? "ai-usd", o = () => a(n, {
138
+ if (n === void 0) return yield* m.die(new F(e.name));
139
+ let r = e.tenantId ?? null, a = t.name ?? "ai-usd", o = () => i(n, {
139
140
  tenantId: r,
140
141
  limitUsd: t.limitUsd,
141
142
  addUsd: 0,
142
143
  ...t.since === void 0 ? {} : { since: t.since }
143
- }).pipe(p.as(null), p.catchTag("AiBudgetExceeded", (e) => p.succeed(e))), s = () => t.estimateUsd === void 0 ? p.void : a(n, {
144
+ }).pipe(m.as(null), m.catchTag("AiBudgetExceeded", (e) => m.succeed(e))), s = () => t.estimateUsd === void 0 ? m.void : i(n, {
144
145
  tenantId: r,
145
146
  limitUsd: t.limitUsd,
146
147
  addUsd: t.estimateUsd,
147
148
  ...t.since === void 0 ? {} : { since: t.since }
148
149
  }), c = yield* o();
149
150
  if (c === null) return yield* s();
150
- if ((t.onExceeded ?? "fail") !== "suspend") return yield* p.fail(c);
151
- let l = yield* g;
152
- return l === void 0 ? yield* p.fail(c) : (yield* y({
151
+ if ((t.onExceeded ?? "fail") !== "suspend") return yield* m.fail(c);
152
+ let l = yield* _;
153
+ return l === void 0 ? yield* m.fail(c) : (yield* b({
153
154
  store: n,
154
- budget: i,
155
+ budget: a,
155
156
  tenantId: r,
156
157
  executionId: l,
157
- workflowName: yield* I(n, l),
158
+ workflowName: yield* L(n, l),
158
159
  stepName: e.name,
159
160
  spentMicroUsd: Math.round(c.spentUsd * 1e6),
160
161
  limitMicroUsd: Math.round(t.limitUsd * 1e6),
161
- hasHeadroom: o().pipe(p.map((e) => e === null)),
162
+ hasHeadroom: o().pipe(m.map((e) => e === null)),
162
163
  ...t.holdTimeoutMs === void 0 ? {} : { timeoutMs: t.holdTimeoutMs },
163
164
  ...t.recheckEveryMs === void 0 ? {} : { recheckEveryMs: t.recheckEveryMs }
164
- }).pipe(p.catchAll((e) => p.die(e))), yield* s());
165
- }), I = (e, t) => p.promise(async () => {
165
+ }).pipe(m.catchAll((e) => m.die(e))), yield* s());
166
+ }), L = (e, t) => m.promise(async () => {
166
167
  let n = await e.query({
167
168
  table: "_voltro_workflow_runs",
168
- predicate: h("executionId", t),
169
+ predicate: g("executionId", t),
169
170
  order: [],
170
171
  take: 1,
171
172
  skip: void 0,
172
173
  projection: void 0
173
174
  });
174
175
  return String(n[0]?.tag ?? "");
175
- }), L = (t) => {
176
- let n = t.provider ?? e(), i = w(t), a = {
177
- ...T(n),
176
+ }), R = (t) => {
177
+ let r = t.provider ?? e(), i = T(t), a = {
178
+ ...E(r),
178
179
  operation: "generateText",
179
180
  offloaded: t.offload === !0,
180
- ...C(i.text, i.system, t.recordPrompt ?? "digest", i.rendered)
181
- }, o = (e) => t.budget === void 0 ? e : p.zipRight(F(t), e);
182
- return t.offload === !0 ? o(N(t, n, "text", null, a, i)) : o(v({
181
+ ...w(i.text, i.system, t.recordPrompt ?? "digest", i.rendered)
182
+ }, o = (e) => t.budget === void 0 ? e : m.zipRight(I(t), e);
183
+ return t.offload === !0 ? o(P(t, r, "text", null, a, i)) : o(y({
183
184
  name: t.name,
184
- success: O,
185
+ success: k,
185
186
  input: a,
186
- retry: t.retry ?? b,
187
- execute: r({
187
+ retry: t.retry ?? x,
188
+ execute: n({
188
189
  prompt: i.text,
189
- provider: n,
190
+ provider: r,
190
191
  ...i.system === void 0 ? {} : { system: i.system },
191
192
  ...t.fallbacks === void 0 ? {} : { fallbacks: t.fallbacks },
192
193
  ...t.maxTokens === void 0 ? {} : { maxTokens: t.maxTokens },
193
194
  ...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions }
194
- }).pipe(p.tap((e) => E(t, n, "generateText", e, i.rendered)), p.tap(() => D(t, i.rendered)), p.map((e) => ({
195
+ }).pipe(m.tap((e) => D(t, r, "generateText", e, i.rendered)), m.tap(() => O(t, i.rendered)), m.map((e) => ({
195
196
  text: e.text,
196
197
  inputTokens: e.usage.inputTokens ?? null,
197
198
  outputTokens: e.usage.outputTokens ?? null,
198
199
  totalTokens: e.usage.totalTokens ?? null
199
200
  })))
200
201
  }));
201
- }, R = (r) => {
202
- let i = r.provider ?? e(), a = w(r), o = {
203
- ...T(i),
202
+ }, z = h.Struct({
203
+ text: h.String,
204
+ language: h.optional(h.String),
205
+ durationSec: h.optional(h.Number)
206
+ }), B = (t) => {
207
+ let n = t.provider ?? e(), r = {
208
+ source: t.source,
209
+ ...t.language === void 0 ? {} : { language: t.language },
210
+ ...t.timestamps === void 0 ? {} : { timestamps: t.timestamps },
211
+ ...t.diarize === void 0 ? {} : { diarize: t.diarize },
212
+ ...t.translateToEnglish === void 0 ? {} : { translateToEnglish: t.translateToEnglish }
213
+ }, i = {
214
+ ...E(n),
215
+ operation: "transcribe",
216
+ offloaded: t.offload === !0
217
+ }, a = (e) => t.budget === void 0 ? e : m.zipRight(I(t), e);
218
+ return t.offload === !0 ? a(P(t, n, "transcription", null, i, {
219
+ text: "",
220
+ system: void 0,
221
+ rendered: void 0
222
+ }, r)) : a(y({
223
+ name: t.name,
224
+ success: z,
225
+ input: i,
226
+ retry: t.retry ?? x,
227
+ execute: o({
228
+ ...r,
229
+ provider: n,
230
+ ...t.resolveRef === void 0 ? {} : { resolveRef: t.resolveRef }
231
+ }).pipe(m.map((e) => ({
232
+ text: e.text,
233
+ ...e.language === void 0 ? {} : { language: e.language },
234
+ ...e.durationSec === void 0 ? {} : { durationSec: e.durationSec }
235
+ })))
236
+ }));
237
+ }, V = (t) => {
238
+ let n = t.provider ?? e(), r = T(t), i = {
239
+ ...E(n),
204
240
  operation: "generateObject",
205
- offloaded: r.offload === !0,
206
- ...C(a.text, a.system, r.recordPrompt ?? "digest", a.rendered)
207
- }, s = (e) => r.budget === void 0 ? e : p.zipRight(F(r), e);
208
- return r.offload === !0 ? s(p.gen(function* () {
209
- let e = yield* n(r.schema, "aiObjectStep"), t = yield* N(r, i, "object", e, o, a);
210
- return yield* m.decodeUnknown(r.schema)(t);
211
- })) : s(v({
212
- name: r.name,
213
- success: r.schema,
214
- input: o,
215
- retry: r.retry ?? b,
216
- execute: t({
217
- prompt: a.text,
218
- schema: r.schema,
219
- provider: i,
220
- ...a.system === void 0 ? {} : { system: a.system },
221
- ...r.fallbacks === void 0 ? {} : { fallbacks: r.fallbacks },
222
- ...r.maxTokens === void 0 ? {} : { maxTokens: r.maxTokens },
223
- ...r.providerOptions === void 0 ? {} : { providerOptions: r.providerOptions }
224
- }).pipe(p.tap((e) => E(r, i, "generateObject", e, a.rendered)), p.tap(() => D(r, a.rendered)), p.map((e) => e.object))
241
+ offloaded: t.offload === !0,
242
+ ...w(r.text, r.system, t.recordPrompt ?? "digest", r.rendered)
243
+ }, o = (e) => t.budget === void 0 ? e : m.zipRight(I(t), e);
244
+ return t.offload === !0 ? o(m.gen(function* () {
245
+ let e = yield* a(t.schema, "aiObjectStep"), o = yield* P(t, n, "object", e, i, r);
246
+ return yield* h.decodeUnknown(t.schema)(o);
247
+ })) : o(y({
248
+ name: t.name,
249
+ success: t.schema,
250
+ input: i,
251
+ retry: t.retry ?? x,
252
+ execute: f({
253
+ prompt: r.text,
254
+ schema: t.schema,
255
+ provider: n,
256
+ ...r.system === void 0 ? {} : { system: r.system },
257
+ ...t.fallbacks === void 0 ? {} : { fallbacks: t.fallbacks },
258
+ ...t.maxTokens === void 0 ? {} : { maxTokens: t.maxTokens },
259
+ ...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions }
260
+ }).pipe(m.tap((e) => D(t, n, "generateObject", e, r.rendered)), m.tap(() => O(t, r.rendered)), m.map((e) => e.object))
225
261
  }));
226
262
  };
227
263
  //#endregion
228
- export { b as AI_STEP_RETRY, P as AiBudgetMisuseError, A as AiOffloadError, j as AiOffloadMisuseError, S as DEFAULT_AI_BUDGET_NAME, x as DEFAULT_OFFLOAD_TIMEOUT_MS, R as aiObjectStep, L as aiStep, o as promptDigest, C as promptRecordFor, w as resolveStepPrompt };
264
+ export { x as AI_STEP_RETRY, F as AiBudgetMisuseError, j as AiOffloadError, M as AiOffloadMisuseError, C as DEFAULT_AI_BUDGET_NAME, S as DEFAULT_OFFLOAD_TIMEOUT_MS, z as TranscriptionStepResult, V as aiObjectStep, R as aiStep, s as promptDigest, w as promptRecordFor, T as resolveStepPrompt, B as transcribeStep };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/ai",
3
- "version": "0.57.0",
3
+ "version": "0.59.0",
4
4
  "description": "Effect-native AI primitives — generateText / generateObject / streamText, tools, agents, media generation, cost tracking + budgets, and provider fallback.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -57,10 +57,10 @@
57
57
  "@ai-sdk/gateway": "^4.0.47",
58
58
  "@ai-sdk/openai": "^4.0.37",
59
59
  "@ai-sdk/provider": "^4.0.7",
60
- "@voltro/cache": "0.57.0",
61
- "@voltro/database": "0.57.0",
62
- "@voltro/protocol": "0.57.0",
63
- "@voltro/workflow": "0.57.0",
60
+ "@voltro/cache": "0.59.0",
61
+ "@voltro/database": "0.59.0",
62
+ "@voltro/protocol": "0.59.0",
63
+ "@voltro/workflow": "0.59.0",
64
64
  "ai": "^7.0.59"
65
65
  },
66
66
  "peerDependencies": {