@voltro/ai 0.74.0 → 0.75.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.
@@ -1,5 +1,6 @@
1
1
  import { DataStore } from '@voltro/database';
2
2
  import { Effect } from 'effect';
3
+ import { PluginMediaPersistMetadata } from '@voltro/protocol';
3
4
  import { Runtime } from 'effect';
4
5
  import { Schema } from 'effect';
5
6
  import { StepRetryPolicy } from '@voltro/workflow';
@@ -244,16 +245,23 @@ declare type GatewayModel = `${GatewayCreator}/${string}`;
244
245
  *
245
246
  * The queue row is the job's identity, allocated before the first paid call.
246
247
  * A replay finds the row; a dispatcher that dies mid-job leaves a lease that
247
- * expires — and the reclaiming dispatcher does NOT submit again: the provider
248
- * has no lookup, so the outcome is reported to the run as `unknown`
249
- * (`AiOffloadError.outcome`) rather than paid for twice. Artifacts are
250
- * persisted through the storage plugin's `mediaPersist` capability under
251
- * `<row>#<attempt>#<index>`, and the run receives URLs and ref ids.
248
+ * expires — and the reclaiming dispatcher does NOT submit again. With a
249
+ * provider registered through `registerMediaTaskProvider` the row also
250
+ * carries the provider's task handle, so the reclaim polls the same task and
251
+ * the run receives its result. A built-in generator has no lookup — and a
252
+ * task job whose handle never reached the row cannot be found either — so
253
+ * those are reported to the run as `unknown` (`AiOffloadError.outcome`)
254
+ * rather than paid for twice. Artifacts are persisted through the storage
255
+ * plugin's `mediaPersist` capability under `<row>#<attempt>#<index>`, and
256
+ * the run receives URLs and ref ids.
252
257
  */
253
258
  export declare const mediaStep: (options: MediaStepOptions) => Effect.Effect<MediaStepResult, unknown>;
254
259
 
