@moxt-ai/mobius-sdk 0.0.3

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 (74) hide show
  1. package/README.md +31 -0
  2. package/dist/bot-owner-resources.d.ts +274 -0
  3. package/dist/bot-owner-resources.d.ts.map +1 -0
  4. package/dist/bot-owner-resources.js +748 -0
  5. package/dist/bot-owner-resources.js.map +1 -0
  6. package/dist/bot-resources.d.ts +152 -0
  7. package/dist/bot-resources.d.ts.map +1 -0
  8. package/dist/bot-resources.js +469 -0
  9. package/dist/bot-resources.js.map +1 -0
  10. package/dist/bot-service-client.d.ts +204 -0
  11. package/dist/bot-service-client.d.ts.map +1 -0
  12. package/dist/bot-service-client.js +587 -0
  13. package/dist/bot-service-client.js.map +1 -0
  14. package/dist/browser.d.ts +166 -0
  15. package/dist/browser.d.ts.map +1 -0
  16. package/dist/browser.js +379 -0
  17. package/dist/browser.js.map +1 -0
  18. package/dist/channel.d.ts +3 -0
  19. package/dist/channel.d.ts.map +1 -0
  20. package/dist/channel.js +3 -0
  21. package/dist/channel.js.map +1 -0
  22. package/dist/client.d.ts +116 -0
  23. package/dist/client.d.ts.map +1 -0
  24. package/dist/client.js +624 -0
  25. package/dist/client.js.map +1 -0
  26. package/dist/errors.d.ts +24 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +47 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/examples/browser.d.ts +13 -0
  31. package/dist/examples/browser.d.ts.map +1 -0
  32. package/dist/examples/browser.js +23 -0
  33. package/dist/examples/browser.js.map +1 -0
  34. package/dist/examples/moxt-server.d.ts +38 -0
  35. package/dist/examples/moxt-server.d.ts.map +1 -0
  36. package/dist/examples/moxt-server.js +81 -0
  37. package/dist/examples/moxt-server.js.map +1 -0
  38. package/dist/examples/node.d.ts +2 -0
  39. package/dist/examples/node.d.ts.map +1 -0
  40. package/dist/examples/node.js +20 -0
  41. package/dist/examples/node.js.map +1 -0
  42. package/dist/examples/platform-server.d.ts +2 -0
  43. package/dist/examples/platform-server.d.ts.map +1 -0
  44. package/dist/examples/platform-server.js +39 -0
  45. package/dist/examples/platform-server.js.map +1 -0
  46. package/dist/examples/workflow.d.ts +20 -0
  47. package/dist/examples/workflow.d.ts.map +1 -0
  48. package/dist/examples/workflow.js +76 -0
  49. package/dist/examples/workflow.js.map +1 -0
  50. package/dist/index.d.ts +10 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +9 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/platform.d.ts +184 -0
  55. package/dist/platform.d.ts.map +1 -0
  56. package/dist/platform.js +434 -0
  57. package/dist/platform.js.map +1 -0
  58. package/dist/project-authentication.d.ts +239 -0
  59. package/dist/project-authentication.d.ts.map +1 -0
  60. package/dist/project-authentication.js +752 -0
  61. package/dist/project-authentication.js.map +1 -0
  62. package/dist/resources.d.ts +602 -0
  63. package/dist/resources.d.ts.map +1 -0
  64. package/dist/resources.js +1411 -0
  65. package/dist/resources.js.map +1 -0
  66. package/dist/server.d.ts +7 -0
  67. package/dist/server.d.ts.map +1 -0
  68. package/dist/server.js +7 -0
  69. package/dist/server.js.map +1 -0
  70. package/dist/service-client.d.ts +392 -0
  71. package/dist/service-client.d.ts.map +1 -0
  72. package/dist/service-client.js +1061 -0
  73. package/dist/service-client.js.map +1 -0
  74. package/package.json +92 -0
