fauna-api 0.0.0-stage → 1.0.676

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.
Files changed (171) hide show
  1. package/dist/brands.d.ts +2 -0
  2. package/dist/brands.js +2 -0
  3. package/dist/index.d.ts +64 -0
  4. package/dist/index.js +121 -0
  5. package/dist/src/ant/chat.d.ts +130 -0
  6. package/dist/src/ant/chat.js +467 -0
  7. package/dist/src/ant/format.d.ts +40 -0
  8. package/dist/src/ant/format.js +143 -0
  9. package/dist/src/ant/graph.d.ts +130 -0
  10. package/dist/src/ant/graph.js +449 -0
  11. package/dist/src/ant/index.d.ts +16 -0
  12. package/dist/src/ant/index.js +61 -0
  13. package/dist/src/ant/persona.d.ts +151 -0
  14. package/dist/src/ant/persona.js +136 -0
  15. package/dist/src/ant/timeline.d.ts +283 -0
  16. package/dist/src/ant/timeline.js +1025 -0
  17. package/dist/src/authentification.d.ts +45 -0
  18. package/dist/src/authentification.js +194 -0
  19. package/dist/src/billing.d.ts +135 -0
  20. package/dist/src/billing.js +128 -0
  21. package/dist/src/calendar.d.ts +83 -0
  22. package/dist/src/calendar.js +133 -0
  23. package/dist/src/chats.d.ts +113 -0
  24. package/dist/src/chats.js +100 -0
  25. package/dist/src/cicada/contacts.d.ts +31 -0
  26. package/dist/src/cicada/contacts.js +28 -0
  27. package/dist/src/cicada/conversations.d.ts +73 -0
  28. package/dist/src/cicada/conversations.js +236 -0
  29. package/dist/src/cicada/inboxes.d.ts +48 -0
  30. package/dist/src/cicada/inboxes.js +82 -0
  31. package/dist/src/cicada/index.d.ts +16 -0
  32. package/dist/src/cicada/index.js +61 -0
  33. package/dist/src/cicada/phone.d.ts +48 -0
  34. package/dist/src/cicada/phone.js +306 -0
  35. package/dist/src/drive.d.ts +80 -0
  36. package/dist/src/drive.js +472 -0
  37. package/dist/src/extensions/index.d.ts +4 -0
  38. package/dist/src/extensions/index.js +5 -0
  39. package/dist/src/extensions/web/index.d.ts +6 -0
  40. package/dist/src/extensions/web/index.js +7 -0
  41. package/dist/src/extensions/web/session.d.ts +106 -0
  42. package/dist/src/extensions/web/session.js +469 -0
  43. package/dist/src/extensions/web/tools.d.ts +13 -0
  44. package/dist/src/extensions/web/tools.js +72 -0
  45. package/dist/src/friends.d.ts +39 -0
  46. package/dist/src/friends.js +119 -0
  47. package/dist/src/groups.d.ts +82 -0
  48. package/dist/src/groups.js +269 -0
  49. package/dist/src/inbox.d.ts +11 -0
  50. package/dist/src/inbox.js +35 -0
  51. package/dist/src/integrations.d.ts +52 -0
  52. package/dist/src/integrations.js +205 -0
  53. package/dist/src/magpie/explorer.d.ts +14 -0
  54. package/dist/src/magpie/explorer.js +36 -0
  55. package/dist/src/magpie/index.d.ts +16 -0
  56. package/dist/src/magpie/index.js +61 -0
  57. package/dist/src/magpie/portfolio.d.ts +52 -0
  58. package/dist/src/magpie/portfolio.js +179 -0
  59. package/dist/src/magpie/quotes.d.ts +35 -0
  60. package/dist/src/magpie/quotes.js +47 -0
  61. package/dist/src/magpie/room.d.ts +61 -0
  62. package/dist/src/magpie/room.js +238 -0
  63. package/dist/src/maps.d.ts +159 -0
  64. package/dist/src/maps.js +171 -0
  65. package/dist/src/marmot/browser.d.ts +139 -0
  66. package/dist/src/marmot/browser.js +389 -0
  67. package/dist/src/marmot/index.d.ts +20 -0
  68. package/dist/src/marmot/index.js +65 -0
  69. package/dist/src/marmot/media.d.ts +56 -0
  70. package/dist/src/marmot/media.js +265 -0
  71. package/dist/src/marmot/research.d.ts +337 -0
  72. package/dist/src/marmot/research.js +1138 -0
  73. package/dist/src/marmot/scraper.d.ts +59 -0
  74. package/dist/src/marmot/scraper.js +94 -0
  75. package/dist/src/marmot/web.d.ts +402 -0
  76. package/dist/src/marmot/web.js +2586 -0
  77. package/dist/src/marmot/workspace.d.ts +81 -0
  78. package/dist/src/marmot/workspace.js +263 -0
  79. package/dist/src/parrot/agent.d.ts +53 -0
  80. package/dist/src/parrot/agent.js +93 -0
  81. package/dist/src/parrot/chat.d.ts +84 -0
  82. package/dist/src/parrot/chat.js +237 -0
  83. package/dist/src/parrot/format.d.ts +128 -0
  84. package/dist/src/parrot/format.js +639 -0
  85. package/dist/src/parrot/generative.d.ts +261 -0
  86. package/dist/src/parrot/generative.js +185 -0
  87. package/dist/src/parrot/index.d.ts +22 -0
  88. package/dist/src/parrot/index.js +67 -0
  89. package/dist/src/parrot/room.d.ts +225 -0
  90. package/dist/src/parrot/room.js +466 -0
  91. package/dist/src/parrot/routing.d.ts +90 -0
  92. package/dist/src/parrot/routing.js +78 -0
  93. package/dist/src/parrot/share.d.ts +126 -0
  94. package/dist/src/parrot/share.js +261 -0
  95. package/dist/src/parrot/socket.d.ts +41 -0
  96. package/dist/src/parrot/socket.js +478 -0
  97. package/dist/src/payments.d.ts +73 -0
  98. package/dist/src/payments.js +107 -0
  99. package/dist/src/private/cards.css +75 -0
  100. package/dist/src/rooms.d.ts +76 -0
  101. package/dist/src/rooms.js +168 -0
  102. package/dist/src/shared/schema.d.ts +24 -0
  103. package/dist/src/shared/schema.js +1 -0
  104. package/dist/src/shared/server.d.ts +65 -0
  105. package/dist/src/shared/server.js +302 -0
  106. package/dist/src/termite/environment.d.ts +110 -0
  107. package/dist/src/termite/environment.js +263 -0
  108. package/dist/src/termite/index.d.ts +14 -0
  109. package/dist/src/termite/index.js +59 -0
  110. package/dist/src/termite/os.d.ts +326 -0
  111. package/dist/src/termite/os.js +572 -0
  112. package/dist/src/termite/versioning.d.ts +94 -0
  113. package/dist/src/termite/versioning.js +217 -0
  114. package/dist/src/tickets.d.ts +43 -0
  115. package/dist/src/tickets.js +138 -0
  116. package/dist/src/travel.d.ts +85 -0
  117. package/dist/src/travel.js +44 -0
  118. package/dist/src/ui/authentification.d.ts +24 -0
  119. package/dist/src/ui/authentification.js +177 -0
  120. package/dist/src/ui/brands.css +11 -0
  121. package/dist/src/ui/brands.d.ts +7 -0
  122. package/dist/src/ui/brands.js +14 -0
  123. package/dist/src/ui/browser.d.ts +74 -0
  124. package/dist/src/ui/browser.js +470 -0
  125. package/dist/src/ui/chat.d.ts +183 -0
  126. package/dist/src/ui/chat.js +2379 -0
  127. package/dist/src/ui/chatPanel.d.ts +109 -0
  128. package/dist/src/ui/chatPanel.js +768 -0
  129. package/dist/src/ui/chatSequence.d.ts +36 -0
  130. package/dist/src/ui/chatSequence.js +42 -0
  131. package/dist/src/ui/crown.d.ts +19 -0
  132. package/dist/src/ui/crown.js +199 -0
  133. package/dist/src/ui/cursor.d.ts +73 -0
  134. package/dist/src/ui/cursor.js +175 -0
  135. package/dist/src/ui/device.d.ts +33 -0
  136. package/dist/src/ui/device.js +49 -0
  137. package/dist/src/ui/drive.d.ts +69 -0
  138. package/dist/src/ui/drive.js +1243 -0
  139. package/dist/src/ui/generative.d.ts +39 -0
  140. package/dist/src/ui/generative.js +313 -0
  141. package/dist/src/ui/hover.d.ts +6 -0
  142. package/dist/src/ui/hover.js +210 -0
  143. package/dist/src/ui/index.d.ts +42 -0
  144. package/dist/src/ui/index.js +87 -0
  145. package/dist/src/ui/integrations.d.ts +13 -0
  146. package/dist/src/ui/integrations.js +175 -0
  147. package/dist/src/ui/maps.d.ts +87 -0
  148. package/dist/src/ui/maps.js +547 -0
  149. package/dist/src/ui/roster.d.ts +32 -0
  150. package/dist/src/ui/roster.js +163 -0
  151. package/dist/src/ui/talk.d.ts +12 -0
  152. package/dist/src/ui/talk.js +560 -0
  153. package/dist/src/ui/tickets.d.ts +13 -0
  154. package/dist/src/ui/tickets.js +966 -0
  155. package/dist/src/ui/toast.d.ts +7 -0
  156. package/dist/src/ui/toast.js +258 -0
  157. package/dist/src/ui/tokenText.d.ts +18 -0
  158. package/dist/src/ui/tokenText.js +96 -0
  159. package/dist/src/ui/tokenized.d.ts +42 -0
  160. package/dist/src/ui/tokenized.js +622 -0
  161. package/dist/src/ui/ui.css +4763 -0
  162. package/dist/src/ui/view.d.ts +23 -0
  163. package/dist/src/ui/view.js +584 -0
  164. package/dist/src/view.d.ts +113 -0
  165. package/dist/src/view.js +386 -0
  166. package/dist/src/webhooks.d.ts +66 -0
  167. package/dist/src/webhooks.js +78 -0
  168. package/dist/ui.d.ts +1 -0
  169. package/dist/ui.js +1 -0
  170. package/package.json +89 -6
  171. package/README.md +0 -3
