@warlock.js/ai-live 4.6.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 ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog — @warlock.js/ai-live
2
+
3
+ All notable changes to `@warlock.js/ai-live` are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
+
7
+ ## 4.6.0
8
+
9
+ ### Added
10
+
11
+ - **First release** — the live & generative rich-media add-on for `@warlock.js/ai`, kept in its own package so core text/image/speech stay dependency-light. A side-effect import (`import "@warlock.js/ai-live"`) mounts `ai.video` + `ai.realtime` onto the shared `Ai` facade.
12
+ - **`ai.video(params)`** — text-to-video (Sora / Veo / Kling-class); the provider's async submit→poll job hidden behind the uniform never-throws `{ data, error, usage, report }` envelope, with per-second cost-truth folded into `Usage.cost` and a `type: "video"` report routed to observers.
13
+ - **`ai.realtime(options)`** — a stateful duplex voice session over a pluggable `RealtimeTransport`: `sendAudio` / `sendText` / `events()` out, `close()` → `RealtimeReport` for the cost/observability surfaces.
14
+ - **Contracts** — `VideoModelContract`, `GeneratedVideo`, `VideoModelPricing`, `VideoOptions`; `RealtimeSession`, `RealtimeTransport`, `RealtimeConnection`, `RealtimeEvent`, `RealtimeReport`, `RealtimeOptions`.
15
+ - **Mocks** — `MockVideoModel` + `MockRealtimeTransport` for deterministic, HTTP- and socket-free tests (scripted responses / event streams, recorded calls).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Hassan Zohdy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # `@warlock.js/ai-live`
2
+
3
+ **Live & generative rich-media for `@warlock.js/ai`** — the two heaviest output
4
+ modalities, kept in their own package so the core stays dependency-light.
5
+
6
+ `@warlock.js/ai` ships the synchronous modality verbs (`ai.agent`, `ai.image`,
7
+ `ai.speech`, `ai.transcribe`). `ai-live` adds the two that need heavyweight,
8
+ demand-gated machinery — a persistent network session and a long-running job —
9
+ mounted onto the same `ai.*` facade by importing the package:
10
+
11
+ ```ts
12
+ import "@warlock.js/ai-live"; // side-effect: lights up ai.realtime + ai.video
13
+ ```
14
+
15
+ ## What it gives you
16
+
17
+ ### `ai.realtime(options)` — duplex realtime voice sessions
18
+ A **stateful, bidirectional voice session** (OpenAI Realtime-class): stream
19
+ microphone audio in, stream synthesized audio + transcripts + tool-calls out,
20
+ with barge-in. Unlike every other `ai.*` verb (one-shot request → result), this
21
+ is a **session primitive** — its closest sibling is `ai.orchestrator`. You open
22
+ a session over a pluggable **transport** (a WebSocket to the provider's realtime
23
+ endpoint), push audio, and consume an async event stream until you `close()` it
24
+ (which yields a final report for cost/observability).
25
+
26
+ ```ts
27
+ const session = await ai.realtime({
28
+ transport: openAiRealtime({ apiKey }), // provider transport (own adapter)
29
+ model: "gpt-realtime",
30
+ voice: "alloy",
31
+ instructions: "You are a friendly phone receptionist.",
32
+ });
33
+
34
+ session.sendAudio(micChunk, "audio/pcm");
35
+ for await (const event of session.events()) {
36
+ if (event.type === "audio") speaker.write(event.base64);
37
+ if (event.type === "transcript" && event.final) log(event.role, event.text);
38
+ }
39
+ const report = await session.close();
40
+ ```
41
+
42
+ ### `ai.video(params)` — text-to-video generation
43
+ Prompt → video (Sora / Veo / Kling-class). Generation is **async** (submit →
44
+ poll), but the adapter hides the polling, so the verb returns the same uniform
45
+ never-throws `{ data, error, usage, report }` envelope as `ai.image`, with
46
+ per-second cost-truth folded into `Usage.cost`.
47
+
48
+ ```ts
49
+ const { data, error, usage } = await ai.video({
50
+ model: sora.video({ name: "sora-2", pricing: { perSecond: 0.1 } }),
51
+ prompt: "a timelapse of a city skyline at dusk, cinematic",
52
+ durationSeconds: 8,
53
+ aspectRatio: "16:9",
54
+ });
55
+ if (!error) download(data.video); // { type: "url" | "base64", ... }
56
+ ```
57
+
58
+ ## Why a separate package
59
+
60
+ - **Heavy / optional deps.** Realtime needs a WebSocket transport (`ws` is an
61
+ optional peer); video pulls long-poll + large-payload handling. Most apps
62
+ using text/image/speech shouldn't carry that weight.
63
+ - **Different shape.** `ai.realtime` is a *session*, not a request; `ai.video`
64
+ is a *long job*. Isolating them keeps the core verbs simple and synchronous.
65
+ - **Same contracts.** Both still produce a `BaseReport` (`type: "realtime"` /
66
+ `"video"`) and route through the shared `observe` seam, so panoptic and the
67
+ cost tree pick them up for free.
68
+
69
+ ## Status
70
+
71
+ `4.6.0` introduces the package with the **`VideoModelContract` / `RealtimeSession`
72
+ contracts**, the `ai.video()` verb (uniform envelope + cost-truth, tested against
73
+ a mock), and the `ai.realtime()` session primitive over a **pluggable transport**
74
+ (tested against a mock transport). The first concrete provider transports
75
+ (OpenAI Realtime WebSocket; Sora / Veo video adapters) are the next implementation
76
+ step — the seams are defined so they drop in without changing the verb surface.
package/cjs/index.cjs ADDED
@@ -0,0 +1,257 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let _warlock_js_ai = require("@warlock.js/ai");
3
+
4
+ //#region ../@warlock.js/ai-live/src/realtime/realtime.ts
5
+ /**
6
+ * Open a live duplex voice session — the stateful primitive of
7
+ * `@warlock.js/ai-live`. Connects through the provided
8
+ * {@link RealtimeOptions.transport} (an OpenAI Realtime WebSocket
9
+ * adapter, a mock in tests), then hands back a {@link RealtimeSession}
10
+ * you drive: push audio/text in, consume the event stream out, and
11
+ * `close()` to end it and receive a `type: "realtime"` report for the
12
+ * cost/observability surfaces.
13
+ *
14
+ * Unlike the one-shot `ai.*` verbs, this returns a long-lived session —
15
+ * its closest sibling is `ai.orchestrator`. Keeping the transport
16
+ * pluggable is what lets the session surface ship without hard-wiring a
17
+ * WebSocket dependency.
18
+ *
19
+ * @example
20
+ * const session = await ai.realtime({ transport, model: "gpt-realtime", voice: "alloy" });
21
+ * session.sendAudio(micChunk, "audio/pcm");
22
+ * for await (const event of session.events()) {
23
+ * if (event.type === "audio") speaker.write(event.base64);
24
+ * }
25
+ * const report = await session.close();
26
+ */
27
+ async function realtime(options) {
28
+ const runId = (0, _warlock_js_ai.generateRunId)("realtime");
29
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
30
+ const startPerf = performance.now();
31
+ const connection = await options.transport.connect({
32
+ model: options.model,
33
+ voice: options.voice,
34
+ instructions: options.instructions
35
+ });
36
+ let report;
37
+ return {
38
+ sendAudio: (base64, mediaType) => connection.sendAudio(base64, mediaType),
39
+ sendText: (text) => connection.sendText(text),
40
+ events: () => connection.events(),
41
+ async close() {
42
+ if (report) return report;
43
+ await connection.close();
44
+ report = {
45
+ runId,
46
+ rootRunId: runId,
47
+ type: "realtime",
48
+ name: options.name ?? "realtime",
49
+ status: "completed",
50
+ startedAt,
51
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
52
+ duration: performance.now() - startPerf,
53
+ ...options.sessionId ? { sessionId: options.sessionId } : {}
54
+ };
55
+ return report;
56
+ }
57
+ };
58
+ }
59
+
60
+ //#endregion
61
+ //#region ../@warlock.js/ai-live/src/video/video.ts
62
+ /**
63
+ * Generate a video from a text prompt — the moving-image verb of the
64
+ * output-modality track. The adapter hides the provider's submit→poll
65
+ * job, so this returns the framework's uniform never-throws envelope:
66
+ *
67
+ * - **Never throws.** Provider failures surface as a typed `AIError`.
68
+ * - **Cost-truth.** `usage.cost` is filled per-second (Sora / Veo) or
69
+ * per-token, folding into the same `Usage.cost` rollup as everything else.
70
+ * - **Observable.** The completed {@link VideoReport} routes to any
71
+ * registered `Observer` via the shared `observe` seam.
72
+ *
73
+ * @example
74
+ * const { data, error } = await ai.video({
75
+ * model: sora.video({ name: "sora-2", pricing: { perSecond: 0.1 } }),
76
+ * prompt: "a timelapse of a city skyline at dusk, cinematic",
77
+ * durationSeconds: 8,
78
+ * });
79
+ * if (!error) download(data.video);
80
+ */
81
+ async function video(params) {
82
+ const { model, prompt } = params;
83
+ const runId = (0, _warlock_js_ai.generateRunId)("video");
84
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
85
+ const startPerf = performance.now();
86
+ const usage = {
87
+ input: 0,
88
+ output: 0,
89
+ total: 0
90
+ };
91
+ let data;
92
+ let error;
93
+ let status = "completed";
94
+ let durationSeconds;
95
+ try {
96
+ const response = await model.generate(prompt, {
97
+ durationSeconds: params.durationSeconds,
98
+ aspectRatio: params.aspectRatio,
99
+ resolution: params.resolution,
100
+ negativePrompt: params.negativePrompt,
101
+ signal: params.signal,
102
+ ...params.options
103
+ });
104
+ Object.assign(usage, response.usage);
105
+ durationSeconds = response.durationSeconds;
106
+ if (usage.cost === void 0) {
107
+ const cost = computeVideoCost(usage, durationSeconds, model.pricing);
108
+ if (cost !== void 0) usage.cost = cost;
109
+ }
110
+ data = { video: response.video };
111
+ } catch (thrown) {
112
+ error = thrown instanceof _warlock_js_ai.AIError ? thrown : new _warlock_js_ai.ProviderError(toMessage(thrown), { cause: thrown });
113
+ status = params.signal?.aborted ? "cancelled" : "failed";
114
+ }
115
+ const report = {
116
+ runId,
117
+ rootRunId: runId,
118
+ name: params.name ?? "video",
119
+ type: "video",
120
+ status,
121
+ error,
122
+ startedAt,
123
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
124
+ duration: performance.now() - startPerf,
125
+ usage,
126
+ children: [],
127
+ model: {
128
+ name: model.name,
129
+ provider: model.provider
130
+ },
131
+ ...durationSeconds !== void 0 ? { durationSeconds } : {},
132
+ reportSchemaVersion: _warlock_js_ai.REPORT_SCHEMA_VERSION
133
+ };
134
+ (0, _warlock_js_ai.stampReportLineage)(report, {
135
+ rootRunId: runId,
136
+ sessionId: params.sessionId
137
+ });
138
+ for (const observer of (0, _warlock_js_ai.resolveObservers)(params.observe)) try {
139
+ await observer.collect(report);
140
+ } catch {}
141
+ return {
142
+ type: "video",
143
+ data,
144
+ error,
145
+ usage,
146
+ report
147
+ };
148
+ }
149
+ /**
150
+ * Price a video run: `perSecond × durationSeconds` (per-second metering,
151
+ * attributed to `cost.output`) wins when configured, otherwise the
152
+ * standard token math. Returns `undefined` when no usable pricing is
153
+ * present.
154
+ */
155
+ function computeVideoCost(usage, durationSeconds, pricing) {
156
+ if (!pricing) return;
157
+ if (pricing.perSecond !== void 0) {
158
+ if (durationSeconds === void 0) return;
159
+ return {
160
+ input: 0,
161
+ output: durationSeconds * pricing.perSecond
162
+ };
163
+ }
164
+ if (pricing.input !== void 0 && pricing.output !== void 0) return (0, _warlock_js_ai.computeCost)(usage, {
165
+ input: pricing.input,
166
+ output: pricing.output
167
+ });
168
+ }
169
+ /** Best-effort message for a non-`AIError` thrown value. */
170
+ function toMessage(thrown) {
171
+ return thrown instanceof Error ? thrown.message : String(thrown);
172
+ }
173
+
174
+ //#endregion
175
+ //#region ../@warlock.js/ai-live/src/mock/index.ts
176
+ /** Deterministic {@link VideoModelContract} double for tests — no HTTP, no polling. */
177
+ var MockVideoModel = class {
178
+ constructor(name, responses, pricing) {
179
+ this.name = name;
180
+ this.responses = responses;
181
+ this.pricing = pricing;
182
+ this.provider = "mock";
183
+ this.calls = [];
184
+ this.callIndex = 0;
185
+ }
186
+ async generate(prompt, options) {
187
+ this.calls.push({
188
+ prompt,
189
+ options
190
+ });
191
+ const response = this.responses[Math.min(this.callIndex, this.responses.length - 1)] ?? {};
192
+ this.callIndex += 1;
193
+ if (response.error) throw response.error;
194
+ return {
195
+ video: response.video ?? {
196
+ type: "url",
197
+ url: "https://mock/video.mp4",
198
+ mediaType: "video/mp4"
199
+ },
200
+ usage: response.usage ?? {
201
+ input: 0,
202
+ output: 0,
203
+ total: 0
204
+ },
205
+ durationSeconds: response.durationSeconds ?? options?.durationSeconds ?? 5
206
+ };
207
+ }
208
+ };
209
+ /** A recording {@link RealtimeConnection} the mock transport hands back. */
210
+ var MockRealtimeConnection = class {
211
+ constructor(scripted) {
212
+ this.scripted = scripted;
213
+ this.sentAudio = [];
214
+ this.sentText = [];
215
+ this.closed = false;
216
+ }
217
+ sendAudio(base64, mediaType) {
218
+ this.sentAudio.push({
219
+ base64,
220
+ mediaType
221
+ });
222
+ }
223
+ sendText(text) {
224
+ this.sentText.push(text);
225
+ }
226
+ async *events() {
227
+ for (const event of this.scripted) yield event;
228
+ }
229
+ async close() {
230
+ this.closed = true;
231
+ }
232
+ };
233
+ /** Deterministic {@link RealtimeTransport} double — scripts the event stream, records sends. */
234
+ var MockRealtimeTransport = class {
235
+ constructor(scriptedEvents = []) {
236
+ this.scriptedEvents = scriptedEvents;
237
+ this.connectConfigs = [];
238
+ }
239
+ async connect(config) {
240
+ this.connectConfigs.push(config);
241
+ this.lastConnection = new MockRealtimeConnection(this.scriptedEvents);
242
+ return this.lastConnection;
243
+ }
244
+ };
245
+
246
+ //#endregion
247
+ //#region ../@warlock.js/ai-live/src/index.ts
248
+ _warlock_js_ai.ai.video = video;
249
+ _warlock_js_ai.ai.realtime = realtime;
250
+
251
+ //#endregion
252
+ exports.MockRealtimeConnection = MockRealtimeConnection;
253
+ exports.MockRealtimeTransport = MockRealtimeTransport;
254
+ exports.MockVideoModel = MockVideoModel;
255
+ exports.realtime = realtime;
256
+ exports.video = video;
257
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["AIError","ProviderError","REPORT_SCHEMA_VERSION"],"sources":["../../../../../../@warlock.js/ai-live/src/realtime/realtime.ts","../../../../../../@warlock.js/ai-live/src/video/video.ts","../../../../../../@warlock.js/ai-live/src/mock/index.ts","../../../../../../@warlock.js/ai-live/src/index.ts"],"sourcesContent":["import { generateRunId } from \"@warlock.js/ai\";\nimport type {\n RealtimeOptions,\n RealtimeReport,\n RealtimeSession,\n} from \"../contracts/realtime.contract\";\n\n/**\n * Open a live duplex voice session — the stateful primitive of\n * `@warlock.js/ai-live`. Connects through the provided\n * {@link RealtimeOptions.transport} (an OpenAI Realtime WebSocket\n * adapter, a mock in tests), then hands back a {@link RealtimeSession}\n * you drive: push audio/text in, consume the event stream out, and\n * `close()` to end it and receive a `type: \"realtime\"` report for the\n * cost/observability surfaces.\n *\n * Unlike the one-shot `ai.*` verbs, this returns a long-lived session —\n * its closest sibling is `ai.orchestrator`. Keeping the transport\n * pluggable is what lets the session surface ship without hard-wiring a\n * WebSocket dependency.\n *\n * @example\n * const session = await ai.realtime({ transport, model: \"gpt-realtime\", voice: \"alloy\" });\n * session.sendAudio(micChunk, \"audio/pcm\");\n * for await (const event of session.events()) {\n * if (event.type === \"audio\") speaker.write(event.base64);\n * }\n * const report = await session.close();\n */\nexport async function realtime(options: RealtimeOptions): Promise<RealtimeSession> {\n const runId = generateRunId(\"realtime\");\n const startedAt = new Date().toISOString();\n const startPerf = performance.now();\n\n const connection = await options.transport.connect({\n model: options.model,\n voice: options.voice,\n instructions: options.instructions,\n });\n\n let report: RealtimeReport | undefined;\n\n return {\n sendAudio: (base64, mediaType) => connection.sendAudio(base64, mediaType),\n sendText: (text) => connection.sendText(text),\n events: () => connection.events(),\n async close(): Promise<RealtimeReport> {\n // Idempotent — closing twice returns the first report, never\n // re-tears-down the connection.\n if (report) {\n return report;\n }\n\n await connection.close();\n\n report = {\n runId,\n rootRunId: runId,\n type: \"realtime\",\n name: options.name ?? \"realtime\",\n status: \"completed\",\n startedAt,\n endedAt: new Date().toISOString(),\n duration: performance.now() - startPerf,\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n };\n\n return report;\n },\n };\n}\n","import {\n AIError,\n computeCost,\n generateRunId,\n ProviderError,\n REPORT_SCHEMA_VERSION,\n resolveObservers,\n stampReportLineage,\n type BaseReport,\n type ExecuteResult,\n type FlowObserveOption,\n type ModelPricing,\n type Usage,\n} from \"@warlock.js/ai\";\nimport type {\n GeneratedVideo,\n VideoModelContract,\n VideoModelPricing,\n} from \"../contracts/video.contract\";\n\n/** Parameters for {@link video}. `model` comes from an adapter's `video({ name })`. */\nexport type VideoParams = {\n model: VideoModelContract;\n prompt: string;\n durationSeconds?: number;\n aspectRatio?: string;\n resolution?: string;\n negativePrompt?: string;\n signal?: AbortSignal;\n observe?: FlowObserveOption;\n sessionId?: string;\n name?: string;\n options?: Record<string, unknown>;\n};\n\n/** Success payload of a {@link video} run. */\nexport type VideoData = { video: GeneratedVideo };\n\n/** The report node a {@link video} run produces (`type: \"video\"`). */\nexport type VideoReport = BaseReport & {\n type: \"video\";\n model: { name: string; provider: string };\n /** Final clip duration in seconds, when reported. */\n durationSeconds?: number;\n};\n\n/** Result envelope of {@link video} — the uniform `{ data, error, usage, report }`. */\nexport type VideoResult = ExecuteResult<VideoData> & { type: \"video\"; report: VideoReport };\n\n/**\n * Generate a video from a text prompt — the moving-image verb of the\n * output-modality track. The adapter hides the provider's submit→poll\n * job, so this returns the framework's uniform never-throws envelope:\n *\n * - **Never throws.** Provider failures surface as a typed `AIError`.\n * - **Cost-truth.** `usage.cost` is filled per-second (Sora / Veo) or\n * per-token, folding into the same `Usage.cost` rollup as everything else.\n * - **Observable.** The completed {@link VideoReport} routes to any\n * registered `Observer` via the shared `observe` seam.\n *\n * @example\n * const { data, error } = await ai.video({\n * model: sora.video({ name: \"sora-2\", pricing: { perSecond: 0.1 } }),\n * prompt: \"a timelapse of a city skyline at dusk, cinematic\",\n * durationSeconds: 8,\n * });\n * if (!error) download(data.video);\n */\nexport async function video(params: VideoParams): Promise<VideoResult> {\n const { model, prompt } = params;\n\n const runId = generateRunId(\"video\");\n const startedAt = new Date().toISOString();\n const startPerf = performance.now();\n\n const usage: Usage = { input: 0, output: 0, total: 0 };\n let data: VideoData | undefined;\n let error: AIError | undefined;\n let status: VideoReport[\"status\"] = \"completed\";\n let durationSeconds: number | undefined;\n\n try {\n const response = await model.generate(prompt, {\n durationSeconds: params.durationSeconds,\n aspectRatio: params.aspectRatio,\n resolution: params.resolution,\n negativePrompt: params.negativePrompt,\n signal: params.signal,\n ...params.options,\n });\n\n Object.assign(usage, response.usage);\n durationSeconds = response.durationSeconds;\n\n if (usage.cost === undefined) {\n const cost = computeVideoCost(usage, durationSeconds, model.pricing);\n if (cost !== undefined) {\n usage.cost = cost;\n }\n }\n\n data = { video: response.video };\n } catch (thrown) {\n error =\n thrown instanceof AIError ? thrown : new ProviderError(toMessage(thrown), { cause: thrown });\n status = params.signal?.aborted ? \"cancelled\" : \"failed\";\n }\n\n const report: VideoReport = {\n runId,\n rootRunId: runId,\n name: params.name ?? \"video\",\n type: \"video\",\n status,\n error,\n startedAt,\n endedAt: new Date().toISOString(),\n duration: performance.now() - startPerf,\n usage,\n children: [],\n model: { name: model.name, provider: model.provider },\n ...(durationSeconds !== undefined ? { durationSeconds } : {}),\n reportSchemaVersion: REPORT_SCHEMA_VERSION,\n };\n\n stampReportLineage(report, { rootRunId: runId, sessionId: params.sessionId });\n\n for (const observer of resolveObservers(params.observe)) {\n try {\n await observer.collect(report);\n } catch {\n // Isolate observer failures — never break the run.\n }\n }\n\n return { type: \"video\", data, error, usage, report };\n}\n\n/**\n * Price a video run: `perSecond × durationSeconds` (per-second metering,\n * attributed to `cost.output`) wins when configured, otherwise the\n * standard token math. Returns `undefined` when no usable pricing is\n * present.\n */\nfunction computeVideoCost(\n usage: Usage,\n durationSeconds: number | undefined,\n pricing: VideoModelPricing | undefined,\n): ModelPricing | undefined {\n if (!pricing) {\n return undefined;\n }\n\n if (pricing.perSecond !== undefined) {\n if (durationSeconds === undefined) {\n return undefined;\n }\n return { input: 0, output: durationSeconds * pricing.perSecond };\n }\n\n if (pricing.input !== undefined && pricing.output !== undefined) {\n return computeCost(usage, { input: pricing.input, output: pricing.output });\n }\n\n return undefined;\n}\n\n/** Best-effort message for a non-`AIError` thrown value. */\nfunction toMessage(thrown: unknown): string {\n return thrown instanceof Error ? thrown.message : String(thrown);\n}\n","import type { Usage } from \"@warlock.js/ai\";\nimport type {\n RealtimeConnectConfig,\n RealtimeConnection,\n RealtimeEvent,\n RealtimeTransport,\n} from \"../contracts/realtime.contract\";\nimport type {\n GeneratedVideo,\n VideoGenerationResponse,\n VideoModelContract,\n VideoModelPricing,\n VideoOptions,\n} from \"../contracts/video.contract\";\n\n/** One scripted response for a {@link MockVideoModel}. */\nexport type MockVideoResponse = {\n video?: GeneratedVideo;\n usage?: Usage;\n durationSeconds?: number;\n error?: Error;\n};\n\n/** Deterministic {@link VideoModelContract} double for tests — no HTTP, no polling. */\nexport class MockVideoModel implements VideoModelContract {\n public readonly provider = \"mock\";\n public readonly calls: { prompt: string; options: VideoOptions | undefined }[] = [];\n\n private callIndex = 0;\n\n public constructor(\n public readonly name: string,\n private readonly responses: MockVideoResponse[],\n public readonly pricing?: VideoModelPricing,\n ) {}\n\n public async generate(\n prompt: string,\n options?: VideoOptions,\n ): Promise<VideoGenerationResponse> {\n this.calls.push({ prompt, options });\n\n const response = this.responses[Math.min(this.callIndex, this.responses.length - 1)] ?? {};\n this.callIndex += 1;\n\n if (response.error) {\n throw response.error;\n }\n\n return {\n video: response.video ?? { type: \"url\", url: \"https://mock/video.mp4\", mediaType: \"video/mp4\" },\n usage: response.usage ?? { input: 0, output: 0, total: 0 },\n durationSeconds: response.durationSeconds ?? options?.durationSeconds ?? 5,\n };\n }\n}\n\n/** A recording {@link RealtimeConnection} the mock transport hands back. */\nexport class MockRealtimeConnection implements RealtimeConnection {\n public readonly sentAudio: { base64: string; mediaType: string }[] = [];\n public readonly sentText: string[] = [];\n public closed = false;\n\n public constructor(private readonly scripted: RealtimeEvent[]) {}\n\n public sendAudio(base64: string, mediaType: string): void {\n this.sentAudio.push({ base64, mediaType });\n }\n\n public sendText(text: string): void {\n this.sentText.push(text);\n }\n\n public async *events(): AsyncIterable<RealtimeEvent> {\n for (const event of this.scripted) {\n yield event;\n }\n }\n\n public async close(): Promise<void> {\n this.closed = true;\n }\n}\n\n/** Deterministic {@link RealtimeTransport} double — scripts the event stream, records sends. */\nexport class MockRealtimeTransport implements RealtimeTransport {\n public readonly connectConfigs: RealtimeConnectConfig[] = [];\n public lastConnection?: MockRealtimeConnection;\n\n public constructor(private readonly scriptedEvents: RealtimeEvent[] = []) {}\n\n public async connect(config: RealtimeConnectConfig): Promise<RealtimeConnection> {\n this.connectConfigs.push(config);\n this.lastConnection = new MockRealtimeConnection(this.scriptedEvents);\n return this.lastConnection;\n }\n}\n","import { ai } from \"@warlock.js/ai\";\nimport { realtime } from \"./realtime/realtime\";\nimport { video } from \"./video/video\";\n\n/**\n * Augment the shared `Ai` facade with this package's two heavy\n * modalities. Importing `@warlock.js/ai-live` mounts `ai.video` +\n * `ai.realtime` as a side effect, mirroring how `@warlock.js/ai-tools`\n * mounts `ai.mcp` / `ai.tools` and `@warlock.js/ai-workspace` mounts\n * `ai.workspace`.\n */\ndeclare module \"@warlock.js/ai\" {\n interface Ai {\n /**\n * Text-to-video generation (Sora / Veo / Kling-class). Async under\n * the hood (submit→poll), surfaced as the uniform never-throws\n * `{ data, error, usage, report }` envelope. Ships in `@warlock.js/ai-live`.\n */\n video: typeof video;\n /**\n * Live duplex voice sessions (OpenAI Realtime-class). A stateful\n * session over a pluggable transport — push audio/text in, consume\n * events out, `close()` for a report. Ships in `@warlock.js/ai-live`.\n */\n realtime: typeof realtime;\n }\n}\n\nai.video = video;\nai.realtime = realtime;\n\nexport { realtime, video };\nexport type { VideoData, VideoParams, VideoReport, VideoResult } from \"./video/video\";\nexport * from \"./contracts/video.contract\";\nexport * from \"./contracts/realtime.contract\";\nexport * from \"./mock\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,eAAsB,SAAS,SAAoD;CACjF,MAAM,0CAAsB,UAAU;CACtC,MAAM,6BAAY,IAAI,KAAK,EAAC,CAAC,YAAY;CACzC,MAAM,YAAY,YAAY,IAAI;CAElC,MAAM,aAAa,MAAM,QAAQ,UAAU,QAAQ;EACjD,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,cAAc,QAAQ;CACxB,CAAC;CAED,IAAI;CAEJ,OAAO;EACL,YAAY,QAAQ,cAAc,WAAW,UAAU,QAAQ,SAAS;EACxE,WAAW,SAAS,WAAW,SAAS,IAAI;EAC5C,cAAc,WAAW,OAAO;EAChC,MAAM,QAAiC;GAGrC,IAAI,QACF,OAAO;GAGT,MAAM,WAAW,MAAM;GAEvB,SAAS;IACP;IACA,WAAW;IACX,MAAM;IACN,MAAM,QAAQ,QAAQ;IACtB,QAAQ;IACR;IACA,0BAAS,IAAI,KAAK,EAAC,CAAC,YAAY;IAChC,UAAU,YAAY,IAAI,IAAI;IAC9B,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;GAC9D;GAEA,OAAO;EACT;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;ACFA,eAAsB,MAAM,QAA2C;CACrE,MAAM,EAAE,OAAO,WAAW;CAE1B,MAAM,0CAAsB,OAAO;CACnC,MAAM,6BAAY,IAAI,KAAK,EAAC,CAAC,YAAY;CACzC,MAAM,YAAY,YAAY,IAAI;CAElC,MAAM,QAAe;EAAE,OAAO;EAAG,QAAQ;EAAG,OAAO;CAAE;CACrD,IAAI;CACJ,IAAI;CACJ,IAAI,SAAgC;CACpC,IAAI;CAEJ,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,SAAS,QAAQ;GAC5C,iBAAiB,OAAO;GACxB,aAAa,OAAO;GACpB,YAAY,OAAO;GACnB,gBAAgB,OAAO;GACvB,QAAQ,OAAO;GACf,GAAG,OAAO;EACZ,CAAC;EAED,OAAO,OAAO,OAAO,SAAS,KAAK;EACnC,kBAAkB,SAAS;EAE3B,IAAI,MAAM,SAAS,QAAW;GAC5B,MAAM,OAAO,iBAAiB,OAAO,iBAAiB,MAAM,OAAO;GACnE,IAAI,SAAS,QACX,MAAM,OAAO;EAEjB;EAEA,OAAO,EAAE,OAAO,SAAS,MAAM;CACjC,SAAS,QAAQ;EACf,QACE,kBAAkBA,yBAAU,SAAS,IAAIC,6BAAc,UAAU,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC;EAC7F,SAAS,OAAO,QAAQ,UAAU,cAAc;CAClD;CAEA,MAAM,SAAsB;EAC1B;EACA,WAAW;EACX,MAAM,OAAO,QAAQ;EACrB,MAAM;EACN;EACA;EACA;EACA,0BAAS,IAAI,KAAK,EAAC,CAAC,YAAY;EAChC,UAAU,YAAY,IAAI,IAAI;EAC9B;EACA,UAAU,CAAC;EACX,OAAO;GAAE,MAAM,MAAM;GAAM,UAAU,MAAM;EAAS;EACpD,GAAI,oBAAoB,SAAY,EAAE,gBAAgB,IAAI,CAAC;EAC3D,qBAAqBC;CACvB;CAEA,uCAAmB,QAAQ;EAAE,WAAW;EAAO,WAAW,OAAO;CAAU,CAAC;CAE5E,KAAK,MAAM,iDAA6B,OAAO,OAAO,GACpD,IAAI;EACF,MAAM,SAAS,QAAQ,MAAM;CAC/B,QAAQ,CAER;CAGF,OAAO;EAAE,MAAM;EAAS;EAAM;EAAO;EAAO;CAAO;AACrD;;;;;;;AAQA,SAAS,iBACP,OACA,iBACA,SAC0B;CAC1B,IAAI,CAAC,SACH;CAGF,IAAI,QAAQ,cAAc,QAAW;EACnC,IAAI,oBAAoB,QACtB;EAEF,OAAO;GAAE,OAAO;GAAG,QAAQ,kBAAkB,QAAQ;EAAU;CACjE;CAEA,IAAI,QAAQ,UAAU,UAAa,QAAQ,WAAW,QACpD,uCAAmB,OAAO;EAAE,OAAO,QAAQ;EAAO,QAAQ,QAAQ;CAAO,CAAC;AAI9E;;AAGA,SAAS,UAAU,QAAyB;CAC1C,OAAO,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM;AACjE;;;;;AClJA,IAAa,iBAAb,MAA0D;CAMxD,AAAO,YACL,AAAgB,MAChB,AAAiB,WACjB,AAAgB,SAChB;EAHgB;EACC;EACD;kBARS;eACsD,CAAC;mBAE9D;CAMjB;CAEH,MAAa,SACX,QACA,SACkC;EAClC,KAAK,MAAM,KAAK;GAAE;GAAQ;EAAQ,CAAC;EAEnC,MAAM,WAAW,KAAK,UAAU,KAAK,IAAI,KAAK,WAAW,KAAK,UAAU,SAAS,CAAC,MAAM,CAAC;EACzF,KAAK,aAAa;EAElB,IAAI,SAAS,OACX,MAAM,SAAS;EAGjB,OAAO;GACL,OAAO,SAAS,SAAS;IAAE,MAAM;IAAO,KAAK;IAA0B,WAAW;GAAY;GAC9F,OAAO,SAAS,SAAS;IAAE,OAAO;IAAG,QAAQ;IAAG,OAAO;GAAE;GACzD,iBAAiB,SAAS,mBAAmB,SAAS,mBAAmB;EAC3E;CACF;AACF;;AAGA,IAAa,yBAAb,MAAkE;CAKhE,AAAO,YAAY,AAAiB,UAA2B;EAA3B;mBAJiC,CAAC;kBACjC,CAAC;gBACtB;CAEgD;CAEhE,AAAO,UAAU,QAAgB,WAAyB;EACxD,KAAK,UAAU,KAAK;GAAE;GAAQ;EAAU,CAAC;CAC3C;CAEA,AAAO,SAAS,MAAoB;EAClC,KAAK,SAAS,KAAK,IAAI;CACzB;CAEA,OAAc,SAAuC;EACnD,KAAK,MAAM,SAAS,KAAK,UACvB,MAAM;CAEV;CAEA,MAAa,QAAuB;EAClC,KAAK,SAAS;CAChB;AACF;;AAGA,IAAa,wBAAb,MAAgE;CAI9D,AAAO,YAAY,AAAiB,iBAAkC,CAAC,GAAG;EAAtC;wBAHsB,CAAC;CAGgB;CAE3E,MAAa,QAAQ,QAA4D;EAC/E,KAAK,eAAe,KAAK,MAAM;EAC/B,KAAK,iBAAiB,IAAI,uBAAuB,KAAK,cAAc;EACpE,OAAO,KAAK;CACd;AACF;;;;ACpEA,kBAAG,QAAQ;AACX,kBAAG,WAAW"}
@@ -0,0 +1,104 @@
1
+ import { AIError } from "@warlock.js/ai";
2
+
3
+ //#region ../@warlock.js/ai-live/src/contracts/realtime.contract.d.ts
4
+ /**
5
+ * One event streamed out of a realtime voice session. A closed union so
6
+ * consumers can `switch` exhaustively over the duplex output.
7
+ *
8
+ * - `audio` — a chunk of synthesized assistant audio (base64).
9
+ * - `transcript` — an incremental or final transcript line for either side.
10
+ * - `tool-call` — the model requested a tool (wire it like an agent tool).
11
+ * - `error` — a typed, non-fatal provider/transport error.
12
+ * - `done` — the session ended (server-side).
13
+ */
14
+ type RealtimeEvent = {
15
+ type: "audio";
16
+ base64: string;
17
+ mediaType: string;
18
+ } | {
19
+ type: "transcript";
20
+ role: "user" | "assistant";
21
+ text: string;
22
+ final: boolean;
23
+ } | {
24
+ type: "tool-call";
25
+ id: string;
26
+ name: string;
27
+ input: unknown;
28
+ } | {
29
+ type: "error";
30
+ error: AIError;
31
+ } | {
32
+ type: "done";
33
+ };
34
+ /** Config a {@link RealtimeTransport} needs to open a connection. */
35
+ type RealtimeConnectConfig = {
36
+ /** Realtime model id (e.g. `"gpt-realtime"`). */model: string; /** Default voice. */
37
+ voice?: string; /** System instructions for the session. */
38
+ instructions?: string;
39
+ };
40
+ /**
41
+ * A live, bidirectional connection to a provider's realtime endpoint —
42
+ * the low-level transport the {@link RealtimeSession} wraps. The first
43
+ * concrete transport is an OpenAI Realtime WebSocket (own adapter); a
44
+ * mock transport drives the tests. Keeping this pluggable is what lets
45
+ * `ai-live` ship the session surface without hard-wiring `ws`.
46
+ */
47
+ interface RealtimeConnection {
48
+ /** Push a chunk of microphone audio (base64) upstream. */
49
+ sendAudio(base64: string, mediaType: string): void;
50
+ /** Push a text message upstream (the model can reply with audio). */
51
+ sendText(text: string): void;
52
+ /** The duplex event stream coming back from the provider. */
53
+ events(): AsyncIterable<RealtimeEvent>;
54
+ /** Tear down the connection. */
55
+ close(): Promise<void>;
56
+ }
57
+ /** Opens a {@link RealtimeConnection}. Implemented per provider. */
58
+ interface RealtimeTransport {
59
+ connect(config: RealtimeConnectConfig): Promise<RealtimeConnection>;
60
+ }
61
+ /** Options for {@link ai.realtime}. */
62
+ type RealtimeOptions = {
63
+ /** The provider transport (e.g. an OpenAI Realtime WebSocket adapter). */transport: RealtimeTransport; /** Realtime model id. */
64
+ model: string; /** Default voice. */
65
+ voice?: string; /** System instructions for the session. */
66
+ instructions?: string; /** Groups this session into a wider request for cost/trace queries. */
67
+ sessionId?: string; /** Report node name (defaults to `"realtime"`). */
68
+ name?: string;
69
+ };
70
+ /**
71
+ * A live duplex voice session — the stateful primitive `ai.realtime()`
72
+ * returns. Push audio/text in, consume {@link RealtimeEvent}s out, and
73
+ * `close()` to end the session and get a report for cost + observability.
74
+ * Its closest sibling is `ai.orchestrator` (a session, not a one-shot).
75
+ */
76
+ interface RealtimeSession {
77
+ /** Push microphone audio (base64) into the session. */
78
+ sendAudio(base64: string, mediaType: string): void;
79
+ /** Push a text turn into the session. */
80
+ sendText(text: string): void;
81
+ /** The duplex event stream (audio / transcript / tool-call / …). */
82
+ events(): AsyncIterable<RealtimeEvent>;
83
+ /** End the session; resolves with the session's report. */
84
+ close(): Promise<RealtimeReport>;
85
+ }
86
+ /**
87
+ * The report a closed {@link RealtimeSession} produces — a flat
88
+ * `type: "realtime"` node for the trace/cost surfaces. (Realtime usage
89
+ * accounting is provider-dependent and refined as transports land.)
90
+ */
91
+ type RealtimeReport = {
92
+ runId: string;
93
+ rootRunId: string;
94
+ type: "realtime";
95
+ name: string;
96
+ status: "completed" | "failed" | "cancelled";
97
+ startedAt: string;
98
+ endedAt: string;
99
+ duration: number;
100
+ sessionId?: string;
101
+ };
102
+ //#endregion
103
+ export { RealtimeConnectConfig, RealtimeConnection, RealtimeEvent, RealtimeOptions, RealtimeReport, RealtimeSession, RealtimeTransport };
104
+ //# sourceMappingURL=realtime.contract.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.contract.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-live/src/contracts/realtime.contract.ts"],"mappings":";;;;;AAYA;;;;;;;;KAAY,aAAA;EACN,IAAA;EAAe,MAAA;EAAgB,SAAA;AAAA;EAC/B,IAAA;EAAoB,IAAA;EAA4B,IAAA;EAAc,KAAA;AAAA;EAC9D,IAAA;EAAmB,EAAA;EAAY,IAAA;EAAc,KAAA;AAAA;EAC7C,IAAA;EAAe,KAAA,EAAO,OAAO;AAAA;EAC7B,IAAA;AAAA;;KAGM,qBAAA;EAgBK,iDAdf,KAAA;EAEA,KAAA,WAkBU;EAhBV,YAAA;AAAA;;;;;;;;UAUe,kBAAA;EAMS;EAJxB,SAAA,CAAU,MAAA,UAAgB,SAAA;EAMjB;EAJT,QAAA,CAAS,IAAA;EAIO;EAFhB,MAAA,IAAU,aAAA,CAAc,aAAA;EAMQ;EAJhC,KAAA,IAAS,OAAA;AAAA;;UAIM,iBAAA;EACf,OAAA,CAAQ,MAAA,EAAQ,qBAAA,GAAwB,OAAA,CAAQ,kBAAA;AAAA;;KAItC,eAAA;EAJF,0EAMR,SAAA,EAAW,iBAAiB,EANoB;EAQhD,KAAA,UARkE;EAUlE,KAAA,WANyB;EAQzB,YAAA,WAN4B;EAQ5B,SAAA,WARW;EAUX,IAAA;AAAA;;;;;AAAI;AASN;UAAiB,eAAA;;EAEf,SAAA,CAAU,MAAA,UAAgB,SAAA;EAIhB;EAFV,QAAA,CAAS,IAAA;EAIA;EAFT,MAAA,IAAU,aAAA,CAAc,aAAA;EAER;EAAhB,KAAA,IAAS,OAAA,CAAQ,cAAA;AAAA;;;;;;KAQP,cAAA;EACV,KAAA;EACA,SAAA;EACA,IAAA;EACA,IAAA;EACA,MAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,SAAA;AAAA"}
@@ -0,0 +1,72 @@
1
+ import { Usage } from "@warlock.js/ai";
2
+
3
+ //#region ../@warlock.js/ai-live/src/contracts/video.contract.d.ts
4
+ /**
5
+ * USD pricing for a text-to-video model. Video providers meter per
6
+ * second of generated video (Sora / Veo / Kling); a token channel is
7
+ * kept for the rare token-metered model. Per-second wins when both are
8
+ * set. Folds into the same `Usage.cost` rollup as every other modality.
9
+ *
10
+ * @example
11
+ * const pricing: VideoModelPricing = { perSecond: 0.1 };
12
+ */
13
+ type VideoModelPricing = {
14
+ /** USD per second of generated video — per-second-metered models. */perSecond?: number; /** USD per 1M input tokens — token-metered models. */
15
+ input?: number; /** USD per 1M output tokens — token-metered models. */
16
+ output?: number;
17
+ };
18
+ /**
19
+ * One generated video, normalized to a discriminated shape (mirrors
20
+ * `GeneratedImage`). Providers return either a hosted URL (typically the
21
+ * common case for video, which is large) or inlined base64 bytes.
22
+ */
23
+ type GeneratedVideo = {
24
+ type: "url";
25
+ url: string;
26
+ mediaType?: string;
27
+ } | {
28
+ type: "base64";
29
+ base64: string;
30
+ mediaType: string;
31
+ };
32
+ /** Options for a single {@link VideoModelContract.generate} request. */
33
+ type VideoOptions = {
34
+ /** Requested clip length in seconds. */durationSeconds?: number; /** Aspect ratio (e.g. `"16:9"`, `"9:16"`). */
35
+ aspectRatio?: string; /** Resolution hint (e.g. `"720p"`, `"1080p"`). */
36
+ resolution?: string; /** Concepts to steer away from. */
37
+ negativePrompt?: string; /** Cancellation handle. */
38
+ signal?: AbortSignal; /** Provider-specific escape hatch — forwarded verbatim. */
39
+ [key: string]: unknown;
40
+ };
41
+ /**
42
+ * Raw result of a {@link VideoModelContract.generate} call. The adapter
43
+ * hides the submit→poll lifecycle and resolves only when the video is
44
+ * ready (or throws a typed `AIError`). The never-throws envelope is
45
+ * added by `ai.video()`.
46
+ */
47
+ type VideoGenerationResponse = {
48
+ video: GeneratedVideo; /** Token usage when the provider reports it; otherwise all-zero. */
49
+ usage: Usage; /** Final clip duration in seconds — drives per-second cost. */
50
+ durationSeconds?: number;
51
+ };
52
+ /**
53
+ * Provider-neutral contract for a text-to-video model — the moving-image
54
+ * sibling of `ImageModelContract`. Produced by an adapter's `video()`
55
+ * factory and consumed by `ai.video()`. `generate()` encapsulates the
56
+ * provider's async job (submit → poll → fetch result).
57
+ */
58
+ interface VideoModelContract {
59
+ readonly name: string;
60
+ readonly provider: string;
61
+ readonly pricing?: VideoModelPricing;
62
+ generate(prompt: string, options?: VideoOptions): Promise<VideoGenerationResponse>;
63
+ }
64
+ /** Configuration passed to an adapter's `video()` factory. */
65
+ type VideoModelConfig = {
66
+ name: string;
67
+ pricing?: VideoModelPricing;
68
+ [key: string]: unknown;
69
+ };
70
+ //#endregion
71
+ export { GeneratedVideo, VideoGenerationResponse, VideoModelConfig, VideoModelContract, VideoModelPricing, VideoOptions };
72
+ //# sourceMappingURL=video.contract.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.contract.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-live/src/contracts/video.contract.ts"],"mappings":";;;;;AAWA;;;;;;;KAAY,iBAAA;EAMJ,qEAJN,SAAA,WAYwB;EAVxB,KAAA,WAUwB;EARxB,MAAA;AAAA;;;;;;KAQU,cAAA;EACN,IAAA;EAAa,GAAA;EAAa,SAAA;AAAA;EAC1B,IAAA;EAAgB,MAAA;EAAgB,SAAA;AAAA;;KAG1B,YAAA;EAYT,wCAVD,eAAA,WAUY;EARZ,WAAA,WAiBiC;EAfjC,UAAA,WAkBY;EAhBZ,cAAA,WAcO;EAZP,MAAA,GAAS,WAAW,EAcb;EAAA,CAZN,GAAA;AAAA;AAcc;AASjB;;;;;AATiB,KALL,uBAAA;EACV,KAAA,EAAO,cAAA,EAiBkD;EAfzD,KAAA,EAAO,KAAK,EAYH;EAVT,eAAA;AAAA;;;;;;;UASe,kBAAA;EAAA,SACN,IAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA,GAAU,iBAAA;EACnB,QAAA,CAAS,MAAA,UAAgB,OAAA,GAAU,YAAA,GAAe,OAAA,CAAQ,uBAAA;AAAA;;KAIhD,gBAAA;EACV,IAAA;EACA,OAAA,GAAU,iBAAiB;EAAA,CAC1B,GAAA;AAAA"}
@@ -0,0 +1,33 @@
1
+ import { RealtimeConnectConfig, RealtimeConnection, RealtimeEvent, RealtimeOptions, RealtimeReport, RealtimeSession, RealtimeTransport } from "./contracts/realtime.contract.mjs";
2
+ import { realtime } from "./realtime/realtime.mjs";
3
+ import { GeneratedVideo, VideoGenerationResponse, VideoModelConfig, VideoModelContract, VideoModelPricing, VideoOptions } from "./contracts/video.contract.mjs";
4
+ import { VideoData, VideoParams, VideoReport, VideoResult, video } from "./video/video.mjs";
5
+ import { MockRealtimeConnection, MockRealtimeTransport, MockVideoModel, MockVideoResponse } from "./mock/index.mjs";
6
+
7
+ //#region ../@warlock.js/ai-live/src/index.d.ts
8
+ /**
9
+ * Augment the shared `Ai` facade with this package's two heavy
10
+ * modalities. Importing `@warlock.js/ai-live` mounts `ai.video` +
11
+ * `ai.realtime` as a side effect, mirroring how `@warlock.js/ai-tools`
12
+ * mounts `ai.mcp` / `ai.tools` and `@warlock.js/ai-workspace` mounts
13
+ * `ai.workspace`.
14
+ */
15
+ declare module "@warlock.js/ai" {
16
+ interface Ai {
17
+ /**
18
+ * Text-to-video generation (Sora / Veo / Kling-class). Async under
19
+ * the hood (submit→poll), surfaced as the uniform never-throws
20
+ * `{ data, error, usage, report }` envelope. Ships in `@warlock.js/ai-live`.
21
+ */
22
+ video: typeof video;
23
+ /**
24
+ * Live duplex voice sessions (OpenAI Realtime-class). A stateful
25
+ * session over a pluggable transport — push audio/text in, consume
26
+ * events out, `close()` for a report. Ships in `@warlock.js/ai-live`.
27
+ */
28
+ realtime: typeof realtime;
29
+ }
30
+ }
31
+ //#endregion
32
+ export { GeneratedVideo, MockRealtimeConnection, MockRealtimeTransport, MockVideoModel, MockVideoResponse, RealtimeConnectConfig, RealtimeConnection, RealtimeEvent, RealtimeOptions, RealtimeReport, RealtimeSession, RealtimeTransport, type VideoData, VideoGenerationResponse, VideoModelConfig, VideoModelContract, VideoModelPricing, VideoOptions, type VideoParams, type VideoReport, type VideoResult, realtime, video };
33
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../../../@warlock.js/ai-live/src/index.ts"],"mappings":";;;;;;;;;;;;AAEsC;;;YAU1B,EAAA;IAAA;;;;;IAMR,KAAA,SAAc,KAAA;IAMW;AAAA;;;;IAAzB,QAAA,SAAiB,QAAQ;EAAA;AAAA"}
package/esm/index.mjs ADDED
@@ -0,0 +1,12 @@
1
+ import { realtime } from "./realtime/realtime.mjs";
2
+ import { video } from "./video/video.mjs";
3
+ import { MockRealtimeConnection, MockRealtimeTransport, MockVideoModel } from "./mock/index.mjs";
4
+ import { ai } from "@warlock.js/ai";
5
+
6
+ //#region ../@warlock.js/ai-live/src/index.ts
7
+ ai.video = video;
8
+ ai.realtime = realtime;
9
+
10
+ //#endregion
11
+ export { MockRealtimeConnection, MockRealtimeTransport, MockVideoModel, realtime, video };
12
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../@warlock.js/ai-live/src/index.ts"],"sourcesContent":["import { ai } from \"@warlock.js/ai\";\nimport { realtime } from \"./realtime/realtime\";\nimport { video } from \"./video/video\";\n\n/**\n * Augment the shared `Ai` facade with this package's two heavy\n * modalities. Importing `@warlock.js/ai-live` mounts `ai.video` +\n * `ai.realtime` as a side effect, mirroring how `@warlock.js/ai-tools`\n * mounts `ai.mcp` / `ai.tools` and `@warlock.js/ai-workspace` mounts\n * `ai.workspace`.\n */\ndeclare module \"@warlock.js/ai\" {\n interface Ai {\n /**\n * Text-to-video generation (Sora / Veo / Kling-class). Async under\n * the hood (submit→poll), surfaced as the uniform never-throws\n * `{ data, error, usage, report }` envelope. Ships in `@warlock.js/ai-live`.\n */\n video: typeof video;\n /**\n * Live duplex voice sessions (OpenAI Realtime-class). A stateful\n * session over a pluggable transport — push audio/text in, consume\n * events out, `close()` for a report. Ships in `@warlock.js/ai-live`.\n */\n realtime: typeof realtime;\n }\n}\n\nai.video = video;\nai.realtime = realtime;\n\nexport { realtime, video };\nexport type { VideoData, VideoParams, VideoReport, VideoResult } from \"./video/video\";\nexport * from \"./contracts/video.contract\";\nexport * from \"./contracts/realtime.contract\";\nexport * from \"./mock\";\n"],"mappings":";;;;;;AA4BA,GAAG,QAAQ;AACX,GAAG,WAAW"}