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,1025 @@
1
+ import { AntFormat } from "./format.js";
2
+ import { FileNode, GraphEdge, GraphNode, XNode, LinkedInNode, } from "./graph.js";
3
+ import { Ant } from "./index.js";
4
+ export { GraphNode, StartNode, TextNode, WebsiteNode, FileNode, XNode, LinkedInNode, GraphEdge, } from "./graph.js";
5
+ import { Room, connect as connectServer } from "../shared/server.js";
6
+ import { connectRoom } from "../parrot/room.js";
7
+ import { fromAccessCode } from "../drive.js";
8
+ import * as Drive from "../drive.js";
9
+ import IsoWebSocket from "isomorphic-ws";
10
+ async function fileRef(authorization, file) {
11
+ let ready = file;
12
+ if (!ready.online) {
13
+ const dest = `tmp/${crypto.randomUUID()}-${ready.name}`;
14
+ const bytes = await ready.download();
15
+ ready = Drive.fromBytes(authorization, dest, ready.contentType, bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes));
16
+ await ready.upload();
17
+ }
18
+ const authz = ready.authorization;
19
+ if ("accessCode" in authz) {
20
+ return { type: "FILE", name: ready.name, contentType: ready.contentType, accessCode: authz.accessCode };
21
+ }
22
+ return {
23
+ type: "FILE",
24
+ name: ready.name,
25
+ contentType: ready.contentType,
26
+ path: authz.path,
27
+ ...(authz.group ? { group: authz.group } : {}),
28
+ };
29
+ }
30
+ /** Answer a persona's call to one of the caller's tools; one it doesn't have comes back declined. */
31
+ function answerClientTool(ws, tools, call) {
32
+ const tool = tools.find((t) => t.function.name === call.name);
33
+ void Promise.resolve(tool ? tool.evaluate(call.args ?? {}) : JSON.stringify({ declined: true }))
34
+ .catch(() => JSON.stringify({ declined: true }))
35
+ .then((result) => {
36
+ try {
37
+ ws.send(JSON.stringify({ event: "tool_result", id: call.id, result: String(result) }));
38
+ }
39
+ catch { /* closed */ }
40
+ });
41
+ }
42
+ async function serializeMessages(authorization, messages) {
43
+ return Promise.all(messages.map(async (message) => ({
44
+ parts: await Promise.all(message.parts.map(async (part) => part.type === "FILE" ? await fileRef(authorization, part.file) : part)),
45
+ role: message.role,
46
+ })));
47
+ }
48
+ // ─── Catalog ─────────────────────────────────────────────────────────────────
49
+ export async function listTimelines(authorization, opts) {
50
+ const response = await fetch(`${Ant.getURL()}/timelines`, {
51
+ method: "GET",
52
+ headers: {
53
+ Authorization: "email" in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
54
+ ...(opts?.group ? { Group: opts.group.id } : {}),
55
+ },
56
+ });
57
+ if (!response.ok)
58
+ throw new Error(await response.text());
59
+ return await response.json();
60
+ }
61
+ /** Create a timeline. `repository` (the owner's) is the computer its personas start from. */
62
+ export async function createTimeline(authorization, name, opts) {
63
+ const response = await fetch(`${Ant.getURL()}/timelines`, {
64
+ method: "POST",
65
+ headers: {
66
+ "Content-Type": "application/json",
67
+ Authorization: "email" in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
68
+ ...(opts?.group ? { Group: opts.group.id } : {}),
69
+ },
70
+ body: JSON.stringify({
71
+ name,
72
+ ...(opts?.audience?.length ? { audience: opts.audience } : {}),
73
+ ...(opts?.repository ? { repository: opts.repository.id } : {}),
74
+ }),
75
+ });
76
+ if (!response.ok)
77
+ throw new Error(await response.text());
78
+ return await response.json();
79
+ }
80
+ export async function deleteTimeline(authorization, id, opts) {
81
+ const response = await fetch(`${Ant.getURL()}/timeline`, {
82
+ method: "DELETE",
83
+ headers: {
84
+ Authorization: "email" in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
85
+ ...(opts?.group ? { Group: opts.group.id } : {}),
86
+ Timeline: id,
87
+ },
88
+ });
89
+ if (!response.ok)
90
+ throw new Error(await response.text());
91
+ }
92
+ export async function renameTimeline(authorization, id, name, opts) {
93
+ const response = await fetch(`${Ant.getURL()}/timeline/rename`, {
94
+ method: "POST",
95
+ headers: {
96
+ "Content-Type": "application/json",
97
+ Authorization: "email" in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
98
+ ...(opts?.group ? { Group: opts.group.id } : {}),
99
+ Timeline: id,
100
+ },
101
+ body: JSON.stringify({ name }),
102
+ });
103
+ if (!response.ok)
104
+ throw new Error(await response.text());
105
+ }
106
+ export async function getTrust(authorization, timelineId, opts) {
107
+ const response = await fetch(`${Ant.getURL()}/timeline/trust`, {
108
+ method: "GET",
109
+ headers: {
110
+ Authorization: "email" in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
111
+ ...(opts?.accessCode
112
+ ? { "Access-Code": opts.accessCode }
113
+ : { Timeline: timelineId, ...(opts?.group ? { Group: opts.group.id } : {}) }),
114
+ },
115
+ });
116
+ if (!response.ok)
117
+ throw new Error(await response.text());
118
+ return await response.json();
119
+ }
120
+ export class Poll {
121
+ constructor(id, goal, query, results = null) {
122
+ Object.defineProperty(this, "id", {
123
+ enumerable: true,
124
+ configurable: true,
125
+ writable: true,
126
+ value: void 0
127
+ });
128
+ Object.defineProperty(this, "goal", {
129
+ enumerable: true,
130
+ configurable: true,
131
+ writable: true,
132
+ value: void 0
133
+ });
134
+ Object.defineProperty(this, "query", {
135
+ enumerable: true,
136
+ configurable: true,
137
+ writable: true,
138
+ value: void 0
139
+ });
140
+ Object.defineProperty(this, "results", {
141
+ enumerable: true,
142
+ configurable: true,
143
+ writable: true,
144
+ value: void 0
145
+ });
146
+ this.id = id;
147
+ this.goal = goal;
148
+ this.query = query;
149
+ this.results = results;
150
+ }
151
+ static fromJSON(json) {
152
+ const raw = json.query;
153
+ const formats = Array.isArray(raw)
154
+ ? raw.map((q) => (q && typeof q === "object" && "type" in q ? AntFormat.fromJSON(q) : q))
155
+ : raw && typeof raw === "object" && "type" in raw
156
+ ? [AntFormat.fromJSON(raw)]
157
+ : [];
158
+ return new Poll(json.id, json.goal ?? "", formats, json.results ?? null);
159
+ }
160
+ toJSON() {
161
+ return {
162
+ id: this.id,
163
+ goal: this.goal,
164
+ query: this.query.map((f) => f.toJSON()),
165
+ results: this.results,
166
+ };
167
+ }
168
+ }
169
+ export class Run {
170
+ constructor(wire) {
171
+ Object.defineProperty(this, "id", {
172
+ enumerable: true,
173
+ configurable: true,
174
+ writable: true,
175
+ value: void 0
176
+ });
177
+ Object.defineProperty(this, "pollId", {
178
+ enumerable: true,
179
+ configurable: true,
180
+ writable: true,
181
+ value: void 0
182
+ });
183
+ Object.defineProperty(this, "iteration", {
184
+ enumerable: true,
185
+ configurable: true,
186
+ writable: true,
187
+ value: void 0
188
+ });
189
+ Object.defineProperty(this, "status", {
190
+ enumerable: true,
191
+ configurable: true,
192
+ writable: true,
193
+ value: void 0
194
+ });
195
+ Object.defineProperty(this, "trajectories", {
196
+ enumerable: true,
197
+ configurable: true,
198
+ writable: true,
199
+ value: void 0
200
+ });
201
+ Object.defineProperty(this, "polls", {
202
+ enumerable: true,
203
+ configurable: true,
204
+ writable: true,
205
+ value: void 0
206
+ });
207
+ Object.defineProperty(this, "progress", {
208
+ enumerable: true,
209
+ configurable: true,
210
+ writable: true,
211
+ value: void 0
212
+ });
213
+ Object.defineProperty(this, "agentIds", {
214
+ enumerable: true,
215
+ configurable: true,
216
+ writable: true,
217
+ value: void 0
218
+ });
219
+ Object.defineProperty(this, "reach", {
220
+ enumerable: true,
221
+ configurable: true,
222
+ writable: true,
223
+ value: void 0
224
+ });
225
+ Object.defineProperty(this, "startedAt", {
226
+ enumerable: true,
227
+ configurable: true,
228
+ writable: true,
229
+ value: void 0
230
+ });
231
+ Object.defineProperty(this, "finishedAt", {
232
+ enumerable: true,
233
+ configurable: true,
234
+ writable: true,
235
+ value: void 0
236
+ });
237
+ Object.defineProperty(this, "error", {
238
+ enumerable: true,
239
+ configurable: true,
240
+ writable: true,
241
+ value: void 0
242
+ });
243
+ this.id = wire.id;
244
+ this.pollId = wire.pollId;
245
+ this.iteration = wire.iteration ?? 0;
246
+ this.status = normalizeRunStatus(wire.status);
247
+ this.trajectories = Array.isArray(wire.trajectories) ? wire.trajectories : [];
248
+ this.polls = wire.polls ?? undefined;
249
+ this.progress = wire.progress
250
+ ?? (wire.polls && typeof wire.polls === "object" ? wire.polls.progress : undefined)
251
+ ?? undefined;
252
+ this.agentIds = wire.agentIds ?? [];
253
+ this.reach = wire.reach && typeof wire.reach === "object" ? wire.reach : undefined;
254
+ this.startedAt = wire.startedAt ?? 0;
255
+ this.finishedAt = wire.finishedAt;
256
+ this.error = wire.error;
257
+ }
258
+ }
259
+ function normalizeRunStatus(raw) {
260
+ const value = String(raw ?? "").toUpperCase();
261
+ if (value === "QUEUED" || value === "RUNNING" || value === "DONE" || value === "ABORTED" || value === "FAILED") {
262
+ return value;
263
+ }
264
+ if (value === "PENDING" || value === "ABORTING")
265
+ return "RUNNING";
266
+ return "QUEUED";
267
+ }
268
+ export function runIsActive(status) {
269
+ const value = normalizeRunStatus(status);
270
+ return value === "QUEUED" || value === "RUNNING";
271
+ }
272
+ export class Agent {
273
+ constructor(parent, id, persona, repository = null) {
274
+ Object.defineProperty(this, "parent", {
275
+ enumerable: true,
276
+ configurable: true,
277
+ writable: true,
278
+ value: void 0
279
+ });
280
+ Object.defineProperty(this, "id", {
281
+ enumerable: true,
282
+ configurable: true,
283
+ writable: true,
284
+ value: void 0
285
+ });
286
+ Object.defineProperty(this, "persona", {
287
+ enumerable: true,
288
+ configurable: true,
289
+ writable: true,
290
+ value: void 0
291
+ });
292
+ /** A repository picked in this agent's own chat, used directly; null when it follows the timeline's. */
293
+ Object.defineProperty(this, "repository", {
294
+ enumerable: true,
295
+ configurable: true,
296
+ writable: true,
297
+ value: void 0
298
+ });
299
+ this.parent = parent;
300
+ this.id = id;
301
+ this.persona = persona;
302
+ this.repository = repository;
303
+ }
304
+ static fromJSON(json, parent) {
305
+ const repository = typeof json?.repository === "number" && json.repository > 0 ? json.repository : null;
306
+ return new Agent(parent, String(json.id), json.persona ?? {}, repository);
307
+ }
308
+ /** Pick a repository for this agent's chats (used directly), or null to follow the timeline's again. */
309
+ setRepository(repository) {
310
+ this.parent.post({ event: "set-agent-repository", agentId: this.id, repository: repository ? repository.id : null });
311
+ }
312
+ /** Lazily mint/open this agent's Parrot ChatRoom. */
313
+ async getChat(hooks) {
314
+ return this.parent.openChat(this.id, hooks);
315
+ }
316
+ async observe(content) {
317
+ const auth = this.parent.authorization;
318
+ return observeAgent(auth.authorization, this.parent.timelineId, this.id, content, "accessCode" in auth
319
+ ? { accessCode: auth.accessCode }
320
+ : auth.group
321
+ ? { group: { id: auth.group } }
322
+ : undefined);
323
+ }
324
+ /** Stream a reply as this agent, under the room's own authorization. `tools` answer the persona's calls to them. */
325
+ generate(messages, opts) {
326
+ const auth = this.parent.authorization;
327
+ return generateAgent(auth.authorization, this.parent.timelineId, this.id, messages, "accessCode" in auth
328
+ ? { accessCode: auth.accessCode, signal: opts?.signal, tools: opts?.tools }
329
+ : { ...(auth.group ? { group: { id: auth.group } } : {}), signal: opts?.signal, tools: opts?.tools });
330
+ }
331
+ toJSON() {
332
+ return { id: this.id, persona: this.persona };
333
+ }
334
+ }
335
+ // ─── Live room ───────────────────────────────────────────────────────────────
336
+ export class TimelineRoom extends Room {
337
+ constructor(endpoint, ws, authorization, id) {
338
+ super(endpoint, ws, authorization, id);
339
+ /** Client-facing timeline id within the current principal. */
340
+ Object.defineProperty(this, "timelineId", {
341
+ enumerable: true,
342
+ configurable: true,
343
+ writable: true,
344
+ value: void 0
345
+ });
346
+ Object.defineProperty(this, "name", {
347
+ enumerable: true,
348
+ configurable: true,
349
+ writable: true,
350
+ value: void 0
351
+ });
352
+ Object.defineProperty(this, "agents", {
353
+ enumerable: true,
354
+ configurable: true,
355
+ writable: true,
356
+ value: void 0
357
+ });
358
+ Object.defineProperty(this, "polls", {
359
+ enumerable: true,
360
+ configurable: true,
361
+ writable: true,
362
+ value: void 0
363
+ });
364
+ Object.defineProperty(this, "runs", {
365
+ enumerable: true,
366
+ configurable: true,
367
+ writable: true,
368
+ value: void 0
369
+ });
370
+ Object.defineProperty(this, "nodes", {
371
+ enumerable: true,
372
+ configurable: true,
373
+ writable: true,
374
+ value: void 0
375
+ });
376
+ Object.defineProperty(this, "edges", {
377
+ enumerable: true,
378
+ configurable: true,
379
+ writable: true,
380
+ value: void 0
381
+ });
382
+ /** Short-lived Drive codes for file nodes (hydrate + upload + remint). */
383
+ Object.defineProperty(this, "fileAccessCodes", {
384
+ enumerable: true,
385
+ configurable: true,
386
+ writable: true,
387
+ value: void 0
388
+ });
389
+ Object.defineProperty(this, "trustEdges", {
390
+ enumerable: true,
391
+ configurable: true,
392
+ writable: true,
393
+ value: void 0
394
+ });
395
+ Object.defineProperty(this, "status", {
396
+ enumerable: true,
397
+ configurable: true,
398
+ writable: true,
399
+ value: void 0
400
+ });
401
+ /** Set when the timeline is deleted while this room is open. */
402
+ Object.defineProperty(this, "removed", {
403
+ enumerable: true,
404
+ configurable: true,
405
+ writable: true,
406
+ value: void 0
407
+ });
408
+ /** The owner's Termite repository personas start from, by id; null when it has none. */
409
+ Object.defineProperty(this, "repository", {
410
+ enumerable: true,
411
+ configurable: true,
412
+ writable: true,
413
+ value: void 0
414
+ });
415
+ /** Who owns the timeline: `credentials:{id}` or `group:{id}`. */
416
+ Object.defineProperty(this, "owner", {
417
+ enumerable: true,
418
+ configurable: true,
419
+ writable: true,
420
+ value: void 0
421
+ });
422
+ Object.defineProperty(this, "repositoryWatchers", {
423
+ enumerable: true,
424
+ configurable: true,
425
+ writable: true,
426
+ value: new Set()
427
+ });
428
+ this.timelineId = id;
429
+ this.name = "";
430
+ this.repository = null;
431
+ this.owner = "";
432
+ this.agents = new Map();
433
+ this.polls = new Map();
434
+ this.runs = new Map();
435
+ this.nodes = new Map();
436
+ this.edges = new Map();
437
+ this.fileAccessCodes = new Map();
438
+ this.trustEdges = new Map();
439
+ this.status = "IDLE";
440
+ this.removed = false;
441
+ }
442
+ /** The group that owns the timeline, whose repositories it takes; undefined for a person's. */
443
+ get group() {
444
+ const match = /^group:(\d+)$/.exec(this.owner);
445
+ return match ? { id: match[1] } : undefined;
446
+ }
447
+ /** Attach one of the owner's repositories, or null to detach. Personas' chat forks of the old one are deleted. */
448
+ async setRepository(repository) {
449
+ this.post({ event: "set-repository", repository: repository ? repository.id : null });
450
+ }
451
+ /** Hear about every repository change, from anyone in the room. Returns a function that stops listening. */
452
+ watchRepository(listener) {
453
+ this.repositoryWatchers.add(listener);
454
+ return () => { this.repositoryWatchers.delete(listener); };
455
+ }
456
+ applyRepository(raw) {
457
+ const repository = typeof raw === "number" && raw > 0 ? raw : null;
458
+ if (repository === this.repository)
459
+ return;
460
+ this.repository = repository;
461
+ for (const listener of this.repositoryWatchers)
462
+ listener(repository);
463
+ }
464
+ /**
465
+ * The trust graph a run ended with: the timeline's graph as the run started,
466
+ * plus everything it changed. `trustEdges` is the graph every run starts from.
467
+ */
468
+ async runTrust(runId) {
469
+ const auth = this.authorization;
470
+ const response = await fetch(`${Ant.getURL()}/timeline/run?runId=${encodeURIComponent(runId)}`, {
471
+ method: "GET",
472
+ headers: {
473
+ Authorization: "email" in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
474
+ ...("accessCode" in auth
475
+ ? { "Access-Code": auth.accessCode }
476
+ : { Timeline: this.timelineId, ...(auth.group ? { Group: auth.group } : {}) }),
477
+ },
478
+ });
479
+ if (!response.ok)
480
+ throw new Error(await response.text());
481
+ const run = await response.json();
482
+ return (Array.isArray(run?.overlay) ? run.overlay : []).filter((e) => e?.from && e?.to && e.weight > 0);
483
+ }
484
+ hydrate(state) {
485
+ this.timelineId = state?.id ?? this.timelineId;
486
+ this.name = state?.name ?? this.name;
487
+ this.owner = typeof state?.owner === "string" ? state.owner : this.owner;
488
+ this.applyRepository(state?.repository);
489
+ this.status = state?.status ?? "IDLE";
490
+ this.agents.clear();
491
+ for (const a of state?.agents ?? []) {
492
+ this.agents.set(a.id, Agent.fromJSON(a, this));
493
+ }
494
+ this.polls.clear();
495
+ for (const p of state?.polls ?? []) {
496
+ this.polls.set(p.id, Poll.fromJSON(p));
497
+ }
498
+ this.runs.clear();
499
+ for (const r of state?.runs ?? []) {
500
+ this.runs.set(r.id, new Run(r));
501
+ }
502
+ this.nodes.clear();
503
+ for (const n of state?.graph?.nodes ?? []) {
504
+ if (n?.id)
505
+ this.nodes.set(n.id, GraphNode.fromJSON(n));
506
+ }
507
+ this.edges.clear();
508
+ for (const e of state?.graph?.edges ?? []) {
509
+ if (e?.id)
510
+ this.edges.set(e.id, GraphEdge.fromJSON(e));
511
+ }
512
+ this.fileAccessCodes.clear();
513
+ this.trustEdges.clear();
514
+ for (const e of state?.trustEdges ?? []) {
515
+ if (e?.from && e?.to && e.weight > 0) {
516
+ this.trustEdges.set(`${e.from}->${e.to}`, e);
517
+ }
518
+ }
519
+ const codes = state?.fileAccessCodes ?? {};
520
+ for (const [nodeId, meta] of Object.entries(codes)) {
521
+ const m = meta;
522
+ if (m?.code)
523
+ this.fileAccessCodes.set(nodeId, m);
524
+ }
525
+ for (const nodeId of this.fileAccessCodes.keys())
526
+ this.attachDriveFile(nodeId);
527
+ }
528
+ attachDriveFile(nodeId) {
529
+ const meta = this.fileAccessCodes.get(nodeId);
530
+ const node = this.nodes.get(nodeId);
531
+ if (!meta?.code || !node)
532
+ return;
533
+ const file = fromAccessCode(this.authorization.authorization, meta.code, {
534
+ name: meta.name,
535
+ contentType: meta.contentType,
536
+ });
537
+ if (node instanceof FileNode)
538
+ node.file = file;
539
+ if (node instanceof XNode || node instanceof LinkedInNode) {
540
+ if (node.media[0])
541
+ node.media[0] = file;
542
+ else
543
+ node.media = [file];
544
+ }
545
+ }
546
+ handleEvent(packet) {
547
+ switch (packet.event) {
548
+ case "upsert-agent": {
549
+ const a = packet.agent ?? packet.data?.agent ?? packet.data;
550
+ if (a?.id)
551
+ this.agents.set(a.id, Agent.fromJSON(a, this));
552
+ break;
553
+ }
554
+ case "remove-agent": {
555
+ const id = packet.id ?? packet.data?.id;
556
+ if (id)
557
+ this.agents.delete(id);
558
+ break;
559
+ }
560
+ case "upsert-poll": {
561
+ const p = packet.poll ?? packet.data?.poll ?? packet.data;
562
+ if (p?.id)
563
+ this.polls.set(p.id, Poll.fromJSON(p));
564
+ break;
565
+ }
566
+ case "remove-poll": {
567
+ const id = packet.id ?? packet.data?.id;
568
+ if (id)
569
+ this.polls.delete(id);
570
+ break;
571
+ }
572
+ case "upsert-run":
573
+ case "run-status": {
574
+ const r = packet.run ?? packet.data?.run ?? packet.data;
575
+ if (r?.id)
576
+ this.runs.set(r.id, new Run(r));
577
+ break;
578
+ }
579
+ case "remove-run": {
580
+ const id = packet.id ?? packet.data?.id;
581
+ if (id)
582
+ this.runs.delete(id);
583
+ break;
584
+ }
585
+ case "status": {
586
+ this.status = packet.status ?? packet.data?.status ?? this.status;
587
+ break;
588
+ }
589
+ case "update-timeline": {
590
+ const timeline = packet.timeline ?? packet.data?.timeline;
591
+ if (timeline?.name)
592
+ this.name = timeline.name;
593
+ if (timeline && "repository" in timeline)
594
+ this.applyRepository(timeline.repository);
595
+ break;
596
+ }
597
+ case "timeline-removed": {
598
+ this.removed = true;
599
+ break;
600
+ }
601
+ case "upsert-graph-node": {
602
+ const n = packet.node ?? packet.data?.node ?? packet.data;
603
+ const accessCode = (packet.accessCode ?? packet.data?.accessCode);
604
+ if (n?.id) {
605
+ const prev = this.nodes.get(n.id);
606
+ const incoming = GraphNode.fromJSON(n);
607
+ if (prev instanceof FileNode && incoming instanceof FileNode) {
608
+ incoming.file = incoming.file ?? prev.file;
609
+ incoming.wirePath = incoming.wirePath || prev.wirePath;
610
+ }
611
+ if ((prev instanceof XNode || prev instanceof LinkedInNode)
612
+ && (incoming instanceof XNode || incoming instanceof LinkedInNode)) {
613
+ if (!incoming.media.length && prev.media.length)
614
+ incoming.media = prev.media;
615
+ }
616
+ this.nodes.set(n.id, incoming);
617
+ }
618
+ if (accessCode?.code && n?.id) {
619
+ this.fileAccessCodes.set(n.id, accessCode);
620
+ this.attachDriveFile(n.id);
621
+ break;
622
+ }
623
+ const node = n?.id ? this.nodes.get(n.id) : undefined;
624
+ const needsFile = node instanceof FileNode
625
+ || ((node instanceof XNode || node instanceof LinkedInNode) && (node.wirePath || node.media[0]));
626
+ if (needsFile && node && !this.fileAccessCodes.has(node.id)) {
627
+ return this.remintFileAccessCode(node.id).then(() => undefined);
628
+ }
629
+ break;
630
+ }
631
+ case "remove-graph-node": {
632
+ const id = packet.id ?? packet.data?.id;
633
+ if (id) {
634
+ this.nodes.delete(id);
635
+ this.fileAccessCodes.delete(id);
636
+ for (const [eid, edge] of [...this.edges]) {
637
+ if (edge.fromNodeId === id || edge.toNodeId === id)
638
+ this.edges.delete(eid);
639
+ }
640
+ }
641
+ break;
642
+ }
643
+ case "upsert-graph-edge": {
644
+ const e = packet.edge ?? packet.data?.edge ?? packet.data;
645
+ if (e?.id)
646
+ this.edges.set(e.id, GraphEdge.fromJSON(e));
647
+ break;
648
+ }
649
+ case "remove-graph-edge": {
650
+ const id = packet.id ?? packet.data?.id;
651
+ if (id)
652
+ this.edges.delete(id);
653
+ break;
654
+ }
655
+ case "upsert-trust-edge": {
656
+ const e = packet.edge ?? packet.data?.edge ?? packet.data;
657
+ if (e?.from && e?.to && e.weight > 0)
658
+ this.trustEdges.set(`${e.from}->${e.to}`, e);
659
+ break;
660
+ }
661
+ case "remove-trust-edge": {
662
+ const from = packet.from ?? packet.data?.from;
663
+ const to = packet.to ?? packet.data?.to;
664
+ if (from && to)
665
+ this.trustEdges.delete(`${from}->${to}`);
666
+ break;
667
+ }
668
+ }
669
+ }
670
+ upsertGraphNode(node) {
671
+ const prev = this.nodes.get(node.id);
672
+ const next = node instanceof GraphNode ? node.clone() : GraphNode.fromJSON(node);
673
+ if (prev instanceof FileNode && next instanceof FileNode) {
674
+ next.file = next.file ?? prev.file;
675
+ next.wirePath = next.wirePath || prev.wirePath;
676
+ }
677
+ this.nodes.set(next.id, next);
678
+ this.post({ event: "upsert-graph-node", node: next.toJSON() });
679
+ return next;
680
+ }
681
+ removeGraphNode(id) {
682
+ if (id === "start")
683
+ return;
684
+ this.nodes.delete(id);
685
+ this.fileAccessCodes.delete(id);
686
+ for (const [eid, edge] of [...this.edges]) {
687
+ if (edge.fromNodeId === id || edge.toNodeId === id)
688
+ this.edges.delete(eid);
689
+ }
690
+ this.post({ event: "remove-graph-node", id });
691
+ }
692
+ upsertGraphEdge(edge) {
693
+ const next = edge instanceof GraphEdge ? edge : GraphEdge.fromJSON(edge);
694
+ this.edges.set(next.id, next);
695
+ this.post({ event: "upsert-graph-edge", edge: next.toJSON() });
696
+ return next;
697
+ }
698
+ removeGraphEdge(id) {
699
+ this.edges.delete(id);
700
+ this.post({ event: "remove-graph-edge", id });
701
+ }
702
+ /** Upload bytes to the host drive and create/update a durable file node. */
703
+ async uploadFileNode(file, opts) {
704
+ const contentType = opts.contentType || "application/octet-stream";
705
+ const body = file instanceof Blob
706
+ ? file
707
+ : file instanceof ArrayBuffer
708
+ ? new Uint8Array(file)
709
+ : file;
710
+ const auth = this.authorization;
711
+ const response = await fetch(`${Ant.getURL()}/timeline/graph/file`, {
712
+ method: "POST",
713
+ headers: {
714
+ Authorization: "email" in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
715
+ ...("accessCode" in auth
716
+ ? { "Access-Code": auth.accessCode }
717
+ : { Timeline: this.timelineId, ...(auth.group ? { Group: auth.group } : {}) }),
718
+ "Content-Type": contentType,
719
+ Filename: opts.name,
720
+ X: String(opts.x),
721
+ Y: String(opts.y),
722
+ ...(opts.nodeId ? { "Node-Id": opts.nodeId } : {}),
723
+ ...(opts.kind ? { Kind: opts.kind } : {}),
724
+ },
725
+ body: body,
726
+ });
727
+ if (!response.ok)
728
+ throw new Error(await response.text());
729
+ const json = await response.json();
730
+ const fileHandle = fromAccessCode(this.authorization.authorization, json.accessCode.code, {
731
+ name: json.accessCode.name,
732
+ contentType: json.accessCode.contentType,
733
+ });
734
+ const node = GraphNode.fromJSON(json.node, fileHandle);
735
+ this.nodes.set(node.id, node);
736
+ this.fileAccessCodes.set(node.id, json.accessCode);
737
+ return { node, accessCode: json.accessCode };
738
+ }
739
+ async remintFileAccessCode(nodeId) {
740
+ const auth = this.authorization;
741
+ const response = await fetch(`${Ant.getURL()}/timeline/graph/file/access-code`, {
742
+ method: "POST",
743
+ headers: {
744
+ "Content-Type": "application/json",
745
+ Authorization: "email" in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
746
+ ...("accessCode" in auth
747
+ ? { "Access-Code": auth.accessCode }
748
+ : { Timeline: this.timelineId, ...(auth.group ? { Group: auth.group } : {}) }),
749
+ },
750
+ body: JSON.stringify({ nodeId }),
751
+ });
752
+ if (!response.ok)
753
+ throw new Error(await response.text());
754
+ const meta = await response.json();
755
+ this.fileAccessCodes.set(nodeId, meta);
756
+ this.attachDriveFile(nodeId);
757
+ return meta;
758
+ }
759
+ /** Build a Drive.File handle for a graph file node (remints if needed). */
760
+ async fileForNode(nodeId) {
761
+ let meta = this.fileAccessCodes.get(nodeId);
762
+ if (!meta?.code)
763
+ meta = await this.remintFileAccessCode(nodeId);
764
+ return fromAccessCode(this.authorization.authorization, meta.code, {
765
+ name: meta.name,
766
+ contentType: meta.contentType,
767
+ });
768
+ }
769
+ /** Remint if needed and return the short-lived Drive access code for a file node.
770
+ * Viewer URL opening stays in the app layer (avoids importing Fauna into ant/). */
771
+ async openGraphFile(nodeId) {
772
+ let meta = this.fileAccessCodes.get(nodeId);
773
+ if (!meta?.code)
774
+ meta = await this.remintFileAccessCode(nodeId);
775
+ return meta;
776
+ }
777
+ upsertAgent(identity) {
778
+ const preferred = String(identity?.id ?? "").trim();
779
+ let id = preferred && !this.agents.has(preferred) ? preferred : "";
780
+ if (!id) {
781
+ let n = 0;
782
+ while (this.agents.has(String(n)))
783
+ n++;
784
+ id = String(n);
785
+ }
786
+ const agent = new Agent(this, id, identity);
787
+ this.agents.set(agent.id, agent);
788
+ this.post({ event: "upsert-agent", agent: agent.toJSON() });
789
+ return agent;
790
+ }
791
+ removeAgent(id) {
792
+ this.agents.delete(id);
793
+ this.post({ event: "remove-agent", id });
794
+ }
795
+ upsertPoll(goal, query) {
796
+ let id = 0;
797
+ while (this.polls.has(String(id)))
798
+ id++;
799
+ const poll = new Poll(String(id), goal, query);
800
+ this.polls.set(poll.id, poll);
801
+ this.post({ event: "upsert-poll", poll: poll.toJSON() });
802
+ return poll;
803
+ }
804
+ removePoll(id) {
805
+ this.polls.delete(id);
806
+ this.post({ event: "remove-poll", id });
807
+ }
808
+ /** Create the poll and queue its run in one request. Resolves the run id;
809
+ * the run itself arrives through the room's `upsert-run` delta. */
810
+ async startRun(goal, query) {
811
+ const auth = this.authorization;
812
+ const response = await fetch(`${Ant.getURL()}/timeline/run`, {
813
+ method: "POST",
814
+ headers: {
815
+ "Content-Type": "application/json",
816
+ Authorization: "email" in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
817
+ ...("accessCode" in auth
818
+ ? { "Access-Code": auth.accessCode }
819
+ : { Timeline: this.timelineId, ...(auth.group ? { Group: auth.group } : {}) }),
820
+ },
821
+ body: JSON.stringify({ goal, query: query.map((f) => f.toJSON()) }),
822
+ });
823
+ if (!response.ok)
824
+ throw new Error(await response.text());
825
+ const { runId } = await response.json();
826
+ return runId;
827
+ }
828
+ async abortRun(runId) {
829
+ const auth = this.authorization;
830
+ const response = await fetch(`${Ant.getURL()}/timeline/run/abort`, {
831
+ method: "POST",
832
+ headers: {
833
+ "Content-Type": "application/json",
834
+ Authorization: "email" in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
835
+ ...("accessCode" in auth
836
+ ? { "Access-Code": auth.accessCode }
837
+ : { Timeline: this.timelineId, ...(auth.group ? { Group: auth.group } : {}) }),
838
+ },
839
+ body: JSON.stringify({ runId }),
840
+ });
841
+ if (!response.ok)
842
+ throw new Error(await response.text());
843
+ }
844
+ /** Lazily mint/open the architect Parrot ChatRoom. */
845
+ async getChat(hooks) {
846
+ return this.openChat("", hooks);
847
+ }
848
+ /**
849
+ * Ensure a Parrot chat (architect when `agentId` is empty) and connect live.
850
+ * Timeline members join by reference (non-guest); access-code guests use the
851
+ * short-lived code so leave/reap semantics stay correct.
852
+ */
853
+ async openChat(agentId, hooks) {
854
+ const auth = this.authorization;
855
+ const response = await fetch(`${Ant.getURL()}/timeline/chat/ensure`, {
856
+ method: "POST",
857
+ headers: {
858
+ "Content-Type": "application/json",
859
+ Authorization: "email" in auth.authorization ? `Token ${auth.authorization.token}` : `ApiKey ${auth.authorization.id}`,
860
+ ...("accessCode" in auth
861
+ ? { "Access-Code": auth.accessCode }
862
+ : { Timeline: this.timelineId, ...(auth.group ? { Group: auth.group } : {}) }),
863
+ },
864
+ body: JSON.stringify({ agentId: agentId || "" }),
865
+ });
866
+ if (!response.ok)
867
+ throw new Error(await response.text());
868
+ const { chatId, reference, code } = await response.json();
869
+ if (!chatId || !code)
870
+ throw new Error("Invalid ensure response.");
871
+ const guest = "accessCode" in this.authorization;
872
+ const target = guest
873
+ ? { code }
874
+ : { reference: reference || `parrot:chat:${chatId}` };
875
+ const { room, self } = await connectRoom(this.authorization.authorization, target, hooks ?? {});
876
+ return { room, self, chatId };
877
+ }
878
+ /**
879
+ * Connect to an owned timeline.
880
+ * Principal is resolved server-side from auth (+ optional Group).
881
+ * `Server` carries only the timeline id for own/group; grant joins may
882
+ * pass a full `principalId:timelineId` via opts.server when needed.
883
+ */
884
+ static async connect(authorization, target, opts) {
885
+ const server = opts?.server ?? target.id;
886
+ let room;
887
+ const user = opts?.hooks ?? {};
888
+ const self = await connectServer({ authorization, server, ...(opts?.group ? { group: opts.group.id } : {}) }, `${Ant.getURL()}/timeline`, {
889
+ ...user,
890
+ createRoom: (endpoint, ws, a, id, state) => {
891
+ room = (user.createRoom?.(endpoint, ws, a, id, state)
892
+ ?? new TimelineRoom(endpoint, ws, a, id));
893
+ return room;
894
+ },
895
+ onConnection: (r, state) => {
896
+ r.hydrate(state);
897
+ user.onConnection?.(r, state);
898
+ },
899
+ onEvent: (r, packet) => applyTimelineEvent(r, packet, user),
900
+ });
901
+ return { room, self };
902
+ }
903
+ static async join(authorization, target, hooks) {
904
+ let room;
905
+ const user = hooks ?? {};
906
+ const self = await connectServer({ authorization, accessCode: target.accessCode }, `${Ant.getURL()}/timeline`, {
907
+ ...user,
908
+ createRoom: (endpoint, ws, a, id, state) => {
909
+ room = (user.createRoom?.(endpoint, ws, a, id, state)
910
+ ?? new TimelineRoom(endpoint, ws, a, id));
911
+ return room;
912
+ },
913
+ onConnection: (r, state) => {
914
+ r.hydrate(state);
915
+ user.onConnection?.(r, state);
916
+ },
917
+ onEvent: (r, packet) => applyTimelineEvent(r, packet, user),
918
+ });
919
+ return { room, self };
920
+ }
921
+ }
922
+ /** Apply a domain frame; if handleEvent remints a file code, notify again after. */
923
+ function applyTimelineEvent(room, packet, user) {
924
+ const handled = room.handleEvent(packet);
925
+ const notify = () => user.onEvent?.(room, packet) ?? true;
926
+ if (handled && typeof handled.then === "function") {
927
+ notify();
928
+ void handled.then(notify);
929
+ return true;
930
+ }
931
+ return notify();
932
+ }
933
+ /** Write a standalone fact onto this agent's Parrot graph (`ant/timelines/…/memory`). */
934
+ export async function observeAgent(authorization, timelineId, agentId, content, opts) {
935
+ const response = await fetch(`${Ant.getURL()}/timeline/agent/observe`, {
936
+ method: "POST",
937
+ headers: {
938
+ "Content-Type": "application/json",
939
+ Authorization: "email" in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
940
+ ...(opts?.accessCode
941
+ ? { "Access-Code": opts.accessCode }
942
+ : { Timeline: timelineId, ...(opts?.group ? { Group: opts.group.id } : {}) }),
943
+ },
944
+ body: JSON.stringify({ agentId, content }),
945
+ });
946
+ if (!response.ok)
947
+ throw new Error(await response.text());
948
+ return await response.json();
949
+ }
950
+ /**
951
+ * Stream a persona reply for one agent (Gemini Flash + medium thinking + memories).
952
+ * Parrot-compatible StreamEvents for UI.Chat generate mode, plus `tool` and
953
+ * `tool-result` events for the persona's own tools. `tools` are answered here
954
+ * when the persona calls them, like `use_desktop` asking for a computer.
955
+ */
956
+ export async function* generateAgent(authorization, timelineId, agentId, messages, opts) {
957
+ const wsURL = Ant.getURL().replace("https://", "wss://").replace("http://", "ws://");
958
+ const authHeaders = {
959
+ Authorization: "email" in authorization ? `Token ${authorization.token}` : `ApiKey ${authorization.id}`,
960
+ ...(opts?.accessCode
961
+ ? { "Access-Code": opts.accessCode }
962
+ : { Timeline: timelineId, ...(opts?.group ? { Group: opts.group.id } : {}) }),
963
+ };
964
+ const ws = new IsoWebSocket(`${wsURL}/timeline/agent/generate?authorization=${encodeURIComponent(JSON.stringify(authHeaders))}`);
965
+ const onAbort = () => { try {
966
+ ws.close();
967
+ }
968
+ catch { /* noop */ } };
969
+ if (opts?.signal) {
970
+ if (opts.signal.aborted)
971
+ onAbort();
972
+ else
973
+ opts.signal.addEventListener("abort", onAbort);
974
+ }
975
+ try {
976
+ await new Promise((resolve, reject) => {
977
+ ws.onopen = () => resolve();
978
+ ws.onerror = () => reject(new Error("WebSocket connection failed"));
979
+ });
980
+ if (opts?.signal?.aborted)
981
+ return;
982
+ const serializedMessages = await serializeMessages(authorization, messages);
983
+ const clientTools = opts?.tools ?? [];
984
+ ws.send(JSON.stringify({ event: "generate", agentId, messages: serializedMessages, tools: clientTools.map((t) => t.function) }));
985
+ ws.send(JSON.stringify({ event: "start" }));
986
+ const eventQueue = [];
987
+ let resolveNext;
988
+ let done = false;
989
+ ws.onmessage = (msg) => {
990
+ try {
991
+ const event = JSON.parse(String(msg.data));
992
+ if (event?.event === "tool_call") {
993
+ answerClientTool(ws, clientTools, event);
994
+ return;
995
+ }
996
+ eventQueue.push(event);
997
+ resolveNext?.();
998
+ }
999
+ catch { /* ignore */ }
1000
+ };
1001
+ ws.onclose = () => { done = true; resolveNext?.(); };
1002
+ ws.onerror = () => { done = true; resolveNext?.(); };
1003
+ while (true) {
1004
+ if (eventQueue.length > 0) {
1005
+ const event = eventQueue.shift();
1006
+ yield event;
1007
+ if (event.event === "done" || event.event === "error")
1008
+ break;
1009
+ }
1010
+ else if (done) {
1011
+ break;
1012
+ }
1013
+ else {
1014
+ await new Promise((resolve) => { resolveNext = resolve; });
1015
+ }
1016
+ }
1017
+ }
1018
+ finally {
1019
+ opts?.signal?.removeEventListener("abort", onAbort);
1020
+ try {
1021
+ ws.close();
1022
+ }
1023
+ catch { /* noop */ }
1024
+ }
1025
+ }