package/dist/client.js ADDED
@@ -0,0 +1,624 @@
1
+ import { AGENT_ACTIVITY_KIND, AGENT_CONTENT_KIND, AGENT_INSTALL_CANCEL_KIND, AGENT_INSTALL_CANCELLED_KIND, AGENT_INSTALL_COMPLETED_KIND, AGENT_INSTALL_FAILED_KIND, AGENT_INSTALL_PROGRESS_KIND, AGENT_INSTALL_REQUEST_KIND, AGENT_INSTALL_STARTED_KIND, AGENT_MESSAGE_DELTA_KIND, decodeAgentActivityEvent, decodeAgentContentEvent, decodeAgentInstallCancelCommand, decodeAgentInstallCancelledEvent, decodeAgentInstallCompletedEvent, decodeAgentInstallFailedEvent, decodeAgentInstallProgressEvent, decodeAgentInstallRequestCommand, decodeAgentInstallStartedEvent, decodeAgentMessageDeltaEvent, decodeCommittedSessionEvent, decodeMessageKind, decodeNativeSessionCancel, decodeNativeSessionCommand, decodeNativeSessionResult, decodeNativeSessionTurnForkRequest, decodeRecordedSessionEvent, decodeRuntimeStatusEvent, decodeSessionCancelCommand, decodeSessionCommandsUpdatedEvent, decodeSessionCompletedEvent, decodeSessionConfigUpdatedEvent, decodeSessionConfigureCommand, decodeSessionElicitationRequestedEvent, decodeSessionElicitationResolvedEvent, decodeSessionElicitationRespondCommand, decodeSessionFailedEvent, decodeSessionInfoUpdatedEvent, decodeSessionOperationFailedEvent, decodeSessionPermissionRequestedEvent, decodeSessionPermissionResolvedEvent, decodeSessionPermissionRespondCommand, decodeSessionPrepareCommand, decodeSessionPromptCommand, decodeSessionReadyEvent, decodeSessionStartedEvent, decodeSessionUsageUpdatedEvent, decodeWorkspaceEntriesEvent, decodeWorkspaceListCommand, encodeAgentInstallCancelCommand, encodeAgentInstallRequestCommand, encodeNativeSessionCancel, encodeNativeSessionCommand, encodeNativeSessionTurnForkRequest, encodeSessionCancelCommand, encodeSessionConfigureCommand, encodeSessionElicitationRespondCommand, encodeSessionPermissionRespondCommand, encodeSessionPrepareCommand, encodeSessionPromptCommand, encodeWorkspaceListCommand, NATIVE_SESSION_CANCEL_KIND, NATIVE_SESSION_REQUEST_KIND, NATIVE_SESSION_RESULT_KIND, NATIVE_SESSION_TURN_FORK_REQUEST_KIND, RUNTIME_STATUS_KIND, SESSION_CANCEL_KIND, SESSION_COMMANDS_UPDATED_KIND, SESSION_COMPLETED_KIND, SESSION_CONFIG_UPDATED_KIND, SESSION_CONFIGURE_KIND, SESSION_ELICITATION_REQUESTED_KIND, SESSION_ELICITATION_RESOLVED_KIND, SESSION_ELICITATION_RESPOND_KIND, SESSION_EVENT_COMMITTED_KIND, SESSION_FAILED_KIND, SESSION_INFO_UPDATED_KIND, SESSION_OPERATION_FAILED_KIND, SESSION_PERMISSION_REQUESTED_KIND, SESSION_PERMISSION_RESOLVED_KIND, SESSION_PERMISSION_RESPOND_KIND, SESSION_PREPARE_KIND, SESSION_PROMPT_KIND, SESSION_READY_KIND, SESSION_STARTED_KIND, SESSION_USAGE_UPDATED_KIND, SessionPromptDisposition, WORKSPACE_ENTRIES_KIND, WORKSPACE_LIST_KIND, } from "@moxt-ai/mobius-protocol";
2
+ import ReconnectingWebSocket, {} from "partysocket/ws";
3
+ const CONNECTION_TIMEOUT_MILLISECONDS = 15_000;
4
+ const MAX_RECONNECTION_DELAY_MILLISECONDS = 10_000;
5
+ const MIN_RECONNECTION_DELAY_MILLISECONDS = 500;
6
+ const OPERATION_TIMEOUT_MILLISECONDS = 120_000;
7
+ const INSTALLATION_TIMEOUT_MILLISECONDS = 11 * 60 * 1_000;
8
+ const TERMINAL_RELAY_CLOSE_CODES = new Set([1002, 1003, 1007, 1008, 4003, 4008]);
9
+ export class MobiusClientError extends Error {
10
+ code;
11
+ constructor(code, message, options = {}) {
12
+ super(message, options);
13
+ this.code = code;
14
+ this.name = "MobiusClientError";
15
+ }
16
+ }
17
+ function readMessageText(event) {
18
+ if (typeof event.data !== "string") {
19
+ throw new MobiusClientError("invalid_protocol_message", "Relay sent a non-text WebSocket message");
20
+ }
21
+ return event.data;
22
+ }
23
+ function readInboundMessage(event) {
24
+ const encoded = readMessageText(event);
25
+ if (decodeMessageKind(encoded) !== SESSION_EVENT_COMMITTED_KIND) {
26
+ return encoded;
27
+ }
28
+ const committed = decodeCommittedSessionEvent(encoded);
29
+ decodeRecordedSessionEvent(committed.payload);
30
+ return committed.payload;
31
+ }
32
+ function readInboundCommittedSequence(event) {
33
+ const encoded = readMessageText(event);
34
+ if (decodeMessageKind(encoded) !== SESSION_EVENT_COMMITTED_KIND) {
35
+ throw new MobiusClientError("invalid_protocol_message", "Relay sent an uncommitted Session event");
36
+ }
37
+ return decodeCommittedSessionEvent(encoded).sequence;
38
+ }
39
+ function encodeOutboundMessage(encode) {
40
+ try {
41
+ return encode();
42
+ }
43
+ catch (error) {
44
+ throw new MobiusClientError("invalid_request", "The requested operation contains invalid data", {
45
+ cause: error,
46
+ });
47
+ }
48
+ }
49
+ function sendImmediately(socket, message) {
50
+ if (!socket.send(message)) {
51
+ throw new MobiusClientError("connection_closed", "Relay connection closed before the message was sent");
52
+ }
53
+ }
54
+ function shouldReconnectAfterClose(event) {
55
+ return !TERMINAL_RELAY_CLOSE_CODES.has(event.code);
56
+ }
57
+ function waitForOpen(socket) {
58
+ if (socket.readyState === WebSocket.OPEN) {
59
+ return Promise.resolve();
60
+ }
61
+ return new Promise((resolve, reject) => {
62
+ const timeout = window.setTimeout(() => {
63
+ cleanup();
64
+ reject(new MobiusClientError("connection_timeout", "Timed out while connecting to the relay"));
65
+ }, CONNECTION_TIMEOUT_MILLISECONDS);
66
+ const cleanup = () => {
67
+ window.clearTimeout(timeout);
68
+ socket.removeEventListener("close", handleClose);
69
+ socket.removeEventListener("open", handleOpen);
70
+ };
71
+ const handleClose = (event) => {
72
+ if (shouldReconnectAfterClose(event)) {
73
+ return;
74
+ }
75
+ cleanup();
76
+ reject(new MobiusClientError("connection_rejected", "The relay rejected the WebSocket connection"));
77
+ };
78
+ const handleOpen = () => {
79
+ cleanup();
80
+ resolve();
81
+ };
82
+ socket.addEventListener("close", handleClose);
83
+ socket.addEventListener("open", handleOpen);
84
+ });
85
+ }
86
+ export class MobiusClient {
87
+ #onActivity;
88
+ #onProtocolError;
89
+ #onStatus;
90
+ #options;
91
+ #socket;
92
+ constructor(socket, options) {
93
+ this.#options = options;
94
+ this.#onActivity = options.onActivity ?? (() => undefined);
95
+ this.#onProtocolError = options.onProtocolError ?? (() => undefined);
96
+ this.#onStatus = options.onStatus ?? (() => undefined);
97
+ this.#socket = socket;
98
+ this.#socket.addEventListener("message", this.#handleChannelMessage);
99
+ this.#socket.addEventListener("close", this.#handleClose);
100
+ }
101
+ ready = async () => {
102
+ await waitForOpen(this.#socket);
103
+ };
104
+ listWorkspace = async (request, signal) => {
105
+ const requestId = request.requestId ?? crypto.randomUUID();
106
+ return await this.#requestReply(requestId, encodeOutboundMessage(() => encodeWorkspaceListCommand({
107
+ bindingId: request.bindingId,
108
+ directoryId: request.directoryId,
109
+ kind: WORKSPACE_LIST_KIND,
110
+ requestId,
111
+ })), WORKSPACE_ENTRIES_KIND, decodeWorkspaceEntriesEvent, (event) => event.requestId, signal);
112
+ };
113
+ prepareSession = async (request, signal) => {
114
+ const requestId = request.requestId ?? crypto.randomUUID();
115
+ return await this.#requestReply(requestId, encodeOutboundMessage(() => encodeSessionPrepareCommand({
116
+ additionalDirectoryIds: request.additionalDirectoryIds,
117
+ agentId: request.agentId,
118
+ bindingId: request.bindingId,
119
+ directoryId: request.directoryId,
120
+ kind: SESSION_PREPARE_KIND,
121
+ requestId,
122
+ sessionId: request.sessionId,
123
+ })), SESSION_READY_KIND, decodeSessionReadyEvent, (event) => event.requestId, signal);
124
+ };
125
+ manageNativeSession = async (command, signal) => {
126
+ signal.throwIfAborted();
127
+ return await this.#requestReply(command.requestId, encodeOutboundMessage(() => encodeNativeSessionCommand(command)), NATIVE_SESSION_RESULT_KIND, decodeNativeSessionResult, (event) => event.requestId, signal, () => {
128
+ try {
129
+ if (this.#socket.readyState === WebSocket.OPEN) {
130
+ sendImmediately(this.#socket, encodeNativeSessionCancel({
131
+ kind: NATIVE_SESSION_CANCEL_KIND,
132
+ requestId: command.requestId,
133
+ sessionId: command.sessionId,
134
+ }));
135
+ }
136
+ }
137
+ catch {
138
+ // The local runtime also cancels requests when the connection closes.
139
+ }
140
+ });
141
+ };
142
+ forkSessionTurn = async (command, signal) => {
143
+ signal.throwIfAborted();
144
+ return await this.#requestReply(command.requestId, encodeOutboundMessage(() => encodeNativeSessionTurnForkRequest(command)), NATIVE_SESSION_RESULT_KIND, decodeNativeSessionResult, (event) => event.requestId, signal, () => {
145
+ try {
146
+ if (this.#socket.readyState === WebSocket.OPEN) {
147
+ sendImmediately(this.#socket, encodeNativeSessionCancel({
148
+ kind: NATIVE_SESSION_CANCEL_KIND,
149
+ requestId: command.requestId,
150
+ sessionId: command.sessionId,
151
+ }));
152
+ }
153
+ }
154
+ catch {
155
+ // The local runtime also cancels requests when the connection closes.
156
+ }
157
+ });
158
+ };
159
+ configureSession = async (request, signal) => {
160
+ const requestId = request.requestId ?? crypto.randomUUID();
161
+ return await this.#requestReply(requestId, encodeOutboundMessage(() => encodeSessionConfigureCommand({
162
+ additionalDirectoryIds: request.additionalDirectoryIds,
163
+ agentId: request.agentId,
164
+ bindingId: request.bindingId,
165
+ booleanValue: request.booleanValue,
166
+ configId: request.configId,
167
+ directoryId: request.directoryId,
168
+ kind: SESSION_CONFIGURE_KIND,
169
+ requestId,
170
+ sessionId: request.sessionId,
171
+ value: request.value,
172
+ valueType: request.valueType,
173
+ })), SESSION_CONFIG_UPDATED_KIND, decodeSessionConfigUpdatedEvent, (event) => event.requestId, signal);
174
+ };
175
+ respondPermission = async (request) => await this.#requestReply(request.interactionId, encodeOutboundMessage(() => encodeSessionPermissionRespondCommand({
176
+ interactionId: request.interactionId,
177
+ kind: SESSION_PERMISSION_RESPOND_KIND,
178
+ optionId: request.optionId,
179
+ outcome: request.outcome,
180
+ sessionId: request.sessionId,
181
+ })), SESSION_PERMISSION_RESOLVED_KIND, decodeSessionPermissionResolvedEvent, (event) => event.interactionId);
182
+ respondElicitation = async (request) => await this.#requestReply(request.interactionId, encodeOutboundMessage(() => encodeSessionElicitationRespondCommand({
183
+ action: request.action,
184
+ content: request.content,
185
+ interactionId: request.interactionId,
186
+ kind: SESSION_ELICITATION_RESPOND_KIND,
187
+ sessionId: request.sessionId,
188
+ })), SESSION_ELICITATION_RESOLVED_KIND, decodeSessionElicitationResolvedEvent, (event) => event.interactionId);
189
+ cancel = (request) => {
190
+ if (this.#socket.readyState !== WebSocket.OPEN) {
191
+ throw new MobiusClientError("runtime_offline", "The relay connection is not open");
192
+ }
193
+ try {
194
+ sendImmediately(this.#socket, encodeOutboundMessage(() => encodeSessionCancelCommand({
195
+ commandId: request.commandId,
196
+ kind: SESSION_CANCEL_KIND,
197
+ sessionId: request.sessionId,
198
+ })));
199
+ }
200
+ catch (error) {
201
+ throw new MobiusClientError("connection_closed", "Could not send cancellation to the relay", {
202
+ cause: error,
203
+ });
204
+ }
205
+ };
206
+ cancelAgentInstallation = (request) => {
207
+ if (this.#socket.readyState !== WebSocket.OPEN) {
208
+ throw new MobiusClientError("runtime_offline", "The relay connection is not open");
209
+ }
210
+ try {
211
+ sendImmediately(this.#socket, encodeOutboundMessage(() => encodeAgentInstallCancelCommand({
212
+ kind: AGENT_INSTALL_CANCEL_KIND,
213
+ requestId: request.requestId,
214
+ })));
215
+ }
216
+ catch (error) {
217
+ throw new MobiusClientError("connection_closed", "Could not send Agent installation cancellation to the relay", { cause: error });
218
+ }
219
+ };
220
+ installAgent = async (request) => {
221
+ if (this.#socket.readyState !== WebSocket.OPEN) {
222
+ throw new MobiusClientError("runtime_offline", "The relay connection is not open");
223
+ }
224
+ const requestId = request.requestId ?? crypto.randomUUID();
225
+ let cleanupInstallation = () => undefined;
226
+ const result = new Promise((resolveInstallation, rejectInstallation) => {
227
+ const timeout = window.setTimeout(() => {
228
+ cleanup();
229
+ rejectInstallation(new MobiusClientError("installation_timeout", "Timed out while waiting for the local Agent installation"));
230
+ }, INSTALLATION_TIMEOUT_MILLISECONDS);
231
+ const cleanup = () => {
232
+ window.clearTimeout(timeout);
233
+ this.#socket.removeEventListener("message", handleMessage);
234
+ this.#socket.removeEventListener("close", handleClose);
235
+ };
236
+ cleanupInstallation = cleanup;
237
+ const handleClose = () => {
238
+ cleanup();
239
+ rejectInstallation(new MobiusClientError("connection_closed", "Relay connection closed while Agent installation was running"));
240
+ };
241
+ const handleMessage = (message) => {
242
+ try {
243
+ const encoded = readInboundMessage(message);
244
+ const kind = decodeMessageKind(encoded);
245
+ if (kind === AGENT_INSTALL_COMPLETED_KIND) {
246
+ const completed = decodeAgentInstallCompletedEvent(encoded);
247
+ if (completed.requestId === requestId) {
248
+ cleanup();
249
+ resolveInstallation(completed);
250
+ }
251
+ return;
252
+ }
253
+ if (kind === AGENT_INSTALL_FAILED_KIND) {
254
+ const failed = decodeAgentInstallFailedEvent(encoded);
255
+ if (failed.requestId === requestId) {
256
+ cleanup();
257
+ rejectInstallation(new MobiusClientError(failed.code, failed.message));
258
+ }
259
+ return;
260
+ }
261
+ if (kind === AGENT_INSTALL_CANCELLED_KIND) {
262
+ const cancelled = decodeAgentInstallCancelledEvent(encoded);
263
+ if (cancelled.requestId === requestId) {
264
+ cleanup();
265
+ rejectInstallation(new MobiusClientError("installation_cancelled", "The local Agent installation was cancelled"));
266
+ }
267
+ return;
268
+ }
269
+ if (kind === SESSION_OPERATION_FAILED_KIND) {
270
+ const failed = decodeSessionOperationFailedEvent(encoded);
271
+ if (failed.requestId === requestId) {
272
+ cleanup();
273
+ rejectInstallation(new MobiusClientError(failed.code, failed.message));
274
+ }
275
+ }
276
+ }
277
+ catch (error) {
278
+ cleanup();
279
+ rejectInstallation(new MobiusClientError("invalid_protocol_message", "Received an invalid Agent installation message", { cause: error }));
280
+ }
281
+ };
282
+ this.#socket.addEventListener("message", handleMessage);
283
+ this.#socket.addEventListener("close", handleClose, { once: true });
284
+ });
285
+ try {
286
+ sendImmediately(this.#socket, encodeOutboundMessage(() => encodeAgentInstallRequestCommand({
287
+ agentId: request.agentId,
288
+ kind: AGENT_INSTALL_REQUEST_KIND,
289
+ requestId,
290
+ })));
291
+ }
292
+ catch (error) {
293
+ cleanupInstallation();
294
+ throw new MobiusClientError("connection_closed", "Could not send the Agent installation request to the relay", { cause: error });
295
+ }
296
+ return await result;
297
+ };
298
+ prompt = async (request) => {
299
+ if (this.#socket.readyState !== WebSocket.OPEN) {
300
+ throw new MobiusClientError("runtime_offline", "The relay connection is not open");
301
+ }
302
+ const commandId = request.commandId ?? crypto.randomUUID();
303
+ const sessionId = request.sessionId ?? crypto.randomUUID();
304
+ const outbound = encodeOutboundMessage(() => encodeSessionPromptCommand({
305
+ additionalDirectoryIds: request.additionalDirectoryIds ?? [],
306
+ agentId: request.agentId,
307
+ bindingId: request.bindingId,
308
+ commandId,
309
+ directoryId: request.directoryId ?? "default",
310
+ disposition: request.disposition ?? SessionPromptDisposition.Reject,
311
+ images: request.images ?? [],
312
+ kind: SESSION_PROMPT_KIND,
313
+ prompt: request.prompt,
314
+ resources: request.resources ?? [],
315
+ sessionId,
316
+ targetCommandId: request.targetCommandId ?? "",
317
+ }));
318
+ let cleanupPrompt = () => undefined;
319
+ const result = new Promise((resolve, reject) => {
320
+ const cleanup = () => {
321
+ this.#socket.removeEventListener("message", handleMessage);
322
+ this.#socket.removeEventListener("close", handleSocketClose);
323
+ };
324
+ cleanupPrompt = cleanup;
325
+ const handleSocketClose = () => {
326
+ cleanup();
327
+ reject(new MobiusClientError("connection_closed", "Relay connection closed while the request was running"));
328
+ };
329
+ const handleMessage = (event) => {
330
+ try {
331
+ const encoded = readInboundMessage(event);
332
+ const kind = decodeMessageKind(encoded);
333
+ if (kind === SESSION_STARTED_KIND) {
334
+ const message = decodeSessionStartedEvent(encoded);
335
+ if (message.commandId === commandId) {
336
+ request.observer?.onStarted?.(message.attemptId);
337
+ }
338
+ return;
339
+ }
340
+ if (kind === AGENT_MESSAGE_DELTA_KIND) {
341
+ const message = decodeAgentMessageDeltaEvent(encoded);
342
+ if (message.commandId === commandId) {
343
+ request.observer?.onDelta?.(message.text, readInboundCommittedSequence(event));
344
+ }
345
+ return;
346
+ }
347
+ if (kind === AGENT_ACTIVITY_KIND) {
348
+ const message = decodeAgentActivityEvent(encoded);
349
+ if (message.commandId === commandId) {
350
+ request.observer?.onActivity?.(message);
351
+ }
352
+ return;
353
+ }
354
+ if (kind === AGENT_CONTENT_KIND) {
355
+ const message = decodeAgentContentEvent(encoded);
356
+ if (message.commandId === commandId) {
357
+ request.observer?.onContent?.(message);
358
+ }
359
+ return;
360
+ }
361
+ if (kind === SESSION_COMPLETED_KIND) {
362
+ const message = decodeSessionCompletedEvent(encoded);
363
+ if (message.commandId === commandId) {
364
+ cleanup();
365
+ resolve({
366
+ sessionId: message.sessionId,
367
+ stopReason: message.stopReason,
368
+ });
369
+ }
370
+ return;
371
+ }
372
+ if (kind === SESSION_FAILED_KIND) {
373
+ const message = decodeSessionFailedEvent(encoded);
374
+ if (message.commandId === commandId) {
375
+ cleanup();
376
+ reject(new MobiusClientError(message.code, message.message));
377
+ }
378
+ }
379
+ }
380
+ catch (error) {
381
+ cleanup();
382
+ reject(new MobiusClientError("invalid_protocol_message", "Received an invalid message from the relay", { cause: error }));
383
+ }
384
+ };
385
+ this.#socket.addEventListener("message", handleMessage);
386
+ this.#socket.addEventListener("close", handleSocketClose, { once: true });
387
+ });
388
+ try {
389
+ sendImmediately(this.#socket, outbound);
390
+ }
391
+ catch (error) {
392
+ cleanupPrompt();
393
+ throw new MobiusClientError("connection_closed", "Could not send the request to the relay", {
394
+ cause: error,
395
+ });
396
+ }
397
+ return result;
398
+ };
399
+ #requestReply = async (requestId, outbound, expectedKind, decode, identify, signal, cancel) => {
400
+ signal?.throwIfAborted();
401
+ if (this.#socket.readyState !== WebSocket.OPEN) {
402
+ throw new MobiusClientError("runtime_offline", "The relay connection is not open");
403
+ }
404
+ let cleanupRequest = () => undefined;
405
+ const result = new Promise((resolve, reject) => {
406
+ const timeout = window.setTimeout(() => {
407
+ cleanup();
408
+ cancel?.();
409
+ reject(new MobiusClientError("operation_timeout", "Timed out while waiting for the local runtime"));
410
+ }, OPERATION_TIMEOUT_MILLISECONDS);
411
+ const cleanup = () => {
412
+ window.clearTimeout(timeout);
413
+ this.#socket.removeEventListener("message", handleMessage);
414
+ this.#socket.removeEventListener("close", handleClose);
415
+ signal?.removeEventListener("abort", handleAbort);
416
+ };
417
+ const handleAbort = () => {
418
+ cleanup();
419
+ cancel?.();
420
+ reject(signal?.reason ??
421
+ new MobiusClientError("operation_cancelled", "Native session operation cancelled"));
422
+ };
423
+ cleanupRequest = cleanup;
424
+ const handleClose = () => {
425
+ cleanup();
426
+ reject(new MobiusClientError("connection_closed", "Relay connection closed while the operation was running"));
427
+ };
428
+ const handleMessage = (message) => {
429
+ try {
430
+ const encoded = readInboundMessage(message);
431
+ const kind = decodeMessageKind(encoded);
432
+ if (kind === SESSION_OPERATION_FAILED_KIND) {
433
+ const failure = decodeSessionOperationFailedEvent(encoded);
434
+ if (failure.requestId === requestId) {
435
+ cleanup();
436
+ reject(new MobiusClientError(failure.code, failure.message));
437
+ }
438
+ return;
439
+ }
440
+ if (kind !== expectedKind) {
441
+ return;
442
+ }
443
+ const event = decode(encoded);
444
+ if (identify(event) === requestId) {
445
+ cleanup();
446
+ resolve(event);
447
+ }
448
+ }
449
+ catch (error) {
450
+ cleanup();
451
+ reject(new MobiusClientError("invalid_protocol_message", "Received an invalid message from the relay", { cause: error }));
452
+ }
453
+ };
454
+ this.#socket.addEventListener("message", handleMessage);
455
+ this.#socket.addEventListener("close", handleClose, { once: true });
456
+ signal?.addEventListener("abort", handleAbort, { once: true });
457
+ });
458
+ try {
459
+ sendImmediately(this.#socket, outbound);
460
+ }
461
+ catch (error) {
462
+ cleanupRequest();
463
+ throw new MobiusClientError("connection_closed", "Could not send the operation to the relay", {
464
+ cause: error,
465
+ });
466
+ }
467
+ return await result;
468
+ };
469
+ close = () => {
470
+ this.#socket.removeEventListener("message", this.#handleChannelMessage);
471
+ this.#socket.removeEventListener("close", this.#handleClose);
472
+ this.#socket.close(1000, "Host closed");
473
+ };
474
+ #handleClose = (event) => {
475
+ if (shouldReconnectAfterClose(event)) {
476
+ this.#options.onReconnecting?.();
477
+ return;
478
+ }
479
+ this.#options.onUnavailable?.();
480
+ };
481
+ #handleChannelMessage = (event) => {
482
+ try {
483
+ const encoded = readInboundMessage(event);
484
+ const kind = decodeMessageKind(encoded);
485
+ if (kind === RUNTIME_STATUS_KIND) {
486
+ this.#onStatus(decodeRuntimeStatusEvent(encoded).online);
487
+ return;
488
+ }
489
+ if (kind === SESSION_PROMPT_KIND) {
490
+ decodeSessionPromptCommand(encoded);
491
+ }
492
+ else if (kind === NATIVE_SESSION_REQUEST_KIND) {
493
+ decodeNativeSessionCommand(encoded);
494
+ }
495
+ else if (kind === NATIVE_SESSION_TURN_FORK_REQUEST_KIND) {
496
+ decodeNativeSessionTurnForkRequest(encoded);
497
+ }
498
+ else if (kind === NATIVE_SESSION_CANCEL_KIND) {
499
+ decodeNativeSessionCancel(encoded);
500
+ }
501
+ else if (kind === NATIVE_SESSION_RESULT_KIND) {
502
+ this.#options.onNativeSessionResult?.(decodeNativeSessionResult(encoded));
503
+ }
504
+ else if (kind === SESSION_CANCEL_KIND) {
505
+ decodeSessionCancelCommand(encoded);
506
+ }
507
+ else if (kind === WORKSPACE_LIST_KIND) {
508
+ decodeWorkspaceListCommand(encoded);
509
+ }
510
+ else if (kind === WORKSPACE_ENTRIES_KIND) {
511
+ this.#options.onWorkspace?.(decodeWorkspaceEntriesEvent(encoded));
512
+ }
513
+ else if (kind === SESSION_PREPARE_KIND) {
514
+ decodeSessionPrepareCommand(encoded);
515
+ }
516
+ else if (kind === SESSION_READY_KIND) {
517
+ this.#options.onReady?.(decodeSessionReadyEvent(encoded));
518
+ }
519
+ else if (kind === SESSION_CONFIGURE_KIND) {
520
+ decodeSessionConfigureCommand(encoded);
521
+ }
522
+ else if (kind === SESSION_CONFIG_UPDATED_KIND) {
523
+ this.#options.onConfig?.(decodeSessionConfigUpdatedEvent(encoded));
524
+ }
525
+ else if (kind === SESSION_COMMANDS_UPDATED_KIND) {
526
+ this.#options.onCommands?.(decodeSessionCommandsUpdatedEvent(encoded));
527
+ }
528
+ else if (kind === SESSION_INFO_UPDATED_KIND) {
529
+ this.#options.onInfo?.(decodeSessionInfoUpdatedEvent(encoded));
530
+ }
531
+ else if (kind === SESSION_USAGE_UPDATED_KIND) {
532
+ this.#options.onUsage?.(decodeSessionUsageUpdatedEvent(encoded));
533
+ }
534
+ else if (kind === SESSION_PERMISSION_REQUESTED_KIND) {
535
+ this.#options.onPermission?.(decodeSessionPermissionRequestedEvent(encoded));
536
+ }
537
+ else if (kind === SESSION_PERMISSION_RESPOND_KIND) {
538
+ decodeSessionPermissionRespondCommand(encoded);
539
+ }
540
+ else if (kind === SESSION_PERMISSION_RESOLVED_KIND) {
541
+ this.#options.onPermissionResolved?.(decodeSessionPermissionResolvedEvent(encoded));
542
+ }
543
+ else if (kind === SESSION_ELICITATION_REQUESTED_KIND) {
544
+ this.#options.onElicitation?.(decodeSessionElicitationRequestedEvent(encoded));
545
+ }
546
+ else if (kind === SESSION_ELICITATION_RESPOND_KIND) {
547
+ decodeSessionElicitationRespondCommand(encoded);
548
+ }
549
+ else if (kind === SESSION_ELICITATION_RESOLVED_KIND) {
550
+ this.#options.onElicitationResolved?.(decodeSessionElicitationResolvedEvent(encoded));
551
+ }
552
+ else if (kind === SESSION_STARTED_KIND) {
553
+ decodeSessionStartedEvent(encoded);
554
+ }
555
+ else if (kind === AGENT_MESSAGE_DELTA_KIND) {
556
+ decodeAgentMessageDeltaEvent(encoded);
557
+ }
558
+ else if (kind === AGENT_ACTIVITY_KIND) {
559
+ decodeAgentActivityEvent(encoded);
560
+ }
561
+ else if (kind === AGENT_CONTENT_KIND) {
562
+ this.#options.onContent?.(decodeAgentContentEvent(encoded));
563
+ }
564
+ else if (kind === AGENT_INSTALL_REQUEST_KIND) {
565
+ decodeAgentInstallRequestCommand(encoded);
566
+ }
567
+ else if (kind === AGENT_INSTALL_CANCEL_KIND) {
568
+ decodeAgentInstallCancelCommand(encoded);
569
+ }
570
+ else if (kind === AGENT_INSTALL_STARTED_KIND) {
571
+ this.#options.onInstallStarted?.(decodeAgentInstallStartedEvent(encoded));
572
+ }
573
+ else if (kind === AGENT_INSTALL_PROGRESS_KIND) {
574
+ this.#options.onInstallProgress?.(decodeAgentInstallProgressEvent(encoded));
575
+ }
576
+ else if (kind === AGENT_INSTALL_COMPLETED_KIND) {
577
+ this.#options.onInstallCompleted?.(decodeAgentInstallCompletedEvent(encoded));
578
+ }
579
+ else if (kind === AGENT_INSTALL_FAILED_KIND) {
580
+ this.#options.onInstallFailed?.(decodeAgentInstallFailedEvent(encoded));
581
+ }
582
+ else if (kind === AGENT_INSTALL_CANCELLED_KIND) {
583
+ this.#options.onInstallCancelled?.(decodeAgentInstallCancelledEvent(encoded));
584
+ }
585
+ else if (kind === SESSION_COMPLETED_KIND) {
586
+ decodeSessionCompletedEvent(encoded);
587
+ }
588
+ else if (kind === SESSION_FAILED_KIND) {
589
+ decodeSessionFailedEvent(encoded);
590
+ }
591
+ else if (kind === SESSION_OPERATION_FAILED_KIND) {
592
+ decodeSessionOperationFailedEvent(encoded);
593
+ }
594
+ else {
595
+ throw new MobiusClientError("invalid_protocol_message", "Relay sent an unsupported message kind");
596
+ }
597
+ this.#onActivity();
598
+ }
599
+ catch (error) {
600
+ this.#onProtocolError(new MobiusClientError("invalid_protocol_message", "Received an invalid message from the relay", {
601
+ cause: error,
602
+ }));
603
+ }
604
+ };
605
+ }
606
+ export async function connectMobiusClient(options) {
607
+ const socket = new ReconnectingWebSocket(options.relayUrl, [], {
608
+ connectionTimeout: CONNECTION_TIMEOUT_MILLISECONDS,
609
+ maxEnqueuedMessages: 0,
610
+ maxReconnectionDelay: MAX_RECONNECTION_DELAY_MILLISECONDS,
611
+ minReconnectionDelay: MIN_RECONNECTION_DELAY_MILLISECONDS * (1 + Math.random()),
612
+ shouldReconnectOnClose: shouldReconnectAfterClose,
613
+ });
614
+ const client = new MobiusClient(socket, options);
615
+ try {
616
+ await client.ready();
617
+ return client;
618
+ }
619
+ catch (error) {
620
+ client.close();
621
+ throw error;
622
+ }
623
+ }
624
+ //# sourceMappingURL=client.js.map