@voltro/ai 0.70.0 → 0.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,864 @@
1
+ import { c as e, o as t, r as n } from "./provider-C_Sms_DA.js";
2
+ import { NoObjectGeneratedError as r, Output as i, experimental_transcribe as a, generateObject as o, generateText as s, jsonSchema as c, stepCountIs as l, tool as u } from "ai";
3
+ import { Context as d, Effect as f, JSONSchema as p, Metric as m, MetricBoundaries as ee, Runtime as te, Schema as h, Stream as ne } from "effect";
4
+ import { and as g, bigint as re, eq as _, generateId as v, gte as ie, id as y, integer as b, isNull as ae, json as x, queryFor as S, registerRetention as C, retentionTtlMsFromEnv as w, table as T, text as E, timestamp as D } from "@voltro/database";
5
+ import { Ajv as oe } from "ajv";
6
+ import { Ajv2019 as se } from "ajv/dist/2019.js";
7
+ import { Ajv2020 as ce } from "ajv/dist/2020.js";
8
+ import le from "ajv-formats";
9
+ import { createHash as ue } from "node:crypto";
10
+ //#region src/tools.ts
11
+ var de = (e, t) => e(t), fe = Symbol.for("@voltro/ai/Tool"), pe = (e) => ({
12
+ ...e,
13
+ [fe]: !0
14
+ }), me = (e) => typeof e == "object" && !!e && e[fe] === !0, he = (e) => {
15
+ let t = e.default;
16
+ if (typeof t != "function") return 0;
17
+ let n = 0;
18
+ for (let r of Object.values(e)) me(r) && r.execute === void 0 && r.handler === void 0 && (r.handler = t, n += 1);
19
+ return n;
20
+ }, ge = (e, t, n) => {
21
+ let r = t ?? te.defaultRuntime;
22
+ return te.runPromise(r)(e, n === void 0 ? {} : { signal: n });
23
+ }, _e = (e, t, n) => n ? e.pipe(f.timeoutFail({
24
+ duration: `${n} millis`,
25
+ onTimeout: () => /* @__PURE__ */ Error(`tool '${t}' timed out`)
26
+ })) : e, ve = (e, t, n) => {
27
+ if (e.execute) return ge(_e(de(e.execute, t), e.name, e.timeoutMs), n.runtime, n.abortSignal);
28
+ if (e.handler) {
29
+ let r = e.handler, i = r(t, n);
30
+ return f.isEffect(i) ? ge(_e(i, e.name, e.timeoutMs), n.runtime, n.abortSignal) : i;
31
+ }
32
+ return Promise.reject(/* @__PURE__ */ Error(`tool '${e.name}' has neither execute nor handler`));
33
+ }, ye = (e) => {
34
+ let t = p.make(e);
35
+ return t && t.type === "object" ? t : {
36
+ type: "object",
37
+ properties: {},
38
+ additionalProperties: !1
39
+ };
40
+ }, be = (e) => {
41
+ let t = e.inputJsonSchema;
42
+ return t === void 0 ? ye(e.input) : t.type === "object" ? t : {
43
+ type: "object",
44
+ properties: {},
45
+ additionalProperties: !0
46
+ };
47
+ }, O = (e, t = { store: void 0 }) => {
48
+ let n = {};
49
+ for (let [r, i] of Object.entries(e)) n[i.name || r] = u({
50
+ description: i.description,
51
+ inputSchema: c(be(i)),
52
+ execute: async (e, n) => {
53
+ let r = n?.abortSignal ?? t.abortSignal;
54
+ r?.throwIfAborted();
55
+ let a = {
56
+ ...t,
57
+ ...n?.toolCallId === void 0 ? {} : { invocationId: n.toolCallId },
58
+ ...r === void 0 ? {} : { abortSignal: r }
59
+ }, o = await f.runPromise(h.decodeUnknown(i.input)(e));
60
+ r?.throwIfAborted();
61
+ let s = await ve(i, o, a);
62
+ return i.output ? f.runPromise(h.decodeUnknown(i.output)(s)) : s;
63
+ }
64
+ });
65
+ return n;
66
+ }, k = class extends h.TaggedError()("AiBudgetExceeded", {
67
+ tenantId: h.NullOr(h.String),
68
+ limitUsd: h.Number,
69
+ spentUsd: h.Number,
70
+ attemptedUsd: h.Number
71
+ }) {}, A = "_voltro_ai_budget", j = "_voltro_ai_budget_reservations", M = T(A, {
72
+ id: y({ prefix: "aib" }),
73
+ bucket: E().maxLength(191),
74
+ tenantId: E().nullable(),
75
+ reservedMicroUsd: re().default("0").narrowedFrom("integer"),
76
+ updatedAt: D().default("now")
77
+ }).unique("byAiBudgetBucket", ["bucket"]), xe = T(j, {
78
+ id: y({ prefix: "air" }),
79
+ reservationId: E().maxLength(191),
80
+ bucket: E().maxLength(191),
81
+ tenantId: E().nullable(),
82
+ amountMicroUsd: re(),
83
+ releasedAt: D().nullable(),
84
+ updatedAt: D().default("now")
85
+ }).unique("byAiBudgetReservation", ["reservationId"]), N = class extends Error {}, Se = (e, t, n) => {
86
+ if (!Number.isFinite(e) || e < 0) throw RangeError(`${t} must be finite and non-negative`);
87
+ let r = e * 1e6, i = n === "up" ? Math.ceil(r) : Math.floor(r);
88
+ if (!Number.isSafeInteger(i)) throw RangeError(`${t} exceeds the safe micro-USD range`);
89
+ return BigInt(i);
90
+ }, P = (e) => {
91
+ if (typeof e == "number" && !Number.isSafeInteger(e)) throw Error("AI budget counter is not an exact integer");
92
+ let t = String(e);
93
+ if (!/^(0|[1-9][0-9]*)$/.test(t)) throw Error("AI budget counter is invalid; refusing to assume zero");
94
+ return BigInt(t);
95
+ }, Ce = (e) => {
96
+ if (typeof e != "string" || e.length === 0 || e.length > 191) throw RangeError("AI budget reservationId must contain 1–191 characters");
97
+ return e;
98
+ }, we = () => {
99
+ let e = w(process.env.VOLTRO_AI_USAGE_TTL_HOURS, 8760);
100
+ for (let t of [A, j]) C({
101
+ source: "plugin",
102
+ table: t,
103
+ timeColumn: "updatedAt",
104
+ ttlMs: e
105
+ });
106
+ }, Te = async (e, t) => {
107
+ for (let n = 0;; n++) try {
108
+ return await e.transactional(t);
109
+ } catch (e) {
110
+ if (!(e instanceof N) || n >= 31) throw e;
111
+ await new Promise((e) => setTimeout(e, n + 1));
112
+ }
113
+ }, Ee = (e) => f.tryPromise({
114
+ try: e,
115
+ catch: (e) => e
116
+ }).pipe(f.catchAll((e) => e instanceof k ? f.fail(e) : f.die(e))), De = (e, t) => f.gen(function* () {
117
+ let n = Se(t.limitUsd, "limitUsd", "down"), r = Se(t.addUsd ?? 0, "addUsd", "up"), i = t.tenantId ?? null;
118
+ if (t.since !== void 0 && !Number.isFinite(t.since.getTime())) throw RangeError("AI budget since must be a valid Date");
119
+ let a = `${i ?? "global"}::${t.since === void 0 ? "all" : t.since.getTime()}`;
120
+ if (a.length > 191) throw RangeError("AI budget tenant/window key exceeds 191 characters");
121
+ let o = Ce(t.reservationId ?? v({
122
+ kind: "typeid",
123
+ prefix: "air"
124
+ }, "_voltro_ai_budget_reservations"));
125
+ we();
126
+ let s = async (e) => {
127
+ let [t] = await e.query(S(M).where(_("bucket", a)).descriptor);
128
+ if (t && t.tenantId !== i) throw Error("AI budget bucket belongs to a different tenant");
129
+ return t;
130
+ }, c = (e) => {
131
+ if (e + r > n) throw new k({
132
+ tenantId: i,
133
+ limitUsd: t.limitUsd,
134
+ spentUsd: Number(e) / 1e6,
135
+ attemptedUsd: t.addUsd ?? 0
136
+ });
137
+ };
138
+ return r === 0n ? yield* Ee(async () => {
139
+ let t = await s(e);
140
+ return c(t ? P(t.reservedMicroUsd) : 0n), null;
141
+ }) : yield* Ee(() => Te(e, async (e) => {
142
+ let t = v({
143
+ kind: "typeid",
144
+ prefix: "air"
145
+ }, j), n = /* @__PURE__ */ new Date(), l = await e.insertIgnore(j, {
146
+ id: t,
147
+ reservationId: o,
148
+ bucket: a,
149
+ tenantId: i,
150
+ amountMicroUsd: String(r),
151
+ releasedAt: null,
152
+ updatedAt: n
153
+ }, { conflictColumns: ["reservationId"] });
154
+ if (l.id !== t) {
155
+ if (l.tenantId !== i || l.bucket !== a || P(l.amountMicroUsd) !== r) throw Error("AI budget reservationId is already bound to another tenant, amount or window");
156
+ if (l.releasedAt !== null) throw Error("AI budget reservation was released; new spend requires a new reservationId");
157
+ return {
158
+ reservationId: o,
159
+ tenantId: i,
160
+ amountMicroUsd: String(r),
161
+ status: "replayed"
162
+ };
163
+ }
164
+ let u = await s(e), d = u ? P(u.reservedMicroUsd) : 0n;
165
+ if (c(d), u) {
166
+ if (await e.updateMany("_voltro_ai_budget", {
167
+ reservedMicroUsd: String(d + r),
168
+ updatedAt: n
169
+ }, { where: g(_("id", u.id), _("reservedMicroUsd", u.reservedMicroUsd)) }) !== 1) throw new N("AI budget counter changed; discard this receipt and retry");
170
+ } else {
171
+ let t = v({
172
+ kind: "typeid",
173
+ prefix: "aib"
174
+ }, A);
175
+ if ((await e.insertIgnore("_voltro_ai_budget", {
176
+ id: t,
177
+ bucket: a,
178
+ tenantId: i,
179
+ reservedMicroUsd: String(r),
180
+ updatedAt: n
181
+ }, { conflictColumns: ["bucket"] })).id !== t) throw new N("AI budget counter was created concurrently; discard this receipt and retry");
182
+ }
183
+ return {
184
+ reservationId: o,
185
+ tenantId: i,
186
+ amountMicroUsd: String(r),
187
+ status: "reserved"
188
+ };
189
+ }));
190
+ }), Oe = (e, t) => f.gen(function* () {
191
+ return Ce(t.reservationId), yield* f.promise(() => Te(e, async (e) => {
192
+ let [n] = await e.query(S(xe).where(g(_("reservationId", t.reservationId), t.tenantId === null ? ae("tenantId") : _("tenantId", t.tenantId))).descriptor);
193
+ if (!n) return "not-found";
194
+ if (n.releasedAt !== null) return "already-released";
195
+ let [r] = await e.query(S(M).where(_("bucket", n.bucket)).descriptor);
196
+ if (!r || r.tenantId !== t.tenantId) throw Error("AI budget counter missing or mismatched; refusing unproved credit");
197
+ let i = P(r.reservedMicroUsd), a = P(n.amountMicroUsd);
198
+ if (a > i) throw Error("AI budget receipt exceeds its counter; refusing unproved credit");
199
+ let o = /* @__PURE__ */ new Date();
200
+ if (await e.updateMany("_voltro_ai_budget_reservations", {
201
+ releasedAt: o,
202
+ updatedAt: o
203
+ }, { where: g(_("id", n.id), ae("releasedAt")) }) !== 1) throw new N("AI budget release raced; retry");
204
+ if (await e.updateMany("_voltro_ai_budget", {
205
+ reservedMicroUsd: String(i - a),
206
+ updatedAt: o
207
+ }, { where: g(_("id", r.id), _("reservedMicroUsd", r.reservedMicroUsd)) }) !== 1) throw new N("AI budget counter changed; discard this release and retry");
208
+ return "released";
209
+ }));
210
+ }), ke = {
211
+ "claude-opus-4-8": {
212
+ inputPer1M: 15,
213
+ outputPer1M: 75
214
+ },
215
+ "claude-opus-4-6": {
216
+ inputPer1M: 15,
217
+ outputPer1M: 75
218
+ },
219
+ "claude-sonnet-4-6": {
220
+ inputPer1M: 3,
221
+ outputPer1M: 15
222
+ },
223
+ "claude-haiku-4-5": {
224
+ inputPer1M: 1,
225
+ outputPer1M: 5
226
+ },
227
+ "claude-haiku-4-5-20251001": {
228
+ inputPer1M: 1,
229
+ outputPer1M: 5
230
+ },
231
+ "gpt-5.5": {
232
+ inputPer1M: 5,
233
+ outputPer1M: 30
234
+ },
235
+ "gpt-4o": {
236
+ inputPer1M: 2.5,
237
+ outputPer1M: 10
238
+ },
239
+ "gpt-4o-mini": {
240
+ inputPer1M: .15,
241
+ outputPer1M: .6
242
+ },
243
+ "gemini-2.5-pro": {
244
+ inputPer1M: 1.25,
245
+ outputPer1M: 10
246
+ },
247
+ "gemini-2.5-flash": {
248
+ inputPer1M: .3,
249
+ outputPer1M: 2.5
250
+ },
251
+ "gemini-2.0-flash": {
252
+ inputPer1M: .1,
253
+ outputPer1M: .4
254
+ }
255
+ }, F = {}, Ae = (e) => {
256
+ let t = F;
257
+ return F = { ...e }, t;
258
+ }, je = () => ({
259
+ ...ke,
260
+ ...F
261
+ }), Me = (e) => {
262
+ let t = je();
263
+ if (t[e] !== void 0) return t[e];
264
+ let n = e.indexOf("/");
265
+ if (n > 0) {
266
+ let r = e.slice(n + 1);
267
+ if (t[r] !== void 0) return t[r];
268
+ }
269
+ }, Ne = (e) => typeof e.unit == "string", Pe = (e) => Ne(e) ? {
270
+ unit: e.unit,
271
+ input: e.input ?? 0,
272
+ output: e.output ?? 0
273
+ } : {
274
+ unit: "tokens",
275
+ input: e.inputTokens ?? 0,
276
+ output: e.outputTokens ?? 0
277
+ }, I = (e, t) => {
278
+ let { unit: n, input: r, output: i } = Pe(e);
279
+ if (t.actualCostUsd !== void 0) {
280
+ if (!Number.isFinite(t.actualCostUsd) || t.actualCostUsd < 0) throw RangeError("estimateCostUsd: actualCostUsd must be a finite, non-negative USD amount.");
281
+ let e = r + i, a = e > 0 ? r / e : 0;
282
+ return {
283
+ inputTokens: r,
284
+ outputTokens: i,
285
+ inputCostUsd: t.actualCostUsd * a,
286
+ outputCostUsd: t.actualCostUsd * (1 - a),
287
+ totalCostUsd: t.actualCostUsd,
288
+ costSource: "gateway",
289
+ unit: n
290
+ };
291
+ }
292
+ if (n !== "tokens" && t.price === void 0) return {
293
+ inputTokens: r,
294
+ outputTokens: i,
295
+ inputCostUsd: 0,
296
+ outputCostUsd: 0,
297
+ totalCostUsd: 0,
298
+ costSource: "unpriced",
299
+ unit: n
300
+ };
301
+ let a = t.price ?? Me(t.model) ?? {
302
+ inputPer1M: 0,
303
+ outputPer1M: 0
304
+ }, o = r / 1e6 * a.inputPer1M, s = i / 1e6 * a.outputPer1M;
305
+ return {
306
+ inputTokens: r,
307
+ outputTokens: i,
308
+ inputCostUsd: o,
309
+ outputCostUsd: s,
310
+ totalCostUsd: o + s,
311
+ costSource: "estimated",
312
+ unit: n
313
+ };
314
+ }, L = "_voltro_ai_usage", Fe = T(L, {
315
+ id: y({ prefix: "aiu" }),
316
+ tenantId: E().nullable(),
317
+ provider: E(),
318
+ model: E(),
319
+ operation: E(),
320
+ agent: E().nullable(),
321
+ inputTokens: b().default(0),
322
+ outputTokens: b().default(0),
323
+ costMicroUsd: b().default(0),
324
+ costSource: E().default("estimated"),
325
+ unit: E().default("tokens"),
326
+ promptId: E().nullable(),
327
+ promptDigest: E().nullable(),
328
+ promptRevision: b().nullable(),
329
+ calledAt: D().default("now")
330
+ }).index(["tenantId"]).index(["promptDigest"]), Ie = (e) => {
331
+ let t = e?.gateway?.cost, n = typeof t == "string" ? t.trim() : void 0, r = typeof t == "number" ? t : n !== void 0 && /^(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(n) ? Number(n) : NaN;
332
+ return Number.isFinite(r) && r >= 0 ? r : void 0;
333
+ }, Le = (e, t) => (C({
334
+ source: "plugin",
335
+ table: L,
336
+ timeColumn: "calledAt",
337
+ ttlMs: w(process.env.VOLTRO_AI_USAGE_TTL_HOURS, 8760)
338
+ }), f.promise(async () => {
339
+ let n = I(t.usage, {
340
+ model: t.model,
341
+ ...t.price === void 0 ? {} : { price: t.price },
342
+ ...t.actualCostUsd === void 0 ? {} : { actualCostUsd: t.actualCostUsd }
343
+ });
344
+ return await e.insert(L, {
345
+ tenantId: t.tenantId ?? null,
346
+ provider: t.provider,
347
+ model: t.model,
348
+ operation: t.operation,
349
+ agent: t.agent ?? null,
350
+ inputTokens: n.inputTokens,
351
+ outputTokens: n.outputTokens,
352
+ costMicroUsd: Math.round(n.totalCostUsd * 1e6),
353
+ costSource: n.costSource,
354
+ unit: n.unit,
355
+ promptId: t.prompt?.promptId ?? null,
356
+ promptDigest: t.prompt?.digest ?? null,
357
+ promptRevision: t.prompt?.revision ?? null,
358
+ calledAt: t.calledAt ?? /* @__PURE__ */ new Date()
359
+ }), n;
360
+ })), Re = (e, t = {}) => f.promise(async () => {
361
+ let n = [
362
+ ...t.tenantId === void 0 ? [] : [_("tenantId", t.tenantId)],
363
+ ...t.since === void 0 ? [] : [ie("calledAt", t.since)],
364
+ ...t.promptDigest === void 0 ? [] : [_("promptDigest", t.promptDigest)]
365
+ ], r = S(Fe), i = n.length === 0 ? r : r.where(n.length === 1 ? n[0] : g(...n));
366
+ return (await e.query(i.descriptor)).reduce((e, t) => e + (Number(t.costMicroUsd) || 0), 0) / 1e6;
367
+ }), ze = ee.exponential({
368
+ start: .001,
369
+ factor: 2,
370
+ count: 16
371
+ }), R = m.counter("voltro_ai_calls_total", { description: "Total AI provider calls (generate + stream)." }), Be = m.counter("voltro_ai_call_errors_total", { description: "AI provider calls that errored." }), z = m.histogram("voltro_ai_call_duration_seconds", ze, "AI provider call duration in seconds."), Ve = m.counter("voltro_ai_input_tokens_total", {
372
+ description: "Total prompt (input) tokens across AI calls.",
373
+ incremental: !0
374
+ }), He = m.counter("voltro_ai_output_tokens_total", {
375
+ description: "Total completion (output) tokens across AI calls.",
376
+ incremental: !0
377
+ }), Ue = m.counter("voltro_ai_cost_microusd_total", {
378
+ description: "Total estimated AI spend in micro-USD (USD × 1e6).",
379
+ incremental: !0
380
+ }), B = (e, t) => ({
381
+ provider: e.name,
382
+ model: e.model ?? e.name,
383
+ operation: t
384
+ }), V = (e, t, n) => e.pipe(f.tagMetrics("provider", t.provider), f.tagMetrics("model", t.model), f.tagMetrics("operation", t.operation), f.tagMetrics("status", n)), We = (e, t) => {
385
+ let n = t.inputTokens ?? 0, r = t.outputTokens ?? 0, i = I({
386
+ inputTokens: n,
387
+ outputTokens: r
388
+ }, { model: e.model }), a = Math.round(i.totalCostUsd * 1e6);
389
+ return f.all([
390
+ V(m.incrementBy(Ve, n), e, "ok"),
391
+ V(m.incrementBy(He, r), e, "ok"),
392
+ V(m.incrementBy(Ue, a), e, "ok")
393
+ ], { discard: !0 });
394
+ }, H = (e, t, n) => f.gen(function* () {
395
+ let r = yield* f.clockWith((e) => e.currentTimeMillis);
396
+ return yield* n.pipe(f.tap((n) => We(e, t(n))), f.tap(() => V(m.increment(R), e, "ok").pipe(f.zipRight(f.clockWith((e) => e.currentTimeMillis).pipe(f.flatMap((t) => V(m.update(z, (t - r) / 1e3), e, "ok")))))), f.tapError(() => V(m.increment(R), e, "error").pipe(f.zipRight(V(m.increment(Be), e, "error")), f.zipRight(f.clockWith((e) => e.currentTimeMillis).pipe(f.flatMap((t) => V(m.update(z, (t - r) / 1e3), e, "error")))))), f.withSpan("voltro.ai.call", { attributes: {
397
+ "ai.provider": e.provider,
398
+ "ai.model": e.model,
399
+ "ai.operation": e.operation
400
+ } }));
401
+ }), Ge = (e, t) => {
402
+ let n = Date.now();
403
+ return t.pipe(ne.tap((t) => t._tag === "done" ? V(m.increment(R), e, "ok").pipe(f.zipRight(V(m.update(z, (Date.now() - n) / 1e3), e, "ok")), f.zipRight(We(e, t.usage ?? {}))) : t._tag === "error" ? V(m.increment(R), e, "error").pipe(f.zipRight(V(m.increment(Be), e, "error")), f.zipRight(V(m.update(z, (Date.now() - n) / 1e3), e, "error"))) : f.void), ne.withSpan("voltro.ai.call", { attributes: {
404
+ "ai.provider": e.provider,
405
+ "ai.model": e.model,
406
+ "ai.operation": e.operation
407
+ } }));
408
+ }, Ke = (e) => {
409
+ let t = structuredClone(e), n = {
410
+ strict: !0,
411
+ strictTypes: !1,
412
+ strictTuples: !1,
413
+ strictRequired: !1,
414
+ allowUnionTypes: !0
415
+ }, r = t.$schema, i = r === "https://json-schema.org/draft/2020-12/schema" ? new ce(n) : r === "https://json-schema.org/draft/2019-09/schema" ? new se(n) : new oe(n);
416
+ le(i);
417
+ let a = i.compile(t);
418
+ if ("$async" in a && a.$async === !0) throw Error("asynchronous output schemas are not supported");
419
+ return c(t, { validate: (e) => a(e) ? {
420
+ success: !0,
421
+ value: e
422
+ } : {
423
+ success: !1,
424
+ error: /* @__PURE__ */ Error("model output does not satisfy the declared JSON Schema")
425
+ } });
426
+ }, U = h.Number.pipe(h.int(), h.nonNegative(), h.lessThanOrEqualTo(2 ** 53 - 1)), qe = h.Struct({
427
+ provider: h.String,
428
+ model: h.String,
429
+ usage: h.Struct({
430
+ inputTokens: h.optional(U),
431
+ outputTokens: h.optional(U),
432
+ totalTokens: h.optional(U),
433
+ completeness: h.Literal("complete", "partial", "unknown")
434
+ }),
435
+ cost: h.Union(h.Struct({
436
+ status: h.Literal("actual"),
437
+ source: h.Literal("gateway"),
438
+ usd: h.Number.pipe(h.finite(), h.nonNegative())
439
+ }), h.Struct({
440
+ status: h.Literal("unknown"),
441
+ source: h.Literal("unreported")
442
+ }))
443
+ }), W = (e) => typeof e == "number" && Number.isSafeInteger(e) && e >= 0 ? e : void 0, G = (e, t, n, r) => {
444
+ let i = typeof n == "object" && n ? n : {}, a = W("inputTokens" in i ? i.inputTokens : void 0), o = W("outputTokens" in i ? i.outputTokens : void 0), s = W("totalTokens" in i ? i.totalTokens : void 0), c = [
445
+ a,
446
+ o,
447
+ s
448
+ ].filter((e) => e !== void 0).length, l = Ie(r);
449
+ return {
450
+ provider: e,
451
+ model: t,
452
+ usage: {
453
+ ...a === void 0 ? {} : { inputTokens: a },
454
+ ...o === void 0 ? {} : { outputTokens: o },
455
+ ...s === void 0 ? {} : { totalTokens: s },
456
+ completeness: c === 3 ? "complete" : c === 0 ? "unknown" : "partial"
457
+ },
458
+ cost: l === void 0 ? {
459
+ status: "unknown",
460
+ source: "unreported"
461
+ } : {
462
+ status: "actual",
463
+ source: "gateway",
464
+ usd: l
465
+ }
466
+ };
467
+ }, K = class extends h.TaggedError()("AiError", {
468
+ reason: h.Literal("generation", "decode"),
469
+ message: h.String,
470
+ evidence: h.optional(qe)
471
+ }) {}, q = (e, t, n) => {
472
+ let r = [e, ...t ?? []], i = (e) => n(r[e]).pipe(f.catchTag("AiError", (t) => t.reason === "generation" && e + 1 < r.length ? i(e + 1) : f.fail(t)));
473
+ return i(0);
474
+ }, Je = (e) => f.gen(function* () {
475
+ let r = e.messages === void 0 ? e.prompt === void 0 ? void 0 : { prompt: e.prompt } : { messages: [...e.messages] };
476
+ if (r === void 0 || e.prompt !== void 0 && e.messages !== void 0) return yield* f.fail(new K({
477
+ reason: "generation",
478
+ message: "generateText: supply exactly one of prompt or messages"
479
+ }));
480
+ let i = e.tools === void 0 ? void 0 : yield* f.runtime(), a = e.tools === void 0 || i === void 0 ? void 0 : O(e.tools, {
481
+ store: void 0,
482
+ ...e.toolContext,
483
+ runtime: i
484
+ });
485
+ return yield* q(e.provider ?? n(), e.fallbacks, (n) => H(B(n, "generateText"), (e) => e.usage, f.tryPromise({
486
+ try: async () => {
487
+ let i = t(n), o = await s({
488
+ model: i,
489
+ ...r,
490
+ ...a === void 0 ? {} : {
491
+ tools: a,
492
+ stopWhen: l(e.maxSteps ?? 8)
493
+ },
494
+ ...e.system === void 0 ? {} : { system: e.system },
495
+ ...e.maxTokens === void 0 ? {} : { maxOutputTokens: e.maxTokens },
496
+ ...e.temperature === void 0 ? {} : { temperature: e.temperature },
497
+ ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
498
+ }), c = a !== void 0 && o.totalUsage !== void 0 ? o.totalUsage : o.usage;
499
+ return {
500
+ text: o.text,
501
+ sources: o.sources,
502
+ usage: {
503
+ inputTokens: c.inputTokens,
504
+ outputTokens: c.outputTokens,
505
+ totalTokens: c.totalTokens
506
+ },
507
+ providerMetadata: o.providerMetadata
508
+ };
509
+ },
510
+ catch: (e) => new K({
511
+ reason: "generation",
512
+ message: String(e?.message ?? e)
513
+ })
514
+ })));
515
+ }), J = (e, t) => f.gen(function* () {
516
+ let n = p.make(e);
517
+ if (n?.type !== "object") {
518
+ let e = n?.anyOf === void 0 ? `type:${JSON.stringify(n?.type ?? null)}` : "anyOf (e.g. Schema.Struct({}) or a union)";
519
+ return yield* f.fail(new K({
520
+ reason: "generation",
521
+ message: `${t}: the output schema must render as a top-level JSON object (type:"object"), but got ${e}. Use a Schema.Struct({ ... }) as the output schema — wrap arrays/scalars in a field (e.g. Schema.Struct({ items: Schema.Array(...) })).`
522
+ }));
523
+ }
524
+ return n;
525
+ }), Ye = (e, t) => J(e, t), Xe = (e) => q(e.provider ?? n(), e.fallbacks, (n) => H(B(n, "generateObject"), (e) => e.usage, f.gen(function* () {
526
+ let i = yield* f.try({
527
+ try: () => Ke(e.jsonSchema),
528
+ catch: () => new K({
529
+ reason: "decode",
530
+ message: "generateObjectJson: invalid or unsupported output JSON Schema; no provider call was made"
531
+ })
532
+ }), a = t(n), s = yield* f.tryPromise({
533
+ try: () => o({
534
+ model: a,
535
+ schema: i,
536
+ prompt: e.prompt,
537
+ ...e.system === void 0 ? {} : { system: e.system },
538
+ ...e.maxTokens === void 0 ? {} : { maxOutputTokens: e.maxTokens },
539
+ ...e.temperature === void 0 ? {} : { temperature: e.temperature },
540
+ ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
541
+ }),
542
+ catch: (e) => r.isInstance(e) ? new K({
543
+ reason: "decode",
544
+ message: "model output failed JSON Schema validation",
545
+ evidence: G(n.name, a.modelId, e.usage)
546
+ }) : new K({
547
+ reason: "generation",
548
+ message: "structured provider call failed",
549
+ evidence: G(n.name, a.modelId, void 0)
550
+ })
551
+ });
552
+ return {
553
+ object: s.object,
554
+ evidence: G(n.name, a.modelId, s.usage, s.providerMetadata),
555
+ usage: {
556
+ inputTokens: s.usage.inputTokens,
557
+ outputTokens: s.usage.outputTokens,
558
+ totalTokens: s.usage.totalTokens
559
+ },
560
+ providerMetadata: s.providerMetadata
561
+ };
562
+ }))), Ze = (e) => f.gen(function* () {
563
+ let t = yield* Xe({
564
+ jsonSchema: yield* J(e.schema, "generateObject"),
565
+ prompt: e.prompt,
566
+ ...e.system === void 0 ? {} : { system: e.system },
567
+ ...e.provider === void 0 ? {} : { provider: e.provider },
568
+ ...e.fallbacks === void 0 ? {} : { fallbacks: e.fallbacks },
569
+ ...e.maxTokens === void 0 ? {} : { maxTokens: e.maxTokens },
570
+ ...e.temperature === void 0 ? {} : { temperature: e.temperature },
571
+ ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
572
+ }), n = yield* h.decodeUnknown(e.schema)(t.object).pipe(f.mapError(() => new K({
573
+ reason: "decode",
574
+ message: "model output failed schema decode",
575
+ evidence: t.evidence
576
+ })));
577
+ return {
578
+ ...t,
579
+ object: n
580
+ };
581
+ }), Qe = (e) => f.gen(function* () {
582
+ let a = yield* f.runtime(), o = yield* J(e.schema, "generateObjectWithTools"), u = {
583
+ store: void 0,
584
+ ...e.toolContext,
585
+ runtime: a
586
+ }, d = O(e.tools, u);
587
+ return yield* q(e.provider ?? n(), e.fallbacks, (n) => H(B(n, "generateObjectWithTools"), (e) => e.usage, f.gen(function* () {
588
+ let a = t(n), u = yield* f.tryPromise({
589
+ try: () => s({
590
+ model: a,
591
+ prompt: e.prompt,
592
+ tools: d,
593
+ stopWhen: l(e.maxSteps ?? 8),
594
+ output: i.object({ schema: c(o) }),
595
+ ...e.system === void 0 ? {} : { system: e.system },
596
+ ...e.maxTokens === void 0 ? {} : { maxOutputTokens: e.maxTokens },
597
+ ...e.temperature === void 0 ? {} : { temperature: e.temperature },
598
+ ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
599
+ }),
600
+ catch: (e) => r.isInstance(e) ? new K({
601
+ reason: "decode",
602
+ message: "model output failed structured decode",
603
+ evidence: G(n.name, a.modelId, e.usage)
604
+ }) : new K({
605
+ reason: "generation",
606
+ message: "structured provider call failed",
607
+ evidence: G(n.name, a.modelId, void 0)
608
+ })
609
+ }), p = u.totalUsage, m = G(n.name, a.modelId, p, u.steps.length === 1 ? u.providerMetadata : void 0), ee = yield* f.try({
610
+ try: () => u.output,
611
+ catch: () => new K({
612
+ reason: "decode",
613
+ message: "model output failed structured decode",
614
+ evidence: m
615
+ })
616
+ });
617
+ return {
618
+ object: yield* h.decodeUnknown(e.schema)(ee).pipe(f.mapError(() => new K({
619
+ reason: "decode",
620
+ message: "model output failed schema decode",
621
+ evidence: m
622
+ }))),
623
+ evidence: m,
624
+ usage: {
625
+ inputTokens: p.inputTokens,
626
+ outputTokens: p.outputTokens,
627
+ totalTokens: p.totalTokens
628
+ },
629
+ providerMetadata: u.providerMetadata
630
+ };
631
+ })));
632
+ }), $e = class extends d.Tag("@voltro/AiService")() {}, et = {
633
+ generateText: (e) => Je(e),
634
+ generateObject: (e) => Ze(e)
635
+ }, tt = async (e, t) => {
636
+ if ("bytes" in e) return {
637
+ audio: e.bytes,
638
+ mediaType: e.mediaType
639
+ };
640
+ if ("url" in e) {
641
+ let t = await fetch(e.url);
642
+ if (!t.ok) throw Error(`transcribe: GET ${e.url} answered ${t.status}.`);
643
+ let n = t.headers.get("content-type") ?? void 0;
644
+ return {
645
+ audio: new Uint8Array(await t.arrayBuffer()),
646
+ ...n === void 0 ? {} : { mediaType: n }
647
+ };
648
+ }
649
+ if (t === void 0) throw Error("transcribe: `source.storageRef` needs a `resolveRef` to turn the reference into bytes.\n → pass `resolveRef: (ref) => storage.read(ref)`. It is injected rather than imported so @voltro/ai does not depend on storage; the app owns tenancy and signing for that read.");
650
+ let { bytes: n, mediaType: r } = await t(e.storageRef);
651
+ return {
652
+ audio: n,
653
+ mediaType: r
654
+ };
655
+ }, nt = (e) => {
656
+ if (!Array.isArray(e) || e.length === 0) return;
657
+ let t = [];
658
+ for (let n of e) {
659
+ let e = typeof n.startSecond == "number" ? n.startSecond : typeof n.start == "number" ? n.start : void 0, r = typeof n.endSecond == "number" ? n.endSecond : typeof n.end == "number" ? n.end : void 0, i = typeof n.text == "string" ? n.text : void 0;
660
+ if (e === void 0 || r === void 0 || i === void 0) continue;
661
+ let a = typeof n.speaker == "string" ? n.speaker : void 0;
662
+ t.push({
663
+ start: e,
664
+ end: r,
665
+ text: i,
666
+ ...a === void 0 ? {} : { speaker: a }
667
+ });
668
+ }
669
+ return t.length > 0 ? t : void 0;
670
+ }, rt = (t) => {
671
+ let r = t.provider ?? n();
672
+ return H(B(r, "transcribe"), () => ({}), f.tryPromise({
673
+ try: async () => {
674
+ let { audio: n, mediaType: i } = await tt(t.source, t.resolveRef), o = await a({
675
+ model: e(r),
676
+ audio: n,
677
+ ...i === void 0 ? {} : { mediaType: i },
678
+ ...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions }
679
+ }), s = t.timestamps === "none" ? void 0 : nt(o.segments);
680
+ return {
681
+ text: o.text,
682
+ ...o.language === void 0 ? {} : { language: o.language },
683
+ ...o.durationInSeconds === void 0 ? {} : { durationSec: o.durationInSeconds },
684
+ ...s === void 0 ? {} : { segments: s },
685
+ ...o.providerMetadata === void 0 ? {} : { providerMetadata: o.providerMetadata }
686
+ };
687
+ },
688
+ catch: (e) => new K({
689
+ reason: "generation",
690
+ message: String(e?.message ?? e)
691
+ })
692
+ }));
693
+ }, it = (e) => `sha256:${ue("sha256").update(e).digest("hex").slice(0, 16)}`, at = class extends h.TaggedError()("PromptRenderError", {
694
+ promptId: h.String,
695
+ missing: h.Array(h.String),
696
+ message: h.String
697
+ }) {}, ot = /\{\{\s*([A-Za-z0-9_.]+)\s*\}\}/g, st = (e) => {
698
+ let t = /* @__PURE__ */ new Set();
699
+ for (let n of e.matchAll(ot)) {
700
+ let e = n[1];
701
+ e !== void 0 && t.add(e);
702
+ }
703
+ return [...t];
704
+ }, ct = (e, t) => it(`${e.length}:${e}${(t ?? "").length}:${t ?? ""}`), lt = (e) => {
705
+ let t = ct(e.template, e.system), n = st(e.template);
706
+ return {
707
+ ...e,
708
+ digest: t,
709
+ variables: n,
710
+ render: (r = {}) => f.suspend(() => {
711
+ let i = n.filter((e) => r[e] === void 0);
712
+ if (i.length > 0) return f.fail(new at({
713
+ promptId: e.id,
714
+ missing: i,
715
+ message: `prompt '${e.id}' needs ${i.map((e) => `{{${e}}}`).join(", ")}, which ${i.length === 1 ? "was" : "were"} not supplied.`
716
+ }));
717
+ let a = e.template.replace(ot, (e, t) => String(r[t]));
718
+ return f.succeed({
719
+ promptId: e.id,
720
+ digest: t,
721
+ ...e.label === void 0 ? {} : { label: e.label },
722
+ prompt: a,
723
+ ...e.system === void 0 ? {} : { system: e.system },
724
+ definition: e
725
+ });
726
+ })
727
+ };
728
+ }, ut = (e) => typeof e == "object" && !!e && typeof e.prompt == "string" && typeof e.digest == "string" && typeof e.promptId == "string", Y = "_voltro_prompts", X = T(Y, {
729
+ id: y({ prefix: "prm" }),
730
+ promptId: E().maxLength(191),
731
+ digest: E().maxLength(191),
732
+ revision: b().default(1),
733
+ label: E().nullable(),
734
+ template: E().nullable(),
735
+ system: E().nullable(),
736
+ templateChars: b().default(0),
737
+ firstSeenAt: D().default("now"),
738
+ lastUsedAt: D().default("now")
739
+ }).unique("byPromptsVersion", ["promptId", "digest"]).index(["promptId"]), dt = 8760, ft = () => {
740
+ C({
741
+ source: "framework",
742
+ table: Y,
743
+ timeColumn: "lastUsedAt",
744
+ ttlMs: w(process.env.VOLTRO_AI_PROMPTS_TTL_HOURS, dt),
745
+ envVar: "VOLTRO_AI_PROMPTS_TTL_HOURS",
746
+ label: "ai prompt versions"
747
+ });
748
+ }, Z = (e) => ({
749
+ promptId: String(e.promptId),
750
+ digest: String(e.digest),
751
+ revision: Number(e.revision) || 1,
752
+ label: e.label ?? null,
753
+ template: e.template ?? null,
754
+ system: e.system ?? null,
755
+ firstSeenAt: e.firstSeenAt ?? null,
756
+ lastUsedAt: e.lastUsedAt ?? null
757
+ }), pt = (e, t) => f.gen(function* () {
758
+ ft();
759
+ let n = t.digest ?? lt(t).digest;
760
+ return yield* f.promise(async () => {
761
+ let r = (await e.query(S(X).where(g(_("promptId", t.id), _("digest", n))).descriptor))[0];
762
+ if (r !== void 0) {
763
+ let t = /* @__PURE__ */ new Date();
764
+ return await e.updateMany(Y, { lastUsedAt: t }, { where: _("id", String(r.id)) }), Z({
765
+ ...r,
766
+ lastUsedAt: t
767
+ });
768
+ }
769
+ let i = (await e.query(S(X).where(_("promptId", t.id)).descriptor)).reduce((e, t) => Math.max(e, Number(t.revision) || 0), 0) + 1, a = /* @__PURE__ */ new Date(), o = {
770
+ id: v({
771
+ kind: "typeid",
772
+ prefix: "prm"
773
+ }, Y),
774
+ promptId: t.id,
775
+ digest: n,
776
+ revision: i,
777
+ label: t.label ?? null,
778
+ template: t.template,
779
+ system: t.system ?? null,
780
+ templateChars: t.template.length,
781
+ firstSeenAt: a,
782
+ lastUsedAt: a
783
+ };
784
+ return Z(await e.insertIgnore(Y, o, { conflictColumns: ["promptId", "digest"] }) ?? o);
785
+ });
786
+ }), mt = (e, t) => f.promise(async () => {
787
+ let n = (await e.query(S(X).where(_("digest", t)).descriptor))[0];
788
+ return n === void 0 ? null : Z(n);
789
+ }), ht = (e, t) => f.promise(async () => [...await e.query(S(X).where(_("promptId", t)).orderBy("revision", "desc").descriptor)].sort((e, t) => (Number(t.revision) || 0) - (Number(e.revision) || 0)).map(Z)), gt = "_voltro_ai_inferences", _t = T(gt, {
790
+ id: y({ prefix: "aiinf" }),
791
+ tenantId: E().nullable(),
792
+ executionId: E(),
793
+ workflowName: E(),
794
+ runId: E().nullable(),
795
+ signalName: E(),
796
+ stepName: E(),
797
+ status: E().oneOf([
798
+ "pending",
799
+ "running",
800
+ "succeeded",
801
+ "failed"
802
+ ]).default("pending"),
803
+ kind: E().oneOf([
804
+ "text",
805
+ "object",
806
+ "transcription"
807
+ ]).default("text"),
808
+ provider: E(),
809
+ model: E(),
810
+ prompt: E(),
811
+ system: E().nullable(),
812
+ promptId: E().nullable(),
813
+ promptDigest: E().nullable(),
814
+ promptRevision: b().nullable(),
815
+ maxTokens: b().nullable(),
816
+ providerOptions: x().nullable(),
817
+ jsonSchema: x().nullable(),
818
+ transcription: x().nullable(),
819
+ result: x().nullable(),
820
+ errorMessage: E().nullable(),
821
+ attempts: b().default(0),
822
+ leaseUntil: D().nullable(),
823
+ claimedBy: E().nullable(),
824
+ enqueuedAt: D().default("now"),
825
+ startedAt: D().nullable(),
826
+ completedAt: D().nullable(),
827
+ durationMs: b().nullable()
828
+ }).index(["status", "enqueuedAt"]).index(["status", "leaseUntil"]).index(["executionId"]).index(["tenantId"]), vt = 3e5, yt = 4, Q = (e, t) => {
829
+ let n = typeof e == "number" ? e : Number(e);
830
+ return Number.isFinite(n) ? Math.trunc(n) : t;
831
+ }, $ = (e) => e == null ? null : String(e), bt = (e) => ({
832
+ id: String(e.id),
833
+ tenantId: $(e.tenantId),
834
+ executionId: String(e.executionId),
835
+ workflowName: String(e.workflowName),
836
+ runId: $(e.runId),
837
+ signalName: String(e.signalName),
838
+ stepName: String(e.stepName),
839
+ kind: e.kind === "object" ? "object" : e.kind === "transcription" ? "transcription" : "text",
840
+ provider: String(e.provider),
841
+ model: String(e.model),
842
+ prompt: String(e.prompt ?? ""),
843
+ system: $(e.system),
844
+ promptId: $(e.promptId),
845
+ promptDigest: $(e.promptDigest),
846
+ promptRevision: e.promptRevision === null || e.promptRevision === void 0 ? null : Q(e.promptRevision, 0),
847
+ maxTokens: e.maxTokens === null || e.maxTokens === void 0 ? null : Q(e.maxTokens, 0),
848
+ providerOptions: e.providerOptions ?? null,
849
+ jsonSchema: e.jsonSchema ?? null,
850
+ transcription: e.transcription ?? null,
851
+ attempts: Q(e.attempts, 0)
852
+ }), xt = (e) => {
853
+ let t = e.attempts + 1;
854
+ return t >= e.maxAttempts ? {
855
+ kind: "give-up",
856
+ attempts: t
857
+ } : {
858
+ kind: "retry",
859
+ attempts: t,
860
+ delayMs: e.retryAfterMs !== void 0 && e.retryAfterMs > 0 ? e.retryAfterMs : Math.min(e.baseDelayMs * 2 ** (t - 1), e.maxDelayMs)
861
+ };
862
+ }, St = (e) => `voltro.ai.infer:${e}`, Ct = (e, t) => `aiinf_${ue("sha256").update(`${e}\u0000${t}`).digest("hex").slice(0, 40)}`;
863
+ //#endregion
864
+ export { pe as $, B as A, je as B, et as C, Je as D, Qe as E, Re as F, j as G, Me as H, Fe as I, xe as J, A as K, I as L, H as M, L as N, Ye as O, ke as P, O as Q, Ie as R, $e as S, Xe as T, Le as U, Pe as V, Ae as W, Oe as X, M as Y, De as Z, ht as _, xt as a, rt as b, bt as c, at as d, me as et, lt as f, ct as g, mt as h, _t as i, Ge as j, qe as k, dt as l, it as m, yt as n, St as o, ut as p, k as q, vt as r, Ct as s, gt as t, he as tt, Y as u, X as v, Ze as w, K as x, pt as y, Ne as z };