@voltro/ai 0.74.0 → 0.76.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,889 +0,0 @@
1
- import { c as e, o as t, r as n } from "./provider-Cts1BRhY.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 = S(xe).where(g(_("reservationId", t.reservationId), t.tenantId === null ? ae("tenantId") : _("tenantId", t.tenantId))).descriptor, [r] = await e.query(n);
193
- if (!r) return "not-found";
194
- if (r.releasedAt !== null) return "already-released";
195
- let i = /* @__PURE__ */ new Date();
196
- if (await e.updateMany("_voltro_ai_budget_reservations", {
197
- releasedAt: i,
198
- updatedAt: i
199
- }, { where: g(_("id", r.id), ae("releasedAt")) }) !== 1) {
200
- let [t] = await e.query(n);
201
- if (t !== void 0 && t.releasedAt !== null) return "already-released";
202
- throw new N("AI budget release raced; retry");
203
- }
204
- let [a] = await e.query(S(M).where(_("bucket", r.bucket)).descriptor);
205
- if (!a || a.tenantId !== t.tenantId) throw Error("AI budget counter missing or mismatched; refusing unproved credit");
206
- let o = P(a.reservedMicroUsd), s = P(r.amountMicroUsd);
207
- if (s > o) throw Error("AI budget receipt exceeds its counter; refusing unproved credit");
208
- if (await e.updateMany("_voltro_ai_budget", {
209
- reservedMicroUsd: String(o - s),
210
- updatedAt: i
211
- }, { where: g(_("id", a.id), _("reservedMicroUsd", a.reservedMicroUsd)) }) !== 1) throw new N("AI budget counter changed; discard this release and retry");
212
- return "released";
213
- }));
214
- }), ke = {
215
- "claude-opus-4-8": {
216
- inputPer1M: 15,
217
- outputPer1M: 75
218
- },
219
- "claude-opus-4-6": {
220
- inputPer1M: 15,
221
- outputPer1M: 75
222
- },
223
- "claude-sonnet-4-6": {
224
- inputPer1M: 3,
225
- outputPer1M: 15
226
- },
227
- "claude-haiku-4-5": {
228
- inputPer1M: 1,
229
- outputPer1M: 5
230
- },
231
- "claude-haiku-4-5-20251001": {
232
- inputPer1M: 1,
233
- outputPer1M: 5
234
- },
235
- "gpt-5.5": {
236
- inputPer1M: 5,
237
- outputPer1M: 30
238
- },
239
- "gpt-4o": {
240
- inputPer1M: 2.5,
241
- outputPer1M: 10
242
- },
243
- "gpt-4o-mini": {
244
- inputPer1M: .15,
245
- outputPer1M: .6
246
- },
247
- "gemini-2.5-pro": {
248
- inputPer1M: 1.25,
249
- outputPer1M: 10
250
- },
251
- "gemini-2.5-flash": {
252
- inputPer1M: .3,
253
- outputPer1M: 2.5
254
- },
255
- "gemini-2.0-flash": {
256
- inputPer1M: .1,
257
- outputPer1M: .4
258
- }
259
- }, F = {}, Ae = (e) => {
260
- let t = F;
261
- return F = { ...e }, t;
262
- }, je = () => ({
263
- ...ke,
264
- ...F
265
- }), Me = (e) => {
266
- let t = je();
267
- if (t[e] !== void 0) return t[e];
268
- let n = e.indexOf("/");
269
- if (n > 0) {
270
- let r = e.slice(n + 1);
271
- if (t[r] !== void 0) return t[r];
272
- }
273
- }, Ne = (e) => typeof e.unit == "string", Pe = (e) => Ne(e) ? {
274
- unit: e.unit,
275
- input: e.input ?? 0,
276
- output: e.output ?? 0
277
- } : {
278
- unit: "tokens",
279
- input: e.inputTokens ?? 0,
280
- output: e.outputTokens ?? 0
281
- }, I = (e, t) => {
282
- let { unit: n, input: r, output: i } = Pe(e);
283
- if (t.actualCostUsd !== void 0) {
284
- if (!Number.isFinite(t.actualCostUsd) || t.actualCostUsd < 0) throw RangeError("estimateCostUsd: actualCostUsd must be a finite, non-negative USD amount.");
285
- let e = r + i, a = e > 0 ? r / e : 0;
286
- return {
287
- inputTokens: r,
288
- outputTokens: i,
289
- inputCostUsd: t.actualCostUsd * a,
290
- outputCostUsd: t.actualCostUsd * (1 - a),
291
- totalCostUsd: t.actualCostUsd,
292
- costSource: "gateway",
293
- unit: n
294
- };
295
- }
296
- if (n !== "tokens" && t.price === void 0) return {
297
- inputTokens: r,
298
- outputTokens: i,
299
- inputCostUsd: 0,
300
- outputCostUsd: 0,
301
- totalCostUsd: 0,
302
- costSource: "unpriced",
303
- unit: n
304
- };
305
- let a = t.price ?? Me(t.model) ?? {
306
- inputPer1M: 0,
307
- outputPer1M: 0
308
- }, o = r / 1e6 * a.inputPer1M, s = i / 1e6 * a.outputPer1M;
309
- return {
310
- inputTokens: r,
311
- outputTokens: i,
312
- inputCostUsd: o,
313
- outputCostUsd: s,
314
- totalCostUsd: o + s,
315
- costSource: "estimated",
316
- unit: n
317
- };
318
- }, L = "_voltro_ai_usage", Fe = T(L, {
319
- id: y({ prefix: "aiu" }),
320
- tenantId: E().nullable(),
321
- provider: E(),
322
- model: E(),
323
- operation: E(),
324
- agent: E().nullable(),
325
- inputTokens: b().default(0),
326
- outputTokens: b().default(0),
327
- costMicroUsd: b().default(0),
328
- costSource: E().default("estimated"),
329
- unit: E().default("tokens"),
330
- promptId: E().nullable(),
331
- promptDigest: E().nullable(),
332
- promptRevision: b().nullable(),
333
- requestId: E().maxLength(191).nullable(),
334
- attempt: b().nullable(),
335
- receiptKey: E().maxLength(191).backfill((e) => `aiu-pre-receipt-${String(e.id)}`),
336
- calledAt: D().default("now")
337
- }).index(["tenantId"]).index(["promptDigest"]).unique("byAiUsageReceipt", ["receiptKey"]), Ie = (e) => {
338
- 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;
339
- return Number.isFinite(r) && r >= 0 ? r : void 0;
340
- }, Le = (e, t) => (C({
341
- source: "plugin",
342
- table: L,
343
- timeColumn: "calledAt",
344
- ttlMs: w(process.env.VOLTRO_AI_USAGE_TTL_HOURS, 8760)
345
- }), f.promise(async () => {
346
- let n = I(t.usage, {
347
- model: t.model,
348
- ...t.price === void 0 ? {} : { price: t.price },
349
- ...t.actualCostUsd === void 0 ? {} : { actualCostUsd: t.actualCostUsd }
350
- }), r = t.receiptKey ?? (t.requestId === void 0 ? v({
351
- kind: "typeid",
352
- prefix: "aiu"
353
- }, "_voltro_ai_usage") : `${t.requestId}#${t.attempt ?? 0}`), i = await e.insertIgnoreWithOutcome(L, {
354
- tenantId: t.tenantId ?? null,
355
- provider: t.provider,
356
- model: t.model,
357
- operation: t.operation,
358
- agent: t.agent ?? null,
359
- inputTokens: n.inputTokens,
360
- outputTokens: n.outputTokens,
361
- costMicroUsd: Math.round(n.totalCostUsd * 1e6),
362
- costSource: n.costSource,
363
- unit: n.unit,
364
- promptId: t.prompt?.promptId ?? null,
365
- promptDigest: t.prompt?.digest ?? null,
366
- promptRevision: t.prompt?.revision ?? null,
367
- requestId: t.requestId ?? null,
368
- attempt: t.attempt ?? null,
369
- receiptKey: r,
370
- calledAt: t.calledAt ?? /* @__PURE__ */ new Date()
371
- }, { conflictColumns: ["receiptKey"] });
372
- return {
373
- ...n,
374
- receipt: i.outcome === "inserted" ? "recorded" : "replayed"
375
- };
376
- })), Re = (e, t = {}) => f.promise(async () => {
377
- let n = [
378
- ...t.tenantId === void 0 ? [] : [_("tenantId", t.tenantId)],
379
- ...t.since === void 0 ? [] : [ie("calledAt", t.since)],
380
- ...t.promptDigest === void 0 ? [] : [_("promptDigest", t.promptDigest)]
381
- ], r = S(Fe), i = n.length === 0 ? r : r.where(n.length === 1 ? n[0] : g(...n));
382
- return (await e.query(i.descriptor)).reduce((e, t) => e + (Number(t.costMicroUsd) || 0), 0) / 1e6;
383
- }), ze = ee.exponential({
384
- start: .001,
385
- factor: 2,
386
- count: 16
387
- }), 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", {
388
- description: "Total prompt (input) tokens across AI calls.",
389
- incremental: !0
390
- }), He = m.counter("voltro_ai_output_tokens_total", {
391
- description: "Total completion (output) tokens across AI calls.",
392
- incremental: !0
393
- }), Ue = m.counter("voltro_ai_cost_microusd_total", {
394
- description: "Total estimated AI spend in micro-USD (USD × 1e6).",
395
- incremental: !0
396
- }), B = (e, t) => ({
397
- provider: e.name,
398
- model: e.model ?? e.name,
399
- operation: t
400
- }), 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) => {
401
- let n = t.inputTokens ?? 0, r = t.outputTokens ?? 0, i = I({
402
- inputTokens: n,
403
- outputTokens: r
404
- }, { model: e.model }), a = Math.round(i.totalCostUsd * 1e6);
405
- return f.all([
406
- V(m.incrementBy(Ve, n), e, "ok"),
407
- V(m.incrementBy(He, r), e, "ok"),
408
- V(m.incrementBy(Ue, a), e, "ok")
409
- ], { discard: !0 });
410
- }, H = (e, t, n) => f.gen(function* () {
411
- let r = yield* f.clockWith((e) => e.currentTimeMillis);
412
- 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: {
413
- "ai.provider": e.provider,
414
- "ai.model": e.model,
415
- "ai.operation": e.operation
416
- } }));
417
- }), Ge = (e, t) => {
418
- let n = Date.now();
419
- 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: {
420
- "ai.provider": e.provider,
421
- "ai.model": e.model,
422
- "ai.operation": e.operation
423
- } }));
424
- }, Ke = (e) => {
425
- let t = structuredClone(e), n = {
426
- strict: !0,
427
- strictTypes: !1,
428
- strictTuples: !1,
429
- strictRequired: !1,
430
- allowUnionTypes: !0
431
- }, 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);
432
- le(i);
433
- let a = i.compile(t);
434
- if ("$async" in a && a.$async === !0) throw Error("asynchronous output schemas are not supported");
435
- return c(t, { validate: (e) => a(e) ? {
436
- success: !0,
437
- value: e
438
- } : {
439
- success: !1,
440
- error: /* @__PURE__ */ Error("model output does not satisfy the declared JSON Schema")
441
- } });
442
- }, U = h.Number.pipe(h.int(), h.nonNegative(), h.lessThanOrEqualTo(2 ** 53 - 1)), qe = h.Struct({
443
- provider: h.String,
444
- model: h.String,
445
- usage: h.Struct({
446
- inputTokens: h.optional(U),
447
- outputTokens: h.optional(U),
448
- totalTokens: h.optional(U),
449
- completeness: h.Literal("complete", "partial", "unknown")
450
- }),
451
- cost: h.Union(h.Struct({
452
- status: h.Literal("actual"),
453
- source: h.Literal("gateway"),
454
- usd: h.Number.pipe(h.finite(), h.nonNegative())
455
- }), h.Struct({
456
- status: h.Literal("unknown"),
457
- source: h.Literal("unreported")
458
- }))
459
- }), W = (e) => typeof e == "number" && Number.isSafeInteger(e) && e >= 0 ? e : void 0, G = (e, t, n, r) => {
460
- 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 = [
461
- a,
462
- o,
463
- s
464
- ].filter((e) => e !== void 0).length, l = Ie(r);
465
- return {
466
- provider: e,
467
- model: t,
468
- usage: {
469
- ...a === void 0 ? {} : { inputTokens: a },
470
- ...o === void 0 ? {} : { outputTokens: o },
471
- ...s === void 0 ? {} : { totalTokens: s },
472
- completeness: c === 3 ? "complete" : c === 0 ? "unknown" : "partial"
473
- },
474
- cost: l === void 0 ? {
475
- status: "unknown",
476
- source: "unreported"
477
- } : {
478
- status: "actual",
479
- source: "gateway",
480
- usd: l
481
- }
482
- };
483
- }, K = class extends h.TaggedError()("AiError", {
484
- reason: h.Literal("generation", "decode"),
485
- message: h.String,
486
- evidence: h.optional(qe)
487
- }) {}, q = (e, t, n) => {
488
- 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)));
489
- return i(0);
490
- }, Je = (e) => f.gen(function* () {
491
- let r = e.messages === void 0 ? e.prompt === void 0 ? void 0 : { prompt: e.prompt } : { messages: [...e.messages] };
492
- if (r === void 0 || e.prompt !== void 0 && e.messages !== void 0) return yield* f.fail(new K({
493
- reason: "generation",
494
- message: "generateText: supply exactly one of prompt or messages"
495
- }));
496
- let i = e.tools === void 0 ? void 0 : yield* f.runtime(), a = e.tools === void 0 || i === void 0 ? void 0 : O(e.tools, {
497
- store: void 0,
498
- ...e.toolContext,
499
- ...e.abortSignal === void 0 ? {} : { abortSignal: e.abortSignal },
500
- runtime: i
501
- });
502
- return yield* q(e.provider ?? n(), e.fallbacks, (n) => H(B(n, "generateText"), (e) => e.usage, f.tryPromise({
503
- try: async () => {
504
- let i = t(n), o = await s({
505
- model: i,
506
- ...r,
507
- ...e.abortSignal === void 0 ? {} : { abortSignal: e.abortSignal },
508
- ...a === void 0 ? {} : {
509
- tools: a,
510
- stopWhen: l(e.maxSteps ?? 8)
511
- },
512
- ...e.system === void 0 ? {} : { system: e.system },
513
- ...e.maxTokens === void 0 ? {} : { maxOutputTokens: e.maxTokens },
514
- ...e.temperature === void 0 ? {} : { temperature: e.temperature },
515
- ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
516
- }), c = a !== void 0 && o.totalUsage !== void 0 ? o.totalUsage : o.usage;
517
- return {
518
- text: o.text,
519
- sources: o.sources,
520
- usage: {
521
- inputTokens: c.inputTokens,
522
- outputTokens: c.outputTokens,
523
- totalTokens: c.totalTokens
524
- },
525
- providerMetadata: o.providerMetadata
526
- };
527
- },
528
- catch: (e) => new K({
529
- reason: "generation",
530
- message: String(e?.message ?? e)
531
- })
532
- })));
533
- }), J = (e, t) => f.gen(function* () {
534
- let n = p.make(e);
535
- if (n?.type !== "object") {
536
- let e = n?.anyOf === void 0 ? `type:${JSON.stringify(n?.type ?? null)}` : "anyOf (e.g. Schema.Struct({}) or a union)";
537
- return yield* f.fail(new K({
538
- reason: "generation",
539
- 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(...) })).`
540
- }));
541
- }
542
- return n;
543
- }), 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* () {
544
- let i = yield* f.try({
545
- try: () => Ke(e.jsonSchema),
546
- catch: () => new K({
547
- reason: "decode",
548
- message: "generateObjectJson: invalid or unsupported output JSON Schema; no provider call was made"
549
- })
550
- }), a = t(n), s = yield* f.tryPromise({
551
- try: () => o({
552
- model: a,
553
- schema: i,
554
- prompt: e.prompt,
555
- ...e.system === void 0 ? {} : { system: e.system },
556
- ...e.maxTokens === void 0 ? {} : { maxOutputTokens: e.maxTokens },
557
- ...e.temperature === void 0 ? {} : { temperature: e.temperature },
558
- ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
559
- }),
560
- catch: (e) => r.isInstance(e) ? new K({
561
- reason: "decode",
562
- message: "model output failed JSON Schema validation",
563
- evidence: G(n.name, a.modelId, e.usage)
564
- }) : new K({
565
- reason: "generation",
566
- message: "structured provider call failed",
567
- evidence: G(n.name, a.modelId, void 0)
568
- })
569
- });
570
- return {
571
- object: s.object,
572
- evidence: G(n.name, a.modelId, s.usage, s.providerMetadata),
573
- usage: {
574
- inputTokens: s.usage.inputTokens,
575
- outputTokens: s.usage.outputTokens,
576
- totalTokens: s.usage.totalTokens
577
- },
578
- providerMetadata: s.providerMetadata
579
- };
580
- }))), Ze = (e) => f.gen(function* () {
581
- let t = yield* Xe({
582
- jsonSchema: yield* J(e.schema, "generateObject"),
583
- prompt: e.prompt,
584
- ...e.system === void 0 ? {} : { system: e.system },
585
- ...e.provider === void 0 ? {} : { provider: e.provider },
586
- ...e.fallbacks === void 0 ? {} : { fallbacks: e.fallbacks },
587
- ...e.maxTokens === void 0 ? {} : { maxTokens: e.maxTokens },
588
- ...e.temperature === void 0 ? {} : { temperature: e.temperature },
589
- ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
590
- }), n = yield* h.decodeUnknown(e.schema)(t.object).pipe(f.mapError(() => new K({
591
- reason: "decode",
592
- message: "model output failed schema decode",
593
- evidence: t.evidence
594
- })));
595
- return {
596
- ...t,
597
- object: n
598
- };
599
- }), Qe = (e) => f.gen(function* () {
600
- let a = yield* f.runtime(), o = yield* J(e.schema, "generateObjectWithTools"), u = {
601
- store: void 0,
602
- ...e.toolContext,
603
- ...e.abortSignal === void 0 ? {} : { abortSignal: e.abortSignal },
604
- runtime: a
605
- }, d = O(e.tools, u);
606
- return yield* q(e.provider ?? n(), e.fallbacks, (n) => H(B(n, "generateObjectWithTools"), (e) => e.usage, f.gen(function* () {
607
- let a = t(n), u = yield* f.tryPromise({
608
- try: () => s({
609
- model: a,
610
- prompt: e.prompt,
611
- tools: d,
612
- ...e.abortSignal === void 0 ? {} : { abortSignal: e.abortSignal },
613
- stopWhen: l(e.maxSteps ?? 8),
614
- output: i.object({ schema: c(o) }),
615
- ...e.system === void 0 ? {} : { system: e.system },
616
- ...e.maxTokens === void 0 ? {} : { maxOutputTokens: e.maxTokens },
617
- ...e.temperature === void 0 ? {} : { temperature: e.temperature },
618
- ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
619
- }),
620
- catch: (e) => r.isInstance(e) ? new K({
621
- reason: "decode",
622
- message: "model output failed structured decode",
623
- evidence: G(n.name, a.modelId, e.usage)
624
- }) : new K({
625
- reason: "generation",
626
- message: "structured provider call failed",
627
- evidence: G(n.name, a.modelId, void 0)
628
- })
629
- }), p = u.totalUsage, m = G(n.name, a.modelId, p, u.steps.length === 1 ? u.providerMetadata : void 0), ee = yield* f.try({
630
- try: () => u.output,
631
- catch: () => new K({
632
- reason: "decode",
633
- message: "model output failed structured decode",
634
- evidence: m
635
- })
636
- });
637
- return {
638
- object: yield* h.decodeUnknown(e.schema)(ee).pipe(f.mapError(() => new K({
639
- reason: "decode",
640
- message: "model output failed schema decode",
641
- evidence: m
642
- }))),
643
- evidence: m,
644
- usage: {
645
- inputTokens: p.inputTokens,
646
- outputTokens: p.outputTokens,
647
- totalTokens: p.totalTokens
648
- },
649
- providerMetadata: u.providerMetadata
650
- };
651
- })));
652
- }), $e = class extends d.Tag("@voltro/AiService")() {}, et = {
653
- generateText: (e) => Je(e),
654
- generateObject: (e) => Ze(e)
655
- }, tt = async (e, t) => {
656
- if ("bytes" in e) return {
657
- audio: e.bytes,
658
- mediaType: e.mediaType
659
- };
660
- if ("url" in e) {
661
- let t = await fetch(e.url);
662
- if (!t.ok) throw Error(`transcribe: GET ${e.url} answered ${t.status}.`);
663
- let n = t.headers.get("content-type") ?? void 0;
664
- return {
665
- audio: new Uint8Array(await t.arrayBuffer()),
666
- ...n === void 0 ? {} : { mediaType: n }
667
- };
668
- }
669
- 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.");
670
- let { bytes: n, mediaType: r } = await t(e.storageRef);
671
- return {
672
- audio: n,
673
- mediaType: r
674
- };
675
- }, nt = (e) => {
676
- if (!Array.isArray(e) || e.length === 0) return;
677
- let t = [];
678
- for (let n of e) {
679
- 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;
680
- if (e === void 0 || r === void 0 || i === void 0) continue;
681
- let a = typeof n.speaker == "string" ? n.speaker : void 0;
682
- t.push({
683
- start: e,
684
- end: r,
685
- text: i,
686
- ...a === void 0 ? {} : { speaker: a }
687
- });
688
- }
689
- return t.length > 0 ? t : void 0;
690
- }, rt = (t) => {
691
- let r = t.provider ?? n();
692
- return H(B(r, "transcribe"), () => ({}), f.tryPromise({
693
- try: async () => {
694
- let { audio: n, mediaType: i } = await tt(t.source, t.resolveRef), o = await a({
695
- model: e(r),
696
- audio: n,
697
- ...i === void 0 ? {} : { mediaType: i },
698
- ...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions }
699
- }), s = t.timestamps === "none" ? void 0 : nt(o.segments);
700
- return {
701
- text: o.text,
702
- ...o.language === void 0 ? {} : { language: o.language },
703
- ...o.durationInSeconds === void 0 ? {} : { durationSec: o.durationInSeconds },
704
- ...s === void 0 ? {} : { segments: s },
705
- ...o.providerMetadata === void 0 ? {} : { providerMetadata: o.providerMetadata }
706
- };
707
- },
708
- catch: (e) => new K({
709
- reason: "generation",
710
- message: String(e?.message ?? e)
711
- })
712
- }));
713
- }, it = (e) => `sha256:${ue("sha256").update(e).digest("hex").slice(0, 16)}`, at = class extends h.TaggedError()("PromptRenderError", {
714
- promptId: h.String,
715
- missing: h.Array(h.String),
716
- message: h.String
717
- }) {}, ot = /\{\{\s*([A-Za-z0-9_.]+)\s*\}\}/g, st = (e) => {
718
- let t = /* @__PURE__ */ new Set();
719
- for (let n of e.matchAll(ot)) {
720
- let e = n[1];
721
- e !== void 0 && t.add(e);
722
- }
723
- return [...t];
724
- }, ct = (e, t) => it(`${e.length}:${e}${(t ?? "").length}:${t ?? ""}`), lt = (e) => {
725
- let t = ct(e.template, e.system), n = st(e.template);
726
- return {
727
- ...e,
728
- digest: t,
729
- variables: n,
730
- render: (r = {}) => f.suspend(() => {
731
- let i = n.filter((e) => r[e] === void 0);
732
- if (i.length > 0) return f.fail(new at({
733
- promptId: e.id,
734
- missing: i,
735
- message: `prompt '${e.id}' needs ${i.map((e) => `{{${e}}}`).join(", ")}, which ${i.length === 1 ? "was" : "were"} not supplied.`
736
- }));
737
- let a = e.template.replace(ot, (e, t) => String(r[t]));
738
- return f.succeed({
739
- promptId: e.id,
740
- digest: t,
741
- ...e.label === void 0 ? {} : { label: e.label },
742
- prompt: a,
743
- ...e.system === void 0 ? {} : { system: e.system },
744
- definition: e
745
- });
746
- })
747
- };
748
- }, ut = (e) => typeof e == "object" && !!e && typeof e.prompt == "string" && typeof e.digest == "string" && typeof e.promptId == "string", Y = "_voltro_prompts", X = T(Y, {
749
- id: y({ prefix: "prm" }),
750
- promptId: E().maxLength(191),
751
- digest: E().maxLength(191),
752
- revision: b().default(1),
753
- label: E().nullable(),
754
- template: E().nullable(),
755
- system: E().nullable(),
756
- templateChars: b().default(0),
757
- firstSeenAt: D().default("now"),
758
- lastUsedAt: D().default("now")
759
- }).unique("byPromptsVersion", ["promptId", "digest"]).index(["promptId"]), dt = 8760, ft = () => {
760
- C({
761
- source: "framework",
762
- table: Y,
763
- timeColumn: "lastUsedAt",
764
- ttlMs: w(process.env.VOLTRO_AI_PROMPTS_TTL_HOURS, dt),
765
- envVar: "VOLTRO_AI_PROMPTS_TTL_HOURS",
766
- label: "ai prompt versions"
767
- });
768
- }, Z = (e) => ({
769
- promptId: String(e.promptId),
770
- digest: String(e.digest),
771
- revision: Number(e.revision) || 1,
772
- label: e.label ?? null,
773
- template: e.template ?? null,
774
- system: e.system ?? null,
775
- firstSeenAt: e.firstSeenAt ?? null,
776
- lastUsedAt: e.lastUsedAt ?? null
777
- }), pt = (e, t) => f.gen(function* () {
778
- ft();
779
- let n = t.digest ?? lt(t).digest;
780
- return yield* f.promise(async () => {
781
- let r = (await e.query(S(X).where(g(_("promptId", t.id), _("digest", n))).descriptor))[0];
782
- if (r !== void 0) {
783
- let t = /* @__PURE__ */ new Date();
784
- return await e.updateMany(Y, { lastUsedAt: t }, { where: _("id", String(r.id)) }), Z({
785
- ...r,
786
- lastUsedAt: t
787
- });
788
- }
789
- 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 = {
790
- id: v({
791
- kind: "typeid",
792
- prefix: "prm"
793
- }, Y),
794
- promptId: t.id,
795
- digest: n,
796
- revision: i,
797
- label: t.label ?? null,
798
- template: t.template,
799
- system: t.system ?? null,
800
- templateChars: t.template.length,
801
- firstSeenAt: a,
802
- lastUsedAt: a
803
- };
804
- return Z(await e.insertIgnore(Y, o, { conflictColumns: ["promptId", "digest"] }) ?? o);
805
- });
806
- }), mt = (e, t) => f.promise(async () => {
807
- let n = (await e.query(S(X).where(_("digest", t)).descriptor))[0];
808
- return n === void 0 ? null : Z(n);
809
- }), 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, {
810
- id: y({ prefix: "aiinf" }),
811
- tenantId: E().nullable(),
812
- executionId: E(),
813
- workflowName: E(),
814
- runId: E().nullable(),
815
- signalName: E(),
816
- stepName: E(),
817
- status: E().oneOf([
818
- "pending",
819
- "running",
820
- "succeeded",
821
- "failed"
822
- ]).default("pending"),
823
- kind: E().oneOf([
824
- "text",
825
- "object",
826
- "transcription",
827
- "media"
828
- ]).default("text"),
829
- provider: E(),
830
- model: E(),
831
- prompt: E(),
832
- system: E().nullable(),
833
- promptId: E().nullable(),
834
- promptDigest: E().nullable(),
835
- promptRevision: b().nullable(),
836
- maxTokens: b().nullable(),
837
- providerOptions: x().nullable(),
838
- jsonSchema: x().nullable(),
839
- transcription: x().nullable(),
840
- media: x().nullable(),
841
- result: x().nullable(),
842
- errorMessage: E().nullable(),
843
- attempts: b().default(0),
844
- fence: b().default(0),
845
- leaseUntil: D().nullable(),
846
- claimedBy: E().nullable(),
847
- enqueuedAt: D().default("now"),
848
- startedAt: D().nullable(),
849
- completedAt: D().nullable(),
850
- durationMs: b().nullable()
851
- }).index(["status", "enqueuedAt"]).index(["status", "leaseUntil"]).index(["executionId"]).index(["tenantId"]), vt = 3e5, yt = 4, Q = (e, t) => {
852
- let n = typeof e == "number" ? e : Number(e);
853
- return Number.isFinite(n) ? Math.trunc(n) : t;
854
- }, $ = (e) => e == null ? null : String(e), bt = (e) => ({
855
- id: String(e.id),
856
- tenantId: $(e.tenantId),
857
- executionId: String(e.executionId),
858
- workflowName: String(e.workflowName),
859
- runId: $(e.runId),
860
- signalName: String(e.signalName),
861
- stepName: String(e.stepName),
862
- kind: e.kind === "object" ? "object" : e.kind === "transcription" ? "transcription" : e.kind === "media" ? "media" : "text",
863
- provider: String(e.provider),
864
- model: String(e.model),
865
- prompt: String(e.prompt ?? ""),
866
- system: $(e.system),
867
- promptId: $(e.promptId),
868
- promptDigest: $(e.promptDigest),
869
- promptRevision: e.promptRevision === null || e.promptRevision === void 0 ? null : Q(e.promptRevision, 0),
870
- maxTokens: e.maxTokens === null || e.maxTokens === void 0 ? null : Q(e.maxTokens, 0),
871
- providerOptions: e.providerOptions ?? null,
872
- jsonSchema: e.jsonSchema ?? null,
873
- transcription: e.transcription ?? null,
874
- media: e.media ?? null,
875
- attempts: Q(e.attempts, 0),
876
- fence: Q(e.fence, 0)
877
- }), xt = (e) => {
878
- let t = e.attempts + 1;
879
- return t >= e.maxAttempts ? {
880
- kind: "give-up",
881
- attempts: t
882
- } : {
883
- kind: "retry",
884
- attempts: t,
885
- delayMs: e.retryAfterMs !== void 0 && e.retryAfterMs > 0 ? e.retryAfterMs : Math.min(e.baseDelayMs * 2 ** (t - 1), e.maxDelayMs)
886
- };
887
- }, St = (e) => `voltro.ai.infer:${e}`, Ct = (e, t) => `aiinf_${ue("sha256").update(`${e}\u0000${t}`).digest("hex").slice(0, 40)}`;
888
- //#endregion
889
- 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 };