@webex/contact-center 3.9.0-next.10 → 3.9.0-next.11
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 +1 -0
- package/dist/cc.js.map +1 -1
- package/dist/metrics/behavioral-events.js +37 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +14 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/config/types.js +22 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Utils.js +42 -1
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/task/TaskManager.js +73 -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 +239 -1
- 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/metrics/constants.d.ts +13 -0
- package/dist/types/services/config/types.d.ts +44 -0
- package/dist/types/services/core/Utils.d.ts +14 -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 +43 -1
- package/dist/types/services/task/types.d.ts +123 -1
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/cc.ts +1 -0
- package/src/metrics/behavioral-events.ts +38 -0
- package/src/metrics/constants.ts +15 -0
- package/src/services/config/types.ts +22 -0
- package/src/services/core/Utils.ts +44 -0
- package/src/services/task/TaskManager.ts +78 -3
- package/src/services/task/constants.ts +6 -0
- package/src/services/task/contact.ts +80 -0
- package/src/services/task/index.ts +285 -1
- package/src/services/task/types.ts +133 -0
- package/test/unit/spec/cc.ts +1 -0
- package/test/unit/spec/metrics/behavioral-events.ts +42 -0
- package/test/unit/spec/services/task/TaskManager.ts +137 -0
- package/test/unit/spec/services/task/contact.ts +31 -1
- package/test/unit/spec/services/task/index.ts +184 -1
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
package/src/metrics/constants.ts
CHANGED
|
@@ -51,6 +51,13 @@ type Enum<T extends Record<string, unknown>> = T[keyof T];
|
|
|
51
51
|
* @property {string} TASK_ACCEPT_CONSULT_SUCCESS - Event name for successful consult acceptance.
|
|
52
52
|
* @property {string} TASK_ACCEPT_CONSULT_FAILED - Event name for failed consult acceptance.
|
|
53
53
|
*
|
|
54
|
+
* @property {string} TASK_CONFERENCE_START_SUCCESS - Event name for successful conference start.
|
|
55
|
+
* @property {string} TASK_CONFERENCE_START_FAILED - Event name for failed conference start.
|
|
56
|
+
* @property {string} TASK_CONFERENCE_END_SUCCESS - Event name for successful conference end.
|
|
57
|
+
* @property {string} TASK_CONFERENCE_END_FAILED - Event name for failed conference end.
|
|
58
|
+
* @property {string} TASK_CONFERENCE_TRANSFER_SUCCESS - Event name for successful conference transfer.
|
|
59
|
+
* @property {string} TASK_CONFERENCE_TRANSFER_FAILED - Event name for failed conference transfer.
|
|
60
|
+
*
|
|
54
61
|
* @property {string} TASK_OUTDIAL_SUCCESS - Event name for successful outdial task.
|
|
55
62
|
* @property {string} TASK_OUTDIAL_FAILED - Event name for failed outdial task.
|
|
56
63
|
*
|
|
@@ -109,6 +116,14 @@ export const METRIC_EVENT_NAMES = {
|
|
|
109
116
|
TASK_ACCEPT_CONSULT_SUCCESS: 'Task Accept Consult Success',
|
|
110
117
|
TASK_ACCEPT_CONSULT_FAILED: 'Task Accept Consult Failed',
|
|
111
118
|
|
|
119
|
+
// Conference Tasks
|
|
120
|
+
TASK_CONFERENCE_START_SUCCESS: 'Task Conference Start Success',
|
|
121
|
+
TASK_CONFERENCE_START_FAILED: 'Task Conference Start Failed',
|
|
122
|
+
TASK_CONFERENCE_END_SUCCESS: 'Task Conference End Success',
|
|
123
|
+
TASK_CONFERENCE_END_FAILED: 'Task Conference End Failed',
|
|
124
|
+
TASK_CONFERENCE_TRANSFER_SUCCESS: 'Task Conference Transfer Success',
|
|
125
|
+
TASK_CONFERENCE_TRANSFER_FAILED: 'Task Conference Transfer Failed',
|
|
126
|
+
|
|
112
127
|
TASK_OUTDIAL_SUCCESS: 'Task Outdial Success',
|
|
113
128
|
TASK_OUTDIAL_FAILED: 'Task Outdial Failed',
|
|
114
129
|
|
|
@@ -45,6 +45,28 @@ export const CC_TASK_EVENTS = {
|
|
|
45
45
|
AGENT_CONSULT_END_FAILED: 'AgentConsultEndFailed',
|
|
46
46
|
/** Event emitted when consultation conference ends */
|
|
47
47
|
AGENT_CONSULT_CONFERENCE_ENDED: 'AgentConsultConferenceEnded',
|
|
48
|
+
/** Event emitted when consultation conference is in progress */
|
|
49
|
+
AGENT_CONSULT_CONFERENCING: 'AgentConsultConferencing',
|
|
50
|
+
/** Event emitted when consultation conference starts */
|
|
51
|
+
AGENT_CONSULT_CONFERENCED: 'AgentConsultConferenced',
|
|
52
|
+
/** Event emitted when consultation conference fails */
|
|
53
|
+
AGENT_CONSULT_CONFERENCE_FAILED: 'AgentConsultConferenceFailed',
|
|
54
|
+
/** Event emitted when participant joins conference */
|
|
55
|
+
PARTICIPANT_JOINED_CONFERENCE: 'ParticipantJoinedConference',
|
|
56
|
+
/** Event emitted when participant leaves conference */
|
|
57
|
+
PARTICIPANT_LEFT_CONFERENCE: 'ParticipantLeftConference',
|
|
58
|
+
/** Event emitted when participant leaving conference fails */
|
|
59
|
+
PARTICIPANT_LEFT_CONFERENCE_FAILED: 'ParticipantLeftConferenceFailed',
|
|
60
|
+
/** Event emitted when consultation conference end fails */
|
|
61
|
+
AGENT_CONSULT_CONFERENCE_END_FAILED: 'AgentConsultConferenceEndFailed',
|
|
62
|
+
/** Event emitted when conference is successfully transferred */
|
|
63
|
+
AGENT_CONFERENCE_TRANSFERRED: 'AgentConferenceTransferred',
|
|
64
|
+
/** Event emitted when conference transfer fails */
|
|
65
|
+
AGENT_CONFERENCE_TRANSFER_FAILED: 'AgentConferenceTransferFailed',
|
|
66
|
+
/** Event emitted when consulted participant is moving/being transferred */
|
|
67
|
+
CONSULTED_PARTICIPANT_MOVING: 'ConsultedParticipantMoving',
|
|
68
|
+
/** Event emitted for post-call activity by participant */
|
|
69
|
+
PARTICIPANT_POST_CALL_ACTIVITY: 'ParticipantPostCallActivity',
|
|
48
70
|
/** Event emitted when contact is blind transferred */
|
|
49
71
|
AGENT_BLIND_TRANSFERRED: 'AgentBlindTransferred',
|
|
50
72
|
/** Event emitted when blind transfer fails */
|
|
@@ -6,6 +6,8 @@ import WebexRequest from './WebexRequest';
|
|
|
6
6
|
import {
|
|
7
7
|
TaskData,
|
|
8
8
|
ConsultTransferPayLoad,
|
|
9
|
+
ConsultConferenceData,
|
|
10
|
+
consultConferencePayloadData,
|
|
9
11
|
CONSULT_TRANSFER_DESTINATION_TYPE,
|
|
10
12
|
Interaction,
|
|
11
13
|
} from '../task/types';
|
|
@@ -284,3 +286,45 @@ export const deriveConsultTransferDestinationType = (
|
|
|
284
286
|
|
|
285
287
|
return CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
|
|
286
288
|
};
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Builds consult conference parameter data using EXACT Agent Desktop logic.
|
|
292
|
+
* This matches the Agent Desktop's consultConference implementation exactly.
|
|
293
|
+
*
|
|
294
|
+
* @param dataPassed - Original consultation data from Agent Desktop format
|
|
295
|
+
* @param interactionIdPassed - The interaction ID for the task
|
|
296
|
+
* @returns Object with interactionId and ConsultConferenceData matching Agent Desktop format
|
|
297
|
+
* @public
|
|
298
|
+
*/
|
|
299
|
+
export const buildConsultConferenceParamData = (
|
|
300
|
+
dataPassed: consultConferencePayloadData,
|
|
301
|
+
interactionIdPassed: string
|
|
302
|
+
): {interactionId: string; data: ConsultConferenceData} => {
|
|
303
|
+
const data: ConsultConferenceData = {
|
|
304
|
+
// Include agentId if present in input data
|
|
305
|
+
...('agentId' in dataPassed && {agentId: dataPassed.agentId}),
|
|
306
|
+
// Handle destAgentId from consultation data
|
|
307
|
+
to: dataPassed.destAgentId,
|
|
308
|
+
destinationType: '',
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// Agent Desktop destination type logic
|
|
312
|
+
if ('destinationType' in dataPassed) {
|
|
313
|
+
if (dataPassed.destinationType === 'DN') {
|
|
314
|
+
data.destinationType = CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER;
|
|
315
|
+
} else if (dataPassed.destinationType === 'EP_DN') {
|
|
316
|
+
data.destinationType = CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT;
|
|
317
|
+
} else {
|
|
318
|
+
// Keep the existing destinationType if it's something else (like "agent" or "Agent")
|
|
319
|
+
// Convert "Agent" to lowercase for consistency
|
|
320
|
+
data.destinationType = dataPassed.destinationType.toLowerCase();
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
data.destinationType = CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
interactionId: interactionIdPassed,
|
|
328
|
+
data,
|
|
329
|
+
};
|
|
330
|
+
};
|
|
@@ -28,6 +28,7 @@ export default class TaskManager extends EventEmitter {
|
|
|
28
28
|
private metricsManager: MetricsManager;
|
|
29
29
|
private static taskManager;
|
|
30
30
|
private wrapupData: WrapupData;
|
|
31
|
+
private agentId: string;
|
|
31
32
|
/**
|
|
32
33
|
* @param contact - Routing Contact layer. Talks to AQMReq layer to convert events to promises
|
|
33
34
|
* @param webCallingService - Webrtc Service Layer
|
|
@@ -52,6 +53,19 @@ export default class TaskManager extends EventEmitter {
|
|
|
52
53
|
this.wrapupData = wrapupData;
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
public setAgentId(agentId: string) {
|
|
57
|
+
this.agentId = agentId;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Gets the current agent ID
|
|
62
|
+
* @returns {string} The agent ID set for this task manager instance
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
public getAgentId(): string {
|
|
66
|
+
return this.agentId;
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
private handleIncomingWebCall = (call: ICall) => {
|
|
56
70
|
const currentTask = Object.values(this.taskCollection).find(
|
|
57
71
|
(task) => task.data.interaction.mediaType === 'telephony'
|
|
@@ -117,7 +131,8 @@ export default class TaskManager extends EventEmitter {
|
|
|
117
131
|
payload.data.interaction?.participants?.[payload.data.agentId]?.isWrapUp ||
|
|
118
132
|
false,
|
|
119
133
|
},
|
|
120
|
-
this.wrapupData
|
|
134
|
+
this.wrapupData,
|
|
135
|
+
this.agentId
|
|
121
136
|
);
|
|
122
137
|
this.taskCollection[payload.data.interactionId] = task;
|
|
123
138
|
// Condition 1: The state is=new i.e it is a incoming task
|
|
@@ -153,8 +168,9 @@ export default class TaskManager extends EventEmitter {
|
|
|
153
168
|
...payload.data,
|
|
154
169
|
isConsulted: false,
|
|
155
170
|
},
|
|
156
|
-
this.wrapupData
|
|
157
|
-
|
|
171
|
+
this.wrapupData,
|
|
172
|
+
this.agentId
|
|
173
|
+
);
|
|
158
174
|
this.taskCollection[payload.data.interactionId] = task;
|
|
159
175
|
if (
|
|
160
176
|
this.webCallingService.loginOption !== LoginOption.BROWSER ||
|
|
@@ -324,6 +340,65 @@ export default class TaskManager extends EventEmitter {
|
|
|
324
340
|
task = this.updateTaskData(task, payload.data);
|
|
325
341
|
task.emit(TASK_EVENTS.TASK_RECORDING_RESUME_FAILED, task);
|
|
326
342
|
break;
|
|
343
|
+
case CC_EVENTS.AGENT_CONSULT_CONFERENCING:
|
|
344
|
+
// Conference is being established - update task state and emit establishing event
|
|
345
|
+
task = this.updateTaskData(task, payload.data);
|
|
346
|
+
task.emit(TASK_EVENTS.TASK_CONFERENCE_ESTABLISHING, task);
|
|
347
|
+
break;
|
|
348
|
+
case CC_EVENTS.AGENT_CONSULT_CONFERENCED:
|
|
349
|
+
// Conference started successfully - update task state and emit event
|
|
350
|
+
task = this.updateTaskData(task, payload.data);
|
|
351
|
+
task.emit(TASK_EVENTS.TASK_CONFERENCE_STARTED, task);
|
|
352
|
+
break;
|
|
353
|
+
case CC_EVENTS.AGENT_CONSULT_CONFERENCE_FAILED:
|
|
354
|
+
// Conference failed - update task state and emit failure event
|
|
355
|
+
task = this.updateTaskData(task, payload.data);
|
|
356
|
+
task.emit(TASK_EVENTS.TASK_CONFERENCE_FAILED, task);
|
|
357
|
+
break;
|
|
358
|
+
case CC_EVENTS.AGENT_CONSULT_CONFERENCE_ENDED:
|
|
359
|
+
// Conference ended - update task state and emit event
|
|
360
|
+
task = this.updateTaskData(task, payload.data);
|
|
361
|
+
task.emit(TASK_EVENTS.TASK_CONFERENCE_ENDED, task);
|
|
362
|
+
break;
|
|
363
|
+
case CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE:
|
|
364
|
+
// Participant joined conference - update task state with participant information and emit event
|
|
365
|
+
task = this.updateTaskData(task, payload.data);
|
|
366
|
+
task.emit(TASK_EVENTS.TASK_PARTICIPANT_JOINED, task);
|
|
367
|
+
break;
|
|
368
|
+
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE:
|
|
369
|
+
// Conference ended - update task state and emit event
|
|
370
|
+
task = this.updateTaskData(task, payload.data);
|
|
371
|
+
task.emit(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
|
|
372
|
+
break;
|
|
373
|
+
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE_FAILED:
|
|
374
|
+
// Conference exit failed - update task state and emit failure event
|
|
375
|
+
task = this.updateTaskData(task, payload.data);
|
|
376
|
+
task.emit(TASK_EVENTS.TASK_PARTICIPANT_LEFT_FAILED, task);
|
|
377
|
+
break;
|
|
378
|
+
case CC_EVENTS.AGENT_CONSULT_CONFERENCE_END_FAILED:
|
|
379
|
+
// Conference end failed - update task state with error details and emit failure event
|
|
380
|
+
task = this.updateTaskData(task, payload.data);
|
|
381
|
+
task.emit(TASK_EVENTS.TASK_CONFERENCE_END_FAILED, task);
|
|
382
|
+
break;
|
|
383
|
+
case CC_EVENTS.AGENT_CONFERENCE_TRANSFERRED:
|
|
384
|
+
// Conference was transferred - update task state and emit transfer success event
|
|
385
|
+
// Note: Backend should provide hasLeft and wrapUpRequired status
|
|
386
|
+
task = this.updateTaskData(task, payload.data);
|
|
387
|
+
task.emit(TASK_EVENTS.TASK_CONFERENCE_TRANSFERRED, task);
|
|
388
|
+
break;
|
|
389
|
+
case CC_EVENTS.AGENT_CONFERENCE_TRANSFER_FAILED:
|
|
390
|
+
// Conference transfer failed - update task state with error details and emit failure event
|
|
391
|
+
task = this.updateTaskData(task, payload.data);
|
|
392
|
+
task.emit(TASK_EVENTS.TASK_CONFERENCE_TRANSFER_FAILED, task);
|
|
393
|
+
break;
|
|
394
|
+
case CC_EVENTS.CONSULTED_PARTICIPANT_MOVING:
|
|
395
|
+
// Participant is being moved/transferred - update task state with movement info
|
|
396
|
+
task = this.updateTaskData(task, payload.data);
|
|
397
|
+
break;
|
|
398
|
+
case CC_EVENTS.PARTICIPANT_POST_CALL_ACTIVITY:
|
|
399
|
+
// Post-call activity for participant - update task state with activity details
|
|
400
|
+
task = this.updateTaskData(task, payload.data);
|
|
401
|
+
break;
|
|
327
402
|
default:
|
|
328
403
|
break;
|
|
329
404
|
}
|
|
@@ -17,6 +17,9 @@ export const PAUSE = '/record/pause';
|
|
|
17
17
|
export const RESUME = '/record/resume';
|
|
18
18
|
export const WRAPUP = '/wrapup';
|
|
19
19
|
export const END = '/end';
|
|
20
|
+
export const CONSULT_CONFERENCE = '/consult/conference';
|
|
21
|
+
export const CONFERENCE_EXIT = '/conference/exit';
|
|
22
|
+
export const CONFERENCE_TRANSFER = '/conference/transfer';
|
|
20
23
|
export const TASK_MANAGER_FILE = 'taskManager';
|
|
21
24
|
export const TASK_FILE = 'task';
|
|
22
25
|
|
|
@@ -36,6 +39,9 @@ export const METHODS = {
|
|
|
36
39
|
END_CONSULT: 'endConsult',
|
|
37
40
|
TRANSFER: 'transfer',
|
|
38
41
|
CONSULT_TRANSFER: 'consultTransfer',
|
|
42
|
+
CONSULT_CONFERENCE: 'consultConference',
|
|
43
|
+
EXIT_CONFERENCE: 'exitConference',
|
|
44
|
+
TRANSFER_CONFERENCE: 'transferConference',
|
|
39
45
|
UPDATE_TASK_DATA: 'updateTaskData',
|
|
40
46
|
RECONCILE_DATA: 'reconcileData',
|
|
41
47
|
|
|
@@ -17,6 +17,9 @@ import {
|
|
|
17
17
|
TRANSFER,
|
|
18
18
|
UNHOLD,
|
|
19
19
|
WRAPUP,
|
|
20
|
+
CONSULT_CONFERENCE,
|
|
21
|
+
CONFERENCE_EXIT,
|
|
22
|
+
CONFERENCE_TRANSFER,
|
|
20
23
|
} from './constants';
|
|
21
24
|
import * as Contact from './types';
|
|
22
25
|
import {DESTINATION_TYPE} from './types';
|
|
@@ -425,5 +428,82 @@ export default function routingContact(aqm: AqmReqs) {
|
|
|
425
428
|
errId: 'Service.aqm.task.cancelCtq',
|
|
426
429
|
},
|
|
427
430
|
})),
|
|
431
|
+
|
|
432
|
+
/*
|
|
433
|
+
* Start consult conference
|
|
434
|
+
*/
|
|
435
|
+
consultConference: aqm.req(
|
|
436
|
+
(p: {interactionId: string; data: Contact.ConsultConferenceData}) => ({
|
|
437
|
+
url: `${TASK_API}${p.interactionId}${CONSULT_CONFERENCE}`,
|
|
438
|
+
data: p.data,
|
|
439
|
+
host: WCC_API_GATEWAY,
|
|
440
|
+
err,
|
|
441
|
+
notifSuccess: {
|
|
442
|
+
bind: {
|
|
443
|
+
type: TASK_MESSAGE_TYPE,
|
|
444
|
+
data: {
|
|
445
|
+
type: [CC_EVENTS.AGENT_CONSULT_CONFERENCED, CC_EVENTS.AGENT_CONSULT_CONFERENCING],
|
|
446
|
+
interactionId: p.interactionId,
|
|
447
|
+
}, // any of the two events can be received for API success event
|
|
448
|
+
},
|
|
449
|
+
msg: {} as Contact.AgentContact,
|
|
450
|
+
},
|
|
451
|
+
notifFail: {
|
|
452
|
+
bind: {
|
|
453
|
+
type: TASK_MESSAGE_TYPE,
|
|
454
|
+
data: {type: CC_EVENTS.AGENT_CONSULT_CONFERENCE_FAILED},
|
|
455
|
+
},
|
|
456
|
+
errId: 'Service.aqm.task.consultConference',
|
|
457
|
+
},
|
|
458
|
+
})
|
|
459
|
+
),
|
|
460
|
+
|
|
461
|
+
/*
|
|
462
|
+
* Exit conference
|
|
463
|
+
*/
|
|
464
|
+
exitConference: aqm.req((p: {interactionId: string}) => ({
|
|
465
|
+
url: `${TASK_API}${p.interactionId}${CONFERENCE_EXIT}`,
|
|
466
|
+
data: {},
|
|
467
|
+
host: WCC_API_GATEWAY,
|
|
468
|
+
err,
|
|
469
|
+
notifSuccess: {
|
|
470
|
+
bind: {
|
|
471
|
+
type: TASK_MESSAGE_TYPE,
|
|
472
|
+
data: {type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE, interactionId: p.interactionId},
|
|
473
|
+
},
|
|
474
|
+
msg: {} as Contact.AgentContact,
|
|
475
|
+
},
|
|
476
|
+
notifFail: {
|
|
477
|
+
bind: {
|
|
478
|
+
type: TASK_MESSAGE_TYPE,
|
|
479
|
+
data: {type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE_FAILED}, // to be finalized
|
|
480
|
+
},
|
|
481
|
+
errId: 'Service.aqm.task.consultConference',
|
|
482
|
+
},
|
|
483
|
+
})),
|
|
484
|
+
|
|
485
|
+
/*
|
|
486
|
+
* Transfer conference
|
|
487
|
+
*/
|
|
488
|
+
conferenceTransfer: aqm.req((p: {interactionId: string}) => ({
|
|
489
|
+
url: `${TASK_API}${p.interactionId}${CONFERENCE_TRANSFER}`,
|
|
490
|
+
data: {},
|
|
491
|
+
host: WCC_API_GATEWAY,
|
|
492
|
+
err,
|
|
493
|
+
notifSuccess: {
|
|
494
|
+
bind: {
|
|
495
|
+
type: TASK_MESSAGE_TYPE,
|
|
496
|
+
data: {type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE, interactionId: p.interactionId},
|
|
497
|
+
},
|
|
498
|
+
msg: {} as Contact.AgentContact,
|
|
499
|
+
},
|
|
500
|
+
notifFail: {
|
|
501
|
+
bind: {
|
|
502
|
+
type: TASK_MESSAGE_TYPE,
|
|
503
|
+
data: {type: CC_EVENTS.AGENT_CONFERENCE_TRANSFER_FAILED},
|
|
504
|
+
},
|
|
505
|
+
errId: 'Service.aqm.task.consultConference',
|
|
506
|
+
},
|
|
507
|
+
})),
|
|
428
508
|
};
|
|
429
509
|
}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
generateTaskErrorObject,
|
|
6
6
|
deriveConsultTransferDestinationType,
|
|
7
7
|
getDestinationAgentId,
|
|
8
|
+
buildConsultConferenceParamData,
|
|
8
9
|
} from '../core/Utils';
|
|
9
10
|
import {Failure} from '../core/GlobalTypes';
|
|
10
11
|
import {LoginOption} from '../../types';
|
|
@@ -138,6 +139,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
138
139
|
public webCallMap: Record<TaskId, CallId>;
|
|
139
140
|
private wrapupData: WrapupData;
|
|
140
141
|
public autoWrapup?: AutoWrapup;
|
|
142
|
+
private agentId: string;
|
|
141
143
|
|
|
142
144
|
/**
|
|
143
145
|
* Creates a new Task instance which provides the following features:
|
|
@@ -150,7 +152,8 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
150
152
|
contact: ReturnType<typeof routingContact>,
|
|
151
153
|
webCallingService: WebCallingService,
|
|
152
154
|
data: TaskData,
|
|
153
|
-
wrapupData: WrapupData
|
|
155
|
+
wrapupData: WrapupData,
|
|
156
|
+
agentId: string
|
|
154
157
|
) {
|
|
155
158
|
super();
|
|
156
159
|
this.contact = contact;
|
|
@@ -161,6 +164,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
161
164
|
this.metricsManager = MetricsManager.getInstance();
|
|
162
165
|
this.registerWebCallListeners();
|
|
163
166
|
this.setupAutoWrapupTimer();
|
|
167
|
+
this.agentId = agentId;
|
|
164
168
|
}
|
|
165
169
|
|
|
166
170
|
/**
|
|
@@ -1488,4 +1492,284 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1488
1492
|
throw err;
|
|
1489
1493
|
}
|
|
1490
1494
|
}
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* Starts a consultation conference by merging the consultation call with the main call
|
|
1498
|
+
*
|
|
1499
|
+
* Creates a three-way conference between the agent, customer, and consulted party
|
|
1500
|
+
* Extracts required consultation data from the current task data
|
|
1501
|
+
* On success, emits a `task:conferenceStarted` event
|
|
1502
|
+
*
|
|
1503
|
+
* @returns Promise<TaskResponse> - Response from the consultation conference API
|
|
1504
|
+
* @throws Error if the operation fails or if consultation data is invalid
|
|
1505
|
+
*
|
|
1506
|
+
* @example
|
|
1507
|
+
* ```typescript
|
|
1508
|
+
* try {
|
|
1509
|
+
* await task.consultConference();
|
|
1510
|
+
* console.log('Conference started successfully');
|
|
1511
|
+
* } catch (error) {
|
|
1512
|
+
* console.error('Failed to start conference:', error);
|
|
1513
|
+
* }
|
|
1514
|
+
* ```
|
|
1515
|
+
*/
|
|
1516
|
+
public async consultConference(): Promise<TaskResponse> {
|
|
1517
|
+
// Extract consultation conference data from task data (used in both try and catch)
|
|
1518
|
+
const consultationData = {
|
|
1519
|
+
agentId: this.agentId,
|
|
1520
|
+
destAgentId: this.data.destAgentId,
|
|
1521
|
+
destinationType: this.data.destinationType || 'agent',
|
|
1522
|
+
};
|
|
1523
|
+
|
|
1524
|
+
try {
|
|
1525
|
+
LoggerProxy.info(`Initiating consult conference to ${consultationData.destAgentId}`, {
|
|
1526
|
+
module: TASK_FILE,
|
|
1527
|
+
method: METHODS.CONSULT_CONFERENCE,
|
|
1528
|
+
interactionId: this.data.interactionId,
|
|
1529
|
+
});
|
|
1530
|
+
|
|
1531
|
+
const paramsDataForConferenceV2 = buildConsultConferenceParamData(
|
|
1532
|
+
consultationData,
|
|
1533
|
+
this.data.interactionId
|
|
1534
|
+
);
|
|
1535
|
+
|
|
1536
|
+
const response = await this.contact.consultConference({
|
|
1537
|
+
interactionId: paramsDataForConferenceV2.interactionId,
|
|
1538
|
+
data: paramsDataForConferenceV2.data,
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1541
|
+
// Track success metrics (following consultTransfer pattern)
|
|
1542
|
+
this.metricsManager.trackEvent(
|
|
1543
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_START_SUCCESS,
|
|
1544
|
+
{
|
|
1545
|
+
taskId: this.data.interactionId,
|
|
1546
|
+
destination: paramsDataForConferenceV2.data.to,
|
|
1547
|
+
destinationType: paramsDataForConferenceV2.data.destinationType,
|
|
1548
|
+
agentId: paramsDataForConferenceV2.data.agentId,
|
|
1549
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
1550
|
+
},
|
|
1551
|
+
['operational', 'behavioral', 'business']
|
|
1552
|
+
);
|
|
1553
|
+
|
|
1554
|
+
LoggerProxy.log(`Consult conference started successfully`, {
|
|
1555
|
+
module: TASK_FILE,
|
|
1556
|
+
method: METHODS.CONSULT_CONFERENCE,
|
|
1557
|
+
interactionId: this.data.interactionId,
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1560
|
+
return response;
|
|
1561
|
+
} catch (error) {
|
|
1562
|
+
const err = generateTaskErrorObject(error, METHODS.CONSULT_CONFERENCE, TASK_FILE);
|
|
1563
|
+
const taskErrorProps = {
|
|
1564
|
+
trackingId: err.data?.trackingId,
|
|
1565
|
+
errorMessage: err.data?.message,
|
|
1566
|
+
errorType: err.data?.errorType,
|
|
1567
|
+
errorData: err.data?.errorData,
|
|
1568
|
+
reasonCode: err.data?.reasonCode,
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
// Track failure metrics (following consultTransfer pattern)
|
|
1572
|
+
// Build conference data for error tracking using extracted data
|
|
1573
|
+
const failedParamsData = buildConsultConferenceParamData(
|
|
1574
|
+
consultationData,
|
|
1575
|
+
this.data.interactionId
|
|
1576
|
+
);
|
|
1577
|
+
|
|
1578
|
+
this.metricsManager.trackEvent(
|
|
1579
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_START_FAILED,
|
|
1580
|
+
{
|
|
1581
|
+
taskId: this.data.interactionId,
|
|
1582
|
+
destination: failedParamsData.data.to,
|
|
1583
|
+
destinationType: failedParamsData.data.destinationType,
|
|
1584
|
+
agentId: failedParamsData.data.agentId,
|
|
1585
|
+
error: error.toString(),
|
|
1586
|
+
...taskErrorProps,
|
|
1587
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1588
|
+
},
|
|
1589
|
+
['operational', 'behavioral', 'business']
|
|
1590
|
+
);
|
|
1591
|
+
|
|
1592
|
+
LoggerProxy.error(`Failed to start consult conference`, {
|
|
1593
|
+
module: TASK_FILE,
|
|
1594
|
+
method: METHODS.CONSULT_CONFERENCE,
|
|
1595
|
+
interactionId: this.data.interactionId,
|
|
1596
|
+
});
|
|
1597
|
+
|
|
1598
|
+
throw err;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
/**
|
|
1603
|
+
* Exits the current conference by removing the agent from the conference call
|
|
1604
|
+
*
|
|
1605
|
+
* Exits the agent from the conference, leaving the customer and consulted party connected
|
|
1606
|
+
* On success, emits a `task:conferenceEnded` event
|
|
1607
|
+
*
|
|
1608
|
+
* @returns Promise<TaskResponse> - Response from the conference exit API
|
|
1609
|
+
* @throws Error if the operation fails or if no active conference exists
|
|
1610
|
+
*
|
|
1611
|
+
* @example
|
|
1612
|
+
* ```typescript
|
|
1613
|
+
* try {
|
|
1614
|
+
* await task.exitConference();
|
|
1615
|
+
* console.log('Successfully exited conference');
|
|
1616
|
+
* } catch (error) {
|
|
1617
|
+
* console.error('Failed to exit conference:', error);
|
|
1618
|
+
* }
|
|
1619
|
+
* ```
|
|
1620
|
+
*/
|
|
1621
|
+
public async exitConference(): Promise<TaskResponse> {
|
|
1622
|
+
try {
|
|
1623
|
+
LoggerProxy.info(`Exiting consult conference`, {
|
|
1624
|
+
module: TASK_FILE,
|
|
1625
|
+
method: METHODS.EXIT_CONFERENCE,
|
|
1626
|
+
interactionId: this.data.interactionId,
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1629
|
+
// Validate that interaction ID exists
|
|
1630
|
+
if (!this.data.interactionId) {
|
|
1631
|
+
throw new Error('Invalid interaction ID');
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
const response = await this.contact.exitConference({
|
|
1635
|
+
interactionId: this.data.interactionId,
|
|
1636
|
+
});
|
|
1637
|
+
|
|
1638
|
+
// Track success metrics (following consultTransfer pattern)
|
|
1639
|
+
this.metricsManager.trackEvent(
|
|
1640
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_END_SUCCESS,
|
|
1641
|
+
{
|
|
1642
|
+
taskId: this.data.interactionId,
|
|
1643
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
1644
|
+
},
|
|
1645
|
+
['operational', 'behavioral', 'business']
|
|
1646
|
+
);
|
|
1647
|
+
|
|
1648
|
+
LoggerProxy.log(`Consult conference exited successfully`, {
|
|
1649
|
+
module: TASK_FILE,
|
|
1650
|
+
method: METHODS.EXIT_CONFERENCE,
|
|
1651
|
+
interactionId: this.data.interactionId,
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
return response;
|
|
1655
|
+
} catch (error) {
|
|
1656
|
+
const err = generateTaskErrorObject(error, METHODS.EXIT_CONFERENCE, TASK_FILE);
|
|
1657
|
+
const taskErrorProps = {
|
|
1658
|
+
trackingId: err.data?.trackingId,
|
|
1659
|
+
errorMessage: err.data?.message,
|
|
1660
|
+
errorType: err.data?.errorType,
|
|
1661
|
+
errorData: err.data?.errorData,
|
|
1662
|
+
reasonCode: err.data?.reasonCode,
|
|
1663
|
+
};
|
|
1664
|
+
|
|
1665
|
+
// Track failure metrics (following consultTransfer pattern)
|
|
1666
|
+
this.metricsManager.trackEvent(
|
|
1667
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_END_FAILED,
|
|
1668
|
+
{
|
|
1669
|
+
taskId: this.data.interactionId,
|
|
1670
|
+
error: error.toString(),
|
|
1671
|
+
...taskErrorProps,
|
|
1672
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1673
|
+
},
|
|
1674
|
+
['operational', 'behavioral', 'business']
|
|
1675
|
+
);
|
|
1676
|
+
|
|
1677
|
+
LoggerProxy.error(`Failed to exit consult conference`, {
|
|
1678
|
+
module: TASK_FILE,
|
|
1679
|
+
method: METHODS.EXIT_CONFERENCE,
|
|
1680
|
+
interactionId: this.data.interactionId,
|
|
1681
|
+
});
|
|
1682
|
+
|
|
1683
|
+
throw err;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
// TODO: Uncomment this method in future PR for Multi-Party Conference support (>3 participants)
|
|
1688
|
+
// Conference transfer will be supported when implementing enhanced multi-party conference functionality
|
|
1689
|
+
/*
|
|
1690
|
+
/**
|
|
1691
|
+
* Transfers the current conference to another agent
|
|
1692
|
+
*
|
|
1693
|
+
* Moves the entire conference (including all participants) to a new agent,
|
|
1694
|
+
* while the current agent exits and goes to wrapup
|
|
1695
|
+
* On success, the current agent receives `task:conferenceEnded` event
|
|
1696
|
+
*
|
|
1697
|
+
* @returns Promise<TaskResponse> - Response from the conference transfer API
|
|
1698
|
+
* @throws Error if the operation fails or if no active conference exists
|
|
1699
|
+
*
|
|
1700
|
+
* @example
|
|
1701
|
+
* ```typescript
|
|
1702
|
+
* try {
|
|
1703
|
+
* await task.transferConference();
|
|
1704
|
+
* console.log('Conference transferred successfully');
|
|
1705
|
+
* } catch (error) {
|
|
1706
|
+
* console.error('Failed to transfer conference:', error);
|
|
1707
|
+
* }
|
|
1708
|
+
* ```
|
|
1709
|
+
*/
|
|
1710
|
+
/* public async transferConference(): Promise<TaskResponse> {
|
|
1711
|
+
try {
|
|
1712
|
+
LoggerProxy.info(`Transferring conference`, {
|
|
1713
|
+
module: TASK_FILE,
|
|
1714
|
+
method: METHODS.TRANSFER_CONFERENCE,
|
|
1715
|
+
interactionId: this.data.interactionId,
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
// Validate that interaction ID exists
|
|
1719
|
+
if (!this.data.interactionId) {
|
|
1720
|
+
throw new Error('Invalid interaction ID');
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
const response = await this.contact.conferenceTransfer({
|
|
1724
|
+
interactionId: this.data.interactionId,
|
|
1725
|
+
});
|
|
1726
|
+
|
|
1727
|
+
// Track success metrics (following consultTransfer pattern)
|
|
1728
|
+
this.metricsManager.trackEvent(
|
|
1729
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_SUCCESS,
|
|
1730
|
+
{
|
|
1731
|
+
taskId: this.data.interactionId,
|
|
1732
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
1733
|
+
},
|
|
1734
|
+
['operational', 'behavioral', 'business']
|
|
1735
|
+
);
|
|
1736
|
+
|
|
1737
|
+
LoggerProxy.log(`Conference transferred successfully`, {
|
|
1738
|
+
module: TASK_FILE,
|
|
1739
|
+
method: METHODS.TRANSFER_CONFERENCE,
|
|
1740
|
+
interactionId: this.data.interactionId,
|
|
1741
|
+
});
|
|
1742
|
+
|
|
1743
|
+
return response;
|
|
1744
|
+
} catch (error) {
|
|
1745
|
+
const err = generateTaskErrorObject(error, METHODS.TRANSFER_CONFERENCE, TASK_FILE);
|
|
1746
|
+
const taskErrorProps = {
|
|
1747
|
+
trackingId: err.data?.trackingId,
|
|
1748
|
+
errorMessage: err.data?.message,
|
|
1749
|
+
errorType: err.data?.errorType,
|
|
1750
|
+
errorData: err.data?.errorData,
|
|
1751
|
+
reasonCode: err.data?.reasonCode,
|
|
1752
|
+
};
|
|
1753
|
+
|
|
1754
|
+
// Track failure metrics (following consultTransfer pattern)
|
|
1755
|
+
this.metricsManager.trackEvent(
|
|
1756
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_FAILED,
|
|
1757
|
+
{
|
|
1758
|
+
taskId: this.data.interactionId,
|
|
1759
|
+
error: error.toString(),
|
|
1760
|
+
...taskErrorProps,
|
|
1761
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1762
|
+
},
|
|
1763
|
+
['operational', 'behavioral', 'business']
|
|
1764
|
+
);
|
|
1765
|
+
|
|
1766
|
+
LoggerProxy.error(`Failed to transfer conference`, {
|
|
1767
|
+
module: TASK_FILE,
|
|
1768
|
+
method: METHODS.TRANSFER_CONFERENCE,
|
|
1769
|
+
interactionId: this.data.interactionId,
|
|
1770
|
+
});
|
|
1771
|
+
|
|
1772
|
+
throw err;
|
|
1773
|
+
}
|
|
1774
|
+
} */
|
|
1491
1775
|
}
|