@multi-agent-protocol/sdk 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/testing.cjs CHANGED
@@ -2034,6 +2034,211 @@ var TestServer = class {
2034
2034
  }
2035
2035
  };
2036
2036
 
2037
+ // src/stream/index.ts
2038
+ function websocketStream(ws) {
2039
+ const messageQueue = [];
2040
+ let messageResolver = null;
2041
+ let closed = false;
2042
+ let closeError = null;
2043
+ ws.addEventListener("message", (event) => {
2044
+ try {
2045
+ const message = JSON.parse(event.data);
2046
+ if (messageResolver) {
2047
+ messageResolver({ value: message, done: false });
2048
+ messageResolver = null;
2049
+ } else {
2050
+ messageQueue.push(message);
2051
+ }
2052
+ } catch {
2053
+ console.error("MAP: Failed to parse WebSocket message:", event.data);
2054
+ }
2055
+ });
2056
+ ws.addEventListener("close", () => {
2057
+ closed = true;
2058
+ if (messageResolver) {
2059
+ messageResolver({ value: void 0, done: true });
2060
+ messageResolver = null;
2061
+ }
2062
+ });
2063
+ ws.addEventListener("error", () => {
2064
+ closeError = new Error("WebSocket error");
2065
+ closed = true;
2066
+ if (messageResolver) {
2067
+ messageResolver({ value: void 0, done: true });
2068
+ messageResolver = null;
2069
+ }
2070
+ });
2071
+ const readable = new ReadableStream({
2072
+ async pull(controller) {
2073
+ if (messageQueue.length > 0) {
2074
+ controller.enqueue(messageQueue.shift());
2075
+ return;
2076
+ }
2077
+ if (closed) {
2078
+ if (closeError) {
2079
+ controller.error(closeError);
2080
+ } else {
2081
+ controller.close();
2082
+ }
2083
+ return;
2084
+ }
2085
+ await new Promise((resolve) => {
2086
+ messageResolver = resolve;
2087
+ }).then((result) => {
2088
+ if (result.done) {
2089
+ controller.close();
2090
+ } else {
2091
+ controller.enqueue(result.value);
2092
+ }
2093
+ });
2094
+ }
2095
+ });
2096
+ const writable = new WritableStream({
2097
+ async write(message) {
2098
+ if (ws.readyState === WebSocket.CONNECTING) {
2099
+ await new Promise((resolve, reject) => {
2100
+ const onOpen = () => {
2101
+ ws.removeEventListener("error", onError);
2102
+ resolve();
2103
+ };
2104
+ const onError = () => {
2105
+ ws.removeEventListener("open", onOpen);
2106
+ reject(new Error("WebSocket failed to connect"));
2107
+ };
2108
+ ws.addEventListener("open", onOpen, { once: true });
2109
+ ws.addEventListener("error", onError, { once: true });
2110
+ });
2111
+ }
2112
+ if (ws.readyState !== WebSocket.OPEN) {
2113
+ throw new Error("WebSocket is not open");
2114
+ }
2115
+ ws.send(JSON.stringify(message));
2116
+ },
2117
+ close() {
2118
+ ws.close();
2119
+ },
2120
+ abort() {
2121
+ ws.close();
2122
+ }
2123
+ });
2124
+ return { readable, writable };
2125
+ }
2126
+ function waitForOpen(ws, timeoutMs = 1e4) {
2127
+ return new Promise((resolve, reject) => {
2128
+ if (ws.readyState === WebSocket.OPEN) {
2129
+ resolve();
2130
+ return;
2131
+ }
2132
+ const timeout = setTimeout(() => {
2133
+ ws.close();
2134
+ reject(new Error(`WebSocket connection timeout after ${timeoutMs}ms`));
2135
+ }, timeoutMs);
2136
+ const onOpen = () => {
2137
+ clearTimeout(timeout);
2138
+ ws.removeEventListener("error", onError);
2139
+ resolve();
2140
+ };
2141
+ const onError = () => {
2142
+ clearTimeout(timeout);
2143
+ ws.removeEventListener("open", onOpen);
2144
+ reject(new Error("WebSocket connection failed"));
2145
+ };
2146
+ ws.addEventListener("open", onOpen, { once: true });
2147
+ ws.addEventListener("error", onError, { once: true });
2148
+ });
2149
+ }
2150
+ function createStreamPair() {
2151
+ const clientToServer = [];
2152
+ const serverToClient = [];
2153
+ let clientToServerResolver = null;
2154
+ let serverToClientResolver = null;
2155
+ let clientToServerClosed = false;
2156
+ let serverToClientClosed = false;
2157
+ function createReadable(queue, _getResolver, setResolver, isClosed) {
2158
+ return new ReadableStream({
2159
+ async pull(controller) {
2160
+ if (queue.length > 0) {
2161
+ controller.enqueue(queue.shift());
2162
+ return;
2163
+ }
2164
+ if (isClosed()) {
2165
+ controller.close();
2166
+ return;
2167
+ }
2168
+ const message = await new Promise((resolve) => {
2169
+ setResolver((msg) => {
2170
+ setResolver(null);
2171
+ resolve(msg);
2172
+ });
2173
+ });
2174
+ if (message === null) {
2175
+ controller.close();
2176
+ } else {
2177
+ controller.enqueue(message);
2178
+ }
2179
+ }
2180
+ });
2181
+ }
2182
+ function createWritable(queue, getResolver, setClosed) {
2183
+ return new WritableStream({
2184
+ write(message) {
2185
+ const resolver = getResolver();
2186
+ if (resolver) {
2187
+ resolver(message);
2188
+ } else {
2189
+ queue.push(message);
2190
+ }
2191
+ },
2192
+ close() {
2193
+ setClosed();
2194
+ const resolver = getResolver();
2195
+ if (resolver) {
2196
+ resolver(null);
2197
+ }
2198
+ }
2199
+ });
2200
+ }
2201
+ const clientStream = {
2202
+ // Client writes to server
2203
+ writable: createWritable(
2204
+ clientToServer,
2205
+ () => clientToServerResolver,
2206
+ () => {
2207
+ clientToServerClosed = true;
2208
+ }
2209
+ ),
2210
+ // Client reads from server
2211
+ readable: createReadable(
2212
+ serverToClient,
2213
+ () => serverToClientResolver,
2214
+ (r) => {
2215
+ serverToClientResolver = r;
2216
+ },
2217
+ () => serverToClientClosed
2218
+ )
2219
+ };
2220
+ const serverStream = {
2221
+ // Server writes to client
2222
+ writable: createWritable(
2223
+ serverToClient,
2224
+ () => serverToClientResolver,
2225
+ () => {
2226
+ serverToClientClosed = true;
2227
+ }
2228
+ ),
2229
+ // Server reads from client
2230
+ readable: createReadable(
2231
+ clientToServer,
2232
+ () => clientToServerResolver,
2233
+ (r) => {
2234
+ clientToServerResolver = r;
2235
+ },
2236
+ () => clientToServerClosed
2237
+ )
2238
+ };
2239
+ return [clientStream, serverStream];
2240
+ }
2241
+
2037
2242
  // src/subscription/index.ts
