@webex/contact-center 3.8.1 → 3.9.0-multipleLLM.1

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 (102) hide show
  1. package/dist/cc.js +106 -63
  2. package/dist/cc.js.map +1 -1
  3. package/dist/index.js +13 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/logger-proxy.js +24 -1
  6. package/dist/logger-proxy.js.map +1 -1
  7. package/dist/metrics/MetricsManager.js +1 -1
  8. package/dist/metrics/MetricsManager.js.map +1 -1
  9. package/dist/metrics/behavioral-events.js +88 -0
  10. package/dist/metrics/behavioral-events.js.map +1 -1
  11. package/dist/metrics/constants.js +26 -1
  12. package/dist/metrics/constants.js.map +1 -1
  13. package/dist/services/AddressBook.js +271 -0
  14. package/dist/services/AddressBook.js.map +1 -0
  15. package/dist/services/EntryPoint.js +227 -0
  16. package/dist/services/EntryPoint.js.map +1 -0
  17. package/dist/services/Queue.js +261 -0
  18. package/dist/services/Queue.js.map +1 -0
  19. package/dist/services/config/constants.js +24 -2
  20. package/dist/services/config/constants.js.map +1 -1
  21. package/dist/services/config/index.js +1 -43
  22. package/dist/services/config/index.js.map +1 -1
  23. package/dist/services/config/types.js +22 -5
  24. package/dist/services/config/types.js.map +1 -1
  25. package/dist/services/core/GlobalTypes.js.map +1 -1
  26. package/dist/services/core/Utils.js +162 -2
  27. package/dist/services/core/Utils.js.map +1 -1
  28. package/dist/services/core/aqm-reqs.js +0 -4
  29. package/dist/services/core/aqm-reqs.js.map +1 -1
  30. package/dist/services/core/websocket/WebSocketManager.js +0 -4
  31. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  32. package/dist/services/task/TaskManager.js +74 -2
  33. package/dist/services/task/TaskManager.js.map +1 -1
  34. package/dist/services/task/constants.js +7 -1
  35. package/dist/services/task/constants.js.map +1 -1
  36. package/dist/services/task/contact.js +86 -0
  37. package/dist/services/task/contact.js.map +1 -1
  38. package/dist/services/task/index.js +384 -72
  39. package/dist/services/task/index.js.map +1 -1
  40. package/dist/services/task/types.js +14 -0
  41. package/dist/services/task/types.js.map +1 -1
  42. package/dist/types/cc.d.ts +77 -43
  43. package/dist/types/index.d.ts +8 -3
  44. package/dist/types/metrics/constants.d.ts +20 -0
  45. package/dist/types/services/AddressBook.d.ts +74 -0
  46. package/dist/types/services/EntryPoint.d.ts +67 -0
  47. package/dist/types/services/Queue.d.ts +76 -0
  48. package/dist/types/services/config/constants.d.ts +23 -1
  49. package/dist/types/services/config/index.d.ts +1 -14
  50. package/dist/types/services/config/types.d.ts +44 -64
  51. package/dist/types/services/core/GlobalTypes.d.ts +25 -0
  52. package/dist/types/services/core/Utils.d.ts +40 -1
  53. package/dist/types/services/task/constants.d.ts +6 -0
  54. package/dist/types/services/task/contact.d.ts +10 -0
  55. package/dist/types/services/task/index.d.ts +44 -2
  56. package/dist/types/services/task/types.d.ts +123 -1
  57. package/dist/types/types.d.ts +162 -0
  58. package/dist/types/utils/PageCache.d.ts +173 -0
  59. package/dist/types.js +17 -0
  60. package/dist/types.js.map +1 -1
  61. package/dist/utils/PageCache.js +192 -0
  62. package/dist/utils/PageCache.js.map +1 -0
  63. package/dist/webex.js +1 -1
  64. package/package.json +10 -10
  65. package/src/cc.ts +122 -81
  66. package/src/index.ts +19 -3
  67. package/src/logger-proxy.ts +24 -1
  68. package/src/metrics/MetricsManager.ts +1 -1
  69. package/src/metrics/behavioral-events.ts +92 -0
  70. package/src/metrics/constants.ts +30 -0
  71. package/src/services/AddressBook.ts +291 -0
  72. package/src/services/EntryPoint.ts +241 -0
  73. package/src/services/Queue.ts +277 -0
  74. package/src/services/config/constants.ts +26 -2
  75. package/src/services/config/index.ts +1 -55
  76. package/src/services/config/types.ts +22 -65
  77. package/src/services/core/GlobalTypes.ts +27 -0
  78. package/src/services/core/Utils.ts +199 -1
  79. package/src/services/core/aqm-reqs.ts +0 -5
  80. package/src/services/core/websocket/WebSocketManager.ts +0 -4
  81. package/src/services/task/TaskManager.ts +79 -3
  82. package/src/services/task/constants.ts +6 -0
  83. package/src/services/task/contact.ts +80 -0
  84. package/src/services/task/index.ts +457 -57
  85. package/src/services/task/types.ts +133 -0
  86. package/src/types.ts +180 -0
  87. package/src/utils/PageCache.ts +252 -0
  88. package/test/unit/spec/cc.ts +31 -82
  89. package/test/unit/spec/metrics/MetricsManager.ts +0 -1
  90. package/test/unit/spec/metrics/behavioral-events.ts +56 -0
  91. package/test/unit/spec/services/AddressBook.ts +332 -0
  92. package/test/unit/spec/services/EntryPoint.ts +259 -0
  93. package/test/unit/spec/services/Queue.ts +323 -0
  94. package/test/unit/spec/services/config/index.ts +0 -71
  95. package/test/unit/spec/services/core/Utils.ts +50 -0
  96. package/test/unit/spec/services/core/aqm-reqs.ts +1 -3
  97. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +0 -4
  98. package/test/unit/spec/services/task/TaskManager.ts +145 -1
  99. package/test/unit/spec/services/task/contact.ts +31 -1
  100. package/test/unit/spec/services/task/index.ts +410 -123
  101. package/umd/contact-center.min.js +2 -2
  102. package/umd/contact-center.min.js.map +1 -1
