@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.
- package/dist/cc.js +106 -63
- package/dist/cc.js.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/logger-proxy.js +24 -1
- package/dist/logger-proxy.js.map +1 -1
- package/dist/metrics/MetricsManager.js +1 -1
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +88 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +26 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +271 -0
- package/dist/services/AddressBook.js.map +1 -0
- package/dist/services/EntryPoint.js +227 -0
- package/dist/services/EntryPoint.js.map +1 -0
- package/dist/services/Queue.js +261 -0
- package/dist/services/Queue.js.map +1 -0
- package/dist/services/config/constants.js +24 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +1 -43
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +22 -5
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/GlobalTypes.js.map +1 -1
- package/dist/services/core/Utils.js +162 -2
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +0 -4
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +0 -4
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/task/TaskManager.js +74 -2
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/constants.js +7 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +86 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/index.js +384 -72
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +14 -0
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +77 -43
- package/dist/types/index.d.ts +8 -3
- package/dist/types/metrics/constants.d.ts +20 -0
- package/dist/types/services/AddressBook.d.ts +74 -0
- package/dist/types/services/EntryPoint.d.ts +67 -0
- package/dist/types/services/Queue.d.ts +76 -0
- package/dist/types/services/config/constants.d.ts +23 -1
- package/dist/types/services/config/index.d.ts +1 -14
- package/dist/types/services/config/types.d.ts +44 -64
- package/dist/types/services/core/GlobalTypes.d.ts +25 -0
- package/dist/types/services/core/Utils.d.ts +40 -1
- package/dist/types/services/task/constants.d.ts +6 -0
- package/dist/types/services/task/contact.d.ts +10 -0
- package/dist/types/services/task/index.d.ts +44 -2
- package/dist/types/services/task/types.d.ts +123 -1
- package/dist/types/types.d.ts +162 -0
- package/dist/types/utils/PageCache.d.ts +173 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +192 -0
- package/dist/utils/PageCache.js.map +1 -0
- package/dist/webex.js +1 -1
- package/package.json +10 -10
- package/src/cc.ts +122 -81
- package/src/index.ts +19 -3
- package/src/logger-proxy.ts +24 -1
- package/src/metrics/MetricsManager.ts +1 -1
- package/src/metrics/behavioral-events.ts +92 -0
- package/src/metrics/constants.ts +30 -0
- package/src/services/AddressBook.ts +291 -0
- package/src/services/EntryPoint.ts +241 -0
- package/src/services/Queue.ts +277 -0
- package/src/services/config/constants.ts +26 -2
- package/src/services/config/index.ts +1 -55
- package/src/services/config/types.ts +22 -65
- package/src/services/core/GlobalTypes.ts +27 -0
- package/src/services/core/Utils.ts +199 -1
- package/src/services/core/aqm-reqs.ts +0 -5
- package/src/services/core/websocket/WebSocketManager.ts +0 -4
- package/src/services/task/TaskManager.ts +79 -3
- package/src/services/task/constants.ts +6 -0
- package/src/services/task/contact.ts +80 -0
- package/src/services/task/index.ts +457 -57
- package/src/services/task/types.ts +133 -0
- package/src/types.ts +180 -0
- package/src/utils/PageCache.ts +252 -0
- package/test/unit/spec/cc.ts +31 -82
- package/test/unit/spec/metrics/MetricsManager.ts +0 -1
- package/test/unit/spec/metrics/behavioral-events.ts +56 -0
- package/test/unit/spec/services/AddressBook.ts +332 -0
- package/test/unit/spec/services/EntryPoint.ts +259 -0
- package/test/unit/spec/services/Queue.ts +323 -0
- package/test/unit/spec/services/config/index.ts +0 -71
- package/test/unit/spec/services/core/Utils.ts +50 -0
- package/test/unit/spec/services/core/aqm-reqs.ts +1 -3
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +0 -4
- package/test/unit/spec/services/task/TaskManager.ts +145 -1
- package/test/unit/spec/services/task/contact.ts +31 -1
- package/test/unit/spec/services/task/index.ts +410 -123
- package/umd/contact-center.min.js +2 -2
- 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
|
-
|
|
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
|
});
|