@voltro/ai 0.29.0 → 0.30.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.
- package/CHANGELOG.md +377 -0
- package/THIRD-PARTY-NOTICES.md +63 -1
- package/dist/index.d.ts +185 -0
- package/dist/index.js +474 -664
- package/dist/inferenceQueue-B25RTJZ4.js +447 -0
- package/dist/workflow.d.ts +304 -0
- package/dist/workflow.js +153 -0
- package/package.json +10 -4
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { DataStore } from '@voltro/database';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { Schema } from 'effect';
|
|
4
|
+
import { StepRetryPolicy } from '@voltro/workflow';
|
|
5
|
+
|
|
6
|
+
/** The provider-call retry default for an INLINE call.
|
|
7
|
+
*
|
|
8
|
+
* A rate limit and a 5xx are how a model call fails, and both are transient.
|
|
9
|
+
* Left to itself an unretried call fails the whole durable run for a condition
|
|
10
|
+
* that resolves in two seconds. Overridable per step; `retry: { maxAttempts:
|
|
11
|
+
* 1 }` opts out. An OFFLOADED call retries in the dispatcher instead, on the
|
|
12
|
+
* same rules — see `decideInferenceFailure`. */
|
|
13
|
+
export declare const AI_STEP_RETRY: StepRetryPolicy;
|
|
14
|
+
|
|
15
|
+
/** Provider-specific knobs forwarded verbatim to the Vercel AI SDK's
|
|
16
|
+
* `providerOptions` on generateText / streamText / generateObject. The outer
|
|
17
|
+
* key is the provider id, the inner record its options. The headline use is
|
|
18
|
+
* REASONING EFFORT on reasoning models — `gpt-5.x` defaults to a high effort
|
|
19
|
+
* that costs many seconds per call even for a one-line answer, so a routing/
|
|
20
|
+
* help agent should pin it low:
|
|
21
|
+
*
|
|
22
|
+
* providerOptions: { openai: { reasoningEffort: 'low' } } // or 'minimal'
|
|
23
|
+
* providerOptions: { anthropic: { thinking: { type: 'disabled' } } }
|
|
24
|
+
*
|
|
25
|
+
* Shape matches the SDK's `ProviderOptions` (Record<provider, Record<key,
|
|
26
|
+
* JSONValue>>). The value is the standard JSON value (mutable object + array,
|
|
27
|
+
* so it stays assignable to the SDK's `SharedV2ProviderOptions` under
|
|
28
|
+
* `exactOptionalPropertyTypes`) — NOT `unknown`, which the SDK rejects. */
|
|
29
|
+
declare type AiJsonValue = null | boolean | number | string | {
|
|
30
|
+
[key: string]: AiJsonValue;
|
|
31
|
+
} | AiJsonValue[];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A schema-constrained completion as a durable step.
|
|
35
|
+
*
|
|
36
|
+
* The schema is the step's success schema too, so the journaled value is
|
|
37
|
+
* decoded on replay exactly as it was on the first run — a structured result
|
|
38
|
+
* that only validated the first time through would be the worst kind of replay
|
|
39
|
+
* bug.
|
|
40
|
+
*
|
|
41
|
+
* Offloaded, the schema is rendered to JSON Schema for the dispatcher (a
|
|
42
|
+
* JavaScript Schema cannot be journaled) and the DECODE still happens here,
|
|
43
|
+
* where the real schema exists.
|
|
44
|
+
*/
|
|
45
|
+
export declare const aiObjectStep: <A, I>(options: AiObjectStepOptions<A, I>) => Effect.Effect<A, unknown>;
|
|
46
|
+
|
|
47
|
+
export declare interface AiObjectStepOptions<A, I> extends AiStepBaseOptions {
|
|
48
|
+
readonly schema: Schema.Schema<A, I>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export declare class AiOffloadError extends Error {
|
|
52
|
+
readonly attempts: number;
|
|
53
|
+
constructor(stepName: string, message: string, attempts: number);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export declare class AiOffloadMisuseError extends Error {
|
|
57
|
+
constructor(stepName: string);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
declare type AiProviderOptions = Record<string, Record<string, AiJsonValue>>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A text completion as a durable step.
|
|
64
|
+
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* const summary = yield* aiStep({
|
|
67
|
+
* name: 'summarise-thread',
|
|
68
|
+
* prompt: `Summarise:\n${thread}`,
|
|
69
|
+
* store: ctx.store,
|
|
70
|
+
* offload: true,
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* On replay the journal answers and the model is not called again.
|
|
75
|
+
*/
|
|
76
|
+
export declare const aiStep: (options: AiStepOptions) => Effect.Effect<AiStepResult, unknown>;
|
|
77
|
+
|
|
78
|
+
export declare interface AiStepBaseOptions {
|
|
79
|
+
/** Step name, as it appears in the journal and the dashboard. It also keys
|
|
80
|
+
* the offloaded call's row, so it has to be stable across a replay — which
|
|
81
|
+
* it is, being a literal in the body. */
|
|
82
|
+
readonly name: string;
|
|
83
|
+
readonly prompt: string;
|
|
84
|
+
readonly system?: string;
|
|
85
|
+
readonly provider?: ProviderConfig;
|
|
86
|
+
readonly fallbacks?: ProviderFallbacks;
|
|
87
|
+
readonly maxTokens?: number;
|
|
88
|
+
readonly providerOptions?: AiProviderOptions;
|
|
89
|
+
readonly retry?: StepRetryPolicy;
|
|
90
|
+
readonly recordPrompt?: PromptRecording;
|
|
91
|
+
/**
|
|
92
|
+
* The app's store.
|
|
93
|
+
*
|
|
94
|
+
* Used for the spend ledger, and REQUIRED for `offload` — that is where the
|
|
95
|
+
* queue lives. Omitting it on an inline call records no usage, which is a
|
|
96
|
+
* legitimate choice for a throwaway call and is reported as such rather than
|
|
97
|
+
* silently assumed.
|
|
98
|
+
*/
|
|
99
|
+
readonly store?: DataStore;
|
|
100
|
+
/** Carried onto the usage row so spend can be split per tenant. */
|
|
101
|
+
readonly tenantId?: string | null;
|
|
102
|
+
/**
|
|
103
|
+
* Suspend the run while the model thinks, instead of holding a worker.
|
|
104
|
+
*
|
|
105
|
+
* The run parks on a durable deferred and a dispatcher performs the call.
|
|
106
|
+
* Costs one suspend/resume round trip; buys back a worker for the length of
|
|
107
|
+
* the call. Requires `store`.
|
|
108
|
+
*/
|
|
109
|
+
readonly offload?: boolean;
|
|
110
|
+
/** End-to-end ceiling on an offloaded call. Default one hour. */
|
|
111
|
+
readonly offloadTimeoutMs?: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export declare interface AiStepOptions extends AiStepBaseOptions {
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** What an `aiStep` returns. The usage tally is part of the RESULT, not only of
|
|
118
|
+
* the ledger — a workflow that wants to branch on token count should not have
|
|
119
|
+
* to query a table to see what it just spent. */
|
|
120
|
+
export declare interface AiStepResult {
|
|
121
|
+
readonly text: string;
|
|
122
|
+
readonly inputTokens: number | null;
|
|
123
|
+
readonly outputTokens: number | null;
|
|
124
|
+
readonly totalTokens: number | null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
declare type AnthropicModel = 'claude-opus-4-8' | 'claude-sonnet-4-6' | 'claude-haiku-4-5-20251001' | (string & {});
|
|
128
|
+
|
|
129
|
+
/** Default ceiling on an offloaded call, end to end — one hour. Generous
|
|
130
|
+
* because the wait itself is free (no worker is held), and a run that gives up
|
|
131
|
+
* on a slow provider at ten minutes is a run somebody has to re-drive by hand. */
|
|
132
|
+
export declare const DEFAULT_OFFLOAD_TIMEOUT_MS: number;
|
|
133
|
+
|
|
134
|
+
/** Creator namespaces the Vercel AI Gateway routes to. Open union — the named
|
|
135
|
+
* arms are autocomplete, any other creator string still works. */
|
|
136
|
+
declare type GatewayCreator = 'openai' | 'anthropic' | 'google' | (string & {});
|
|
137
|
+
|
|
138
|
+
/** The gateway addresses models as `creator/model` ids. The template-literal
|
|
139
|
+
* type enforces that shape at COMPILE time — what `providerFromEnv` otherwise
|
|
140
|
+
* only catches as a runtime throw (`{ name: 'gateway', model: 'gpt-5.5' }` is
|
|
141
|
+
* now a type error, not a boot crash). */
|
|
142
|
+
declare type GatewayModel = `${GatewayCreator}/${string}`;
|
|
143
|
+
|
|
144
|
+
/** A scripted inline file the mock model emits on a turn (usually an image).
|
|
145
|
+
* `data` is base64 (a short ascii string works for assertions). */
|
|
146
|
+
declare interface MockFile {
|
|
147
|
+
readonly mediaType: string;
|
|
148
|
+
readonly data: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** A consumable sequence of model turns, plus a recorder for asserting on
|
|
152
|
+
* what the model was asked. Each `doGenerate`/`doStream` advances the
|
|
153
|
+
* cursor by one turn; running past the end repeats the last turn's text
|
|
154
|
+
* (or empties) so a loop that over-steps doesn't hang. */
|
|
155
|
+
declare class MockScript {
|
|
156
|
+
private readonly turns;
|
|
157
|
+
private cursor;
|
|
158
|
+
readonly calls: Array<{
|
|
159
|
+
readonly prompt: unknown;
|
|
160
|
+
readonly tools: ReadonlyArray<string>;
|
|
161
|
+
}>;
|
|
162
|
+
constructor(turns: ReadonlyArray<MockTurn>);
|
|
163
|
+
record(prompt: unknown, tools: ReadonlyArray<string>): void;
|
|
164
|
+
next(): MockTurn;
|
|
165
|
+
reset(): void;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** A scripted citation the mock model emits on a turn (RAG grounding). */
|
|
169
|
+
declare interface MockSource {
|
|
170
|
+
readonly sourceType?: 'url' | 'document';
|
|
171
|
+
readonly id?: string;
|
|
172
|
+
readonly url?: string;
|
|
173
|
+
readonly title?: string;
|
|
174
|
+
readonly mediaType?: string;
|
|
175
|
+
readonly filename?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** A scripted tool call the mock model emits on a turn. */
|
|
179
|
+
declare interface MockToolCall {
|
|
180
|
+
readonly name: string;
|
|
181
|
+
readonly input: unknown;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** One model turn. A turn can carry text (streamed word-by-word), scripted
|
|
185
|
+
* tool calls (which trigger the SDK's tool loop), cited sources, inline files,
|
|
186
|
+
* or an error. A turn with tool calls + no text drives one LLM↔tool
|
|
187
|
+
* round-trip. */
|
|
188
|
+
declare interface MockTurn {
|
|
189
|
+
readonly text?: string;
|
|
190
|
+
/** Reasoning ("thinking") the mock streams before the answer text. */
|
|
191
|
+
readonly reasoning?: string;
|
|
192
|
+
readonly toolCalls?: ReadonlyArray<MockToolCall>;
|
|
193
|
+
readonly sources?: ReadonlyArray<MockSource>;
|
|
194
|
+
readonly files?: ReadonlyArray<MockFile>;
|
|
195
|
+
readonly error?: {
|
|
196
|
+
readonly message: string;
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
declare type OpenAIModel = 'gpt-5.5' | 'gpt-4o' | 'gpt-4o-mini' | (string & {});
|
|
201
|
+
|
|
202
|
+
/** The digest form. A prefix, not the whole hash: this is a correlation handle,
|
|
203
|
+
* and a full sha256 in a dashboard cell is a wall of hex nobody reads. */
|
|
204
|
+
export declare const promptDigest: (prompt: string) => string;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* What gets written to `_voltro_workflow_run_steps.input` for a prompt.
|
|
208
|
+
*
|
|
209
|
+
* Exported because it is the security-relevant half of this module and it must
|
|
210
|
+
* be assertable on its own: "the raw prompt is not in the recorded input" is a
|
|
211
|
+
* property about a string, and testing it through a live model call would test
|
|
212
|
+
* the mock instead.
|
|
213
|
+
*/
|
|
214
|
+
export declare const promptRecordFor: (prompt: string, system: string | undefined, mode: PromptRecording) => Record<string, unknown>;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* How the prompt is written to the step row the dashboard renders.
|
|
218
|
+
*
|
|
219
|
+
* `'digest'` (default) — a sha256 prefix plus the character count. Enough to
|
|
220
|
+
* tell two runs apart, to spot a prompt that ballooned, and to correlate a
|
|
221
|
+
* cached result; not enough to leak the content of one.
|
|
222
|
+
*
|
|
223
|
+
* `'full'` — the prompt verbatim. Right for a prompt built from constants and
|
|
224
|
+
* a row id; wrong for one built from a customer's message, and typing it out is
|
|
225
|
+
* the point.
|
|
226
|
+
*
|
|
227
|
+
* `'none'` — record nothing about the prompt.
|
|
228
|
+
*/
|
|
229
|
+
export declare type PromptRecording = 'digest' | 'full' | 'none';
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* A resolved provider choice — a DISCRIMINATED UNION on `name`. Each provider
|
|
233
|
+
* only carries the fields that apply to it: the mock-only `mockText` / `script`
|
|
234
|
+
* cannot appear on a real provider, and a real provider always carries a
|
|
235
|
+
* `model` typed to that provider's ids. `apiKey` / `baseURL` switch
|
|
236
|
+
* `resolveModel` to a per-config provider instance (per-agent key / BYOK);
|
|
237
|
+
* omit them to fall back to the provider's standard env var (OPENAI_API_KEY /
|
|
238
|
+
* ANTHROPIC_API_KEY / AI_GATEWAY_API_KEY).
|
|
239
|
+
*/
|
|
240
|
+
declare type ProviderConfig = {
|
|
241
|
+
readonly name: 'mock';
|
|
242
|
+
/** Optional for mock — defaults to `'mock'`. */
|
|
243
|
+
readonly model?: string;
|
|
244
|
+
/** The exact text the mock returns (instead of echoing the prompt).
|
|
245
|
+
* Lets tests/demos drive `generateObject` with canned JSON. */
|
|
246
|
+
readonly mockText?: string;
|
|
247
|
+
/** A multi-turn script. Takes precedence over `mockText` — each
|
|
248
|
+
* `doGenerate`/`doStream` consumes the next turn, so the SDK's tool
|
|
249
|
+
* loop runs deterministically. */
|
|
250
|
+
readonly script?: MockScript;
|
|
251
|
+
/** Provider metadata the mock attaches to its `doGenerate` result — lets a
|
|
252
|
+
* test exercise the gateway-cost path (`gatewayCostUsd`) deterministically
|
|
253
|
+
* by faking `{ gateway: { cost } }`. Also surfaced by the mock speech +
|
|
254
|
+
* video media models. */
|
|
255
|
+
readonly providerMetadata?: AiProviderOptions;
|
|
256
|
+
/** Canned output for the media models (`resolveImageModel` /
|
|
257
|
+
* `resolveSpeechModel` / `resolveVideoModel`). Every field is optional and
|
|
258
|
+
* falls back to a deterministic default, so `useMockAi` yields valid media
|
|
259
|
+
* without configuration; set a field to assert on exact bytes / URL. */
|
|
260
|
+
readonly mockMedia?: {
|
|
261
|
+
/** base64 image payload `generateImage` decodes to bytes (default: a
|
|
262
|
+
* 1×1 PNG header, so media-type detection resolves to `image/png`). */
|
|
263
|
+
readonly imageBase64?: string;
|
|
264
|
+
/** base64 audio payload `generateSpeech` decodes to bytes. */
|
|
265
|
+
readonly audioBase64?: string;
|
|
266
|
+
/** URL the mock video model yields (the default branch — most video
|
|
267
|
+
* providers return a URL rather than inline bytes). */
|
|
268
|
+
readonly videoUrl?: string;
|
|
269
|
+
/** base64 the mock video model yields INSTEAD of a URL — exercises the
|
|
270
|
+
* bytes branch of `generateVideo`. Takes precedence over `videoUrl`. */
|
|
271
|
+
readonly videoBase64?: string;
|
|
272
|
+
};
|
|
273
|
+
} | {
|
|
274
|
+
readonly name: 'anthropic';
|
|
275
|
+
readonly model: AnthropicModel;
|
|
276
|
+
readonly apiKey?: string;
|
|
277
|
+
readonly baseURL?: string;
|
|
278
|
+
} | {
|
|
279
|
+
readonly name: 'openai';
|
|
280
|
+
readonly model: OpenAIModel;
|
|
281
|
+
readonly apiKey?: string;
|
|
282
|
+
readonly baseURL?: string;
|
|
283
|
+
} | {
|
|
284
|
+
readonly name: 'gateway';
|
|
285
|
+
/** A `creator/model` id, e.g. 'openai/gpt-5.5'. */
|
|
286
|
+
readonly model: GatewayModel;
|
|
287
|
+
readonly apiKey?: string;
|
|
288
|
+
readonly baseURL?: string;
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* An ordered provider/model fallback chain. When a call FAILS on the primary
|
|
293
|
+
* provider (`provider ?? providerFromEnv()`) — after that provider's OWN
|
|
294
|
+
* SDK-level retries — the call re-runs against `fallbacks[0]`, then
|
|
295
|
+
* `fallbacks[1]`, … until one succeeds. Exhausting every option surfaces the
|
|
296
|
+
* LAST provider's typed error (an `AiError({ reason: 'generation' })`). Only a
|
|
297
|
+
* `generation` failure (the provider call itself) falls through — a `decode`
|
|
298
|
+
* failure (the model answered but the output didn't satisfy the schema) is a
|
|
299
|
+
* prompt/schema problem another provider won't fix, so it surfaces immediately.
|
|
300
|
+
* An empty / absent chain leaves behavior unchanged.
|
|
301
|
+
*/
|
|
302
|
+
declare type ProviderFallbacks = ReadonlyArray<ProviderConfig>;
|
|
303
|
+
|
|
304
|
+
export { }
|
package/dist/workflow.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { r as e } from "./provider-BOC5wBxx.js";
|
|
2
|
+
import { O as t, f as n, g as r, h as i, j as a, o, s, t as c } from "./inferenceQueue-B25RTJZ4.js";
|
|
3
|
+
import { Effect as l, Schema as u } from "effect";
|
|
4
|
+
import { eq as d } from "@voltro/database";
|
|
5
|
+
import { createHash as f } from "node:crypto";
|
|
6
|
+
import { CurrentWorkflowExecutionId as p, awaitSignalSuspending as m, step as h } from "@voltro/workflow";
|
|
7
|
+
//#region src/inferStep.ts
|
|
8
|
+
var g = {
|
|
9
|
+
maxAttempts: 4,
|
|
10
|
+
strategy: "exponential",
|
|
11
|
+
baseDelay: "1 second",
|
|
12
|
+
maxDelay: "30 seconds",
|
|
13
|
+
jitter: !0,
|
|
14
|
+
respectRetryAfter: !0
|
|
15
|
+
}, _ = 60 * 6e4, v = (e) => `sha256:${f("sha256").update(e).digest("hex").slice(0, 16)}`, y = (e, t, n) => n === "none" ? {} : n === "full" ? {
|
|
16
|
+
prompt: e,
|
|
17
|
+
...t === void 0 ? {} : { system: t }
|
|
18
|
+
} : {
|
|
19
|
+
promptDigest: v(e),
|
|
20
|
+
promptChars: e.length,
|
|
21
|
+
...t === void 0 ? {} : {
|
|
22
|
+
systemDigest: v(t),
|
|
23
|
+
systemChars: t.length
|
|
24
|
+
}
|
|
25
|
+
}, b = (e) => ({
|
|
26
|
+
provider: String(e.provider ?? "unknown"),
|
|
27
|
+
model: String(e.model ?? "unknown")
|
|
28
|
+
}), x = (e, n, r, i) => {
|
|
29
|
+
let o = e.store;
|
|
30
|
+
if (o === void 0) return l.void;
|
|
31
|
+
let { provider: s, model: c } = b(n), u = t(i.providerMetadata);
|
|
32
|
+
return a(o, {
|
|
33
|
+
provider: s,
|
|
34
|
+
model: c,
|
|
35
|
+
operation: r,
|
|
36
|
+
agent: e.name,
|
|
37
|
+
usage: i.usage,
|
|
38
|
+
...e.tenantId === void 0 ? {} : { tenantId: e.tenantId },
|
|
39
|
+
...u === void 0 ? {} : { actualCostUsd: u }
|
|
40
|
+
}).pipe(l.asVoid, l.catchAllCause(() => l.void));
|
|
41
|
+
}, S = u.Struct({
|
|
42
|
+
text: u.String,
|
|
43
|
+
inputTokens: u.NullOr(u.Number),
|
|
44
|
+
outputTokens: u.NullOr(u.Number),
|
|
45
|
+
totalTokens: u.NullOr(u.Number)
|
|
46
|
+
}), C = (e) => typeof e == "object" && !!e && e.__voltro_ai_error === !0, w = class extends Error {
|
|
47
|
+
attempts;
|
|
48
|
+
constructor(e, t, n) {
|
|
49
|
+
super(`aiStep('${e}'): the offloaded model call gave up after ${n} attempt(s): ${t}. The queued call is in _voltro_ai_inferences with status 'failed' — the Flow tab shows it with the provider's own message.`), this.name = "AiOffloadError", this.attempts = n;
|
|
50
|
+
}
|
|
51
|
+
}, T = class extends Error {
|
|
52
|
+
constructor(e) {
|
|
53
|
+
super(`aiStep('${e}'): offload: true needs \`store\` — the queued call lives in a table and the dispatcher reads it from there. Pass ctx.store.`), this.name = "AiOffloadMisuseError";
|
|
54
|
+
}
|
|
55
|
+
}, E = (e, t, n, r) => l.gen(function* () {
|
|
56
|
+
let i = e.store;
|
|
57
|
+
if (i === void 0) return yield* l.die(new T(e.name));
|
|
58
|
+
let a = yield* p;
|
|
59
|
+
if (a === void 0) return yield* l.die(/* @__PURE__ */ Error(`aiStep('${e.name}'): offload: true is only valid inside a workflow body — there is no execution to suspend here.`));
|
|
60
|
+
let { provider: u, model: f } = b(t), m = s(a, e.name), h = yield* l.promise(() => i.query({
|
|
61
|
+
table: "_voltro_workflow_runs",
|
|
62
|
+
predicate: d("executionId", a),
|
|
63
|
+
order: [],
|
|
64
|
+
take: 1,
|
|
65
|
+
skip: void 0,
|
|
66
|
+
projection: void 0
|
|
67
|
+
})), g = String(h[0]?.tag ?? ""), _ = h[0]?.id;
|
|
68
|
+
return yield* l.promise(() => i.insertIgnore(c, {
|
|
69
|
+
id: m,
|
|
70
|
+
tenantId: e.tenantId ?? null,
|
|
71
|
+
executionId: a,
|
|
72
|
+
workflowName: g,
|
|
73
|
+
runId: typeof _ == "string" ? _ : null,
|
|
74
|
+
signalName: o(m),
|
|
75
|
+
stepName: e.name,
|
|
76
|
+
status: "pending",
|
|
77
|
+
kind: n,
|
|
78
|
+
provider: u,
|
|
79
|
+
model: f,
|
|
80
|
+
prompt: e.prompt,
|
|
81
|
+
system: e.system ?? null,
|
|
82
|
+
maxTokens: e.maxTokens ?? null,
|
|
83
|
+
providerOptions: e.providerOptions ?? null,
|
|
84
|
+
jsonSchema: r,
|
|
85
|
+
attempts: 0,
|
|
86
|
+
enqueuedAt: /* @__PURE__ */ new Date()
|
|
87
|
+
}, { conflictColumns: ["id"] })), m;
|
|
88
|
+
}), D = (e, t, n, r, i) => l.gen(function* () {
|
|
89
|
+
let a = yield* h({
|
|
90
|
+
name: `${e.name}:enqueue`,
|
|
91
|
+
success: u.String,
|
|
92
|
+
input: i,
|
|
93
|
+
execute: E(e, t, n, r)
|
|
94
|
+
}), s = yield* m({ store: e.store }, {
|
|
95
|
+
name: o(a),
|
|
96
|
+
schema: u.Unknown,
|
|
97
|
+
timeoutMs: e.offloadTimeoutMs ?? 36e5
|
|
98
|
+
});
|
|
99
|
+
return C(s) ? yield* l.die(new w(e.name, s.message, s.attempts)) : s;
|
|
100
|
+
}), O = (t) => {
|
|
101
|
+
let n = t.provider ?? e(), r = {
|
|
102
|
+
...b(n),
|
|
103
|
+
operation: "generateText",
|
|
104
|
+
offloaded: t.offload === !0,
|
|
105
|
+
...y(t.prompt, t.system, t.recordPrompt ?? "digest")
|
|
106
|
+
};
|
|
107
|
+
return t.offload === !0 ? D(t, n, "text", null, r) : h({
|
|
108
|
+
name: t.name,
|
|
109
|
+
success: S,
|
|
110
|
+
input: r,
|
|
111
|
+
retry: t.retry ?? g,
|
|
112
|
+
execute: i({
|
|
113
|
+
prompt: t.prompt,
|
|
114
|
+
provider: n,
|
|
115
|
+
...t.system === void 0 ? {} : { system: t.system },
|
|
116
|
+
...t.fallbacks === void 0 ? {} : { fallbacks: t.fallbacks },
|
|
117
|
+
...t.maxTokens === void 0 ? {} : { maxTokens: t.maxTokens },
|
|
118
|
+
...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions }
|
|
119
|
+
}).pipe(l.tap((e) => x(t, n, "generateText", e)), l.map((e) => ({
|
|
120
|
+
text: e.text,
|
|
121
|
+
inputTokens: e.usage.inputTokens ?? null,
|
|
122
|
+
outputTokens: e.usage.outputTokens ?? null,
|
|
123
|
+
totalTokens: e.usage.totalTokens ?? null
|
|
124
|
+
})))
|
|
125
|
+
});
|
|
126
|
+
}, k = (t) => {
|
|
127
|
+
let i = t.provider ?? e(), a = {
|
|
128
|
+
...b(i),
|
|
129
|
+
operation: "generateObject",
|
|
130
|
+
offloaded: t.offload === !0,
|
|
131
|
+
...y(t.prompt, t.system, t.recordPrompt ?? "digest")
|
|
132
|
+
};
|
|
133
|
+
return t.offload === !0 ? l.gen(function* () {
|
|
134
|
+
let e = yield* r(t.schema, "aiObjectStep"), n = yield* D(t, i, "object", e, a);
|
|
135
|
+
return yield* u.decodeUnknown(t.schema)(n);
|
|
136
|
+
}) : h({
|
|
137
|
+
name: t.name,
|
|
138
|
+
success: t.schema,
|
|
139
|
+
input: a,
|
|
140
|
+
retry: t.retry ?? g,
|
|
141
|
+
execute: n({
|
|
142
|
+
prompt: t.prompt,
|
|
143
|
+
schema: t.schema,
|
|
144
|
+
provider: i,
|
|
145
|
+
...t.system === void 0 ? {} : { system: t.system },
|
|
146
|
+
...t.fallbacks === void 0 ? {} : { fallbacks: t.fallbacks },
|
|
147
|
+
...t.maxTokens === void 0 ? {} : { maxTokens: t.maxTokens },
|
|
148
|
+
...t.providerOptions === void 0 ? {} : { providerOptions: t.providerOptions }
|
|
149
|
+
}).pipe(l.tap((e) => x(t, i, "generateObject", e)), l.map((e) => e.object))
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
//#endregion
|
|
153
|
+
export { g as AI_STEP_RETRY, w as AiOffloadError, T as AiOffloadMisuseError, _ as DEFAULT_OFFLOAD_TIMEOUT_MS, k as aiObjectStep, O as aiStep, v as promptDigest, y as promptRecordFor };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.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",
|
|
@@ -37,6 +37,11 @@
|
|
|
37
37
|
"types": "./dist/test.d.ts",
|
|
38
38
|
"import": "./dist/test.js",
|
|
39
39
|
"default": "./dist/test.js"
|
|
40
|
+
},
|
|
41
|
+
"./workflow": {
|
|
42
|
+
"types": "./dist/workflow.d.ts",
|
|
43
|
+
"import": "./dist/workflow.js",
|
|
44
|
+
"default": "./dist/workflow.js"
|
|
40
45
|
}
|
|
41
46
|
},
|
|
42
47
|
"main": "./dist/index.js",
|
|
@@ -51,9 +56,10 @@
|
|
|
51
56
|
"@ai-sdk/gateway": "^4.0.30",
|
|
52
57
|
"@ai-sdk/openai": "^4.0.22",
|
|
53
58
|
"@ai-sdk/provider": "^4.0.4",
|
|
54
|
-
"@voltro/cache": "0.
|
|
55
|
-
"@voltro/database": "0.
|
|
56
|
-
"@voltro/protocol": "0.
|
|
59
|
+
"@voltro/cache": "0.30.0",
|
|
60
|
+
"@voltro/database": "0.30.0",
|
|
61
|
+
"@voltro/protocol": "0.30.0",
|
|
62
|
+
"@voltro/workflow": "0.30.0",
|
|
57
63
|
"ai": "^7.0.40"
|
|
58
64
|
},
|
|
59
65
|
"peerDependencies": {
|