@@ -276,4 +276,54 @@ describe('Utils', () => {
276
276
  });
277
277
  });
278
278
  });
279
+
280
+ describe('getDestinationAgentId', () => {
281
+ const currentAgentId = 'agent-current-123';
282
+
283
+ it('returns another Agent id when present and not in wrap-up', () => {
284
+ const participants: any = {
285
+ [currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
286
+ agent1: {type: 'Agent', id: 'agent-1', isWrapUp: false},
287
+ customer1: {type: 'Customer', id: 'cust-1', isWrapUp: false},
288
+ };
289
+
290
+ const result = Utils.getDestinationAgentId(participants, currentAgentId);
291
+ expect(result).toBe('agent-1');
292
+ });
293
+
294
+ it('ignores self and wrap-up participants', () => {
295
+ const participants: any = {
296
+ [currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
297
+ agentWrap: {type: 'Agent', id: 'agent-wrap', isWrapUp: true},
298
+ };
299
+
300
+ const result = Utils.getDestinationAgentId(participants, currentAgentId);
301
+ expect(result).toBe('');
302
+ });
303
+
304
+ it('supports DN, EpDn and entryPoint types', () => {
305
+ const participantsDN: any = {
306
+ [currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
307
+ dn1: {type: 'DN', id: 'dn-1', isWrapUp: false},
308
+ };
309
+ expect(Utils.getDestinationAgentId(participantsDN, currentAgentId)).toBe('dn-1');
310
+
311
+ const participantsEpDn: any = {
312
+ [currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
313
+ epdn1: {type: 'EpDn', id: 'epdn-1', isWrapUp: false},
314
+ };
315
+ expect(Utils.getDestinationAgentId(participantsEpDn, currentAgentId)).toBe('epdn-1');
316
+
317
+ const participantsEntry: any = {
318
+ [currentAgentId]: {type: 'Agent', id: currentAgentId, isWrapUp: false},
319
+ entry1: {type: 'entryPoint', id: 'entry-1', isWrapUp: false},
320
+ };
321
+ expect(Utils.getDestinationAgentId(participantsEntry, currentAgentId)).toBe('entry-1');
322
+ });
323
+
324
+ it('returns empty string when participants is missing or empty', () => {
325
+ expect(Utils.getDestinationAgentId(undefined as any, currentAgentId)).toBe('');
326
+ expect(Utils.getDestinationAgentId({} as any, currentAgentId)).toBe('');
327
+ });
328
+ });
279
329
  });
@@ -381,9 +381,7 @@ describe('AqmReqs', () => {
381
381
  data: { type: 'KeepaliveEvent' },
382
382
  })
383
383
  );
384
-
385
- expect(LoggerProxy.info).toHaveBeenCalledWith('Keepalive from web socket', {"method": "onMessage", "module": AQM_REQS_FILE});
386
-
384
+
387
385
  // Unhandled event
388
386
  webSocketManagerInstance.emit(
389
387
  'message',
@@ -200,10 +200,6 @@ describe('WebSocketManager', () => {
200
200
  await new Promise((resolve) => setTimeout(resolve, 10));
201
201
 
202
202
  expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
203
- expect(LoggerProxy.info).toHaveBeenCalledWith(
204
- '[WebSocketStatus] | desktop online status is false',
205
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
206
- );
207
203
  expect(LoggerProxy.error).toHaveBeenCalledWith(
208
204
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: network issue',
209
205
  { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
@@ -658,6 +658,13 @@ describe('TaskManager', () => {
658
658
  });
659
659
 
660
660
  it('should emit TASK_CONSULT_ACCEPTED event on AGENT_CONSULTING event', () => {
661
+ const initialConsultingPayload = {
662
+ data: {
663
+ ...initalPayload.data,
664
+ type: CC_EVENTS.AGENT_OFFER_CONSULT,
665
+ },
666
+ };
667
+
661
668
  const consultingPayload = {
662
669
  data: {
663
670
  ...initalPayload.data,
@@ -672,8 +679,8 @@ describe('TaskManager', () => {
672
679
  });
673
680
 
674
681
  const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
682
+ webSocketManagerMock.emit('message', JSON.stringify(initialConsultingPayload));
675
683
  webSocketManagerMock.emit('message', JSON.stringify(consultingPayload));
676
- expect(taskManager.getTask(taskId).updateTaskData).toHaveBeenCalledWith(consultingPayload.data);
677
684
  expect(taskManager.getTask(taskId).data.isConsulted).toBe(true);
678
685
  expect(taskEmitSpy).toHaveBeenCalledWith(
679
686
  TASK_EVENTS.TASK_CONSULT_ACCEPTED,
@@ -1346,6 +1353,143 @@ describe('TaskManager', () => {
1346
1353
  expect(spy).toHaveBeenCalledWith(taskEvent, task);
1347
1354
  });
1348
1355
  });
1356
+ });
1357
+
1358
+ describe('Conference event handling', () => {
1359
+ let task;
1360
+
1361
+ beforeEach(() => {
1362
+ task = {
1363
+ data: { interactionId: taskId },
1364
+ emit: jest.fn(),
1365
+ updateTaskData: jest.fn().mockImplementation((updatedData) => {
1366
+ // Mock the updateTaskData method to actually update task.data
1367
+ task.data = { ...task.data, ...updatedData };
1368
+ return task;
1369
+ }),
1370
+ };
1371
+ taskManager.taskCollection[taskId] = task;
1372
+ });
1373
+
1374
+ it('should handle AGENT_CONSULT_CONFERENCED event', () => {
1375
+ const payload = {
1376
+ data: {
1377
+ type: CC_EVENTS.AGENT_CONSULT_CONFERENCED,
1378
+ interactionId: taskId,
1379
+ isConferencing: true,
1380
+ },
1381
+ };
1382
+
1383
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1384
+
1385
+ expect(task.data.isConferencing).toBe(true);
1386
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
1387
+ });
1388
+
1389
+ it('should handle AGENT_CONSULT_CONFERENCING event', () => {
1390
+ const payload = {
1391
+ data: {
1392
+ type: CC_EVENTS.AGENT_CONSULT_CONFERENCING,
1393
+ interactionId: taskId,
1394
+ isConferencing: true,
1395
+ },
1396
+ };
1397
+
1398
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1399
+
1400
+ expect(task.data.isConferencing).toBe(true);
1401
+ // No task event emission for conferencing - only for conferenced (completed)
1402
+ expect(task.emit).not.toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
1403
+ });
1404
+
1405
+ it('should handle AGENT_CONSULT_CONFERENCE_FAILED event', () => {
1406
+ const payload = {
1407
+ data: {
1408
+ type: CC_EVENTS.AGENT_CONSULT_CONFERENCE_FAILED,
1409
+ interactionId: taskId,
1410
+ reason: 'Network error',
1411
+ },
1412
+ };
1413
+
1414
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1415
+
1416
+ expect(task.data.reason).toBe('Network error');
1417
+ // No event emission expected for failure - handled by contact method promise rejection
1418
+ });
1419
+
1420
+ it('should handle PARTICIPANT_JOINED_CONFERENCE event', () => {
1421
+ const payload = {
1422
+ data: {
1423
+ type: CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE,
1424
+ interactionId: taskId,
1425
+ participantId: 'new-participant-123',
1426
+ participantType: 'agent',
1427
+ },
1428
+ };
1429
+
1430
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1431
+
1432
+ expect(task.data.participantId).toBe('new-participant-123');
1433
+ expect(task.data.participantType).toBe('agent');
1434
+ // No specific task event emission for participant joined - just data update
1435
+ });
1436
+
1437
+ it('should handle PARTICIPANT_LEFT_CONFERENCE event', () => {
1438
+ const payload = {
1439
+ data: {
1440
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
1441
+ interactionId: taskId,
1442
+ isConferencing: false,
1443
+ },
1444
+ };
1445
+
1446
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1447
+
1448
+ expect(task.data.isConferencing).toBe(false);
1449
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
1450
+ });
1451
+
1452
+ it('should handle PARTICIPANT_LEFT_CONFERENCE_FAILED event', () => {
1453
+ const payload = {
1454
+ data: {
1455
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE_FAILED,
1456
+ interactionId: taskId,
1457
+ reason: 'Exit failed',
1458
+ },
1459
+ };
1460
+
1461
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1462
+
1463
+ expect(task.data.reason).toBe('Exit failed');
1464
+ // No event emission expected for failure - handled by contact method promise rejection
1465
+ });
1466
+
1467
+ it('should only update task for matching interactionId', () => {
1468
+ const otherTaskId = 'other-task-id';
1469
+ const otherTask = {
1470
+ data: { interactionId: otherTaskId },
1471
+ emit: jest.fn(),
1472
+ };
1473
+ taskManager.taskCollection[otherTaskId] = otherTask;
1474
+
1475
+ const payload = {
1476
+ data: {
1477
+ type: CC_EVENTS.AGENT_CONSULT_CONFERENCED,
1478
+ interactionId: taskId,
1479
+ isConferencing: true,
1480
+ },
1481
+ };
1482
+
1483
+ webSocketManagerMock.emit('message', JSON.stringify(payload));
1484
+
1485
+ // Only the matching task should be updated
1486
+ expect(task.data.isConferencing).toBe(true);
1487
+ expect(task.emit).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
1488
+
1489
+ // Other task should not be affected
1490
+ expect(otherTask.data.isConferencing).toBeUndefined();
1491
+ expect(otherTask.emit).not.toHaveBeenCalled();
1492
+ });
1349
1493
  });
1350
1494
  });
1351
1495
 
@@ -197,7 +197,37 @@ describe("Routing contacts", () => {
197
197
  const req = contact.wrapup({
198
198
  interactionId: "interactionId",
199
199
  data: { wrapUpReason: "testWrapUpReason", auxCodeId: "auxCodeID1234", isAutoWrapup: "on" }
200
- } as any);
200
+ } as any);
201
+ expect(req).toBeDefined();
202
+ });
203
+
204
+ it("consultConference", () => {
205
+ fakeAqm.pendingRequests = {};
206
+ const consultData = {
207
+ agentId: "current-agent-id",
208
+ to: "destination-agent-id",
209
+ destinationType: "agent"
210
+ };
211
+ const req = contact.consultConference({
212
+ interactionId: "test-interaction-123",
213
+ data: consultData
214
+ });
215
+ expect(req).toBeDefined();
216
+ });
217
+
218
+ it("exitConference", () => {
219
+ fakeAqm.pendingRequests = {};
220
+ const req = contact.exitConference({
221
+ interactionId: "test-interaction-456"
222
+ });
223
+ expect(req).toBeDefined();
224
+ });
225
+
226
+ it("conferenceTransfer", () => {
227
+ fakeAqm.pendingRequests = {};
228
+ const req = contact.conferenceTransfer({
229
+ interactionId: "test-interaction-transfer-123"
230
+ });
201
231
  expect(req).toBeDefined();
202
232
  });
203
233
  });