@symbolica/agentica 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/LICENSE +21 -77
  2. package/README.md +10 -9
  3. package/THIRD_PARTY_NOTICES.md +27 -0
  4. package/dist/src/agentica/agent.d.ts +3 -2
  5. package/dist/src/agentica/agent.d.ts.map +1 -1
  6. package/dist/src/agentica/agent.js +3 -4
  7. package/dist/src/agentica/agent.js.map +1 -1
  8. package/dist/src/agentica/agentic.d.ts.map +1 -1
  9. package/dist/src/agentica/agentic.js +1 -3
  10. package/dist/src/agentica/agentic.js.map +1 -1
  11. package/dist/src/agentica/common.d.ts +10 -5
  12. package/dist/src/agentica/common.d.ts.map +1 -1
  13. package/dist/src/agentica/common.js +32 -17
  14. package/dist/src/agentica/common.js.map +1 -1
  15. package/dist/src/agentica-unplugin.d.ts +2 -2
  16. package/dist/src/agentica-unplugin.d.ts.map +1 -1
  17. package/dist/src/bundlers/esbuild.d.ts +1 -1
  18. package/dist/src/bundlers/vite.d.ts +1 -1
  19. package/dist/src/client-session-manager/client-session-manager.d.ts +10 -8
  20. package/dist/src/client-session-manager/client-session-manager.d.ts.map +1 -1
  21. package/dist/src/client-session-manager/client-session-manager.js +172 -95
  22. package/dist/src/client-session-manager/client-session-manager.js.map +1 -1
  23. package/dist/src/client-session-manager/types.d.ts +1 -1
  24. package/dist/src/client-session-manager/types.d.ts.map +1 -1
  25. package/dist/src/coming-soon.d.ts +7 -18
  26. package/dist/src/coming-soon.d.ts.map +1 -1
  27. package/dist/src/coming-soon.js +21 -41
  28. package/dist/src/coming-soon.js.map +1 -1
  29. package/dist/src/version.d.ts +1 -1
  30. package/dist/src/version.js +1 -1
  31. package/dist/src/warpc/msg-protocol/concept/python-mirrors/str.d.ts +7 -0
  32. package/dist/src/warpc/msg-protocol/concept/python-mirrors/str.d.ts.map +1 -0
  33. package/dist/src/warpc/msg-protocol/concept/python-mirrors/str.js +144 -0
  34. package/dist/src/warpc/msg-protocol/concept/python-mirrors/str.js.map +1 -0
  35. package/dist/src/warpc/msg-protocol/concept/python-mirrors/str.test.d.ts +2 -0
  36. package/dist/src/warpc/msg-protocol/concept/python-mirrors/str.test.d.ts.map +1 -0
  37. package/dist/src/warpc/msg-protocol/concept/python-mirrors/str.test.js +253 -0
  38. package/dist/src/warpc/msg-protocol/concept/python-mirrors/str.test.js.map +1 -0
  39. package/dist/src/warpc/msg-protocol/concept/python-mirrors/utils.d.ts +5 -0
  40. package/dist/src/warpc/msg-protocol/concept/python-mirrors/utils.d.ts.map +1 -0
  41. package/dist/src/warpc/msg-protocol/concept/python-mirrors/utils.js +17 -0
  42. package/dist/src/warpc/msg-protocol/concept/python-mirrors/utils.js.map +1 -0
  43. package/dist/src/warpc/msg-protocol/concept/resource/system-msg.d.ts +2 -1
  44. package/dist/src/warpc/msg-protocol/concept/resource/system-msg.d.ts.map +1 -1
  45. package/dist/src/warpc/msg-protocol/concept/resource/system-msg.js +14 -10
  46. package/dist/src/warpc/msg-protocol/concept/resource/system-msg.js.map +1 -1
  47. package/dist-transformer/agentica/agent.d.ts +4 -2
  48. package/dist-transformer/agentica/agent.d.ts.map +1 -1
  49. package/dist-transformer/agentica/agent.js +3 -3
  50. package/dist-transformer/agentica/agentic.d.ts.map +1 -1
  51. package/dist-transformer/agentica/agentic.js +1 -3
  52. package/dist-transformer/agentica/common.d.ts +23 -13
  53. package/dist-transformer/agentica/common.d.ts.map +1 -1
  54. package/dist-transformer/agentica/common.js +46 -25
  55. package/dist-transformer/client-session-manager/client-session-manager.d.ts +20 -12
  56. package/dist-transformer/client-session-manager/client-session-manager.d.ts.map +1 -1
  57. package/dist-transformer/client-session-manager/client-session-manager.js +214 -108
  58. package/dist-transformer/client-session-manager/types.d.ts +1 -1
  59. package/dist-transformer/client-session-manager/types.d.ts.map +1 -1
  60. package/dist-transformer/coming-soon.d.ts +7 -18
  61. package/dist-transformer/coming-soon.d.ts.map +1 -1
  62. package/dist-transformer/coming-soon.js +21 -39
  63. package/dist-transformer/version.d.ts +1 -1
  64. package/dist-transformer/version.js +1 -1
  65. package/dist-transformer/warpc/msg-protocol/concept/python-mirrors/str.d.ts +7 -0
  66. package/dist-transformer/warpc/msg-protocol/concept/python-mirrors/str.d.ts.map +1 -0
  67. package/dist-transformer/warpc/msg-protocol/concept/python-mirrors/str.js +151 -0
  68. package/dist-transformer/warpc/msg-protocol/concept/python-mirrors/utils.d.ts +5 -0
  69. package/dist-transformer/warpc/msg-protocol/concept/python-mirrors/utils.d.ts.map +1 -0
  70. package/dist-transformer/warpc/msg-protocol/concept/python-mirrors/utils.js +16 -0
  71. package/dist-transformer/warpc/msg-protocol/concept/resource/system-msg.d.ts +2 -1
  72. package/dist-transformer/warpc/msg-protocol/concept/resource/system-msg.d.ts.map +1 -1
  73. package/dist-transformer/warpc/msg-protocol/concept/resource/system-msg.js +14 -11
  74. package/package.json +5 -3