255
- export declare interface MediaStepOptions extends Omit<AiStepBaseOptions, 'system' | 'promptTemplate' | 'promptVars' | 'offload' | 'tools' | 'maxSteps' | 'toolContext' | 'fallbacks' | 'maxTokens'> {
260
+ export declare interface MediaStepOptions extends Omit<AiStepBaseOptions, 'system' | 'promptTemplate' | 'promptVars' | 'offload' | 'tools' | 'maxSteps' | 'toolContext' | 'fallbacks' | 'maxTokens' | 'provider'> {
256
261
  readonly modality: 'image' | 'video' | 'speech';
262
+ /** A built-in provider, or the name of one registered with
263
+ * `registerMediaTaskProvider` — the dispatcher routes by the name. */
264
+ readonly provider?: ProviderConfig | RegisteredMediaTaskConfig;
257
265
  /** Provider parameters — `n`, `size`, `aspectRatio`, `seed` for an image;
258
266
  * `durationSeconds`, `resolution`, `fps` for a video; `voice`, `format` for
259
267
  * speech. Passed through to the generator, journaled with the job. */
@@ -263,6 +271,9 @@ export declare interface MediaStepOptions extends Omit<AiStepBaseOptions, 'syste
263
271
  readonly inputs?: Record<string, unknown>;
264
272
  /** Required: a media job is always an external job with a durable identity. */
265
273
  readonly store: DataStore;
274
+ /** Who the stored artifacts belong to, how they are served, and the tags they
275
+ * are found by — handed to the storage plugin's `mediaPersist` as-is. */
276
+ readonly persist?: PluginMediaPersistMetadata;
266
277
  }
267
278
 
268
279
  export declare interface MediaStepResult {
@@ -490,6 +501,15 @@ declare type ProviderConfig = {
490
501
  */
491
502
  declare type ProviderFallbacks = ReadonlyArray<ProviderConfig>;
492
503
 
504
+ /**
505
+ * The provider config `mediaStep` accepts for a registered task provider —
506
+ * named, not enumerated, exactly like `RegisteredSpeechConfig`.
507
+ */
508
+ declare interface RegisteredMediaTaskConfig {
509
+ readonly name: string;
510
+ readonly model?: string;
511
+ }
512
+
493
513
  /** What `.render(vars)` produces — a stamp plus the text to send. */
494
514
  declare interface RenderedPrompt extends PromptStamp {
495
515
  readonly prompt: string;
package/dist/workflow.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { r as e } from "./provider-Cts1BRhY.js";
2
- import { D as t, E as n, O as r, R as i, U as a, Z as o, b as s, m as c, o as l, p as u, s as d, t as f, w as p, y as m } from "./inferenceQueue-CXEVU6mI.js";
2
+ import { D as t, O as n, T as r, V as i, b as a, k as o, m as s, o as c, p as l, q as u, s as d, t as f, tt as p, y as m } from "./inferenceQueue-CdWTzRp7.js";
3
3
  import { Effect as h, Schema as g } from "effect";
4
4
  import { eq as _ } from "@voltro/database";
5
5
  import { CurrentWorkflowExecutionId as v, awaitSignalSuspending as y, step as b, suspendForBudget as x } from "@voltro/workflow";
@@ -24,14 +24,14 @@ var S = {
24
24
  ...t === void 0 ? {} : { system: t }
25
25
  } : {
26
26
  ...i,
27
- promptDigest: c(e),
27
+ promptDigest: s(e),
28
28
  promptChars: e.length,
29
29
  ...t === void 0 ? {} : {
30
- systemDigest: c(t),
30
+ systemDigest: s(t),
31
31
  systemChars: t.length
32
32
  }
33
33
  };
34
- }, E = (e) => u(e.prompt) ? {
34
+ }, E = (e) => l(e.prompt) ? {
35
35
  text: e.prompt.prompt,
36
36
  system: e.system ?? e.prompt.system,
37
37
  rendered: e.prompt
@@ -40,22 +40,22 @@ var S = {
40
40
  system: e.system,
41
41
  rendered: void 0
42
42
  }, D = (e) => ({
43
- provider: String(e.provider ?? "unknown"),
43
+ provider: String(e.name),
44
44
  model: String(e.model ?? "unknown")
45
- }), O = (e, t, n, r, o) => {
46
- let s = e.store;
47
- if (s === void 0) return h.void;
48
- let { provider: c, model: l } = D(t), u = i(r.providerMetadata);
49
- return a(s, {
50
- provider: c,
51
- model: l,
45
+ }), O = (e, t, n, r, a) => {
46
+ let o = e.store;
47
+ if (o === void 0) return h.void;
48
+ let { provider: s, model: c } = D(t), l = i(r.providerMetadata);
49
+ return u(o, {
50
+ provider: s,
51
+ model: c,
52
52
  operation: n,
53
53
  agent: e.name,
54
54
  usage: r.usage,
55
55
  ...e.tenantId === void 0 ? {} : { tenantId: e.tenantId },
56
- ...u === void 0 ? {} : { actualCostUsd: u },
57
- ...o === void 0 ? {} : { prompt: o }
58
- }).pipe(h.asVoid, h.catchAllCause(() => h.void));
56
+ ...l === void 0 ? {} : { actualCostUsd: l },
57
+ ...a === void 0 ? {} : { prompt: a }
58
+ });
59
59
  }, k = (e, t) => {
60
60
  let n = e.store;
61
61
  return n === void 0 || t === void 0 ? h.void : m(n, {
@@ -80,11 +80,11 @@ var S = {
80
80
  }, P = (e, t, n, r, i, a, o) => h.gen(function* () {
81
81
  let s = e.store;
82
82
  if (s === void 0) return yield* h.die(new N(e.name));
83
- let c = yield* v;
84
- if (c === void 0) return yield* h.die(/* @__PURE__ */ Error(`aiStep('${e.name}'): offload: true is only valid inside a workflow body — there is no execution to suspend here.`));
85
- let { provider: u, model: p } = D(t), m = d(c, e.name), g = yield* h.promise(() => s.query({
83
+ let l = yield* v;
84
+ if (l === void 0) return yield* h.die(/* @__PURE__ */ Error(`aiStep('${e.name}'): offload: true is only valid inside a workflow body — there is no execution to suspend here.`));
85
+ let { provider: u, model: p } = D(t), m = d(l, e.name), g = yield* h.promise(() => s.query({
86
86
  table: "_voltro_workflow_runs",
87
- predicate: _("executionId", c),
87
+ predicate: _("executionId", l),
88
88
  order: [],
89
89
  take: 1,
90
90
  skip: void 0,
@@ -93,10 +93,10 @@ var S = {
93
93
  return yield* h.promise(() => s.insertIgnore(f, {
94
94
  id: m,
95
95
  tenantId: e.tenantId ?? null,
96
- executionId: c,
96
+ executionId: l,
97
97
  workflowName: y,
98
98
  runId: typeof b == "string" ? b : null,
99
- signalName: l(m),
99
+ signalName: c(m),
100
100
  stepName: e.name,
101
101
  status: "pending",
102
102
  kind: n,
@@ -117,7 +117,7 @@ var S = {
117
117
  enqueuedAt: /* @__PURE__ */ new Date()
118
118
  }, { conflictColumns: ["id"] })), m;
119
119
  }), F = (e, t, n, r, i, a, o, s) => h.gen(function* () {
120
- let c = yield* b({
120
+ let l = yield* b({
121
121
  name: `${e.name}:enqueue`,
122
122
  success: g.String,
123
123
  input: i,
@@ -125,7 +125,7 @@ var S = {
125
125
  });
126
126
  yield* k(e, a.rendered);
127
127
  let u = yield* y({ store: e.store }, {
128
- name: l(c),
128
+ name: c(l),
129
129
  schema: g.Unknown,
130
130
  timeoutMs: e.offloadTimeoutMs ?? 36e5
131
131
  });
@@ -139,12 +139,12 @@ var S = {
139
139
  if (t === void 0) return;
140
140
  let n = e.store;
141
141
  if (n === void 0) return yield* h.die(new I(e.name));
142
- let r = e.tenantId ?? null, i = t.name ?? "ai-usd", a = yield* v, s = () => o(n, {
142
+ let r = e.tenantId ?? null, i = t.name ?? "ai-usd", a = yield* v, o = () => p(n, {
143
143
  tenantId: r,
144
144
  limitUsd: t.limitUsd,
145
145
  addUsd: 0,
146
146
  ...t.since === void 0 ? {} : { since: t.since }
147
- }).pipe(h.as(null), h.catchTag("AiBudgetExceeded", (e) => h.succeed(e))), c = () => t.estimateUsd === void 0 ? h.void : o(n, {
147
+ }).pipe(h.as(null), h.catchTag("AiBudgetExceeded", (e) => h.succeed(e))), s = () => t.estimateUsd === void 0 ? h.void : p(n, {
148
148
  tenantId: r,
149
149
  limitUsd: t.limitUsd,
150
150
  addUsd: t.estimateUsd,
@@ -154,20 +154,20 @@ var S = {
154
154
  e.name
155
155
  ])) },
156
156
  ...t.since === void 0 ? {} : { since: t.since }
157
- }).pipe(h.asVoid), l = yield* s();
158
- return l === null ? yield* c() : (t.onExceeded ?? "fail") !== "suspend" || a === void 0 ? yield* h.fail(l) : (yield* x({
157
+ }).pipe(h.asVoid), c = yield* o();
158
+ return c === null ? yield* s() : (t.onExceeded ?? "fail") !== "suspend" || a === void 0 ? yield* h.fail(c) : (yield* x({
159
159
  store: n,
160
160
  budget: i,
161
161
  tenantId: r,
162
162
  executionId: a,
163
163
  workflowName: yield* R(n, a),
164
164
  stepName: e.name,
165
- spentMicroUsd: Math.round(l.spentUsd * 1e6),
165
+ spentMicroUsd: Math.round(c.spentUsd * 1e6),
166
166
  limitMicroUsd: Math.round(t.limitUsd * 1e6),
167
- hasHeadroom: s().pipe(h.map((e) => e === null)),
167
+ hasHeadroom: o().pipe(h.map((e) => e === null)),
168
168
  ...t.holdTimeoutMs === void 0 ? {} : { timeoutMs: t.holdTimeoutMs },
169
169
  ...t.recheckEveryMs === void 0 ? {} : { recheckEveryMs: t.recheckEveryMs }
170
- }).pipe(h.catchAll((e) => h.die(e))), yield* c());
170
+ }).pipe(h.catchAll((e) => h.die(e))), yield* s());
171
171
  }), R = (e, t) => h.promise(async () => {
172
172
  let n = await e.query({
173
173
  table: "_voltro_workflow_runs",
@@ -178,29 +178,29 @@ var S = {
178
178
  projection: void 0
179
179
  });
180
180
  return String(n[0]?.tag ?? "");
181
- }), z = (n) => {
182
- let r = n.provider ?? e(), i = E(n), a = {
181
+ }), z = (t) => {
182
+ let r = t.provider ?? e(), i = E(t), a = {
183
183
  ...D(r),
184
184
  operation: "generateText",
185
- offloaded: n.offload === !0,
186
- ...T(i.text, i.system, n.recordPrompt ?? "digest", i.rendered)
187
- }, o = (e) => n.budget === void 0 ? e : h.zipRight(L(n), e);
188
- return n.offload === !0 ? o(F(n, r, "text", null, a, i)) : o(b({
189
- name: n.name,
185
+ offloaded: t.offload === !0,
186
+ ...T(i.text, i.system, t.recordPrompt ?? "digest", i.rendered)
187
+ }, o = (e) => t.budget === void 0 ? e : h.zipRight(L(t), e);
188
+ return t.offload === !0 ? o(F(t, r, "text", null, a, i)) : o(b({
189
+ name: t.name,
190
190
  success: A,
191
191
  input: a,
192
- retry: n.retry ?? S,
193
- execute: t({
192
+ retry: t.retry ?? S,
193
+ execute: n({
194
194
  prompt: i.text,
195
195
  provider: r,
196
196
  ...i.system === void 0 ? {} : { system: i.system },
197
- ...n.fallbacks === void 0 ? {} : { fallbacks: n.fallbacks },
198
- ...n.maxTokens === void 0 ? {} : { maxTokens: n.maxTokens },
199
- ...n.providerOptions === void 0 ? {} : { providerOptions: n.providerOptions },
200
- ...n.tools === void 0 ? {} : { tools: n.tools },
201
- ...n.maxSteps === void 0 ? {} : { maxSteps: n.maxSteps },
202
- ...n.toolContext === void 0 ? {} : { toolContext: n.toolContext }
203
- }).pipe(h.tap((e) => O(n, r, "generateText", e, i.rendered)), h.tap(() => k(n, i.rendered)), h.map((e) => ({
197
+ ...t.fallbacks === void 0 ? {} : { fallbacks: t.fallbacks },
198
+ ...t.maxTokens === void 0 ? {} : { maxTokens: t.maxTokens },
199
+ ...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions },
200
+ ...t.tools === void 0 ? {} : { tools: t.tools },
201
+ ...t.maxSteps === void 0 ? {} : { maxSteps: t.maxSteps },
202
+ ...t.toolContext === void 0 ? {} : { toolContext: t.toolContext }
203
+ }).pipe(h.tap((e) => O(t, r, "generateText", e, i.rendered)), h.tap(() => k(t, i.rendered)), h.map((e) => ({
204
204
  text: e.text,
205
205
  inputTokens: e.usage.inputTokens ?? null,
206
206
  outputTokens: e.usage.outputTokens ?? null,
@@ -222,17 +222,17 @@ var S = {
222
222
  ...D(n),
223
223
  operation: "transcribe",
224
224
  offloaded: t.offload === !0
225
- }, a = (e) => t.budget === void 0 ? e : h.zipRight(L(t), e);
226
- return t.offload === !0 ? a(F(t, n, "transcription", null, i, {
225
+ }, o = (e) => t.budget === void 0 ? e : h.zipRight(L(t), e);
226
+ return t.offload === !0 ? o(F(t, n, "transcription", null, i, {
227
227
  text: "",
228
228
  system: void 0,
229
229
  rendered: void 0
230
- }, r)) : a(b({
230
+ }, r)) : o(b({
231
231
  name: t.name,
232
232
  success: B,
233
233
  input: i,
234
234
  retry: t.retry ?? S,
235
- execute: s({
235
+ execute: a({
236
236
  ...r,
237
237
  provider: n,
238
238
  ...t.resolveRef === void 0 ? {} : { resolveRef: t.resolveRef }
@@ -249,7 +249,8 @@ var S = {
249
249
  }), i = {
250
250
  modality: t.modality,
251
251
  params: t.params ?? {},
252
- inputs: t.inputs ?? {}
252
+ inputs: t.inputs ?? {},
253
+ ...t.persist === void 0 ? {} : { persist: t.persist }
253
254
  }, a = {
254
255
  ...D(n),
255
256
  operation: `generate${t.modality[0].toUpperCase()}${t.modality.slice(1)}`,
@@ -261,42 +262,42 @@ var S = {
261
262
  ...t,
262
263
  offload: !0
263
264
  }, n, "media", null, a, r, void 0, i));
264
- }, U = (t) => {
265
- let i = t.provider ?? e(), a = E(t), o = {
265
+ }, U = (n) => {
266
+ let i = n.provider ?? e(), a = E(n), s = {
266
267
  ...D(i),
267
268
  operation: "generateObject",
268
- offloaded: t.offload === !0,
269
- ...T(a.text, a.system, t.recordPrompt ?? "digest", a.rendered)
270
- }, s = (e) => t.budget === void 0 ? e : h.zipRight(L(t), e);
271
- return t.offload === !0 ? s(h.gen(function* () {
272
- let e = yield* r(t.schema, "aiObjectStep"), n = yield* F(t, i, "object", e, o, a);
273
- return yield* g.decodeUnknown(t.schema)(n);
274
- })) : s(b({
275
- name: t.name,
276
- success: t.schema,
277
- input: o,
278
- retry: t.retry ?? S,
279
- execute: (t.tools === void 0 ? p({
269
+ offloaded: n.offload === !0,
270
+ ...T(a.text, a.system, n.recordPrompt ?? "digest", a.rendered)
271
+ }, c = (e) => n.budget === void 0 ? e : h.zipRight(L(n), e);
272
+ return n.offload === !0 ? c(h.gen(function* () {
273
+ let e = yield* o(n.schema, "aiObjectStep"), t = yield* F(n, i, "object", e, s, a);
274
+ return yield* g.decodeUnknown(n.schema)(t);
275
+ })) : c(b({
276
+ name: n.name,
277
+ success: n.schema,
278
+ input: s,
279
+ retry: n.retry ?? S,
280
+ execute: (n.tools === void 0 ? r({
280
281
  prompt: a.text,
281
- schema: t.schema,
282
+ schema: n.schema,
282
283
  provider: i,
283
284
  ...a.system === void 0 ? {} : { system: a.system },
284
- ...t.fallbacks === void 0 ? {} : { fallbacks: t.fallbacks },
285
- ...t.maxTokens === void 0 ? {} : { maxTokens: t.maxTokens },
286
- ...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions }
287
- }) : n({
285
+ ...n.fallbacks === void 0 ? {} : { fallbacks: n.fallbacks },
286
+ ...n.maxTokens === void 0 ? {} : { maxTokens: n.maxTokens },
287
+ ...n.providerOptions === void 0 ? {} : { providerOptions: n.providerOptions }
288
+ }) : t({
288
289
  prompt: a.text,
289
- schema: t.schema,
290
+ schema: n.schema,
290
291
  provider: i,
291
- tools: t.tools,
292
- ...t.maxSteps === void 0 ? {} : { maxSteps: t.maxSteps },
293
- ...t.toolContext === void 0 ? {} : { toolContext: t.toolContext },
292
+ tools: n.tools,
293
+ ...n.maxSteps === void 0 ? {} : { maxSteps: n.maxSteps },
294
+ ...n.toolContext === void 0 ? {} : { toolContext: n.toolContext },
294
295
  ...a.system === void 0 ? {} : { system: a.system },
295
- ...t.fallbacks === void 0 ? {} : { fallbacks: t.fallbacks },
296
- ...t.maxTokens === void 0 ? {} : { maxTokens: t.maxTokens },
297
- ...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions }
298
- })).pipe(h.tap((e) => O(t, i, "generateObject", e, a.rendered)), h.tap(() => k(t, a.rendered)), h.map((e) => e.object))
296
+ ...n.fallbacks === void 0 ? {} : { fallbacks: n.fallbacks },
297
+ ...n.maxTokens === void 0 ? {} : { maxTokens: n.maxTokens },
298
+ ...n.providerOptions === void 0 ? {} : { providerOptions: n.providerOptions }
299
+ })).pipe(h.tap((e) => O(n, i, "generateObject", e, a.rendered)), h.tap(() => k(n, a.rendered)), h.map((e) => e.object))
299
300
  }));
300
301
  };
301
302
  //#endregion
302
- export { S as AI_STEP_RETRY, I as AiBudgetMisuseError, M as AiOffloadError, N as AiOffloadMisuseError, w as DEFAULT_AI_BUDGET_NAME, C as DEFAULT_OFFLOAD_TIMEOUT_MS, B as TranscriptionStepResult, U as aiObjectStep, z as aiStep, H as mediaStep, c as promptDigest, T as promptRecordFor, E as resolveStepPrompt, V as transcribeStep };
303
+ export { S as AI_STEP_RETRY, I as AiBudgetMisuseError, M as AiOffloadError, N as AiOffloadMisuseError, w as DEFAULT_AI_BUDGET_NAME, C as DEFAULT_OFFLOAD_TIMEOUT_MS, B as TranscriptionStepResult, U as aiObjectStep, z as aiStep, H as mediaStep, s as promptDigest, T as promptRecordFor, E as resolveStepPrompt, V as transcribeStep };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/ai",
3
- "version": "0.74.0",
3
+ "version": "0.75.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",
@@ -55,10 +55,10 @@
55
55
  "dependencies": {
56
56
  "@ai-sdk/anthropic": "^4.0.49",
57
57
  "@ai-sdk/openai": "^4.0.58",
58
- "@voltro/cache": "0.74.0",
59
- "@voltro/database": "0.74.0",
60
- "@voltro/protocol": "0.74.0",
61
- "@voltro/workflow": "0.74.0",
58
+ "@voltro/cache": "0.75.0",
59
+ "@voltro/database": "0.75.0",
60
+ "@voltro/protocol": "0.75.0",
61
+ "@voltro/workflow": "0.75.0",
62
62
  "ajv": "^8.20.0",
63
63
  "ajv-formats": "^3.0.1"
64
64
  },