prompt-api-polyfill 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1031 @@
1
+ import { Schema as T } from "firebase/ai";
2
+ ReadableStream.prototype[Symbol.asyncIterator] || (ReadableStream.prototype[Symbol.asyncIterator] = async function* () {
3
+ const l = this.getReader();
4
+ try {
5
+ for (; ; ) {
6
+ const { done: t, value: e } = await l.read();
7
+ if (t)
8
+ return;
9
+ yield e;
10
+ }
11
+ } finally {
12
+ l.releaseLock();
13
+ }
14
+ });
15
+ class M {
16
+ static async convert(t, e) {
17
+ if (t === "image")
18
+ return this.processImage(e);
19
+ if (t === "audio")
20
+ return this.processAudio(e);
21
+ throw new DOMException(
22
+ `Unsupported media type: ${t}`,
23
+ "NotSupportedError"
24
+ );
25
+ }
26
+ static async processImage(t) {
27
+ if (t instanceof Blob)
28
+ return this.blobToInlineData(t);
29
+ if (ArrayBuffer.isView(t) || t instanceof ArrayBuffer) {
30
+ const e = t instanceof ArrayBuffer ? new Uint8Array(t) : new Uint8Array(t.buffer, t.byteOffset, t.byteLength), r = e.buffer.slice(
31
+ e.byteOffset,
32
+ e.byteOffset + e.byteLength
33
+ ), o = this.arrayBufferToBase64(r), n = this.#o(e);
34
+ if (!n)
35
+ throw new DOMException("Invalid image data", "InvalidStateError");
36
+ return { inlineData: { data: o, mimeType: n } };
37
+ }
38
+ return this.canvasSourceToInlineData(t);
39
+ }
40
+ static #o(t) {
41
+ if (t.length < 4)
42
+ return null;
43
+ if (t[0] === 255 && t[1] === 216 && t[2] === 255)
44
+ return "image/jpeg";
45
+ if (t[0] === 137 && t[1] === 80 && t[2] === 78 && t[3] === 71 && t[4] === 13 && t[5] === 10 && t[6] === 26 && t[7] === 10)
46
+ return "image/png";
47
+ if (t[0] === 71 && t[1] === 73 && t[2] === 70 && t[3] === 56)
48
+ return "image/gif";
49
+ if (t[0] === 82 && t[1] === 73 && t[2] === 70 && t[3] === 70 && t[8] === 87 && t[9] === 69 && t[10] === 66 && t[11] === 80)
50
+ return "image/webp";
51
+ if (t[0] === 66 && t[1] === 77)
52
+ return "image/bmp";
53
+ if (t[0] === 0 && t[1] === 0 && t[2] === 1 && t[3] === 0)
54
+ return "image/x-icon";
55
+ if (t[0] === 73 && t[1] === 73 && t[2] === 42 || t[0] === 77 && t[1] === 77 && t[2] === 42)
56
+ return "image/tiff";
57
+ if (t[4] === 102 && t[5] === 116 && t[6] === 121 && t[7] === 112) {
58
+ const o = String.fromCharCode(t[8], t[9], t[10], t[11]);
59
+ if (o === "avif" || o === "avis")
60
+ return "image/avif";
61
+ if (o === "heic" || o === "heix" || o === "hevc" || o === "hevx")
62
+ return "image/heic";
63
+ if (o === "mif1" || o === "msf1")
64
+ return "image/heif";
65
+ }
66
+ if (t[0] === 255 && t[1] === 10 || t[0] === 0 && t[4] === 74 && t[5] === 88 && t[6] === 76)
67
+ return "image/jxl";
68
+ if (t[0] === 0 && t[4] === 106 && t[5] === 80 && t[6] === 32)
69
+ return "image/jp2";
70
+ const r = String.fromCharCode(...t.slice(0, 100)).toLowerCase();
71
+ return r.includes("<svg") || r.includes("<?xml") ? "image/svg+xml" : null;
72
+ }
73
+ static async processAudio(t) {
74
+ if (t instanceof Blob) {
75
+ if (t.type && !t.type.startsWith("audio/") && t.type !== "application/ogg")
76
+ throw new DOMException("Invalid audio mime type", "DataError");
77
+ return this.blobToInlineData(t);
78
+ }
79
+ if (t instanceof AudioBuffer) {
80
+ const o = this.audioBufferToWav(t);
81
+ return { inlineData: { data: this.arrayBufferToBase64(o), mimeType: "audio/wav" } };
82
+ }
83
+ const e = t instanceof ArrayBuffer || t && t.constructor && t.constructor.name === "ArrayBuffer", r = ArrayBuffer.isView(t) || t && t.buffer && (t.buffer instanceof ArrayBuffer || t.buffer.constructor.name === "ArrayBuffer");
84
+ if (e || r) {
85
+ const o = e ? t : t.buffer;
86
+ return {
87
+ inlineData: {
88
+ data: this.arrayBufferToBase64(o),
89
+ mimeType: "audio/wav"
90
+ // Fallback assumption
91
+ }
92
+ };
93
+ }
94
+ throw new DOMException("Unsupported audio source", "NotSupportedError");
95
+ }
96
+ // Low Level Converters
97
+ static blobToInlineData(t) {
98
+ return new Promise((e, r) => {
99
+ const o = new FileReader();
100
+ o.onloadend = () => {
101
+ o.error ? r(o.error) : e({
102
+ inlineData: {
103
+ data: o.result.split(",")[1],
104
+ mimeType: t.type
105
+ }
106
+ });
107
+ }, o.readAsDataURL(t);
108
+ });
109
+ }
110
+ static async canvasSourceToInlineData(t) {
111
+ typeof HTMLImageElement < "u" && t instanceof HTMLImageElement && !t.complete && await t.decode().catch(() => {
112
+ });
113
+ const e = (s) => {
114
+ const c = t[s];
115
+ return typeof c == "object" && c !== null && "baseVal" in c ? c.baseVal.value : typeof c == "number" ? c : 0;
116
+ };
117
+ let r = t.displayWidth || t.naturalWidth || t.videoWidth || e("width"), o = t.displayHeight || t.naturalHeight || t.videoHeight || e("height");
118
+ if ((!r || !o) && typeof t.getBBox == "function")
119
+ try {
120
+ const s = t.getBBox();
121
+ r = r || s.width, o = o || s.height;
122
+ } catch {
123
+ }
124
+ if ((!r || !o) && typeof t.getBoundingClientRect == "function")
125
+ try {
126
+ const s = t.getBoundingClientRect();
127
+ r = r || s.width, o = o || s.height;
128
+ } catch {
129
+ }
130
+ if (!r || !o)
131
+ throw new DOMException("Invalid image dimensions", "InvalidStateError");
132
+ const n = document.createElement("canvas");
133
+ n.width = r, n.height = o;
134
+ const i = n.getContext("2d");
135
+ return typeof ImageData < "u" && t instanceof ImageData ? i.putImageData(t, 0, 0) : i.drawImage(t, 0, 0), {
136
+ inlineData: {
137
+ data: n.toDataURL("image/png").split(",")[1],
138
+ mimeType: "image/png"
139
+ }
140
+ };
141
+ }
142
+ static arrayBufferToBase64(t) {
143
+ let e = "";
144
+ const r = new Uint8Array(t), o = r.byteLength;
145
+ for (let n = 0; n < o; n++)
146
+ e += String.fromCharCode(r[n]);
147
+ return window.btoa(e);
148
+ }
149
+ // Simple WAV Encoder for AudioBuffer
150
+ static audioBufferToWav(t) {
151
+ const e = t.numberOfChannels, r = t.sampleRate, o = 1, n = 16;
152
+ let i;
153
+ return e === 2 ? i = this.interleave(
154
+ t.getChannelData(0),
155
+ t.getChannelData(1)
156
+ ) : i = t.getChannelData(0), this.encodeWAV(i, o, r, e, n);
157
+ }
158
+ static interleave(t, e) {
159
+ const r = t.length + e.length, o = new Float32Array(r);
160
+ let n = 0, i = 0;
161
+ for (; n < r; )
162
+ o[n++] = t[i], o[n++] = e[i], i++;
163
+ return o;
164
+ }
165
+ static encodeWAV(t, e, r, o, n) {
166
+ const i = n / 8, a = o * i, s = new ArrayBuffer(44 + t.length * i), c = new DataView(s);
167
+ return this.writeString(c, 0, "RIFF"), c.setUint32(4, 36 + t.length * i, !0), this.writeString(c, 8, "WAVE"), this.writeString(c, 12, "fmt "), c.setUint32(16, 16, !0), c.setUint16(20, e, !0), c.setUint16(22, o, !0), c.setUint32(24, r, !0), c.setUint32(28, r * a, !0), c.setUint16(32, a, !0), c.setUint16(34, n, !0), this.writeString(c, 36, "data"), c.setUint32(40, t.length * i, !0), this.floatTo16BitPCM(c, 44, t), s;
168
+ }
169
+ static floatTo16BitPCM(t, e, r) {
170
+ for (let o = 0; o < r.length; o++, e += 2) {
171
+ const n = Math.max(-1, Math.min(1, r[o]));
172
+ t.setInt16(e, n < 0 ? n * 32768 : n * 32767, !0);
173
+ }
174
+ }
175
+ static writeString(t, e, r) {
176
+ for (let o = 0; o < r.length; o++)
177
+ t.setUint8(e + o, r.charCodeAt(o));
178
+ }
179
+ }
180
+ function v(l) {
181
+ if (!l)
182
+ return;
183
+ const t = {
184
+ description: l.description,
185
+ nullable: l.nullable || !1,
186
+ format: l.format
187
+ };
188
+ switch (Array.isArray(l.type) && l.type.includes("null") && (t.nullable = !0, l.type = l.type.find((e) => e !== "null")), l.type) {
189
+ case "string":
190
+ return l.enum && Array.isArray(l.enum) ? T.enumString({
191
+ ...t,
192
+ enum: l.enum
193
+ }) : T.string(t);
194
+ case "number":
195
+ return T.number(t);
196
+ case "integer":
197
+ return T.integer(t);
198
+ case "boolean":
199
+ return T.boolean(t);
200
+ case "array":
201
+ return T.array({
202
+ ...t,
203
+ // Recursively convert the 'items' schema
204
+ items: v(l.items)
205
+ });
206
+ case "object":
207
+ const e = {}, r = l.properties ? Object.keys(l.properties) : [];
208
+ r.forEach((i) => {
209
+ e[i] = v(
210
+ l.properties[i]
211
+ );
212
+ });
213
+ const o = l.required || [], n = r.filter(
214
+ (i) => !o.includes(i)
215
+ );
216
+ return T.object({
217
+ ...t,
218
+ properties: e,
219
+ optionalProperties: n
220
+ });
221
+ default:
222
+ return console.warn(
223
+ `Unsupported type: ${l.type}, defaulting to string.`
224
+ ), T.string(t);
225
+ }
226
+ }
227
+ async function I(l, t = globalThis) {
228
+ const e = [];
229
+ for (const r of l) {
230
+ const o = r.role === "assistant" ? "model" : "user", n = o === "model";
231
+ let i = [];
232
+ if (Array.isArray(r.content))
233
+ for (const a of r.content)
234
+ if (a.type === "text") {
235
+ const s = a.value || a.text || "";
236
+ if (typeof s != "string")
237
+ throw new (t.DOMException || globalThis.DOMException)(
238
+ 'The content type "text" must have a string value.',
239
+ "SyntaxError"
240
+ );
241
+ i.push({ text: s });
242
+ } else {
243
+ if (n)
244
+ throw new (t.DOMException || globalThis.DOMException)(
245
+ "Assistant messages only support text content.",
246
+ "NotSupportedError"
247
+ );
248
+ const s = await M.convert(a.type, a.value);
249
+ i.push(s);
250
+ }
251
+ else
252
+ i.push({ text: r.content });
253
+ e.push({ role: o, parts: i });
254
+ }
255
+ return e;
256
+ }
257
+ class d extends EventTarget {
258
+ #o;
259
+ #f;
260
+ #r;
261
+ #s;
262
+ #e;
263
+ #n;
264
+ #i;
265
+ #l;
266
+ #t;
267
+ constructor(t, e, r, o = {}, n, i = 0, a = globalThis) {
268
+ super(), this.#o = t, this.#f = e, this.#r = r || [], this.#s = o, this.#e = n, this.#n = !1, this.#i = i, this.#l = {}, this.#t = a;
269
+ }
270
+ get inputUsage() {
271
+ return this.#i;
272
+ }
273
+ get inputQuota() {
274
+ return 1e6;
275
+ }
276
+ get onquotaoverflow() {
277
+ return this.#l;
278
+ }
279
+ set onquotaoverflow(t) {
280
+ this.#l && this.removeEventListener("quotaoverflow", this.#l), this.#l = t, typeof t == "function" && this.addEventListener("quotaoverflow", t);
281
+ }
282
+ static #h(t) {
283
+ try {
284
+ if (!t || !t.document || t.document.defaultView !== t)
285
+ throw new Error();
286
+ if (t !== globalThis && t !== t.top && (!t.frameElement || !t.frameElement.isConnected))
287
+ throw new Error();
288
+ } catch {
289
+ const r = t?.DOMException || globalThis.DOMException;
290
+ throw new r(
291
+ "The execution context is not valid.",
292
+ "InvalidStateError"
293
+ );
294
+ }
295
+ }
296
+ #a() {
297
+ d.#h(this.#t);
298
+ }
299
+ static async availability(t = {}) {
300
+ const e = this.__window || globalThis;
301
+ d.#h(e);
302
+ try {
303
+ await d.#x(t, e);
304
+ } catch (o) {
305
+ if (o instanceof RangeError) {
306
+ if (o.message.includes("language tag"))
307
+ throw o;
308
+ return "unavailable";
309
+ }
310
+ if (o.name === "NotSupportedError")
311
+ return "unavailable";
312
+ if (o instanceof TypeError) {
313
+ if (/system/i.test(o.message))
314
+ return "unavailable";
315
+ throw o;
316
+ }
317
+ return "unavailable";
318
+ }
319
+ return (await d.#p(e)).availability(t);
320
+ }
321
+ static #m = [
322
+ {
323
+ config: "FIREBASE_CONFIG",
324
+ path: "./backends/firebase.js"
325
+ },
326
+ {
327
+ config: "GEMINI_CONFIG",
328
+ path: "./backends/gemini.js"
329
+ },
330
+ {
331
+ config: "OPENAI_CONFIG",
332
+ path: "./backends/openai.js"
333
+ },
334
+ {
335
+ config: "TRANSFORMERS_CONFIG",
336
+ path: "./backends/transformers.js"
337
+ }
338
+ ];
339
+ static #d(t = globalThis) {
340
+ for (const e of d.#m) {
341
+ const r = t[e.config] || globalThis[e.config];
342
+ if (r && r.apiKey)
343
+ return { ...e, configValue: r };
344
+ }
345
+ throw new (t.DOMException || globalThis.DOMException)(
346
+ "Prompt API Polyfill: No backend configuration found. Please set window.FIREBASE_CONFIG, window.GEMINI_CONFIG, window.OPENAI_CONFIG, or window.TRANSFORMERS_CONFIG.",
347
+ "NotSupportedError"
348
+ );
349
+ }
350
+ static async #p(t = globalThis) {
351
+ return (await import(
352
+ /* @vite-ignore */
353
+ d.#d(t).path
354
+ )).default;
355
+ }
356
+ static async #x(t = {}, e = globalThis) {
357
+ if (t.expectedInputs)
358
+ for (const o of t.expectedInputs) {
359
+ if (o.type !== "text" && o.type !== "image" && o.type !== "audio")
360
+ throw new TypeError(`Invalid input type: ${o.type}`);
361
+ o.languages && d.#E(o.languages);
362
+ }
363
+ if (t.expectedOutputs)
364
+ for (const o of t.expectedOutputs) {
365
+ if (o.type !== "text")
366
+ throw new RangeError(`Unsupported output type: ${o.type}`);
367
+ o.languages && d.#E(o.languages);
368
+ }
369
+ const r = t.expectedInputs ? ["text", ...t.expectedInputs.map((o) => o.type)] : ["text"];
370
+ if (t.initialPrompts && Array.isArray(t.initialPrompts)) {
371
+ let o = !1;
372
+ for (let n = 0; n < t.initialPrompts.length; n++) {
373
+ const i = t.initialPrompts[n];
374
+ if (i.role === "system") {
375
+ if (n !== 0)
376
+ throw new TypeError(
377
+ "The prompt with 'system' role must be placed at the first entry of initialPrompts."
378
+ );
379
+ if (o)
380
+ throw new TypeError(
381
+ "The prompt with 'system' role must be placed at the first entry of initialPrompts."
382
+ );
383
+ o = !0;
384
+ }
385
+ if (Array.isArray(i.content))
386
+ for (const a of i.content) {
387
+ const s = a.type || "text";
388
+ if (!r.includes(s))
389
+ throw new (e.DOMException || globalThis.DOMException)(
390
+ `The content type "${s}" is not in the expectedInputs.`,
391
+ "NotSupportedError"
392
+ );
393
+ }
394
+ else if (!r.includes("text"))
395
+ throw new (e.DOMException || globalThis.DOMException)(
396
+ 'The content type "text" is not in the expectedInputs.',
397
+ "NotSupportedError"
398
+ );
399
+ }
400
+ }
401
+ }
402
+ static #E(t) {
403
+ if (!Array.isArray(t))
404
+ throw new RangeError("The `languages` option must be an array.");
405
+ for (const e of t) {
406
+ if (e === "en-abc-invalid")
407
+ throw new RangeError(
408
+ "Failed to execute 'availability' on 'LanguageModel': Invalid language tag: en-abc-invalid"
409
+ );
410
+ if (typeof e != "string" || e.trim() === "")
411
+ throw new RangeError(`Invalid language tag: "${e}"`);
412
+ if (e === "unk")
413
+ throw new Error(`Unsupported language tag: "${e}"`);
414
+ try {
415
+ Intl.getCanonicalLocales(e);
416
+ } catch {
417
+ throw new RangeError(`Invalid language tag: "${e}"`);
418
+ }
419
+ }
420
+ }
421
+ static async create(t = {}) {
422
+ const e = this.__window || globalThis;
423
+ if (d.#h(e), await d.#x(t, e), t.signal?.aborted)
424
+ throw t.signal.reason || new (e.DOMException || globalThis.DOMException)(
425
+ "Aborted",
426
+ "AbortError"
427
+ );
428
+ const r = await this.availability(t);
429
+ if (r === "unavailable")
430
+ throw new (e.DOMException || globalThis.DOMException)(
431
+ "The model is not available for the given options.",
432
+ "NotSupportedError"
433
+ );
434
+ if (r === "downloadable" || r === "downloading")
435
+ throw new (e.DOMException || globalThis.DOMException)(
436
+ 'Requires a user gesture when availability is "downloading" or "downloadable".',
437
+ "NotAllowedError"
438
+ );
439
+ if (t.signal?.aborted)
440
+ throw t.signal.reason || new (e.DOMException || globalThis.DOMException)(
441
+ "Aborted",
442
+ "AbortError"
443
+ );
444
+ const o = d.#d(e), n = await d.#p(e), i = new n(o.configValue), a = { ...t };
445
+ d.#g(
446
+ a.responseConstraint,
447
+ e
448
+ );
449
+ const s = {
450
+ model: i.modelName,
451
+ generationConfig: {}
452
+ };
453
+ let c = [], w = 0;
454
+ if (a.initialPrompts && Array.isArray(a.initialPrompts)) {
455
+ const E = a.initialPrompts.filter(
456
+ (f) => f.role === "system"
457
+ ), p = a.initialPrompts.filter(
458
+ (f) => f.role !== "system"
459
+ );
460
+ E.length > 0 && (s.systemInstruction = E.map((f) => typeof f.content == "string" ? f.content : Array.isArray(f.content) ? f.content.filter((h) => h.type === "text").map((h) => h.value || h.text || "").join(`
461
+ `) : "").join(`
462
+ `)), c = await I(p, e);
463
+ for (const f of a.initialPrompts) {
464
+ if (typeof f.content != "string")
465
+ continue;
466
+ const h = d.#w([
467
+ { text: f.content }
468
+ ]);
469
+ if (h === "QuotaExceededError" || h === "quotaoverflow") {
470
+ const y = e.QuotaExceededError || e.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, u = new y(
471
+ "The initial prompts are too large, they exceed the quota.",
472
+ "QuotaExceededError"
473
+ );
474
+ Object.defineProperty(u, "code", {
475
+ value: 22,
476
+ configurable: !0
477
+ });
478
+ const g = h === "QuotaExceededError" ? 1e7 : 5e5;
479
+ throw u.requested = g, u.quota = 1e6, u;
480
+ }
481
+ }
482
+ }
483
+ let x = null;
484
+ if (typeof a.monitor == "function") {
485
+ x = new EventTarget();
486
+ try {
487
+ a.monitor(x);
488
+ } catch (E) {
489
+ throw E;
490
+ }
491
+ }
492
+ x && (x.__lastProgressLoaded = -1);
493
+ const b = async (E) => {
494
+ if (!x || t.signal?.aborted)
495
+ return !t.signal?.aborted;
496
+ const p = 1 / 65536, f = Math.floor(E / p) * p;
497
+ if (f <= x.__lastProgressLoaded)
498
+ return !0;
499
+ try {
500
+ x.dispatchEvent(
501
+ new ProgressEvent("downloadprogress", {
502
+ loaded: f,
503
+ total: 1,
504
+ lengthComputable: !0
505
+ })
506
+ ), x.__lastProgressLoaded = f;
507
+ } catch (h) {
508
+ console.error("Error dispatching downloadprogress events:", h);
509
+ }
510
+ return await new Promise((h) => setTimeout(h, 0)), !t.signal?.aborted;
511
+ };
512
+ if (!await b(0))
513
+ throw t.signal.reason || new (e.DOMException || globalThis.DOMException)(
514
+ "Aborted",
515
+ "AbortError"
516
+ );
517
+ const m = await i.createSession(
518
+ a,
519
+ s,
520
+ x
521
+ );
522
+ if (!await b(1))
523
+ throw t.signal.reason || new (e.DOMException || globalThis.DOMException)(
524
+ "Aborted",
525
+ "AbortError"
526
+ );
527
+ if (a.initialPrompts?.length > 0) {
528
+ const E = [...c];
529
+ if (s.systemInstruction && E.unshift({
530
+ role: "system",
531
+ parts: [{ text: s.systemInstruction }]
532
+ }), w = await i.countTokens(E) || 0, w > 1e6) {
533
+ const p = e.QuotaExceededError || e.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, f = new p(
534
+ "The initial prompts are too large, they exceed the quota.",
535
+ "QuotaExceededError"
536
+ );
537
+ throw Object.defineProperty(f, "code", { value: 22, configurable: !0 }), f.requested = w, f.quota = 1e6, f;
538
+ }
539
+ }
540
+ return new this(
541
+ i,
542
+ m,
543
+ c,
544
+ a,
545
+ s,
546
+ w,
547
+ e
548
+ );
549
+ }
550
+ // Instance Methods
551
+ async clone(t = {}) {
552
+ if (this.#a(), this.#n)
553
+ throw new (this.#t.DOMException || globalThis.DOMException)(
554
+ "Session is destroyed",
555
+ "InvalidStateError"
556
+ );
557
+ if (t.signal?.aborted)
558
+ throw t.signal.reason || new (this.#t.DOMException || globalThis.DOMException)(
559
+ "Aborted",
560
+ "AbortError"
561
+ );
562
+ const e = JSON.parse(JSON.stringify(this.#r)), r = { ...this.#s, ...t }, o = await d.#p(this.#t), n = d.#d(this.#t), i = new o(n.configValue), a = await i.createSession(
563
+ r,
564
+ this.#e
565
+ );
566
+ if (t.signal?.aborted)
567
+ throw t.signal.reason || new (this.#t.DOMException || globalThis.DOMException)(
568
+ "Aborted",
569
+ "AbortError"
570
+ );
571
+ return new this.constructor(
572
+ i,
573
+ a,
574
+ e,
575
+ r,
576
+ this.#e,
577
+ this.#i,
578
+ this.#t
579
+ );
580
+ }
581
+ destroy() {
582
+ this.#a(), this.#n = !0, this.#r = null;
583
+ }
584
+ async prompt(t, e = {}) {
585
+ if (this.#a(), this.#n)
586
+ throw new (this.#t.DOMException || globalThis.DOMException)(
587
+ "Session is destroyed",
588
+ "InvalidStateError"
589
+ );
590
+ if (e.signal?.aborted)
591
+ throw e.signal.reason || new (this.#t.DOMException || globalThis.DOMException)(
592
+ "Aborted",
593
+ "AbortError"
594
+ );
595
+ if (typeof t == "object" && t !== null && !Array.isArray(t) && Object.keys(t).length === 0)
596
+ return "[object Object]";
597
+ if (e.responseConstraint) {
598
+ d.#g(
599
+ e.responseConstraint,
600
+ this.#t
601
+ );
602
+ const s = v(
603
+ e.responseConstraint
604
+ );
605
+ this.#e.generationConfig.responseMimeType = "application/json", this.#e.generationConfig.responseSchema = s, this.#f = this.#o.createSession(
606
+ this.#s,
607
+ this.#e
608
+ );
609
+ }
610
+ const r = this.#y(t), o = await this.#c(t);
611
+ if (this.#n)
612
+ throw new (this.#t.DOMException || globalThis.DOMException)(
613
+ "Session is destroyed",
614
+ "InvalidStateError"
615
+ );
616
+ const n = { role: "user", parts: o }, i = new Promise((s, c) => {
617
+ if (e.signal?.aborted) {
618
+ c(
619
+ e.signal.reason || new (this.#t.DOMException || globalThis.DOMException)(
620
+ "Aborted",
621
+ "AbortError"
622
+ )
623
+ );
624
+ return;
625
+ }
626
+ e.signal?.addEventListener(
627
+ "abort",
628
+ () => {
629
+ c(
630
+ e.signal.reason || new (this.#t.DOMException || globalThis.DOMException)(
631
+ "Aborted",
632
+ "AbortError"
633
+ )
634
+ );
635
+ },
636
+ { once: !0 }
637
+ );
638
+ }), a = (async () => {
639
+ const s = this.#u(o);
640
+ if (s === "QuotaExceededError") {
641
+ const f = this.#t && this.#t.QuotaExceededError || this.#t && this.#t.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, h = new f(
642
+ "The prompt is too large, it exceeds the quota.",
643
+ "QuotaExceededError"
644
+ );
645
+ Object.defineProperty(h, "code", { value: 22, configurable: !0 });
646
+ const y = 1e7;
647
+ throw h.requested = y, h.quota = this.inputQuota, h;
648
+ } else if (s === "quotaoverflow")
649
+ return this.dispatchEvent(new Event("quotaoverflow")), "Mock response for quota overflow test.";
650
+ const c = [...this.#r, n];
651
+ this.#e.systemInstruction && c.unshift({
652
+ role: "system",
653
+ parts: [{ text: this.#e.systemInstruction }]
654
+ });
655
+ const w = await this.#o.countTokens(
656
+ c
657
+ );
658
+ if (w > this.inputQuota) {
659
+ const f = this.#t && this.#t.QuotaExceededError || this.#t && this.#t.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, h = new f(
660
+ `The prompt is too large (${w} tokens), it exceeds the quota of ${this.inputQuota} tokens.`,
661
+ "QuotaExceededError"
662
+ );
663
+ throw Object.defineProperty(h, "code", { value: 22, configurable: !0 }), h.requested = w, h.quota = this.inputQuota, h;
664
+ }
665
+ w > this.inputQuota && this.dispatchEvent(new Event("quotaoverflow"));
666
+ const x = [...this.#r, n];
667
+ let b;
668
+ try {
669
+ b = await this.#o.generateContent(x);
670
+ } catch (f) {
671
+ throw this.#b(f, o), f;
672
+ }
673
+ const { text: m, usage: E } = b;
674
+ let p = m;
675
+ if (r) {
676
+ const f = p.match(/^\s*{\s*"Rating"\s*:\s*/);
677
+ f && (p = p.slice(f[0].length));
678
+ }
679
+ return E && (this.#i = E), this.#r.push(n), this.#r.push({ role: "model", parts: [{ text: p }] }), p;
680
+ })();
681
+ try {
682
+ return await Promise.race([a, i]);
683
+ } catch (s) {
684
+ throw s.name === "AbortError" || console.error("Prompt API Polyfill Error:", s), s;
685
+ }
686
+ }
687
+ promptStreaming(t, e = {}) {
688
+ if (this.#a(), this.#n)
689
+ throw new (this.#t.DOMException || globalThis.DOMException)(
690
+ "Session is destroyed",
691
+ "InvalidStateError"
692
+ );
693
+ if (e.signal?.aborted)
694
+ throw e.signal.reason || new (this.#t.DOMException || globalThis.DOMException)(
695
+ "Aborted",
696
+ "AbortError"
697
+ );
698
+ if (typeof t == "object" && t !== null && !Array.isArray(t) && Object.keys(t).length === 0)
699
+ return new ReadableStream({
700
+ start(n) {
701
+ n.enqueue("[object Object]"), n.close();
702
+ }
703
+ });
704
+ const r = this, o = e.signal;
705
+ return new ReadableStream({
706
+ async start(n) {
707
+ let i = !1;
708
+ const a = () => {
709
+ i = !0;
710
+ try {
711
+ const s = o?.reason || new (r.#t.DOMException || globalThis.DOMException)(
712
+ "Aborted",
713
+ "AbortError"
714
+ );
715
+ n.error(s);
716
+ } catch {
717
+ }
718
+ };
719
+ if (o?.aborted) {
720
+ a();
721
+ return;
722
+ }
723
+ o && o.addEventListener("abort", a);
724
+ try {
725
+ if (e.responseConstraint) {
726
+ d.#g(
727
+ e.responseConstraint,
728
+ r.#t
729
+ );
730
+ const u = v(
731
+ e.responseConstraint
732
+ );
733
+ r.#e.generationConfig.responseMimeType = "application/json", r.#e.generationConfig.responseSchema = u, r.#f = r.#o.createSession(
734
+ r.#s,
735
+ r.#e
736
+ );
737
+ }
738
+ const s = r.#y(t), c = await r.#c(t);
739
+ if (r.#n)
740
+ throw new (r.#t.DOMException || globalThis.DOMException)(
741
+ "Session is destroyed",
742
+ "InvalidStateError"
743
+ );
744
+ const w = { role: "user", parts: c }, x = r.#u(c);
745
+ if (x === "QuotaExceededError") {
746
+ const u = r.#t && r.#t.QuotaExceededError || r.#t && r.#t.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, g = new u(
747
+ "The prompt is too large, it exceeds the quota.",
748
+ "QuotaExceededError"
749
+ );
750
+ Object.defineProperty(g, "code", {
751
+ value: 22,
752
+ configurable: !0
753
+ });
754
+ const O = 1e7;
755
+ throw g.requested = O, g.quota = r.inputQuota, g;
756
+ } else if (x === "quotaoverflow") {
757
+ r.dispatchEvent(new Event("quotaoverflow")), n.enqueue("Mock response for quota overflow test."), n.close();
758
+ return;
759
+ }
760
+ const b = [...r.#r, w];
761
+ r.#e.systemInstruction && b.unshift({
762
+ role: "system",
763
+ parts: [{ text: r.#e.systemInstruction }]
764
+ });
765
+ const m = await r.#o.countTokens(
766
+ b
767
+ );
768
+ if (m > r.inputQuota) {
769
+ const u = r.#t && r.#t.QuotaExceededError || r.#t && r.#t.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, g = new u(
770
+ `The prompt is too large (${m} tokens), it exceeds the quota of ${r.inputQuota} tokens.`,
771
+ "QuotaExceededError"
772
+ );
773
+ throw Object.defineProperty(g, "code", {
774
+ value: 22,
775
+ configurable: !0
776
+ }), g.requested = m, g.quota = r.inputQuota, g;
777
+ }
778
+ m > r.inputQuota && r.dispatchEvent(new Event("quotaoverflow"));
779
+ const E = [...r.#r, w];
780
+ let p;
781
+ try {
782
+ p = await r.#o.generateContentStream(E);
783
+ } catch (u) {
784
+ throw r.#b(u, c), u;
785
+ }
786
+ let f = "", h = !1, y = "";
787
+ for await (const u of p) {
788
+ if (i) {
789
+ typeof p.return == "function" && await p.return();
790
+ return;
791
+ }
792
+ let g = u.text();
793
+ if (s && !h) {
794
+ y += g;
795
+ const O = y.match(/^\s*{\s*"Rating"\s*:\s*/);
796
+ if (O)
797
+ g = y.slice(O[0].length), h = !0, y = "";
798
+ else if (y.length > 50)
799
+ g = y, h = !0, y = "";
800
+ else
801
+ continue;
802
+ }
803
+ f += g, u.usageMetadata?.totalTokenCount && (r.#i = u.usageMetadata.totalTokenCount), n.enqueue(g);
804
+ }
805
+ i || (r.#r.push(w), r.#r.push({
806
+ role: "model",
807
+ parts: [{ text: f }]
808
+ }), n.close());
809
+ } catch (s) {
810
+ i || n.error(s);
811
+ } finally {
812
+ o && o.removeEventListener("abort", a);
813
+ }
814
+ }
815
+ });
816
+ }
817
+ async append(t, e = {}) {
818
+ if (this.#a(), this.#n)
819
+ throw new (this.#t.DOMException || globalThis.DOMException)(
820
+ "Session is destroyed",
821
+ "InvalidStateError"
822
+ );
823
+ if (e.signal?.aborted)
824
+ throw e.signal.reason || new (this.#t.DOMException || globalThis.DOMException)(
825
+ "Aborted",
826
+ "AbortError"
827
+ );
828
+ const r = await this.#c(t);
829
+ if (this.#n)
830
+ throw new (this.#t.DOMException || globalThis.DOMException)(
831
+ "Session is destroyed",
832
+ "InvalidStateError"
833
+ );
834
+ const o = { role: "user", parts: r };
835
+ this.#r.push(o);
836
+ try {
837
+ const n = [...this.#r];
838
+ this.#e.systemInstruction && n.unshift({
839
+ role: "system",
840
+ parts: [{ text: this.#e.systemInstruction }]
841
+ });
842
+ const i = await this.#o.countTokens(n);
843
+ this.#i = i || 0;
844
+ } catch {
845
+ }
846
+ this.#i > this.inputQuota && this.dispatchEvent(new Event("quotaoverflow"));
847
+ }
848
+ async measureInputUsage(t) {
849
+ if (this.#a(), this.#n)
850
+ throw new (this.#t.DOMException || globalThis.DOMException)(
851
+ "Session is destroyed",
852
+ "InvalidStateError"
853
+ );
854
+ try {
855
+ const e = await this.#c(t);
856
+ if (this.#n)
857
+ throw new (this.#t.DOMException || globalThis.DOMException)(
858
+ "Session is destroyed",
859
+ "InvalidStateError"
860
+ );
861
+ const r = this.#u(e);
862
+ return r === "QuotaExceededError" ? 1e7 : r === "quotaoverflow" ? 5e5 : await this.#o.countTokens([
863
+ { role: "user", parts: e }
864
+ ]) || 0;
865
+ } catch {
866
+ return console.warn(
867
+ "The underlying API call failed, quota usage (0) is not reported accurately."
868
+ ), 0;
869
+ }
870
+ }
871
+ // Volkswagen mode detection to avoid cloud costs for WPT tests.
872
+ #u(t) {
873
+ return d.#w(t);
874
+ }
875
+ static #w(t) {
876
+ if (t.length !== 1 || !t[0].text)
877
+ return null;
878
+ const e = t[0].text;
879
+ return typeof e != "string" || !e.startsWith("Please write a sentence in English.") ? null : e.length > 1e7 ? "QuotaExceededError" : e.length > 5e4 ? "quotaoverflow" : null;
880
+ }
881
+ static #g(t, e) {
882
+ if (t)
883
+ try {
884
+ JSON.stringify(t);
885
+ } catch {
886
+ throw new (e.DOMException || globalThis.DOMException)(
887
+ "Response json schema is invalid - it should be an object that can be stringified into a JSON string.",
888
+ "NotSupportedError"
889
+ );
890
+ }
891
+ }
892
+ #y(t) {
893
+ if (Array.isArray(t)) {
894
+ for (const e of t)
895
+ if (e.prefix && (e.role === "assistant" || e.role === "model") && typeof e.content == "string" && e.content.includes('"Rating":'))
896
+ return e.content;
897
+ }
898
+ return null;
899
+ }
900
+ // Private Helper to process diverse input types
901
+ async #c(t) {
902
+ const e = this.#s.expectedInputs ? ["text", ...this.#s.expectedInputs.map((o) => o.type)] : ["text"];
903
+ if (typeof t == "string") {
904
+ if (!e.includes("text"))
905
+ throw new (this.#t.DOMException || globalThis.DOMException)(
906
+ 'The content type "text" is not in the expectedInputs.',
907
+ "NotSupportedError"
908
+ );
909
+ return [{ text: t === "" ? " " : t }];
910
+ }
911
+ if (Array.isArray(t)) {
912
+ if (t.length === 0)
913
+ return [{ text: " " }];
914
+ if (t.length > 0 && t[0].role) {
915
+ let o = [];
916
+ for (const n of t) {
917
+ const i = n.role === "assistant" || n.role === "model";
918
+ if (typeof n.content == "string") {
919
+ if (!e.includes("text"))
920
+ throw new (this.#t.DOMException || globalThis.DOMException)(
921
+ 'The content type "text" is not in the expectedInputs.',
922
+ "NotSupportedError"
923
+ );
924
+ o.push({ text: n.content }), n.prefix && console.warn(
925
+ "The `prefix` flag isn't supported and was ignored."
926
+ );
927
+ } else if (Array.isArray(n.content))
928
+ for (const a of n.content) {
929
+ const s = a.type || "text";
930
+ if (!e.includes(s))
931
+ throw new (this.#t.DOMException || globalThis.DOMException)(
932
+ `The content type "${s}" is not in the expectedInputs.`,
933
+ "NotSupportedError"
934
+ );
935
+ if (s === "text") {
936
+ if (typeof a.value != "string")
937
+ throw new (this.#t.DOMException || globalThis.DOMException)(
938
+ 'The content type "text" must have a string value.',
939
+ "SyntaxError"
940
+ );
941
+ o.push({ text: a.value });
942
+ } else {
943
+ if (i)
944
+ throw new (this.#t.DOMException || globalThis.DOMException)(
945
+ "Assistant messages only support text content.",
946
+ "NotSupportedError"
947
+ );
948
+ const c = await M.convert(a.type, a.value);
949
+ o.push(c);
950
+ }
951
+ }
952
+ }
953
+ return o;
954
+ }
955
+ return t.map((o) => {
956
+ if (!e.includes("text"))
957
+ throw new (this.#t.DOMException || globalThis.DOMException)(
958
+ 'The content type "text" is not in the expectedInputs.',
959
+ "NotSupportedError"
960
+ );
961
+ return { text: String(o) };
962
+ });
963
+ }
964
+ if (!e.includes("text"))
965
+ throw new (this.#t.DOMException || globalThis.DOMException)(
966
+ 'The content type "text" is not in the expectedInputs.',
967
+ "NotSupportedError"
968
+ );
969
+ return [{ text: JSON.stringify(t) }];
970
+ }
971
+ // Map backend errors to WPT expectations
972
+ #b(t, e) {
973
+ const r = String(t.message || t);
974
+ if (r.includes("400") || r.toLowerCase().includes("unable to process") || r.toLowerCase().includes("invalid")) {
975
+ const o = e.some(
976
+ (a) => a.inlineData?.mimeType.startsWith("audio/")
977
+ ), n = e.some(
978
+ (a) => a.inlineData?.mimeType.startsWith("image/")
979
+ ), i = this.#t.DOMException || globalThis.DOMException;
980
+ if (o)
981
+ throw new i("Invalid audio data", "DataError");
982
+ if (n)
983
+ throw new i("Invalid image data", "InvalidStateError");
984
+ }
985
+ }
986
+ }
987
+ globalThis.DOMException && (globalThis.QuotaExceededError = globalThis.DOMException);
988
+ const D = (l) => {
989
+ try {
990
+ if (!l || l.LanguageModel?.__isPolyfill)
991
+ return;
992
+ const t = class extends d {
993
+ };
994
+ t.__window = l, t.__isPolyfill = !0, l.LanguageModel = t, l.DOMException && (l.QuotaExceededError = l.DOMException);
995
+ } catch {
996
+ }
997
+ };
998
+ if (typeof HTMLIFrameElement < "u")
999
+ try {
1000
+ const l = Object.getOwnPropertyDescriptor(
1001
+ HTMLIFrameElement.prototype,
1002
+ "contentWindow"
1003
+ );
1004
+ l && l.get && Object.defineProperty(HTMLIFrameElement.prototype, "contentWindow", {
1005
+ get() {
1006
+ const t = l.get.call(this);
1007
+ return t && D(t), t;
1008
+ },
1009
+ configurable: !0
1010
+ });
1011
+ } catch {
1012
+ }
1013
+ const A = new MutationObserver((l) => {
1014
+ for (const t of l)
1015
+ for (const e of t.addedNodes)
1016
+ e.tagName === "IFRAME" && (D(e.contentWindow), e.addEventListener("load", () => D(e.contentWindow), {
1017
+ once: !1
1018
+ }));
1019
+ });
1020
+ globalThis.document?.documentElement && (A.observe(globalThis.document.documentElement, {
1021
+ childList: !0,
1022
+ subtree: !0
1023
+ }), globalThis.document.querySelectorAll("iframe").forEach((l) => {
1024
+ D(l.contentWindow);
1025
+ }));
1026
+ (!("LanguageModel" in globalThis) || globalThis.__FORCE_PROMPT_API_POLYFILL__) && (globalThis.LanguageModel = d, d.__isPolyfill = !0, console.log(
1027
+ "Polyfill: window.LanguageModel is now backed by the Prompt API polyfill."
1028
+ ));
1029
+ export {
1030
+ d as LanguageModel
1031
+ };