@@ -20,9 +20,9 @@ export interface InvokeAgentParams {
20
20
  parentIid?: string;
21
21
  }
22
22
  export declare class ClientSessionManager {
23
- private websocket;
24
- private tasks;
25
- private sendQueue;
23
+ private sessionManagers;
24
+ private smLocks;
25
+ private uidToSm;
26
26
  private uidIidRecvQueue;
27
27
  private uidIidException;
28
28
  private matchIid;
@@ -46,15 +46,17 @@ export declare class ClientSessionManager {
46
46
  setEndpoints(baseHttp: string, baseWs: string): void;
47
47
  private registerSession;
48
48
  private buildHeaders;
49
- private wsBackgroundTaskWriter;
50
- private wsBackgroundTaskReader;
51
- private _ensureWebSocketConnection;
49
+ private smWriter;
50
+ private smReader;
51
+ private _failSmFutures;
52
+ private _cleanupSessionManager;
53
+ private _ensureSmConnection;
52
54
  private _initAgentState;
53
55
  newAgent(cmar: CreateAgentRequest, parentLogger?: ScopedLogger): Promise<string>;
54
56
  invokeAgent(params: InvokeAgentParams, parentLogger?: ScopedLogger): Promise<AgentInvocationHandle>;
55
57
  echo(cancelSignal: AbortSignal, uid: string, iid?: string): AsyncGenerator<Chunk, void, unknown>;
56
58
  logs(uid: string, iid?: string, params?: Record<string, any>): Promise<Array<Record<string, any>>>;
57
- fetchUsage(uid: string, iid: string, lastTotal?: Usage): Promise<{
59
+ fetchUsage(uid: string, iid: string, _lastTotal?: Usage): Promise<{
58
60
  usage: Usage;
59
61
  newTotal: Usage;
60
62
  }>;
@@ -69,5 +71,5 @@ declare global {
69
71
  var __AGENTICA_AGENTIC_MANAGER: ClientSessionManager | undefined;
70
72
  }
71
73
  export declare const __AGENTIC_MANAGER: ClientSessionManager;
72
- export declare const __AGENTIC_PROTO_VER = "typescript/0.3.1";
74
+ export declare const __AGENTIC_PROTO_VER = "typescript/0.4.0";
73
75
  //# sourceMappingURL=client-session-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-session-manager.d.ts","sourceRoot":"","sources":["../../../src/client-session-manager/client-session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client-session-manager.d.ts","sourceRoot":"","sources":["../../../src/client-session-manager/client-session-manager.ts"],"names":[],"mappings":"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"}
@@ -27,9 +27,9 @@ import { injectTraceContext } from "../otel-config.js";
27
27
  import { CustomLogFW } from "../otel-logging.js";
28
28
  import { version } from "../version.js";
29
29
  export class ClientSessionManager {
30
- websocket = null;
31
- tasks = null;
32
- sendQueue = null;
30
+ sessionManagers = new Map();
31
+ smLocks = new Map();
32
+ uidToSm = new Map();
33
33
  uidIidRecvQueue;
34
34
  uidIidException;
35
35
  matchIid;
@@ -136,29 +136,28 @@ export class ClientSessionManager {
136
136
  headers['X-Client-Session-ID'] = this.clientSessionId;
137
137
  return headers;
138
138
  }
139
- async wsBackgroundTaskWriter(control) {
139
+ async smWriter(smId, control) {
140
140
  await waitForTracing;
141
- const wsLogger = this.logger.withScope('ws-writer');
141
+ const wsLogger = this.logger.withScope(`ws-writer-${smId.slice(0, 8)}`);
142
142
  wsLogger.debug('Writer task started');
143
- const ws = this.websocket;
144
143
  try {
145
144
  while (!control.shouldStop) {
145
+ const smc = this.sessionManagers.get(smId);
146
+ if (!smc) {
147
+ wsLogger.debug('Session manager connection removed, exiting writer');
148
+ break;
149
+ }
146
150
  try {
147
- const sendQueue = this.sendQueue;
148
- if (!sendQueue) {
149
- wsLogger.debug('Send queue removed, exiting writer');
150
- break;
151
- }
152
- const msg = await sendQueue.get();
151
+ const msg = await smc.sendQueue.get();
153
152
  const msgUid = msg.uid;
154
153
  const msgLogger = msgUid ? (this.uidToLogger.get(msgUid) ?? wsLogger) : wsLogger;
155
- if (ws.readyState !== 1) {
154
+ if (smc.websocket.readyState !== 1) {
156
155
  const error = new WebSocketConnectionError(`cannot send as websocket is not open.`);
157
156
  enrichError(error, { uid: msgUid, sessionId: this.clientSessionId });
158
157
  throw error;
159
158
  }
160
159
  msgLogger.debug(`Sending ${msg.type} message`);
161
- ws.send(encodeMessage(msg));
160
+ smc.websocket.send(encodeMessage(msg));
162
161
  }
163
162
  catch (error) {
164
163
  if (error instanceof Error && error.message === 'Queue closed') {
@@ -172,23 +171,20 @@ export class ClientSessionManager {
172
171
  }
173
172
  catch (error) {
174
173
  wsLogger.error('Writer task failed', error);
175
- for (const [matchId, handlers] of this.matchIid.entries()) {
176
- handlers.reject(new WebSocketConnectionError(`WebSocket writer failed: ${error.message}`));
177
- this.matchIid.delete(matchId);
178
- }
179
- for (const [_, exceptionMap] of this.uidIidException.entries()) {
180
- for (const [_iid, handlers] of exceptionMap.entries()) {
181
- handlers.reject(new WebSocketConnectionError(`WebSocket writer failed: ${error.message}`));
182
- }
183
- }
174
+ await this._cleanupSessionManager(smId);
184
175
  throw error;
185
176
  }
186
177
  }
187
- async wsBackgroundTaskReader(control) {
178
+ async smReader(smId, control) {
188
179
  await waitForTracing;
189
- const wsLogger = this.logger.withScope('ws-reader');
180
+ const wsLogger = this.logger.withScope(`ws-reader-${smId.slice(0, 8)}`);
190
181
  wsLogger.debug('Reader task started');
191
- const ws = this.websocket;
182
+ const smc = this.sessionManagers.get(smId);
183
+ if (!smc) {
184
+ wsLogger.warn('Session manager connection not found');
185
+ return;
186
+ }
187
+ const ws = smc.websocket;
192
188
  ws.onmessage = (event) => {
193
189
  if (control.shouldStop)
194
190
  return;
@@ -289,45 +285,99 @@ export class ClientSessionManager {
289
285
  ws.onclose = (event) => {
290
286
  wsLogger.debug(`WebSocket closed (code=${event.code}, reason=${event.reason || 'none'})`);
291
287
  control.shouldStop = true;
292
- for (const [matchId, handlers] of this.matchIid.entries()) {
293
- handlers.reject(new WebSocketConnectionError(`WebSocket closed: ${event.reason || 'Connection closed'}`));
294
- this.matchIid.delete(matchId);
295
- }
296
- for (const [_, exceptionMap] of this.uidIidException.entries()) {
297
- for (const [_iid, handlers] of exceptionMap.entries()) {
298
- handlers.reject(new WebSocketConnectionError(`WebSocket closed: ${event.reason || 'Connection closed'}`));
299
- }
300
- exceptionMap.clear();
301
- }
288
+ this._failSmFutures(smId, `WebSocket closed: ${event.reason || 'Connection closed'}`);
302
289
  resolve();
303
290
  };
304
291
  ws.onerror = (_error) => {
305
292
  wsLogger.error('WebSocket error');
306
293
  control.shouldStop = true;
307
- for (const [matchId, handlers] of this.matchIid.entries()) {
308
- handlers.reject(new WebSocketConnectionError('WebSocket error occurred'));
309
- this.matchIid.delete(matchId);
310
- }
311
- for (const [_, exceptionMap] of this.uidIidException.entries()) {
312
- for (const [_iid, handlers] of exceptionMap.entries()) {
313
- handlers.reject(new WebSocketConnectionError('WebSocket error occurred'));
314
- }
315
- exceptionMap.clear();
316
- }
294
+ this._failSmFutures(smId, 'WebSocket error occurred');
317
295
  resolve();
318
296
  };
319
297
  });
320
298
  }
321
- async _ensureWebSocketConnection() {
322
- if (this.websocket && this.websocket.readyState === 1) {
299
+ _failSmFutures(smId, reason) {
300
+ const affectedUids = [];
301
+ for (const [uid, sid] of this.uidToSm.entries()) {
302
+ if (sid === smId) {
303
+ affectedUids.push(uid);
304
+ }
305
+ }
306
+ for (const [matchId, handlers] of this.matchIid.entries()) {
307
+ handlers.reject(new WebSocketConnectionError(reason));
308
+ this.matchIid.delete(matchId);
309
+ }
310
+ for (const uid of affectedUids) {
311
+ const exceptionMap = this.uidIidException.get(uid);
312
+ if (exceptionMap) {
313
+ for (const [_iid, handlers] of exceptionMap.entries()) {
314
+ handlers.reject(new WebSocketConnectionError(reason));
315
+ }
316
+ exceptionMap.clear();
317
+ }
318
+ }
319
+ }
320
+ async _cleanupSessionManager(smId) {
321
+ const smc = this.sessionManagers.get(smId);
322
+ if (!smc) {
323
323
  return;
324
324
  }
325
+ this.logger.debug(`Cleaning up session manager ${smId.slice(0, 8)}`);
326
+ this.sessionManagers.delete(smId);
327
+ this.smLocks.delete(smId);
328
+ const [readerControl, writerControl] = smc.tasks;
329
+ readerControl.shouldStop = true;
330
+ writerControl.shouldStop = true;
331
+ smc.sendQueue.close();
332
+ try {
333
+ if (smc.websocket.readyState === 0 || smc.websocket.readyState === 1) {
334
+ smc.websocket.close(1000, 'Normal closure');
335
+ }
336
+ }
337
+ catch (error) {
338
+ this.logger.warn(`Failed to close WebSocket for session manager ${smId.slice(0, 8)}`, error);
339
+ }
340
+ await Promise.allSettled([readerControl.promise, writerControl.promise]);
341
+ this._failSmFutures(smId, 'Session manager connection closed');
342
+ const affectedUids = [];
343
+ for (const [uid, sid] of this.uidToSm.entries()) {
344
+ if (sid === smId) {
345
+ affectedUids.push(uid);
346
+ }
347
+ }
348
+ for (const uid of affectedUids) {
349
+ this.uidToSm.delete(uid);
350
+ }
351
+ this.logger.debug(`Cleaned up session manager ${smId.slice(0, 8)}`);
352
+ }
353
+ async _ensureSmConnection(smId) {
354
+ const existing = this.sessionManagers.get(smId);
355
+ if (existing && existing.websocket.readyState === 1) {
356
+ return;
357
+ }
358
+ const existingLock = this.smLocks.get(smId);
359
+ if (existingLock) {
360
+ await existingLock;
361
+ return;
362
+ }
363
+ let resolveLock;
364
+ const lockPromise = new Promise((resolve) => {
365
+ resolveLock = resolve;
366
+ });
367
+ this.smLocks.set(smId, lockPromise);
325
368
  await waitForTracing;
326
- const span = this.logger.startSpan('sdk.websocket_connection');
369
+ const span = this.logger.startSpan('sdk.sm_connection');
370
+ span.setAttribute('session_manager.id', smId);
327
371
  try {
328
- this.sendQueue = new Queue();
372
+ const doubleCheck = this.sessionManagers.get(smId);
373
+ if (doubleCheck && doubleCheck.websocket.readyState === 1) {
374
+ resolveLock();
375
+ this.smLocks.delete(smId);
376
+ return;
377
+ }
378
+ const sendQueue = new Queue();
329
379
  const websocket_uri = `${this.baseWs}/socket`;
330
- this.logger.debug(`Connecting WebSocket`);
380
+ this.logger.debug(`Connecting WebSocket for session manager ${smId.slice(0, 8)}`);
331
381
  span.setAttribute('websocket.uri', websocket_uri);
332
382
  span.setAttribute('websocket.state', 'connecting');
333
383
  const headers = {};
@@ -347,7 +397,6 @@ export class ClientSessionManager {
347
397
  ws.binaryType = 'arraybuffer';
348
398
  return new Promise((resolve, reject) => {
349
399
  ws.onopen = () => {
350
- this.websocket = ws;
351
400
  try {
352
401
  ws._socket?.unref?.();
353
402
  }
@@ -361,23 +410,32 @@ export class ClientSessionManager {
361
410
  shouldStop: false,
362
411
  promise: Promise.resolve(),
363
412
  };
364
- readerControl.promise = this.wsBackgroundTaskReader(readerControl).catch((error) => {
365
- this.logger.error('Reader background task crashed', error);
413
+ const smc = {
414
+ websocket: ws,
415
+ sendQueue,
416
+ tasks: [readerControl, writerControl],
417
+ };
418
+ this.sessionManagers.set(smId, smc);
419
+ readerControl.promise = this.smReader(smId, readerControl).catch((error) => {
420
+ this.logger.error(`Reader task crashed for session manager ${smId.slice(0, 8)}`, error);
366
421
  });
367
- writerControl.promise = this.wsBackgroundTaskWriter(writerControl).catch((error) => {
368
- this.logger.error('Writer background task crashed', error);
422
+ writerControl.promise = this.smWriter(smId, writerControl).catch((error) => {
423
+ this.logger.error(`Writer task crashed for session manager ${smId.slice(0, 8)}`, error);
369
424
  });
370
- this.tasks = [readerControl, writerControl];
371
- this.logger.info(`WebSocket connected`);
425
+ this.logger.info(`WebSocket connected for session manager ${smId.slice(0, 8)}`);
372
426
  span.setAttribute('websocket.state', 'connected');
373
427
  span.end();
428
+ resolveLock();
429
+ this.smLocks.delete(smId);
374
430
  resolve();
375
431
  };
376
432
  ws.onerror = (error) => {
377
- this.logger.error(`WebSocket connection failed:\n${error.toString()}`);
433
+ this.logger.error(`WebSocket connection failed for session manager ${smId.slice(0, 8)}:\n${error.toString()}`);
378
434
  span.setAttribute('websocket.state', 'error');
379
435
  span.recordException(error);
380
436
  span.end();
437
+ resolveLock();
438
+ this.smLocks.delete(smId);
381
439
  reject(new WebSocketConnectionError('WebSocket connection failed'));
382
440
  };
383
441
  });
@@ -386,6 +444,8 @@ export class ClientSessionManager {
386
444
  span.setAttribute('websocket.state', 'error');
387
445
  span.recordException(error);
388
446
  span.end();
447
+ resolveLock();
448
+ this.smLocks.delete(smId);
389
449
  throw error;
390
450
  }
391
451
  }
@@ -457,10 +517,22 @@ export class ClientSessionManager {
457
517
  logger.warn(message);
458
518
  }
459
519
  }
460
- const uid = await response.text();
520
+ const responseData = await response.json();
521
+ const uid = responseData.uid;
522
+ const smId = responseData.session_manager_id;
523
+ if (!uid) {
524
+ logger.error(`Server response missing "uid" field: ${JSON.stringify(responseData)}`);
525
+ throw new ConnectionError('Invalid server response: missing "uid" field');
526
+ }
527
+ if (!smId) {
528
+ logger.error(`Server response missing "session_manager_id" field: ${JSON.stringify(responseData)}`);
529
+ throw new ConnectionError('Invalid server response: missing "session_manager_id" field');
530
+ }
461
531
  logger.info('Created agent');
462
532
  span.setAttribute('agent.uid', uid);
463
- await this._ensureWebSocketConnection();
533
+ span.setAttribute('agent.session_manager_id', smId);
534
+ this.uidToSm.set(uid, smId);
535
+ await this._ensureSmConnection(smId);
464
536
  this.knownUids.add(uid);
465
537
  this._initAgentState(uid, parentLogger);
466
538
  return uid;
@@ -493,7 +565,20 @@ export class ClientSessionManager {
493
565
  enrichError(error, { uid, sessionId: this.clientSessionId });
494
566
  throw error;
495
567
  }
568
+ const smId = this.uidToSm.get(uid);
569
+ if (!smId) {
570
+ const error = new WebSocketConnectionError(`No session manager found for agent ${uid}`);
571
+ enrichError(error, { uid, sessionId: this.clientSessionId });
572
+ throw error;
573
+ }
574
+ const smc = this.sessionManagers.get(smId);
575
+ if (!smc || smc.websocket.readyState !== 1) {
576
+ const error = new WebSocketConnectionError(`No active connection for session manager ${smId}`);
577
+ enrichError(error, { uid, sessionId: this.clientSessionId });
578
+ throw error;
579
+ }
496
580
  span.setAttribute('agent.uid', uid);
581
+ span.setAttribute('agent.session_manager_id', smId);
497
582
  span.setAttribute('agent.task_desc', typeof taskDesc === 'string' ? taskDesc : taskDesc.template);
498
583
  span.setAttribute('invocation.streaming', streaming);
499
584
  const matchId = this.idIssuer();
@@ -506,11 +591,11 @@ export class ClientSessionManager {
506
591
  prompt: taskDesc,
507
592
  streaming: streaming,
508
593
  };
509
- invLogger.debug(`Invoking with match_id=${matchId}`);
594
+ invLogger.debug(`Invoking with match_id=${matchId} on session manager ${smId.slice(0, 8)}`);
510
595
  const iidPromise = new Promise((resolve, reject) => {
511
596
  this.matchIid.set(matchId, { resolve, reject });
512
597
  });
513
- this.sendQueue.put(msg);
598
+ smc.sendQueue.put(msg);
514
599
  const iid = await iidPromise;
515
600
  this.iidToUid.set(iid, uid);
516
601
  invLogger.info(`Invocation created with iid=${iid}`);
@@ -527,8 +612,13 @@ export class ClientSessionManager {
527
612
  return { resolvers: { resolve, reject, promise }, promise };
528
613
  })();
529
614
  this.uidIidException.get(uid).set(iid, resolvers);
615
+ const capturedSmId = smId;
530
616
  return {
531
617
  send_message: async (data) => {
618
+ const currentSmc = this.sessionManagers.get(capturedSmId);
619
+ if (!currentSmc || currentSmc.websocket.readyState !== 1) {
620
+ throw new WebSocketConnectionError(`Session manager connection closed for ${capturedSmId}`);
621
+ }
532
622
  const dataMsg = {
533
623
  type: 'data',
534
624
  uid,
@@ -536,7 +626,7 @@ export class ClientSessionManager {
536
626
  data,
537
627
  timestamp: new Date().toISOString(),
538
628
  };
539
- this.sendQueue.put(dataMsg);
629
+ currentSmc.sendQueue.put(dataMsg);
540
630
  invLogger.debug(`Queued ${data.length} bytes to send`);
541
631
  },
542
632
  recv_message: async () => {
@@ -728,23 +818,27 @@ export class ClientSessionManager {
728
818
  }
729
819
  return response.json();
730
820
  }
731
- async fetchUsage(uid, iid, lastTotal) {
821
+ async fetchUsage(uid, iid, _lastTotal) {
732
822
  let total = Usage.zero();
733
823
  const logs = await this.logs(uid, iid, { type: 'sm_inference_usage' });
734
824
  for (const log of logs) {
735
825
  const logUsage = log.usage;
736
826
  if (logUsage) {
737
- total = total.add(Usage.fromCompletions(logUsage, total));
827
+ total = total.add(Usage.fromCompletions(logUsage));
738
828
  }
739
829
  }
740
- let usage = total;
741
- if (lastTotal) {
742
- usage = total.sub(lastTotal.replace({ outputTokens: 0 }));
743
- }
744
- return { usage, newTotal: total };
830
+ return { usage: total, newTotal: total };
745
831
  }
746
832
  agentExists(uid) {
747
- return this.knownUids.has(uid) && this.websocket !== null && this.websocket.readyState === 1;
833
+ if (!this.knownUids.has(uid)) {
834
+ return false;
835
+ }
836
+ const smId = this.uidToSm.get(uid);
837
+ if (!smId) {
838
+ return false;
839
+ }
840
+ const smc = this.sessionManagers.get(smId);
841
+ return smc !== undefined && smc.websocket.readyState === 1;
748
842
  }
749
843
  getUidForIid(iid) {
750
844
  return this.iidToUid.get(iid);
@@ -796,6 +890,7 @@ export class ClientSessionManager {
796
890
  this.uidIidException.delete(uid);
797
891
  this.knownUids.delete(uid);
798
892
  this.uidToLogger.delete(uid);
893
+ this.uidToSm.delete(uid);
799
894
  logger.debug(`Closed agent ${uid.slice(0, 8)}`);
800
895
  await this.destroyAgent(uid);
801
896
  this.unrefConnection();
@@ -807,32 +902,14 @@ export class ClientSessionManager {
807
902
  const span = this.logger.startSpan('stop');
808
903
  try {
809
904
  const agentCount = this.knownUids.size;
810
- this.logger.debug(`CSM Stop: stopping with ${agentCount} agent(s)`);
905
+ const smCount = this.sessionManagers.size;
906
+ this.logger.debug(`CSM Stop: stopping with ${agentCount} agent(s) on ${smCount} session manager(s)`);
811
907
  span.setAttribute('agent_count', agentCount);
908
+ span.setAttribute('session_manager_count', smCount);
812
909
  const uids = Array.from(this.knownUids);
813
910
  await Promise.allSettled(uids.map((uid) => this.closeAgent(uid)));
814
- if (this.sendQueue) {
815
- this.sendQueue.close();
816
- this.sendQueue = null;
817
- }
818
- if (this.websocket) {
819
- try {
820
- if (this.websocket.readyState === 0 || this.websocket.readyState === 1) {
821
- this.websocket.close(1000, 'Normal closure');
822
- }
823
- }
824
- catch (error) {
825
- this.logger.warn('Failed to close WebSocket', error);
826
- }
827
- this.websocket = null;
828
- }
829
- if (this.tasks) {
830
- const [readerControl, writerControl] = this.tasks;
831
- readerControl.shouldStop = true;
832
- writerControl.shouldStop = true;
833
- await Promise.allSettled([readerControl.promise, writerControl.promise]);
834
- this.tasks = null;
835
- }
911
+ const smIds = Array.from(this.sessionManagers.keys());
912
+ await Promise.allSettled(smIds.map((smId) => this._cleanupSessionManager(smId)));
836
913
  this.logger.debug('All resources cleaned up');
837
914
  this.isStopped = true;
838
915
  if (this.invocationGuard) {