@ai-ecoverse/pi-audio 1.18.0 → 1.19.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/README.md +3 -1
- package/dist/fish/catalog.js +78 -0
- package/dist/fish/catalog.js.map +7 -0
- package/dist/fish/index.js +5 -0
- package/dist/fish/index.js.map +7 -0
- package/dist/fish/speak.js +269 -0
- package/dist/fish/speak.js.map +7 -0
- package/dist/fish/transcribe.js +158 -0
- package/dist/fish/transcribe.js.map +7 -0
- package/dist/fish/wire.js +386 -0
- package/dist/fish/wire.js.map +7 -0
- package/dist/gemini-live/session.js +32 -15
- package/dist/gemini-live/session.js.map +2 -2
- package/dist/openai-realtime/session.js +35 -9
- package/dist/openai-realtime/session.js.map +2 -2
- package/dist/openai-realtime/socket.js +12 -0
- package/dist/openai-realtime/socket.js.map +2 -2
- package/dist/talker.js +71 -27
- package/dist/talker.js.map +3 -3
- package/dist/types/fish/catalog.d.ts +1 -0
- package/dist/types/fish/index.d.ts +1 -0
- package/dist/types/fish/speak.d.ts +4 -0
- package/dist/types/fish/transcribe.d.ts +4 -0
- package/dist/types/fish/wire.d.ts +27 -0
- package/dist/types/openai-realtime/socket.d.ts +1 -0
- package/dist/types/talker.d.ts +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { requestHeaders } from "../openai/wire.js";
|
|
2
|
+
const boundary = "pi-audio-fish-boundary";
|
|
3
|
+
const filenames = {
|
|
4
|
+
"audio/wav": "audio.wav",
|
|
5
|
+
"audio/wave": "audio.wav",
|
|
6
|
+
"audio/x-wav": "audio.wav",
|
|
7
|
+
"audio/mpeg": "audio.mp3",
|
|
8
|
+
"audio/mp3": "audio.mp3",
|
|
9
|
+
"audio/flac": "audio.flac",
|
|
10
|
+
"audio/ogg": "audio.ogg",
|
|
11
|
+
"audio/opus": "audio.opus",
|
|
12
|
+
"audio/webm": "audio.webm",
|
|
13
|
+
"audio/mp4": "audio.m4a",
|
|
14
|
+
"audio/m4a": "audio.m4a",
|
|
15
|
+
"audio/aac": "audio.aac"
|
|
16
|
+
};
|
|
17
|
+
const speechNames = {
|
|
18
|
+
pcm16: "pcm",
|
|
19
|
+
wav: "wav",
|
|
20
|
+
mp3: "mp3",
|
|
21
|
+
opus: "opus"
|
|
22
|
+
};
|
|
23
|
+
class ByteWriter {
|
|
24
|
+
#bytes = [];
|
|
25
|
+
byte(value) {
|
|
26
|
+
this.#bytes.push(value & 255);
|
|
27
|
+
}
|
|
28
|
+
u16(value) {
|
|
29
|
+
this.byte(value >> 8);
|
|
30
|
+
this.byte(value);
|
|
31
|
+
}
|
|
32
|
+
u32(value) {
|
|
33
|
+
this.byte(value >>> 24);
|
|
34
|
+
this.byte(value >>> 16);
|
|
35
|
+
this.byte(value >>> 8);
|
|
36
|
+
this.byte(value);
|
|
37
|
+
}
|
|
38
|
+
f64(value) {
|
|
39
|
+
const view = new DataView(new ArrayBuffer(8));
|
|
40
|
+
view.setFloat64(0, value);
|
|
41
|
+
for (let index = 0; index < 8; index += 1) this.byte(view.getUint8(index));
|
|
42
|
+
}
|
|
43
|
+
raw(bytes) {
|
|
44
|
+
for (const byte of bytes) this.byte(byte);
|
|
45
|
+
}
|
|
46
|
+
toArray() {
|
|
47
|
+
return Uint8Array.from(this.#bytes);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
class ByteReader {
|
|
51
|
+
#offset = 0;
|
|
52
|
+
#data;
|
|
53
|
+
constructor(data) {
|
|
54
|
+
this.#data = data;
|
|
55
|
+
}
|
|
56
|
+
byte() {
|
|
57
|
+
const value = this.#data[this.#offset];
|
|
58
|
+
if (value === void 0) throw new Error("Fish frame ended early");
|
|
59
|
+
this.#offset += 1;
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
u16() {
|
|
63
|
+
return this.byte() << 8 | this.byte();
|
|
64
|
+
}
|
|
65
|
+
u32() {
|
|
66
|
+
return (this.byte() << 24 | this.byte() << 16 | this.byte() << 8 | this.byte()) >>> 0;
|
|
67
|
+
}
|
|
68
|
+
i16() {
|
|
69
|
+
const value = this.u16();
|
|
70
|
+
return value > 32767 ? value - 65536 : value;
|
|
71
|
+
}
|
|
72
|
+
i32() {
|
|
73
|
+
return this.u32() | 0;
|
|
74
|
+
}
|
|
75
|
+
u64() {
|
|
76
|
+
const high = this.u32();
|
|
77
|
+
const low = this.u32();
|
|
78
|
+
return high * 4294967296 + low;
|
|
79
|
+
}
|
|
80
|
+
i64() {
|
|
81
|
+
const high = this.i32();
|
|
82
|
+
const low = this.u32();
|
|
83
|
+
return high * 4294967296 + low;
|
|
84
|
+
}
|
|
85
|
+
f32() {
|
|
86
|
+
const copy = new Uint8Array(4);
|
|
87
|
+
copy.set(this.bytes(4));
|
|
88
|
+
return new DataView(copy.buffer).getFloat32(0);
|
|
89
|
+
}
|
|
90
|
+
f64() {
|
|
91
|
+
const copy = new Uint8Array(8);
|
|
92
|
+
copy.set(this.bytes(8));
|
|
93
|
+
return new DataView(copy.buffer).getFloat64(0);
|
|
94
|
+
}
|
|
95
|
+
bytes(length) {
|
|
96
|
+
const start = this.#offset;
|
|
97
|
+
if (start + length > this.#data.length) throw new Error("Fish frame ended early");
|
|
98
|
+
this.#offset = start + length;
|
|
99
|
+
return this.#data.subarray(start, this.#offset);
|
|
100
|
+
}
|
|
101
|
+
done() {
|
|
102
|
+
return this.#offset === this.#data.length;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function packString(value, out) {
|
|
106
|
+
const bytes = new TextEncoder().encode(value);
|
|
107
|
+
if (bytes.length < 32) out.byte(160 | bytes.length);
|
|
108
|
+
else if (bytes.length < 256) {
|
|
109
|
+
out.byte(217);
|
|
110
|
+
out.byte(bytes.length);
|
|
111
|
+
} else if (bytes.length < 65536) {
|
|
112
|
+
out.byte(218);
|
|
113
|
+
out.u16(bytes.length);
|
|
114
|
+
} else throw new Error("String too long");
|
|
115
|
+
out.raw(bytes);
|
|
116
|
+
}
|
|
117
|
+
function packBin(value, out) {
|
|
118
|
+
if (value.byteLength < 256) {
|
|
119
|
+
out.byte(196);
|
|
120
|
+
out.byte(value.byteLength);
|
|
121
|
+
} else if (value.byteLength < 65536) {
|
|
122
|
+
out.byte(197);
|
|
123
|
+
out.u16(value.byteLength);
|
|
124
|
+
} else throw new Error("Binary too long");
|
|
125
|
+
out.raw(value);
|
|
126
|
+
}
|
|
127
|
+
function packNumber(value, out) {
|
|
128
|
+
if (!Number.isInteger(value)) {
|
|
129
|
+
out.byte(203);
|
|
130
|
+
out.f64(value);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (value >= 0 && value <= 127) {
|
|
134
|
+
out.byte(value);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (value < 0 && value >= -32) {
|
|
138
|
+
out.byte(value & 255);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (value >= 0 && value <= 255) {
|
|
142
|
+
out.byte(204);
|
|
143
|
+
out.byte(value);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (value >= 0 && value <= 65535) {
|
|
147
|
+
out.byte(205);
|
|
148
|
+
out.u16(value);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (value >= 0 && value <= 4294967295) {
|
|
152
|
+
out.byte(206);
|
|
153
|
+
out.u32(value);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (value < 0 && value >= -128) {
|
|
157
|
+
out.byte(208);
|
|
158
|
+
out.byte(value & 255);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
throw new Error("Integer out of range");
|
|
162
|
+
}
|
|
163
|
+
function packArray(values, out) {
|
|
164
|
+
if (values.length < 16) out.byte(144 | values.length);
|
|
165
|
+
else if (values.length < 65536) {
|
|
166
|
+
out.byte(220);
|
|
167
|
+
out.u16(values.length);
|
|
168
|
+
} else throw new Error("Array too long");
|
|
169
|
+
for (const value of values) packInto(value, out);
|
|
170
|
+
}
|
|
171
|
+
function packMap(value, out) {
|
|
172
|
+
const entries = Object.entries(value);
|
|
173
|
+
if (entries.length < 16) out.byte(128 | entries.length);
|
|
174
|
+
else if (entries.length < 65536) {
|
|
175
|
+
out.byte(222);
|
|
176
|
+
out.u16(entries.length);
|
|
177
|
+
} else throw new Error("Map too long");
|
|
178
|
+
for (const [key, item] of entries) {
|
|
179
|
+
packString(key, out);
|
|
180
|
+
packInto(item, out);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function packInto(value, out) {
|
|
184
|
+
if (value === null) {
|
|
185
|
+
out.byte(192);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (typeof value === "boolean") {
|
|
189
|
+
out.byte(value ? 195 : 194);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (typeof value === "number") {
|
|
193
|
+
packNumber(value, out);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (typeof value === "string") {
|
|
197
|
+
packString(value, out);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (value instanceof Uint8Array) {
|
|
201
|
+
packBin(value, out);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (Array.isArray(value)) {
|
|
205
|
+
packArray(value, out);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
packMap(value, out);
|
|
209
|
+
}
|
|
210
|
+
function unpackString(reader, length) {
|
|
211
|
+
return new TextDecoder().decode(reader.bytes(length));
|
|
212
|
+
}
|
|
213
|
+
function unpackArray(reader, length) {
|
|
214
|
+
const values = [];
|
|
215
|
+
for (let index = 0; index < length; index += 1) values.push(unpackOne(reader));
|
|
216
|
+
return values;
|
|
217
|
+
}
|
|
218
|
+
function unpackMap(reader, length) {
|
|
219
|
+
const value = {};
|
|
220
|
+
for (let index = 0; index < length; index += 1) {
|
|
221
|
+
const key = unpackOne(reader);
|
|
222
|
+
if (typeof key !== "string") throw new Error("Fish frame key was not a string");
|
|
223
|
+
value[key] = unpackOne(reader);
|
|
224
|
+
}
|
|
225
|
+
return value;
|
|
226
|
+
}
|
|
227
|
+
function unpackSized(reader, marker) {
|
|
228
|
+
if (marker === 192) return null;
|
|
229
|
+
if (marker === 194) return false;
|
|
230
|
+
if (marker === 195) return true;
|
|
231
|
+
if (marker === 196) return reader.bytes(reader.byte());
|
|
232
|
+
if (marker === 197) return reader.bytes(reader.u16());
|
|
233
|
+
if (marker === 198) return reader.bytes(reader.u32());
|
|
234
|
+
if (marker === 202) return reader.f32();
|
|
235
|
+
if (marker === 203) return reader.f64();
|
|
236
|
+
if (marker === 204) return reader.byte();
|
|
237
|
+
if (marker === 205) return reader.u16();
|
|
238
|
+
if (marker === 206) return reader.u32();
|
|
239
|
+
if (marker === 207) return reader.u64();
|
|
240
|
+
if (marker === 208) return reader.byte() << 24 >> 24;
|
|
241
|
+
if (marker === 209) return reader.i16();
|
|
242
|
+
if (marker === 210) return reader.i32();
|
|
243
|
+
if (marker === 211) return reader.i64();
|
|
244
|
+
return void 0;
|
|
245
|
+
}
|
|
246
|
+
function unpackOne(reader) {
|
|
247
|
+
const marker = reader.byte();
|
|
248
|
+
if (marker <= 127) return marker;
|
|
249
|
+
if (marker >= 224) return marker - 256;
|
|
250
|
+
const sized = unpackSized(reader, marker);
|
|
251
|
+
if (sized !== void 0) return sized;
|
|
252
|
+
if ((marker & 224) === 160) return unpackString(reader, marker & 31);
|
|
253
|
+
if (marker === 217) return unpackString(reader, reader.byte());
|
|
254
|
+
if (marker === 218) return unpackString(reader, reader.u16());
|
|
255
|
+
if (marker === 219) return unpackString(reader, reader.u32());
|
|
256
|
+
if ((marker & 240) === 144) return unpackArray(reader, marker & 15);
|
|
257
|
+
if (marker === 220) return unpackArray(reader, reader.u16());
|
|
258
|
+
if (marker === 221) return unpackArray(reader, reader.u32());
|
|
259
|
+
if ((marker & 240) === 128) return unpackMap(reader, marker & 15);
|
|
260
|
+
if (marker === 222) return unpackMap(reader, reader.u16());
|
|
261
|
+
if (marker === 223) return unpackMap(reader, reader.u32());
|
|
262
|
+
throw new Error("Unsupported Fish frame");
|
|
263
|
+
}
|
|
264
|
+
function pack(value) {
|
|
265
|
+
const out = new ByteWriter();
|
|
266
|
+
packInto(value, out);
|
|
267
|
+
return out.toArray();
|
|
268
|
+
}
|
|
269
|
+
function unpack(data) {
|
|
270
|
+
const reader = new ByteReader(data);
|
|
271
|
+
const value = unpackOne(reader);
|
|
272
|
+
if (!reader.done()) throw new Error("Fish frame had trailing bytes");
|
|
273
|
+
return value;
|
|
274
|
+
}
|
|
275
|
+
function mediaType(mimeType) {
|
|
276
|
+
const type = mimeType.split(";")[0]?.trim().toLowerCase();
|
|
277
|
+
if (!type) throw new Error(`Unsupported audio type ${mimeType}`);
|
|
278
|
+
return type;
|
|
279
|
+
}
|
|
280
|
+
function audioFilename(mimeType) {
|
|
281
|
+
const name = filenames[mediaType(mimeType)];
|
|
282
|
+
if (!name) throw new Error(`Unsupported audio type ${mimeType}`);
|
|
283
|
+
return name;
|
|
284
|
+
}
|
|
285
|
+
function encodeForm(file, fields) {
|
|
286
|
+
const chunks = [];
|
|
287
|
+
const encoder = new TextEncoder();
|
|
288
|
+
const write = (value) => {
|
|
289
|
+
chunks.push(encoder.encode(value));
|
|
290
|
+
};
|
|
291
|
+
for (const [name, value] of Object.entries(fields)) {
|
|
292
|
+
write(`--${boundary}\r
|
|
293
|
+
Content-Disposition: form-data; name="${name}"\r
|
|
294
|
+
\r
|
|
295
|
+
${value}\r
|
|
296
|
+
`);
|
|
297
|
+
}
|
|
298
|
+
const header = `--${boundary}\r
|
|
299
|
+
Content-Disposition: form-data; name="audio"; filename="${file.filename}"\r
|
|
300
|
+
Content-Type: ${file.mimeType}\r
|
|
301
|
+
\r
|
|
302
|
+
`;
|
|
303
|
+
write(header);
|
|
304
|
+
chunks.push(file.data);
|
|
305
|
+
write(`\r
|
|
306
|
+
--${boundary}--\r
|
|
307
|
+
`);
|
|
308
|
+
const body = new Uint8Array(chunks.reduce((sum, chunk) => sum + chunk.length, 0));
|
|
309
|
+
let offset = 0;
|
|
310
|
+
for (const chunk of chunks) {
|
|
311
|
+
body.set(chunk, offset);
|
|
312
|
+
offset += chunk.length;
|
|
313
|
+
}
|
|
314
|
+
return body.buffer;
|
|
315
|
+
}
|
|
316
|
+
function formType() {
|
|
317
|
+
return `multipart/form-data; boundary=${boundary}`;
|
|
318
|
+
}
|
|
319
|
+
function fishHeaders(model, options) {
|
|
320
|
+
const headers = requestHeaders(model, options);
|
|
321
|
+
headers.model = model.id;
|
|
322
|
+
return headers;
|
|
323
|
+
}
|
|
324
|
+
function socketUrl(baseUrl, path) {
|
|
325
|
+
const url = new URL(baseUrl);
|
|
326
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
327
|
+
url.pathname = `${url.pathname.replace(/\/$/, "")}/${path}`;
|
|
328
|
+
url.search = "";
|
|
329
|
+
return url;
|
|
330
|
+
}
|
|
331
|
+
function speechFormatName(format) {
|
|
332
|
+
const name = speechNames[format.encoding];
|
|
333
|
+
if (!name) throw new Error(`Unsupported speech format ${format.encoding}`);
|
|
334
|
+
return name;
|
|
335
|
+
}
|
|
336
|
+
function connectSocket(url, headers) {
|
|
337
|
+
const Socket = WebSocket;
|
|
338
|
+
return new Socket(url, { headers });
|
|
339
|
+
}
|
|
340
|
+
function awaitOpen(socket, label, fail) {
|
|
341
|
+
return new Promise((resolve) => {
|
|
342
|
+
let opened = false;
|
|
343
|
+
socket.addEventListener("open", () => {
|
|
344
|
+
opened = true;
|
|
345
|
+
resolve();
|
|
346
|
+
});
|
|
347
|
+
socket.addEventListener("error", () => {
|
|
348
|
+
fail(`${label} socket failed`);
|
|
349
|
+
if (!opened) resolve();
|
|
350
|
+
});
|
|
351
|
+
socket.addEventListener("close", () => {
|
|
352
|
+
if (!opened) {
|
|
353
|
+
fail(`${label} socket closed`);
|
|
354
|
+
resolve();
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
async function messageBytes(data) {
|
|
360
|
+
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
361
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
362
|
+
if (data instanceof Uint8Array) return data;
|
|
363
|
+
if (typeof Blob !== "undefined" && data instanceof Blob) {
|
|
364
|
+
return new Uint8Array(await data.arrayBuffer());
|
|
365
|
+
}
|
|
366
|
+
throw new Error("Unsupported socket message");
|
|
367
|
+
}
|
|
368
|
+
function sameFormat(left, right) {
|
|
369
|
+
return left.encoding === right.encoding && left.sampleRate === right.sampleRate && left.channels === right.channels;
|
|
370
|
+
}
|
|
371
|
+
export {
|
|
372
|
+
audioFilename,
|
|
373
|
+
awaitOpen,
|
|
374
|
+
connectSocket,
|
|
375
|
+
encodeForm,
|
|
376
|
+
fishHeaders,
|
|
377
|
+
formType,
|
|
378
|
+
mediaType,
|
|
379
|
+
messageBytes,
|
|
380
|
+
pack,
|
|
381
|
+
sameFormat,
|
|
382
|
+
socketUrl,
|
|
383
|
+
speechFormatName,
|
|
384
|
+
unpack
|
|
385
|
+
};
|
|
386
|
+
//# sourceMappingURL=wire.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/fish/wire.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ProviderRequestOptions } from '@earendil-works/pi-ai';\nimport type { AudioFormat } from '../audio.ts';\nimport { requestHeaders } from '../openai/wire.ts';\n\nconst boundary = 'pi-audio-fish-boundary';\n\nconst filenames: Record<string, string> = {\n 'audio/wav': 'audio.wav',\n 'audio/wave': 'audio.wav',\n 'audio/x-wav': 'audio.wav',\n 'audio/mpeg': 'audio.mp3',\n 'audio/mp3': 'audio.mp3',\n 'audio/flac': 'audio.flac',\n 'audio/ogg': 'audio.ogg',\n 'audio/opus': 'audio.opus',\n 'audio/webm': 'audio.webm',\n 'audio/mp4': 'audio.m4a',\n 'audio/m4a': 'audio.m4a',\n 'audio/aac': 'audio.aac',\n};\n\nconst speechNames: Record<string, string> = {\n pcm16: 'pcm',\n wav: 'wav',\n mp3: 'mp3',\n opus: 'opus',\n};\n\nexport type PackValue =\n | null\n | boolean\n | number\n | string\n | Uint8Array\n | PackValue[]\n | { [key: string]: PackValue };\n\nexport interface FishFile {\n data: Uint8Array;\n mimeType: string;\n filename: string;\n}\n\nclass ByteWriter {\n readonly #bytes: number[] = [];\n\n byte(value: number): void {\n this.#bytes.push(value & 0xff);\n }\n\n u16(value: number): void {\n this.byte(value >> 8);\n this.byte(value);\n }\n\n u32(value: number): void {\n this.byte(value >>> 24);\n this.byte(value >>> 16);\n this.byte(value >>> 8);\n this.byte(value);\n }\n\n f64(value: number): void {\n const view = new DataView(new ArrayBuffer(8));\n view.setFloat64(0, value);\n for (let index = 0; index < 8; index += 1) this.byte(view.getUint8(index));\n }\n\n raw(bytes: Uint8Array): void {\n for (const byte of bytes) this.byte(byte);\n }\n\n toArray(): Uint8Array {\n return Uint8Array.from(this.#bytes);\n }\n}\n\nclass ByteReader {\n #offset = 0;\n readonly #data: Uint8Array;\n\n constructor(data: Uint8Array) {\n this.#data = data;\n }\n\n byte(): number {\n const value = this.#data[this.#offset];\n if (value === undefined) throw new Error('Fish frame ended early');\n this.#offset += 1;\n return value;\n }\n\n u16(): number {\n return (this.byte() << 8) | this.byte();\n }\n\n u32(): number {\n return ((this.byte() << 24) | (this.byte() << 16) | (this.byte() << 8) | this.byte()) >>> 0;\n }\n\n i16(): number {\n const value = this.u16();\n return value > 0x7fff ? value - 0x10000 : value;\n }\n\n i32(): number {\n return this.u32() | 0;\n }\n\n u64(): number {\n const high = this.u32();\n const low = this.u32();\n return high * 0x100000000 + low;\n }\n\n i64(): number {\n const high = this.i32();\n const low = this.u32();\n return high * 0x100000000 + low;\n }\n\n f32(): number {\n const copy = new Uint8Array(4);\n copy.set(this.bytes(4));\n return new DataView(copy.buffer).getFloat32(0);\n }\n\n f64(): number {\n const copy = new Uint8Array(8);\n copy.set(this.bytes(8));\n return new DataView(copy.buffer).getFloat64(0);\n }\n\n bytes(length: number): Uint8Array {\n const start = this.#offset;\n if (start + length > this.#data.length) throw new Error('Fish frame ended early');\n this.#offset = start + length;\n return this.#data.subarray(start, this.#offset);\n }\n\n done(): boolean {\n return this.#offset === this.#data.length;\n }\n}\n\nfunction packString(value: string, out: ByteWriter): void {\n const bytes = new TextEncoder().encode(value);\n if (bytes.length < 32) out.byte(0xa0 | bytes.length);\n else if (bytes.length < 256) {\n out.byte(0xd9);\n out.byte(bytes.length);\n } else if (bytes.length < 65536) {\n out.byte(0xda);\n out.u16(bytes.length);\n } else throw new Error('String too long');\n out.raw(bytes);\n}\n\nfunction packBin(value: Uint8Array, out: ByteWriter): void {\n if (value.byteLength < 256) {\n out.byte(0xc4);\n out.byte(value.byteLength);\n } else if (value.byteLength < 65536) {\n out.byte(0xc5);\n out.u16(value.byteLength);\n } else throw new Error('Binary too long');\n out.raw(value);\n}\n\nfunction packNumber(value: number, out: ByteWriter): void {\n if (!Number.isInteger(value)) {\n out.byte(0xcb);\n out.f64(value);\n return;\n }\n if (value >= 0 && value <= 0x7f) {\n out.byte(value);\n return;\n }\n if (value < 0 && value >= -32) {\n out.byte(value & 0xff);\n return;\n }\n if (value >= 0 && value <= 0xff) {\n out.byte(0xcc);\n out.byte(value);\n return;\n }\n if (value >= 0 && value <= 0xffff) {\n out.byte(0xcd);\n out.u16(value);\n return;\n }\n if (value >= 0 && value <= 0xffffffff) {\n out.byte(0xce);\n out.u32(value);\n return;\n }\n if (value < 0 && value >= -128) {\n out.byte(0xd0);\n out.byte(value & 0xff);\n return;\n }\n throw new Error('Integer out of range');\n}\n\nfunction packArray(values: PackValue[], out: ByteWriter): void {\n if (values.length < 16) out.byte(0x90 | values.length);\n else if (values.length < 65536) {\n out.byte(0xdc);\n out.u16(values.length);\n } else throw new Error('Array too long');\n for (const value of values) packInto(value, out);\n}\n\nfunction packMap(value: { [key: string]: PackValue }, out: ByteWriter): void {\n const entries = Object.entries(value);\n if (entries.length < 16) out.byte(0x80 | entries.length);\n else if (entries.length < 65536) {\n out.byte(0xde);\n out.u16(entries.length);\n } else throw new Error('Map too long');\n for (const [key, item] of entries) {\n packString(key, out);\n packInto(item, out);\n }\n}\n\nfunction packInto(value: PackValue, out: ByteWriter): void {\n if (value === null) {\n out.byte(0xc0);\n return;\n }\n if (typeof value === 'boolean') {\n out.byte(value ? 0xc3 : 0xc2);\n return;\n }\n if (typeof value === 'number') {\n packNumber(value, out);\n return;\n }\n if (typeof value === 'string') {\n packString(value, out);\n return;\n }\n if (value instanceof Uint8Array) {\n packBin(value, out);\n return;\n }\n if (Array.isArray(value)) {\n packArray(value, out);\n return;\n }\n packMap(value, out);\n}\n\nfunction unpackString(reader: ByteReader, length: number): string {\n return new TextDecoder().decode(reader.bytes(length));\n}\n\nfunction unpackArray(reader: ByteReader, length: number): PackValue[] {\n const values: PackValue[] = [];\n for (let index = 0; index < length; index += 1) values.push(unpackOne(reader));\n return values;\n}\n\nfunction unpackMap(reader: ByteReader, length: number): { [key: string]: PackValue } {\n const value: { [key: string]: PackValue } = {};\n for (let index = 0; index < length; index += 1) {\n const key = unpackOne(reader);\n if (typeof key !== 'string') throw new Error('Fish frame key was not a string');\n value[key] = unpackOne(reader);\n }\n return value;\n}\n\nfunction unpackSized(reader: ByteReader, marker: number): PackValue | undefined {\n if (marker === 0xc0) return null;\n if (marker === 0xc2) return false;\n if (marker === 0xc3) return true;\n if (marker === 0xc4) return reader.bytes(reader.byte());\n if (marker === 0xc5) return reader.bytes(reader.u16());\n if (marker === 0xc6) return reader.bytes(reader.u32());\n if (marker === 0xca) return reader.f32();\n if (marker === 0xcb) return reader.f64();\n if (marker === 0xcc) return reader.byte();\n if (marker === 0xcd) return reader.u16();\n if (marker === 0xce) return reader.u32();\n if (marker === 0xcf) return reader.u64();\n if (marker === 0xd0) return (reader.byte() << 24) >> 24;\n if (marker === 0xd1) return reader.i16();\n if (marker === 0xd2) return reader.i32();\n if (marker === 0xd3) return reader.i64();\n return undefined;\n}\n\nfunction unpackOne(reader: ByteReader): PackValue {\n const marker = reader.byte();\n if (marker <= 0x7f) return marker;\n if (marker >= 0xe0) return marker - 0x100;\n const sized = unpackSized(reader, marker);\n if (sized !== undefined) return sized;\n if ((marker & 0xe0) === 0xa0) return unpackString(reader, marker & 0x1f);\n if (marker === 0xd9) return unpackString(reader, reader.byte());\n if (marker === 0xda) return unpackString(reader, reader.u16());\n if (marker === 0xdb) return unpackString(reader, reader.u32());\n if ((marker & 0xf0) === 0x90) return unpackArray(reader, marker & 0x0f);\n if (marker === 0xdc) return unpackArray(reader, reader.u16());\n if (marker === 0xdd) return unpackArray(reader, reader.u32());\n if ((marker & 0xf0) === 0x80) return unpackMap(reader, marker & 0x0f);\n if (marker === 0xde) return unpackMap(reader, reader.u16());\n if (marker === 0xdf) return unpackMap(reader, reader.u32());\n throw new Error('Unsupported Fish frame');\n}\n\nexport function pack(value: PackValue): Uint8Array {\n const out = new ByteWriter();\n packInto(value, out);\n return out.toArray();\n}\n\nexport function unpack(data: Uint8Array): PackValue {\n const reader = new ByteReader(data);\n const value = unpackOne(reader);\n if (!reader.done()) throw new Error('Fish frame had trailing bytes');\n return value;\n}\n\nexport function mediaType(mimeType: string): string {\n const type = mimeType.split(';')[0]?.trim().toLowerCase();\n if (!type) throw new Error(`Unsupported audio type ${mimeType}`);\n return type;\n}\n\nexport function audioFilename(mimeType: string): string {\n const name = filenames[mediaType(mimeType)];\n if (!name) throw new Error(`Unsupported audio type ${mimeType}`);\n return name;\n}\n\nexport function encodeForm(file: FishFile, fields: Record<string, string>): ArrayBuffer {\n const chunks: Uint8Array[] = [];\n const encoder = new TextEncoder();\n const write = (value: string) => {\n chunks.push(encoder.encode(value));\n };\n for (const [name, value] of Object.entries(fields)) {\n write(`--${boundary}\\r\\nContent-Disposition: form-data; name=\"${name}\"\\r\\n\\r\\n${value}\\r\\n`);\n }\n const header =\n `--${boundary}\\r\\nContent-Disposition: form-data; name=\"audio\"; filename=\"${file.filename}\"\\r\\n` +\n `Content-Type: ${file.mimeType}\\r\\n\\r\\n`;\n write(header);\n chunks.push(file.data);\n write(`\\r\\n--${boundary}--\\r\\n`);\n const body = new Uint8Array(chunks.reduce((sum, chunk) => sum + chunk.length, 0));\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.length;\n }\n return body.buffer;\n}\n\nexport function formType(): string {\n return `multipart/form-data; boundary=${boundary}`;\n}\n\nexport function fishHeaders(\n model: { id: string; provider: string; headers?: Record<string, string> },\n options: ProviderRequestOptions | undefined\n): Record<string, string> {\n const headers = requestHeaders(model, options);\n headers.model = model.id;\n return headers;\n}\n\nexport function socketUrl(baseUrl: string, path: string): URL {\n const url = new URL(baseUrl);\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';\n url.pathname = `${url.pathname.replace(/\\/$/, '')}/${path}`;\n url.search = '';\n return url;\n}\n\nexport function speechFormatName(format: AudioFormat): string {\n const name = speechNames[format.encoding];\n if (!name) throw new Error(`Unsupported speech format ${format.encoding}`);\n return name;\n}\n\nexport function connectSocket(url: string, headers: Record<string, string>): WebSocket {\n const Socket = WebSocket as unknown as new (\n address: string,\n init: { headers: Record<string, string> }\n ) => WebSocket;\n return new Socket(url, { headers });\n}\n\nexport function awaitOpen(\n socket: WebSocket,\n label: string,\n fail: (message: string) => void\n): Promise<void> {\n return new Promise((resolve) => {\n let opened = false;\n socket.addEventListener('open', () => {\n opened = true;\n resolve();\n });\n socket.addEventListener('error', () => {\n fail(`${label} socket failed`);\n if (!opened) resolve();\n });\n socket.addEventListener('close', () => {\n if (!opened) {\n fail(`${label} socket closed`);\n resolve();\n }\n });\n });\n}\n\nexport async function messageBytes(data: unknown): Promise<Uint8Array> {\n if (typeof data === 'string') return new TextEncoder().encode(data);\n if (data instanceof ArrayBuffer) return new Uint8Array(data);\n if (data instanceof Uint8Array) return data;\n if (typeof Blob !== 'undefined' && data instanceof Blob) {\n return new Uint8Array(await data.arrayBuffer());\n }\n throw new Error('Unsupported socket message');\n}\n\nexport function sameFormat(left: AudioFormat, right: AudioFormat): boolean {\n return (\n left.encoding === right.encoding &&\n left.sampleRate === right.sampleRate &&\n left.channels === right.channels\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -205,6 +205,8 @@ class GeminiSession {
|
|
|
205
205
|
#closed = false;
|
|
206
206
|
#ended = false;
|
|
207
207
|
#meters;
|
|
208
|
+
#toolGroups = /* @__PURE__ */ new Map();
|
|
209
|
+
#toolGroupOf = /* @__PURE__ */ new Map();
|
|
208
210
|
constructor(model, context, vocabulary, open, target, wire) {
|
|
209
211
|
this.model = model;
|
|
210
212
|
this.#context = context;
|
|
@@ -285,20 +287,14 @@ class GeminiSession {
|
|
|
285
287
|
this.#assertOpen();
|
|
286
288
|
const send = () => {
|
|
287
289
|
const mode = delivery === void 0 ? "interrupt" : delivery;
|
|
288
|
-
this.#
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
status: result.isError ? "error" : "ok",
|
|
297
|
-
retryable: false,
|
|
298
|
-
message: resultText(result)
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
]
|
|
290
|
+
this.#queueTool(callId, {
|
|
291
|
+
id: callId,
|
|
292
|
+
name: result.toolName,
|
|
293
|
+
scheduling: scheduling[mode],
|
|
294
|
+
response: {
|
|
295
|
+
status: result.isError ? "error" : "ok",
|
|
296
|
+
retryable: false,
|
|
297
|
+
message: resultText(result)
|
|
302
298
|
}
|
|
303
299
|
});
|
|
304
300
|
};
|
|
@@ -440,23 +436,44 @@ class GeminiSession {
|
|
|
440
436
|
next.send(JSON.stringify({ setup: this.#setup(handle) }));
|
|
441
437
|
return next;
|
|
442
438
|
}
|
|
439
|
+
#queueTool(callId, response) {
|
|
440
|
+
const groupId = this.#toolGroupOf.get(callId) ?? "";
|
|
441
|
+
const group = groupId.length === 0 ? void 0 : this.#toolGroups.get(groupId);
|
|
442
|
+
if (group === void 0) {
|
|
443
|
+
this.#send({ toolResponse: { functionResponses: [response] } });
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
group.responses.push(response);
|
|
447
|
+
group.pending.delete(callId);
|
|
448
|
+
this.#toolGroupOf.delete(callId);
|
|
449
|
+
if (group.pending.size > 0) return;
|
|
450
|
+
this.#toolGroups.delete(groupId);
|
|
451
|
+
this.#send({ toolResponse: { functionResponses: group.responses } });
|
|
452
|
+
}
|
|
443
453
|
#onToolCall(value) {
|
|
444
454
|
const call = record(value);
|
|
445
455
|
if (call === void 0 || !Array.isArray(call.functionCalls)) return;
|
|
456
|
+
const ids = [];
|
|
446
457
|
for (const entry of call.functionCalls) {
|
|
447
458
|
const fn = record(entry);
|
|
448
459
|
if (fn === void 0) continue;
|
|
460
|
+
const id = text(fn.id);
|
|
461
|
+
if (id.length > 0) ids.push(id);
|
|
449
462
|
this.#push({
|
|
450
463
|
type: "tool_call",
|
|
451
464
|
blocking: this.model.toolCalls === "blocking",
|
|
452
465
|
call: {
|
|
453
466
|
type: "toolCall",
|
|
454
|
-
id
|
|
467
|
+
id,
|
|
455
468
|
name: text(fn.name),
|
|
456
469
|
arguments: argumentsOf(fn.args)
|
|
457
470
|
}
|
|
458
471
|
});
|
|
459
472
|
}
|
|
473
|
+
const groupId = ids.at(0);
|
|
474
|
+
if (groupId === void 0) return;
|
|
475
|
+
this.#toolGroups.set(groupId, { pending: new Set(ids), responses: [] });
|
|
476
|
+
for (const id of ids) this.#toolGroupOf.set(id, groupId);
|
|
460
477
|
}
|
|
461
478
|
#onCancel(value) {
|
|
462
479
|
const cancellation = record(value);
|