2038
2243
  var Subscription = class {
2039
2244
  id;
@@ -2350,7 +2555,7 @@ function createSubscription(id, unsubscribe, options, sendAck) {
2350
2555
  }
2351
2556
 
2352
2557
  // src/connection/client.ts
2353
- var ClientConnection = class {
2558
+ var ClientConnection = class _ClientConnection {
2354
2559
  #connection;
2355
2560
  #subscriptions = /* @__PURE__ */ new Map();
2356
2561
  #subscriptionStates = /* @__PURE__ */ new Map();
@@ -2374,6 +2579,59 @@ var ClientConnection = class {
2374
2579
  }
2375
2580
  }
2376
2581
  // ===========================================================================
2582
+ // Static Factory Methods
2583
+ // ===========================================================================
2584
+ /**
2585
+ * Connect to a MAP server via WebSocket URL.
2586
+ *
2587
+ * Handles:
2588
+ * - WebSocket creation and connection
2589
+ * - Stream wrapping
2590
+ * - Auto-configuration of createStream for reconnection
2591
+ * - Initial MAP protocol connect handshake
2592
+ *
2593
+ * @param url - WebSocket URL (ws:// or wss://)
2594
+ * @param options - Connection options
2595
+ * @returns Connected ClientConnection instance
2596
+ *
2597
+ * @example
2598
+ * ```typescript
2599
+ * const client = await ClientConnection.connect('ws://localhost:8080', {
2600
+ * name: 'MyClient',
2601
+ * reconnection: true
2602
+ * });
2603
+ *
2604
+ * // Already connected, ready to use
2605
+ * const agents = await client.listAgents();
2606
+ * ```
2607
+ */
2608
+ static async connect(url, options) {
2609
+ const parsedUrl = new URL(url);
2610
+ if (!["ws:", "wss:"].includes(parsedUrl.protocol)) {
2611
+ throw new Error(
2612
+ `Unsupported protocol: ${parsedUrl.protocol}. Use ws: or wss:`
2613
+ );
2614
+ }
2615
+ const timeout = options?.connectTimeout ?? 1e4;
2616
+ const ws = new WebSocket(url);
2617
+ await waitForOpen(ws, timeout);
2618
+ const stream = websocketStream(ws);
2619
+ const createStream = async () => {
2620
+ const newWs = new WebSocket(url);
2621
+ await waitForOpen(newWs, timeout);
2622
+ return websocketStream(newWs);
2623
+ };
2624
+ const reconnection = options?.reconnection === true ? { enabled: true } : typeof options?.reconnection === "object" ? options.reconnection : void 0;
2625
+ const client = new _ClientConnection(stream, {
2626
+ name: options?.name,
2627
+ capabilities: options?.capabilities,
2628
+ createStream,
2629
+ reconnection
2630
+ });
2631
+ await client.connect({ auth: options?.auth });
2632
+ return client;
2633
+ }
2634
+ // ===========================================================================
2377
2635
  // Connection Lifecycle
2378
2636
  // ===========================================================================
2379
2637
  /**
@@ -2386,6 +2644,7 @@ var ClientConnection = class {
2386
2644
  name: this.#options.name,
2387
2645
  capabilities: this.#options.capabilities,
2388
2646
  sessionId: options?.sessionId,
2647
+ resumeToken: options?.resumeToken,
2389
2648
  auth: options?.auth
2390
2649
  };
2391
2650
  const result = await this.#connection.sendRequest(CORE_METHODS.CONNECT, params);
@@ -2398,14 +2657,18 @@ var ClientConnection = class {
2398
2657
  }
2399
2658
  /**
2400
2659
  * Disconnect from the MAP system
2660
+ * @param reason - Optional reason for disconnecting
2661
+ * @returns Resume token that can be used to resume this session later
2401
2662
  */
2402
2663
  async disconnect(reason) {
2403
- if (!this.#connected) return;
2664
+ if (!this.#connected) return void 0;
2665
+ let resumeToken;
2404
2666
  try {
2405
- await this.#connection.sendRequest(
2667
+ const result = await this.#connection.sendRequest(
2406
2668
  CORE_METHODS.DISCONNECT,
2407
2669
  reason ? { reason } : void 0
2408
2670
  );
2671
+ resumeToken = result.resumeToken;
2409
2672
  } finally {
2410
2673
  for (const subscription of this.#subscriptions.values()) {
2411
2674
  subscription._close();
@@ -2414,6 +2677,7 @@ var ClientConnection = class {
2414
2677
  await this.#connection.close();
2415
2678
  this.#connected = false;
2416
2679
  }
2680
+ return resumeToken;
2417
2681
  }
2418
2682
  /**
2419
2683
  * Whether the client is connected
@@ -2948,99 +3212,6 @@ var ClientConnection = class {
2948
3212
  }
2949
3213
  };
2950
3214
 
2951
- // src/stream/index.ts
2952
- function createStreamPair() {
2953
- const clientToServer = [];
2954
- const serverToClient = [];
2955
- let clientToServerResolver = null;
2956
- let serverToClientResolver = null;
2957
- let clientToServerClosed = false;
2958
- let serverToClientClosed = false;
2959
- function createReadable(queue, _getResolver, setResolver, isClosed) {
2960
- return new ReadableStream({
2961
- async pull(controller) {
2962
- if (queue.length > 0) {
2963
- controller.enqueue(queue.shift());
2964
- return;
2965
- }
2966
- if (isClosed()) {
2967
- controller.close();
2968
- return;
2969
- }
2970
- const message = await new Promise((resolve) => {
2971
- setResolver((msg) => {
2972
- setResolver(null);
2973
- resolve(msg);
2974
- });
2975
- });
2976
- if (message === null) {
2977
- controller.close();
2978
- } else {
2979
- controller.enqueue(message);
2980
- }
2981
- }
2982
- });
2983
- }
2984
- function createWritable(queue, getResolver, setClosed) {
2985
- return new WritableStream({
2986
- write(message) {
2987
- const resolver = getResolver();
2988
- if (resolver) {
2989
- resolver(message);
2990
- } else {
2991
- queue.push(message);
2992
- }
2993
- },
2994
- close() {
2995
- setClosed();
2996
- const resolver = getResolver();
2997
- if (resolver) {
2998
- resolver(null);
2999
- }
3000
- }
3001
- });
3002
- }
3003
- const clientStream = {
3004
- // Client writes to server
3005
- writable: createWritable(
3006
- clientToServer,
3007
- () => clientToServerResolver,
3008
- () => {
3009
- clientToServerClosed = true;
3010
- }
3011
- ),
3012
- // Client reads from server
3013
- readable: createReadable(
3014
- serverToClient,
3015
- () => serverToClientResolver,
3016
- (r) => {
3017
- serverToClientResolver = r;
3018
- },
3019
- () => serverToClientClosed
3020
- )
3021
- };
3022
- const serverStream = {
3023
- // Server writes to client
3024
- writable: createWritable(
3025
- serverToClient,
3026
- () => serverToClientResolver,
3027
- () => {
3028
- serverToClientClosed = true;
3029
- }
3030
- ),
3031
- // Server reads from client
3032
- readable: createReadable(
3033
- clientToServer,
3034
- () => clientToServerResolver,
3035
- (r) => {
3036
- clientToServerResolver = r;
3037
- },
3038
- () => clientToServerClosed
3039
- )
3040
- };
3041
- return [clientStream, serverStream];
3042
- }
3043
-
3044
3215
  // src/testing/client.ts
3045
3216
  var TestClient = class _TestClient {
3046
3217
  #connection;
@@ -3233,7 +3404,7 @@ var TestClient = class _TestClient {
3233
3404
  };
3234
3405
 
3235
3406
  // src/connection/agent.ts
3236
- var AgentConnection = class {
3407
+ var AgentConnection = class _AgentConnection {
3237
3408
  #connection;
3238
3409
  #subscriptions = /* @__PURE__ */ new Map();
3239
3410
  #options;
@@ -3260,6 +3431,66 @@ var AgentConnection = class {
3260
3431
  }
3261
3432
  }
3262
3433
  // ===========================================================================
3434
+ // Static Factory Methods
3435
+ // ===========================================================================
3436
+ /**
3437
+ * Connect and register an agent via WebSocket URL.
3438
+ *
3439
+ * Handles:
3440
+ * - WebSocket creation and connection
3441
+ * - Stream wrapping
3442
+ * - Auto-configuration of createStream for reconnection
3443
+ * - Initial MAP protocol connect handshake
3444
+ * - Agent registration
3445
+ *
3446
+ * @param url - WebSocket URL (ws:// or wss://)
3447
+ * @param options - Connection and agent options
3448
+ * @returns Connected and registered AgentConnection instance
3449
+ *
3450
+ * @example
3451
+ * ```typescript
3452
+ * const agent = await AgentConnection.connect('ws://localhost:8080', {
3453
+ * name: 'Worker',
3454
+ * role: 'processor',
3455
+ * reconnection: true
3456
+ * });
3457
+ *
3458
+ * // Already registered, ready to work
3459
+ * agent.onMessage(handleMessage);
3460
+ * await agent.busy();
3461
+ * ```
3462
+ */
3463
+ static async connect(url, options) {
3464
+ const parsedUrl = new URL(url);
3465
+ if (!["ws:", "wss:"].includes(parsedUrl.protocol)) {
3466
+ throw new Error(
3467
+ `Unsupported protocol: ${parsedUrl.protocol}. Use ws: or wss:`
3468
+ );
3469
+ }
3470
+ const timeout = options?.connectTimeout ?? 1e4;
3471
+ const ws = new WebSocket(url);
3472
+ await waitForOpen(ws, timeout);
3473
+ const stream = websocketStream(ws);
3474
+ const createStream = async () => {
3475
+ const newWs = new WebSocket(url);
3476
+ await waitForOpen(newWs, timeout);
3477
+ return websocketStream(newWs);
3478
+ };
3479
+ const reconnection = options?.reconnection === true ? { enabled: true } : typeof options?.reconnection === "object" ? options.reconnection : void 0;
3480
+ const agent = new _AgentConnection(stream, {
3481
+ name: options?.name,
3482
+ role: options?.role,
3483
+ capabilities: options?.capabilities,
3484
+ visibility: options?.visibility,
3485
+ parent: options?.parent,
3486
+ scopes: options?.scopes,
3487
+ createStream,
3488
+ reconnection
3489
+ });
3490
+ await agent.connect({ auth: options?.auth });
3491
+ return agent;
3492
+ }
3493
+ // ===========================================================================
3263
3494
  // Connection Lifecycle
3264
3495
  // ===========================================================================
3265
3496
  /**
@@ -3272,6 +3503,7 @@ var AgentConnection = class {
3272
3503
  participantId: options?.agentId,
3273
3504
  name: this.#options.name,
3274
3505
  capabilities: this.#options.capabilities,
3506
+ resumeToken: options?.resumeToken,
3275
3507
  auth: options?.auth
3276
3508
  };
3277
3509
  const connectResult = await this.#connection.sendRequest(CORE_METHODS.CONNECT, connectParams);
@@ -3296,9 +3528,12 @@ var AgentConnection = class {
3296
3528
  }
3297
3529
  /**
3298
3530
  * Disconnect from the MAP system
3531
+ * @param reason - Optional reason for disconnecting
3532
+ * @returns Resume token that can be used to resume this session later
3299
3533
  */
3300
3534
  async disconnect(reason) {
3301
- if (!this.#connected) return;
3535
+ if (!this.#connected) return void 0;
3536
+ let resumeToken;
3302
3537
  try {
3303
3538
  if (this.#agentId) {
3304
3539
  await this.#connection.sendRequest(LIFECYCLE_METHODS.AGENTS_UNREGISTER, {
@@ -3306,10 +3541,11 @@ var AgentConnection = class {
3306
3541
  reason
3307
3542
  });
3308
3543
  }
3309
- await this.#connection.sendRequest(
3544
+ const result = await this.#connection.sendRequest(
3310
3545
  CORE_METHODS.DISCONNECT,
3311
3546
  reason ? { reason } : void 0
3312
3547
  );
3548
+ resumeToken = result.resumeToken;
3313
3549
  } finally {
3314
3550
  for (const subscription of this.#subscriptions.values()) {
3315
3551
  subscription._close();
@@ -3318,6 +3554,7 @@ var AgentConnection = class {
3318
3554
  await this.#connection.close();
3319
3555
  this.#connected = false;
3320
3556
  }
3557
+ return resumeToken;
3321
3558
  }
3322
3559
  /**
3323
3560
  * Whether the agent is connected