@@ -0,0 +1,478 @@
1
+ // The socket transport shared by Parrot's generative and agent functions. Not
2
+ // re-exported: Generative.* and Agent.* are the public surface.
3
+ import { Parrot } from "./index.js";
4
+ import { fromBytes, fromAccessCode, pull } from "../drive.js";
5
+ import { Role } from "./generative.js";
6
+ import WebSocket from "isomorphic-ws";
7
+ /** A Parrot socket URL; `group` adds the Group header (shared memory, group billing). */
8
+ export function socketUrl(path, authorization, group) {
9
+ const wsURL = Parrot.getURL().replace('https://', 'wss://').replace('http://', 'ws://');
10
+ const authParam = encodeURIComponent(JSON.stringify({
11
+ Authorization: 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
12
+ ...(group ? { Group: group.id } : {}),
13
+ }));
14
+ return `${wsURL}${path}?authorization=${authParam}`;
15
+ }
16
+ async function ensureOnline(authorization, file, dest) {
17
+ if (file.online)
18
+ return file;
19
+ const bytes = await file.download();
20
+ const data = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
21
+ const ready = fromBytes(authorization, dest, file.contentType, data);
22
+ await ready.upload();
23
+ return ready;
24
+ }
25
+ function fileRef(file) {
26
+ const authorization = file.authorization;
27
+ if ('accessCode' in authorization) {
28
+ return { type: 'FILE', name: file.name, contentType: file.contentType, accessCode: authorization.accessCode };
29
+ }
30
+ return {
31
+ type: 'FILE',
32
+ name: file.name,
33
+ contentType: file.contentType,
34
+ path: authorization.path,
35
+ ...(authorization.group ? { group: authorization.group } : {}),
36
+ };
37
+ }
38
+ /** FILE parts become path or access code refs (uploading offline files first); no binaries go up. */
39
+ export async function prepareMessages(authorization, messages) {
40
+ for (const part of messages.flatMap((message) => message.parts)) {
41
+ if (part.type === 'FILE' && !part.file.online) {
42
+ part.file = await ensureOnline(authorization, part.file, `tmp/${crypto.randomUUID()}-${part.file.name}`);
43
+ }
44
+ }
45
+ return messages.map((message) => ({
46
+ parts: message.parts.map((part) => part.type === 'FILE' ? fileRef(part.file) : part),
47
+ role: message.role,
48
+ author: message.author,
49
+ }));
50
+ }
51
+ function toBytes(data) {
52
+ if (data instanceof Uint8Array)
53
+ return data;
54
+ if (data instanceof ArrayBuffer)
55
+ return new Uint8Array(data);
56
+ if (ArrayBuffer.isView(data))
57
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
58
+ return new Uint8Array();
59
+ }
60
+ function decodeAudioDelta(delta) {
61
+ if (delta instanceof Uint8Array)
62
+ return delta;
63
+ if (typeof delta === 'string') {
64
+ const binary = atob(delta);
65
+ const bytes = new Uint8Array(binary.length);
66
+ for (let i = 0; i < binary.length; i++)
67
+ bytes[i] = binary.charCodeAt(i);
68
+ return bytes;
69
+ }
70
+ if (Array.isArray(delta))
71
+ return new Uint8Array(delta);
72
+ return toBytes(delta);
73
+ }
74
+ function concatBytes(chunks) {
75
+ let total = 0;
76
+ for (const chunk of chunks)
77
+ total += chunk.length;
78
+ const out = new Uint8Array(total);
79
+ let offset = 0;
80
+ for (const chunk of chunks) {
81
+ out.set(chunk, offset);
82
+ offset += chunk.length;
83
+ }
84
+ return out;
85
+ }
86
+ function isFaunaFile(value) {
87
+ return !!value && typeof value.download === 'function';
88
+ }
89
+ function filePartNeedsBinary(part) {
90
+ return typeof part.fileIndex === 'number' && !part.path && !part.accessCode && !isFaunaFile(part.file);
91
+ }
92
+ async function hydrateFilePart(authorization, part, binaries, fallbackType) {
93
+ if (isFaunaFile(part.file))
94
+ return { type: 'FILE', file: part.file };
95
+ const name = part.name ?? 'file';
96
+ const contentType = part.contentType ?? fallbackType;
97
+ if (part.accessCode) {
98
+ return { type: 'FILE', file: fromAccessCode(authorization, part.accessCode, { name, contentType }) };
99
+ }
100
+ if (typeof part.fileIndex === 'number' && binaries[part.fileIndex]) {
101
+ return { type: 'FILE', file: fromBytes(authorization, name, contentType, binaries[part.fileIndex]) };
102
+ }
103
+ if (part.path) {
104
+ return { type: 'FILE', file: await pull({ authorization, path: part.path, group: part.group }) };
105
+ }
106
+ return { type: 'FILE', file: fromBytes(authorization, name, contentType, new Uint8Array()) };
107
+ }
108
+ async function hydrateContent(authorization, content, binaries, fallbackType) {
109
+ const used = new Set();
110
+ const parts = [];
111
+ for (const part of content.parts) {
112
+ if (part && part.type === 'FILE') {
113
+ const wire = part;
114
+ if (typeof wire.fileIndex === 'number')
115
+ used.add(wire.fileIndex);
116
+ if (isFaunaFile(wire.file)) {
117
+ parts.push({ type: 'FILE', file: wire.file });
118
+ }
119
+ else {
120
+ parts.push(await hydrateFilePart(authorization, wire, binaries, fallbackType));
121
+ }
122
+ }
123
+ else {
124
+ parts.push(part);
125
+ }
126
+ }
127
+ for (let i = 0; i < binaries.length; i++) {
128
+ if (used.has(i))
129
+ continue;
130
+ parts.push({
131
+ type: 'FILE',
132
+ file: fromBytes(authorization, `output-${i}`, fallbackType, binaries[i]),
133
+ });
134
+ }
135
+ return { ...content, parts, role: content.role ?? Role.MODEL, createdAt: new Date(content.createdAt) };
136
+ }
137
+ function responseReady(content, binaries) {
138
+ if (!content?.parts)
139
+ return false;
140
+ return content.parts.every((part) => part?.type !== 'FILE' || !filePartNeedsBinary(part) || binaries[part.fileIndex] !== undefined);
141
+ }
142
+ async function drainSocketToTextResponse(authorization, ws, fallbackType = 'application/octet-stream') {
143
+ const binaries = [];
144
+ let text = '';
145
+ let usage = { promptTokens: 0, completionTokens: 0 };
146
+ let response;
147
+ let error;
148
+ let closed = false;
149
+ let gotDone = false;
150
+ let notify;
151
+ ws.onmessage = (msg) => {
152
+ const data = msg.data;
153
+ if (typeof data !== 'string') {
154
+ binaries.push(toBytes(data));
155
+ notify?.();
156
+ return;
157
+ }
158
+ try {
159
+ const parsed = JSON.parse(data);
160
+ if (parsed.event === 'error') {
161
+ const err = new Error(parsed.message);
162
+ if (parsed.code)
163
+ err.code = parsed.code;
164
+ error = err;
165
+ }
166
+ else if (parsed.event === 'text') {
167
+ text += parsed.delta ?? '';
168
+ }
169
+ else if (parsed.event === 'done') {
170
+ if (parsed.usage)
171
+ usage = parsed.usage;
172
+ gotDone = true;
173
+ }
174
+ else if (parsed.content && parsed.usage) {
175
+ response = parsed;
176
+ }
177
+ }
178
+ catch { }
179
+ notify?.();
180
+ };
181
+ ws.onclose = () => { closed = true; notify?.(); };
182
+ ws.onerror = () => { closed = true; notify?.(); };
183
+ while (!closed && !error) {
184
+ if (response && responseReady(response.content, binaries))
185
+ break;
186
+ if (gotDone && text && binaries.length === 0 && !response)
187
+ break;
188
+ await new Promise((resolve) => { notify = resolve; });
189
+ }
190
+ if (error)
191
+ throw error;
192
+ if (response) {
193
+ return {
194
+ content: await hydrateContent(authorization, response.content, binaries, fallbackType),
195
+ usage: response.usage ?? usage,
196
+ };
197
+ }
198
+ const parts = [];
199
+ if (text)
200
+ parts.push({ type: 'TEXT', text });
201
+ for (let i = 0; i < binaries.length; i++) {
202
+ parts.push({
203
+ type: 'FILE',
204
+ file: fromBytes(authorization, `output-${i}`, fallbackType, binaries[i]),
205
+ });
206
+ }
207
+ return { content: { parts, role: Role.MODEL, createdAt: new Date() }, usage };
208
+ }
209
+ /** One generate frame in, one TextResponse (with any files) out. */
210
+ export async function generateMedia(authorization, path, model, options, fallbackType) {
211
+ const { content, group, ...extra } = options;
212
+ const messages = await prepareMessages(authorization, content ?? []);
213
+ const ws = new WebSocket(socketUrl(path, authorization, group));
214
+ ws.binaryType = 'arraybuffer';
215
+ try {
216
+ await new Promise((resolve, reject) => {
217
+ ws.onopen = () => resolve();
218
+ ws.onerror = () => reject(new Error('WebSocket connection failed'));
219
+ });
220
+ const drained = drainSocketToTextResponse(authorization, ws, fallbackType);
221
+ ws.send(JSON.stringify({ event: 'generate', model, messages, ...extra }));
222
+ ws.send(JSON.stringify({ event: 'start' }));
223
+ return await drained;
224
+ }
225
+ finally {
226
+ try {
227
+ ws.close();
228
+ }
229
+ catch { }
230
+ }
231
+ }
232
+ function replyToolResult(ws, tools, event) {
233
+ if (!tools)
234
+ return;
235
+ const tool = tools.find((t) => t.function.name === event.name);
236
+ if (tool) {
237
+ tool.evaluate(event.args).then((result) => {
238
+ ws.send(JSON.stringify({ event: 'tool_result', id: event.id, result }));
239
+ }).catch((err) => {
240
+ ws.send(JSON.stringify({ event: 'tool_result', id: event.id, result: `Error: ${err.message}` }));
241
+ });
242
+ }
243
+ else {
244
+ ws.send(JSON.stringify({ event: 'tool_result', id: event.id, result: `Error: Tool not found for ${event.name}.` }));
245
+ }
246
+ }
247
+ /** Reads a socket's events in order until done, error, or close. */
248
+ async function* readEvents(ws, push) {
249
+ const queue = [];
250
+ let resolveNext = undefined;
251
+ let done = false;
252
+ ws.onmessage = (msg) => {
253
+ push(msg, queue);
254
+ resolveNext?.();
255
+ };
256
+ ws.onclose = () => {
257
+ done = true;
258
+ resolveNext?.();
259
+ };
260
+ ws.onerror = () => {
261
+ done = true;
262
+ resolveNext?.();
263
+ };
264
+ while (true) {
265
+ if (queue.length > 0) {
266
+ const event = queue.shift();
267
+ yield event;
268
+ if (event.event === 'done' || event.event === 'error')
269
+ break;
270
+ }
271
+ else if (done) {
272
+ break;
273
+ }
274
+ else {
275
+ await new Promise((resolve) => { resolveNext = resolve; });
276
+ }
277
+ }
278
+ }
279
+ /** Streaming text generation on `path`. A singular Tool forces it; an array lets the model choose. */
280
+ export async function* streamText(authorization, path, model, options = {}) {
281
+ const toolDefs = options.tools
282
+ ? (Array.isArray(options.tools) ? options.tools.map((t) => t.function) : options.tools.function)
283
+ : undefined;
284
+ const tools = options.tools
285
+ ? (Array.isArray(options.tools) ? options.tools : [options.tools])
286
+ : undefined;
287
+ const serializedMessages = await prepareMessages(authorization, options.content ?? []);
288
+ const ws = new WebSocket(socketUrl(path, authorization, options.group));
289
+ // Cancellation: closing the socket makes the server stop streaming and ends
290
+ // the read loop (onclose flips `done`). Wired before connecting so an abort
291
+ // during the handshake still tears the socket down.
292
+ const onAbort = () => { try {
293
+ ws.close();
294
+ }
295
+ catch { } };
296
+ if (options.signal) {
297
+ if (options.signal.aborted)
298
+ onAbort();
299
+ else
300
+ options.signal.addEventListener('abort', onAbort);
301
+ }
302
+ try {
303
+ await new Promise((resolve, reject) => {
304
+ ws.onopen = () => resolve();
305
+ ws.onerror = () => reject(new Error('WebSocket connection failed'));
306
+ });
307
+ if (options.signal?.aborted)
308
+ return;
309
+ ws.send(JSON.stringify({
310
+ event: 'generate',
311
+ model,
312
+ messages: serializedMessages,
313
+ tools: toolDefs,
314
+ maxTools: options.maxTools,
315
+ memories: options.memories,
316
+ reasoning: options.reasoning,
317
+ }));
318
+ ws.send(JSON.stringify({ event: 'start' }));
319
+ yield* readEvents(ws, (msg, queue) => {
320
+ try {
321
+ const event = JSON.parse(msg.data);
322
+ // Server-handled tools are forwarded only for rendering: the server
323
+ // already ran them and won't accept a result.
324
+ if (event.event === 'tool_call' && !event.server && tools) {
325
+ replyToolResult(ws, tools, event);
326
+ }
327
+ queue.push(event);
328
+ }
329
+ catch { }
330
+ });
331
+ }
332
+ finally {
333
+ options.signal?.removeEventListener('abort', onAbort);
334
+ try {
335
+ ws.close();
336
+ }
337
+ catch { }
338
+ }
339
+ }
340
+ /** Buffers a text stream into a TextResponse. */
341
+ export async function collectText(stream) {
342
+ let text = '';
343
+ let usage = { promptTokens: 0, completionTokens: 0 };
344
+ for await (const event of stream) {
345
+ if (event.event === 'text') {
346
+ text += event.delta;
347
+ }
348
+ else if (event.event === 'done') {
349
+ usage = event.usage;
350
+ }
351
+ else if (event.event === 'error') {
352
+ const err = new Error(event.message);
353
+ if (event.code)
354
+ err.code = event.code;
355
+ throw err;
356
+ }
357
+ }
358
+ return { content: { parts: [{ type: 'TEXT', text }], role: Role.MODEL, createdAt: new Date() }, usage };
359
+ }
360
+ /** Realtime voice on `path`: PCM16 16 kHz in from `audio`, PCM16 24 kHz out as audio events. */
361
+ export async function* streamVoice(authorization, path, model, options = {}) {
362
+ const toolDefs = options.tools
363
+ ? (Array.isArray(options.tools) ? options.tools.map((t) => t.function) : options.tools.function)
364
+ : undefined;
365
+ const tools = options.tools
366
+ ? (Array.isArray(options.tools) ? options.tools : [options.tools])
367
+ : undefined;
368
+ const serializedMessages = await prepareMessages(authorization, options.content ?? []);
369
+ const ws = new WebSocket(socketUrl(path, authorization, options.group));
370
+ ws.binaryType = 'arraybuffer';
371
+ const onAbort = () => { try {
372
+ ws.close();
373
+ }
374
+ catch { } };
375
+ if (options.signal) {
376
+ if (options.signal.aborted)
377
+ onAbort();
378
+ else
379
+ options.signal.addEventListener('abort', onAbort);
380
+ }
381
+ try {
382
+ await new Promise((resolve, reject) => {
383
+ ws.onopen = () => resolve();
384
+ ws.onerror = () => reject(new Error('WebSocket connection failed'));
385
+ });
386
+ if (options.signal?.aborted)
387
+ return;
388
+ ws.send(JSON.stringify({
389
+ event: 'generate',
390
+ model,
391
+ messages: serializedMessages,
392
+ tools: toolDefs,
393
+ maxTools: options.maxTools,
394
+ voice: options.voice,
395
+ memories: options.memories,
396
+ }));
397
+ ws.send(JSON.stringify({ event: 'start' }));
398
+ if (options.audio) {
399
+ void (async () => {
400
+ try {
401
+ for await (const chunk of options.audio) {
402
+ if (ws.readyState !== WebSocket.OPEN)
403
+ break;
404
+ ws.send(chunk);
405
+ }
406
+ }
407
+ catch { }
408
+ })();
409
+ }
410
+ yield* readEvents(ws, (msg, queue) => {
411
+ const data = msg.data;
412
+ if (typeof data !== 'string') {
413
+ queue.push({ event: 'audio', delta: toBytes(data), contentType: 'audio/pcm' });
414
+ return;
415
+ }
416
+ try {
417
+ const parsed = JSON.parse(data);
418
+ if (parsed.event === 'audio') {
419
+ queue.push({ event: 'audio', delta: decodeAudioDelta(parsed.delta), contentType: 'audio/pcm' });
420
+ }
421
+ else {
422
+ const event = parsed;
423
+ if (event.event === 'tool_call' && !parsed.server && tools) {
424
+ replyToolResult(ws, tools, event);
425
+ }
426
+ queue.push(event);
427
+ }
428
+ }
429
+ catch { }
430
+ });
431
+ }
432
+ finally {
433
+ options.signal?.removeEventListener('abort', onAbort);
434
+ try {
435
+ ws.close();
436
+ }
437
+ catch { }
438
+ }
439
+ }
440
+ /** Buffers a voice stream: the audio as one PCM file, then the input and output transcripts. */
441
+ export async function collectVoice(authorization, stream) {
442
+ const audio = [];
443
+ let inputTranscript = '';
444
+ let outputTranscript = '';
445
+ let usage = { promptTokens: 0, completionTokens: 0 };
446
+ for await (const event of stream) {
447
+ if (event.event === 'audio') {
448
+ audio.push(event.delta);
449
+ }
450
+ else if (event.event === 'input_transcript') {
451
+ inputTranscript += event.delta;
452
+ }
453
+ else if (event.event === 'output_transcript') {
454
+ outputTranscript += event.delta;
455
+ }
456
+ else if (event.event === 'done') {
457
+ usage = event.usage;
458
+ }
459
+ else if (event.event === 'error') {
460
+ const err = new Error(event.message);
461
+ if (event.code)
462
+ err.code = event.code;
463
+ throw err;
464
+ }
465
+ }
466
+ const parts = [];
467
+ if (audio.length > 0) {
468
+ parts.push({
469
+ type: 'FILE',
470
+ file: fromBytes(authorization, 'voice.pcm', 'audio/pcm', concatBytes(audio)),
471
+ });
472
+ }
473
+ if (inputTranscript)
474
+ parts.push({ type: 'TEXT', text: inputTranscript });
475
+ if (outputTranscript)
476
+ parts.push({ type: 'TEXT', text: outputTranscript });
477
+ return { content: { parts, role: Role.MODEL, createdAt: new Date() }, usage };
478
+ }
@@ -0,0 +1,73 @@
1
+ import { ApiKey, Credentials } from "./authentification.js";
2
+ export type PaymentStatus = 'pending' | 'succeeded' | 'expired' | 'refunded' | 'disputed';
3
+ /** A payment to a person through their payout account. Amounts are in dollars. */
4
+ export type Payment = {
5
+ id: string;
6
+ status: PaymentStatus;
7
+ amount: number;
8
+ /** Fauna's fee, taken from what the payee receives. */
9
+ fee: number;
10
+ refunded: number;
11
+ currency: string;
12
+ /** The payee's email. */
13
+ payee: string;
14
+ payer?: string;
15
+ /** Your own label, to find the payment again. */
16
+ reference: string;
17
+ description: string;
18
+ created: Date;
19
+ /** Where the payer pays. Only returned by `create`. */
20
+ url?: string;
21
+ };
22
+ /** What `create` needs. `amount` is in dollars; usd is the only currency for now. */
23
+ export type PaymentRequest = {
24
+ /** Email of the Fauna account that gets paid. */
25
+ payee: string;
26
+ amount: number;
27
+ payer?: string;
28
+ currency?: string;
29
+ description?: string;
30
+ reference?: string;
31
+ /** Where Checkout sends the payer back, with ?payment=paid or ?payment=cancelled. */
32
+ returnUrl?: string;
33
+ cancelUrl?: string;
34
+ };
35
+ /** Whether you can be paid. Payments need `chargesEnabled`. */
36
+ export type Payouts = {
37
+ connected: boolean;
38
+ chargesEnabled: boolean;
39
+ payoutsEnabled: boolean;
40
+ detailsSubmitted: boolean;
41
+ };
42
+ /** What a payment of `amount` costs: Fauna's fee and what the payee receives. */
43
+ export type Quote = {
44
+ amount: number;
45
+ fee: number;
46
+ payout: number;
47
+ };
48
+ /** Start or continue setting up payouts. Open the returned URL; Stripe sends you back with ?payouts=connected. */
49
+ export declare function connect(credentials: Credentials, options?: {
50
+ returnUrl?: string;
51
+ }): Promise<{
52
+ url: string;
53
+ }>;
54
+ export declare function payouts(credentials: Credentials): Promise<Payouts>;
55
+ /** A link into your payouts dashboard: balance, payouts and bank details. */
56
+ export declare function dashboard(credentials: Credentials): Promise<{
57
+ url: string;
58
+ }>;
59
+ export declare function quote(authorization: Credentials | ApiKey, amount: number): Promise<Quote>;
60
+ /**
61
+ * Ask for a payment to `payee`. Send the payer to the returned `url`. With an API
62
+ * key, that key's webhooks hear `payment.succeeded`, `payment.expired`,
63
+ * `payment.refunded` and `payment.disputed`.
64
+ */
65
+ export declare function create(authorization: Credentials | ApiKey, request: PaymentRequest): Promise<Payment>;
66
+ /** A payment you made, paid or are paid by. */
67
+ export declare function get(authorization: Credentials | ApiKey, id: string): Promise<Payment>;
68
+ /** Payments you asked for, newest first, optionally those with one reference. */
69
+ export declare function list(authorization: Credentials | ApiKey, query?: {
70
+ reference?: string;
71
+ }): Promise<Payment[]>;
72
+ /** Refund a completed payment in full, Fauna's fee included. Whoever made it, or its payee, can. */
73
+ export declare function refund(authorization: Credentials | ApiKey, id: string): Promise<Payment>;
@@ -0,0 +1,107 @@
1
+ import { Fauna } from "../index.js";
2
+ function hydrate(raw) {
3
+ return { ...raw, created: new Date(raw.created) };
4
+ }
5
+ /** Start or continue setting up payouts. Open the returned URL; Stripe sends you back with ?payouts=connected. */
6
+ export async function connect(credentials, options = {}) {
7
+ const response = await fetch(`${Fauna.getURL()}/payments/payouts/connect`, {
8
+ method: "POST",
9
+ headers: {
10
+ "Content-Type": "application/json",
11
+ "Authorization": `Token ${credentials.token}`
12
+ },
13
+ body: JSON.stringify({ returnUrl: options.returnUrl })
14
+ });
15
+ if (!response.ok)
16
+ throw new Error(await response.text());
17
+ return await response.json();
18
+ }
19
+ export async function payouts(credentials) {
20
+ const response = await fetch(`${Fauna.getURL()}/payments/payouts`, {
21
+ method: "GET",
22
+ headers: {
23
+ "Authorization": `Token ${credentials.token}`
24
+ }
25
+ });
26
+ if (!response.ok)
27
+ throw new Error(await response.text());
28
+ return await response.json();
29
+ }
30
+ /** A link into your payouts dashboard: balance, payouts and bank details. */
31
+ export async function dashboard(credentials) {
32
+ const response = await fetch(`${Fauna.getURL()}/payments/payouts/dashboard`, {
33
+ method: "POST",
34
+ headers: {
35
+ "Authorization": `Token ${credentials.token}`
36
+ }
37
+ });
38
+ if (!response.ok)
39
+ throw new Error(await response.text());
40
+ return await response.json();
41
+ }
42
+ export async function quote(authorization, amount) {
43
+ const response = await fetch(`${Fauna.getURL()}/payments/quote?amount=${encodeURIComponent(String(amount))}`, {
44
+ method: "GET",
45
+ headers: {
46
+ "Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`
47
+ }
48
+ });
49
+ if (!response.ok)
50
+ throw new Error(await response.text());
51
+ return await response.json();
52
+ }
53
+ /**
54
+ * Ask for a payment to `payee`. Send the payer to the returned `url`. With an API
55
+ * key, that key's webhooks hear `payment.succeeded`, `payment.expired`,
56
+ * `payment.refunded` and `payment.disputed`.
57
+ */
58
+ export async function create(authorization, request) {
59
+ const response = await fetch(`${Fauna.getURL()}/payments`, {
60
+ method: "POST",
61
+ headers: {
62
+ "Content-Type": "application/json",
63
+ "Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`
64
+ },
65
+ body: JSON.stringify(request)
66
+ });
67
+ if (!response.ok)
68
+ throw new Error(await response.text());
69
+ return hydrate(await response.json());
70
+ }
71
+ /** A payment you made, paid or are paid by. */
72
+ export async function get(authorization, id) {
73
+ const response = await fetch(`${Fauna.getURL()}/payments/${encodeURIComponent(id)}`, {
74
+ method: "GET",
75
+ headers: {
76
+ "Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`
77
+ }
78
+ });
79
+ if (!response.ok)
80
+ throw new Error(await response.text());
81
+ return hydrate(await response.json());
82
+ }
83
+ /** Payments you asked for, newest first, optionally those with one reference. */
84
+ export async function list(authorization, query = {}) {
85
+ const search = query.reference !== undefined ? `?reference=${encodeURIComponent(query.reference)}` : '';
86
+ const response = await fetch(`${Fauna.getURL()}/payments${search}`, {
87
+ method: "GET",
88
+ headers: {
89
+ "Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`
90
+ }
91
+ });
92
+ if (!response.ok)
93
+ throw new Error(await response.text());
94
+ return (await response.json()).map(hydrate);
95
+ }
96
+ /** Refund a completed payment in full, Fauna's fee included. Whoever made it, or its payee, can. */
97
+ export async function refund(authorization, id) {
98
+ const response = await fetch(`${Fauna.getURL()}/payments/${encodeURIComponent(id)}/refund`, {
99
+ method: "POST",
100
+ headers: {
101
+ "Authorization": 'email' in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`
102
+ }
103
+ });
104
+ if (!response.ok)
105
+ throw new Error(await response.text());
106
+ return hydrate(await response.json());
107
+ }