@voltro/ai 0.32.0 → 0.34.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,447 +0,0 @@
1
- import { a as e, r as t } from "./provider-BOC5wBxx.js";
2
- import { Output as n, generateObject as r, generateText as i, jsonSchema as a, stepCountIs as o, tool as s } from "ai";
3
- import { Context as c, Effect as l, JSONSchema as u, Metric as d, MetricBoundaries as ee, Runtime as f, Schema as p, Stream as m } from "effect";
4
- import { and as h, eq as g, generateId as te, gte as ne, id as _, integer as v, json as y, queryFor as b, registerRetention as x, retentionTtlMsFromEnv as S, table as C, text as w, timestamp as T } from "@voltro/database";
5
- import { createHash as re } from "node:crypto";
6
- //#region src/tools.ts
7
- var ie = (e, t) => e(t), E = Symbol.for("@voltro/ai/Tool"), ae = (e) => ({
8
- ...e,
9
- [E]: !0
10
- }), oe = (e) => typeof e == "object" && !!e && e[E] === !0, se = (e) => {
11
- let t = e.default;
12
- if (typeof t != "function") return 0;
13
- let n = 0;
14
- for (let r of Object.values(e)) oe(r) && r.execute === void 0 && r.handler === void 0 && (r.handler = t, n += 1);
15
- return n;
16
- }, D = (e, t) => {
17
- let n = t ?? f.defaultRuntime;
18
- return f.runPromise(n)(e);
19
- }, O = (e, t, n) => n ? e.pipe(l.timeoutFail({
20
- duration: `${n} millis`,
21
- onTimeout: () => /* @__PURE__ */ Error(`tool '${t}' timed out`)
22
- })) : e, ce = (e, t, n) => {
23
- if (e.execute) return D(O(ie(e.execute, t), e.name, e.timeoutMs), n.runtime);
24
- if (e.handler) {
25
- let r = e.handler, i = r(t, n);
26
- return l.isEffect(i) ? D(O(i, e.name, e.timeoutMs), n.runtime) : i;
27
- }
28
- return Promise.reject(/* @__PURE__ */ Error(`tool '${e.name}' has neither execute nor handler`));
29
- }, le = (e) => {
30
- let t = u.make(e);
31
- return t && t.type === "object" ? t : {
32
- type: "object",
33
- properties: {},
34
- additionalProperties: !1
35
- };
36
- }, k = (e, t = { store: void 0 }) => {
37
- let n = {};
38
- for (let [r, i] of Object.entries(e)) n[i.name || r] = s({
39
- description: i.description,
40
- inputSchema: a(le(i.input)),
41
- execute: async (e) => {
42
- let n = await l.runPromise(p.decodeUnknown(i.input)(e)), r = await ce(i, n, t);
43
- return i.output ? l.runPromise(p.decodeUnknown(i.output)(r)) : r;
44
- }
45
- });
46
- return n;
47
- }, A = {
48
- "claude-opus-4-8": {
49
- inputPer1M: 15,
50
- outputPer1M: 75
51
- },
52
- "claude-opus-4-6": {
53
- inputPer1M: 15,
54
- outputPer1M: 75
55
- },
56
- "claude-sonnet-4-6": {
57
- inputPer1M: 3,
58
- outputPer1M: 15
59
- },
60
- "claude-haiku-4-5": {
61
- inputPer1M: 1,
62
- outputPer1M: 5
63
- },
64
- "claude-haiku-4-5-20251001": {
65
- inputPer1M: 1,
66
- outputPer1M: 5
67
- },
68
- "gpt-5.5": {
69
- inputPer1M: 5,
70
- outputPer1M: 30
71
- },
72
- "gpt-4o": {
73
- inputPer1M: 2.5,
74
- outputPer1M: 10
75
- },
76
- "gpt-4o-mini": {
77
- inputPer1M: .15,
78
- outputPer1M: .6
79
- },
80
- "gemini-2.5-pro": {
81
- inputPer1M: 1.25,
82
- outputPer1M: 10
83
- },
84
- "gemini-2.5-flash": {
85
- inputPer1M: .3,
86
- outputPer1M: 2.5
87
- },
88
- "gemini-2.0-flash": {
89
- inputPer1M: .1,
90
- outputPer1M: .4
91
- }
92
- }, j = {}, ue = (e) => {
93
- let t = j;
94
- return j = { ...e }, t;
95
- }, M = () => ({
96
- ...A,
97
- ...j
98
- }), N = (e) => {
99
- let t = M();
100
- if (t[e] !== void 0) return t[e];
101
- let n = e.indexOf("/");
102
- if (n > 0) {
103
- let r = e.slice(n + 1);
104
- if (t[r] !== void 0) return t[r];
105
- }
106
- }, P = (e, t) => {
107
- let n = e.inputTokens ?? 0, r = e.outputTokens ?? 0;
108
- if (t.actualCostUsd !== void 0) {
109
- let e = n + r, i = e > 0 ? n / e : 0;
110
- return {
111
- inputTokens: n,
112
- outputTokens: r,
113
- inputCostUsd: t.actualCostUsd * i,
114
- outputCostUsd: t.actualCostUsd * (1 - i),
115
- totalCostUsd: t.actualCostUsd,
116
- costSource: "gateway"
117
- };
118
- }
119
- let i = t.price ?? N(t.model) ?? {
120
- inputPer1M: 0,
121
- outputPer1M: 0
122
- }, a = n / 1e6 * i.inputPer1M, o = r / 1e6 * i.outputPer1M;
123
- return {
124
- inputTokens: n,
125
- outputTokens: r,
126
- inputCostUsd: a,
127
- outputCostUsd: o,
128
- totalCostUsd: a + o,
129
- costSource: "estimated"
130
- };
131
- }, F = "_voltro_ai_usage", I = C(F, {
132
- id: _({ prefix: "aiu" }),
133
- tenantId: w().nullable(),
134
- provider: w(),
135
- model: w(),
136
- operation: w(),
137
- agent: w().nullable(),
138
- inputTokens: v().default(0),
139
- outputTokens: v().default(0),
140
- costMicroUsd: v().default(0),
141
- costSource: w().default("estimated"),
142
- calledAt: T().default("now")
143
- }).index(["tenantId"]), de = (e) => {
144
- let t = e?.gateway?.cost, n = typeof t == "number" ? t : typeof t == "string" ? Number(t) : NaN;
145
- return Number.isFinite(n) ? n : void 0;
146
- }, fe = (e, t) => (x({
147
- table: F,
148
- timeColumn: "calledAt",
149
- ttlMs: S(process.env.VOLTRO_AI_USAGE_TTL_HOURS, 24 * 365)
150
- }), l.promise(async () => {
151
- let n = P(t.usage, {
152
- model: t.model,
153
- ...t.price === void 0 ? {} : { price: t.price },
154
- ...t.actualCostUsd === void 0 ? {} : { actualCostUsd: t.actualCostUsd }
155
- });
156
- return await e.insert(F, {
157
- tenantId: t.tenantId ?? null,
158
- provider: t.provider,
159
- model: t.model,
160
- operation: t.operation,
161
- agent: t.agent ?? null,
162
- inputTokens: n.inputTokens,
163
- outputTokens: n.outputTokens,
164
- costMicroUsd: Math.round(n.totalCostUsd * 1e6),
165
- costSource: n.costSource,
166
- calledAt: t.calledAt ?? /* @__PURE__ */ new Date()
167
- }), n;
168
- })), pe = (e, t = {}) => l.promise(async () => {
169
- let n = [...t.tenantId === void 0 ? [] : [g("tenantId", t.tenantId)], ...t.since === void 0 ? [] : [ne("calledAt", t.since)]], r = b(I), i = n.length === 0 ? r : r.where(n.length === 1 ? n[0] : h(...n));
170
- return (await e.query(i.descriptor)).reduce((e, t) => e + (Number(t.costMicroUsd) || 0), 0) / 1e6;
171
- }), L = class extends p.TaggedError()("AiBudgetExceeded", {
172
- tenantId: p.NullOr(p.String),
173
- limitUsd: p.Number,
174
- spentUsd: p.Number,
175
- attemptedUsd: p.Number
176
- }) {}, R = "_voltro_ai_budget", z = C(R, {
177
- id: _({ prefix: "aib" }),
178
- bucket: w().maxLength(191),
179
- tenantId: w().nullable(),
180
- reservedMicroUsd: v().default(0),
181
- updatedAt: T().default("now")
182
- }).unique("byAiBudgetBucket", ["bucket"]), me = (e, t) => `${e ?? "global"}::${t === void 0 ? "all" : String(t.getTime())}`, B = 32, he = (e, t) => l.gen(function* () {
183
- x({
184
- table: R,
185
- timeColumn: "updatedAt",
186
- ttlMs: S(process.env.VOLTRO_AI_USAGE_TTL_HOURS, 24 * 365)
187
- });
188
- let n = t.addUsd ?? 0, r = Math.round(n * 1e6), i = Math.round(t.limitUsd * 1e6), a = me(t.tenantId, t.since), o = t.tenantId ?? null, s = (e) => new L({
189
- tenantId: o,
190
- limitUsd: t.limitUsd,
191
- spentUsd: e / 1e6,
192
- attemptedUsd: n
193
- }), c = yield* l.promise(async () => {
194
- for (let t = 0; t < B; t++) {
195
- t > 0 && await new Promise((e) => setTimeout(e, t));
196
- let n = (await e.query(b(z).where(g("bucket", a)).descriptor))[0], s = n && Number(n.reservedMicroUsd) || 0;
197
- if (s + r > i) return {
198
- ok: !1,
199
- reservedMicro: s
200
- };
201
- if (r === 0) return { ok: !0 };
202
- if (n) {
203
- if (await e.updateMany("_voltro_ai_budget", {
204
- reservedMicroUsd: s + r,
205
- updatedAt: /* @__PURE__ */ new Date()
206
- }, { where: h(g("id", String(n.id)), g("reservedMicroUsd", s)) }) === 1) return { ok: !0 };
207
- } else {
208
- let t = te({
209
- kind: "typeid",
210
- prefix: "aib"
211
- }, R), n = await e.insertIgnore(R, {
212
- id: t,
213
- bucket: a,
214
- tenantId: o,
215
- reservedMicroUsd: r,
216
- updatedAt: /* @__PURE__ */ new Date()
217
- }, { conflictColumns: ["bucket"] });
218
- if (String(n.id) === t) return { ok: !0 };
219
- }
220
- }
221
- throw Error(`requireAiBudget: contention on bucket '${a}' exceeded ${B} attempts`);
222
- });
223
- if (!c.ok) return yield* l.fail(s(c.reservedMicro));
224
- }), ge = ee.exponential({
225
- start: .001,
226
- factor: 2,
227
- count: 16
228
- }), V = d.counter("voltro_ai_calls_total", { description: "Total AI provider calls (generate + stream)." }), H = d.counter("voltro_ai_call_errors_total", { description: "AI provider calls that errored." }), U = d.histogram("voltro_ai_call_duration_seconds", ge, "AI provider call duration in seconds."), _e = d.counter("voltro_ai_input_tokens_total", {
229
- description: "Total prompt (input) tokens across AI calls.",
230
- incremental: !0
231
- }), ve = d.counter("voltro_ai_output_tokens_total", {
232
- description: "Total completion (output) tokens across AI calls.",
233
- incremental: !0
234
- }), ye = d.counter("voltro_ai_cost_microusd_total", {
235
- description: "Total estimated AI spend in micro-USD (USD × 1e6).",
236
- incremental: !0
237
- }), W = (e, t) => ({
238
- provider: e.name,
239
- model: e.model ?? e.name,
240
- operation: t
241
- }), G = (e, t, n) => e.pipe(l.tagMetrics("provider", t.provider), l.tagMetrics("model", t.model), l.tagMetrics("operation", t.operation), l.tagMetrics("status", n)), K = (e, t) => {
242
- let n = t.inputTokens ?? 0, r = t.outputTokens ?? 0, i = P({
243
- inputTokens: n,
244
- outputTokens: r
245
- }, { model: e.model }), a = Math.round(i.totalCostUsd * 1e6);
246
- return l.all([
247
- G(d.incrementBy(_e, n), e, "ok"),
248
- G(d.incrementBy(ve, r), e, "ok"),
249
- G(d.incrementBy(ye, a), e, "ok")
250
- ], { discard: !0 });
251
- }, q = (e, t, n) => l.gen(function* () {
252
- let r = yield* l.clockWith((e) => e.currentTimeMillis);
253
- return yield* n.pipe(l.tap((n) => K(e, t(n))), l.tap(() => G(d.increment(V), e, "ok").pipe(l.zipRight(l.clockWith((e) => e.currentTimeMillis).pipe(l.flatMap((t) => G(d.update(U, (t - r) / 1e3), e, "ok")))))), l.tapError(() => G(d.increment(V), e, "error").pipe(l.zipRight(G(d.increment(H), e, "error")), l.zipRight(l.clockWith((e) => e.currentTimeMillis).pipe(l.flatMap((t) => G(d.update(U, (t - r) / 1e3), e, "error")))))), l.withSpan("voltro.ai.call", { attributes: {
254
- "ai.provider": e.provider,
255
- "ai.model": e.model,
256
- "ai.operation": e.operation
257
- } }));
258
- }), be = (e, t) => {
259
- let n = Date.now();
260
- return t.pipe(m.tap((t) => t._tag === "done" ? G(d.increment(V), e, "ok").pipe(l.zipRight(G(d.update(U, (Date.now() - n) / 1e3), e, "ok")), l.zipRight(K(e, t.usage ?? {}))) : t._tag === "error" ? G(d.increment(V), e, "error").pipe(l.zipRight(G(d.increment(H), e, "error")), l.zipRight(G(d.update(U, (Date.now() - n) / 1e3), e, "error"))) : l.void), m.withSpan("voltro.ai.call", { attributes: {
261
- "ai.provider": e.provider,
262
- "ai.model": e.model,
263
- "ai.operation": e.operation
264
- } }));
265
- }, J = class extends p.TaggedError()("AiError", {
266
- reason: p.Literal("generation", "decode"),
267
- message: p.String
268
- }) {}, Y = (e, t, n) => {
269
- let r = [e, ...t ?? []], i = (e) => n(r[e]).pipe(l.catchTag("AiError", (t) => t.reason === "generation" && e + 1 < r.length ? i(e + 1) : l.fail(t)));
270
- return i(0);
271
- }, X = (n) => Y(n.provider ?? t(), n.fallbacks, (t) => q(W(t, "generateText"), (e) => e.usage, l.tryPromise({
272
- try: async () => {
273
- let r = await i({
274
- model: e(t),
275
- prompt: n.prompt,
276
- ...n.system === void 0 ? {} : { system: n.system },
277
- ...n.maxTokens === void 0 ? {} : { maxOutputTokens: n.maxTokens },
278
- ...n.providerOptions === void 0 ? {} : { providerOptions: n.providerOptions }
279
- });
280
- return {
281
- text: r.text,
282
- usage: {
283
- inputTokens: r.usage.inputTokens,
284
- outputTokens: r.usage.outputTokens,
285
- totalTokens: r.usage.totalTokens
286
- },
287
- providerMetadata: r.providerMetadata
288
- };
289
- },
290
- catch: (e) => new J({
291
- reason: "generation",
292
- message: String(e?.message ?? e)
293
- })
294
- }))), Z = (e, t) => l.gen(function* () {
295
- let n = u.make(e);
296
- if (n?.type !== "object") {
297
- let e = n?.anyOf === void 0 ? `type:${JSON.stringify(n?.type ?? null)}` : "anyOf (e.g. Schema.Struct({}) or a union)";
298
- return yield* l.fail(new J({
299
- reason: "generation",
300
- 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(...) })).`
301
- }));
302
- }
303
- return n;
304
- }), xe = (e, t) => Z(e, t), Q = (n) => Y(n.provider ?? t(), n.fallbacks, (t) => q(W(t, "generateObject"), (e) => e.usage, l.gen(function* () {
305
- let i = e(t), o = yield* l.tryPromise({
306
- try: () => r({
307
- model: i,
308
- schema: a(n.jsonSchema),
309
- prompt: n.prompt,
310
- ...n.system === void 0 ? {} : { system: n.system },
311
- ...n.maxTokens === void 0 ? {} : { maxOutputTokens: n.maxTokens },
312
- ...n.providerOptions === void 0 ? {} : { providerOptions: n.providerOptions }
313
- }),
314
- catch: (e) => new J({
315
- reason: "generation",
316
- message: String(e?.message ?? e)
317
- })
318
- });
319
- return {
320
- object: o.object,
321
- usage: {
322
- inputTokens: o.usage.inputTokens,
323
- outputTokens: o.usage.outputTokens,
324
- totalTokens: o.usage.totalTokens
325
- },
326
- providerMetadata: o.providerMetadata
327
- };
328
- }))), Se = (e) => l.gen(function* () {
329
- let t = yield* Q({
330
- jsonSchema: yield* Z(e.schema, "generateObject"),
331
- prompt: e.prompt,
332
- ...e.system === void 0 ? {} : { system: e.system },
333
- ...e.provider === void 0 ? {} : { provider: e.provider },
334
- ...e.fallbacks === void 0 ? {} : { fallbacks: e.fallbacks },
335
- ...e.maxTokens === void 0 ? {} : { maxTokens: e.maxTokens },
336
- ...e.providerOptions === void 0 ? {} : { providerOptions: e.providerOptions }
337
- }), n = yield* p.decodeUnknown(e.schema)(t.object).pipe(l.mapError((e) => new J({
338
- reason: "decode",
339
- message: `model output failed schema decode: ${String(e)}`
340
- })));
341
- return {
342
- ...t,
343
- object: n
344
- };
345
- }), Ce = (r) => l.gen(function* () {
346
- let s = yield* l.runtime(), c = yield* Z(r.schema, "generateObjectWithTools"), u = {
347
- store: void 0,
348
- ...r.toolContext,
349
- runtime: s
350
- }, d = k(r.tools, u);
351
- return yield* Y(r.provider ?? t(), r.fallbacks, (t) => q(W(t, "generateObjectWithTools"), (e) => e.usage, l.gen(function* () {
352
- let s = e(t), u = yield* l.tryPromise({
353
- try: () => i({
354
- model: s,
355
- prompt: r.prompt,
356
- tools: d,
357
- stopWhen: o(r.maxSteps ?? 8),
358
- output: n.object({ schema: a(c) }),
359
- ...r.system === void 0 ? {} : { system: r.system },
360
- ...r.maxTokens === void 0 ? {} : { maxOutputTokens: r.maxTokens },
361
- ...r.providerOptions === void 0 ? {} : { providerOptions: r.providerOptions }
362
- }),
363
- catch: (e) => new J({
364
- reason: "generation",
365
- message: String(e?.message ?? e)
366
- })
367
- });
368
- return {
369
- object: yield* p.decodeUnknown(r.schema)(u.output).pipe(l.mapError((e) => new J({
370
- reason: "decode",
371
- message: `model output failed schema decode: ${String(e)}`
372
- }))),
373
- usage: {
374
- inputTokens: u.usage.inputTokens,
375
- outputTokens: u.usage.outputTokens,
376
- totalTokens: u.usage.totalTokens
377
- },
378
- providerMetadata: u.providerMetadata
379
- };
380
- })));
381
- }), we = class extends c.Tag("@voltro/AiService")() {}, Te = {
382
- generateText: (e) => X(e),
383
- generateObject: (e) => Se(e)
384
- }, Ee = "_voltro_ai_inferences", De = C(Ee, {
385
- id: _({ prefix: "aiinf" }),
386
- tenantId: w().nullable(),
387
- executionId: w(),
388
- workflowName: w(),
389
- runId: w().nullable(),
390
- signalName: w(),
391
- stepName: w(),
392
- status: w().oneOf([
393
- "pending",
394
- "running",
395
- "succeeded",
396
- "failed"
397
- ]).default("pending"),
398
- kind: w().oneOf(["text", "object"]).default("text"),
399
- provider: w(),
400
- model: w(),
401
- prompt: w(),
402
- system: w().nullable(),
403
- maxTokens: v().nullable(),
404
- providerOptions: y().nullable(),
405
- jsonSchema: y().nullable(),
406
- result: y().nullable(),
407
- errorMessage: w().nullable(),
408
- attempts: v().default(0),
409
- leaseUntil: T().nullable(),
410
- claimedBy: w().nullable(),
411
- enqueuedAt: T().default("now"),
412
- startedAt: T().nullable(),
413
- completedAt: T().nullable(),
414
- durationMs: v().nullable()
415
- }).index(["status", "enqueuedAt"]).index(["status", "leaseUntil"]).index(["executionId"]).index(["tenantId"]), Oe = 5 * 6e4, ke = 4, Ae = (e, t) => {
416
- let n = typeof e == "number" ? e : Number(e);
417
- return Number.isFinite(n) ? Math.trunc(n) : t;
418
- }, $ = (e) => e == null ? null : String(e), je = (e) => ({
419
- id: String(e.id),
420
- tenantId: $(e.tenantId),
421
- executionId: String(e.executionId),
422
- workflowName: String(e.workflowName),
423
- runId: $(e.runId),
424
- signalName: String(e.signalName),
425
- stepName: String(e.stepName),
426
- kind: e.kind === "object" ? "object" : "text",
427
- provider: String(e.provider),
428
- model: String(e.model),
429
- prompt: String(e.prompt ?? ""),
430
- system: $(e.system),
431
- maxTokens: e.maxTokens === null || e.maxTokens === void 0 ? null : Ae(e.maxTokens, 0),
432
- providerOptions: e.providerOptions ?? null,
433
- jsonSchema: e.jsonSchema ?? null,
434
- attempts: Ae(e.attempts, 0)
435
- }), Me = (e) => {
436
- let t = e.attempts + 1;
437
- return t >= e.maxAttempts ? {
438
- kind: "give-up",
439
- attempts: t
440
- } : {
441
- kind: "retry",
442
- attempts: t,
443
- delayMs: e.retryAfterMs !== void 0 && e.retryAfterMs > 0 ? e.retryAfterMs : Math.min(e.baseDelayMs * 2 ** (t - 1), e.maxDelayMs)
444
- };
445
- }, Ne = (e) => `voltro.ai.infer:${e}`, Pe = (e, t) => `aiinf_${re("sha256").update(`${e}\u0000${t}`).digest("hex").slice(0, 40)}`;
446
- //#endregion
447
- export { N as A, A as C, P as D, I as E, ae as F, oe as I, se as L, he as M, ue as N, de as O, k as P, L as S, pe as T, W as _, Me as a, R as b, je as c, Te as d, Se as f, xe as g, X as h, De as i, fe as j, M as k, J as l, Ce as m, ke as n, Ne as o, Q as p, Oe as r, Pe as s, Ee as t, we as u, be as v, z as w, F as x, q as y };