@webex/contact-center 3.8.1 → 3.9.0-multi-llms.2
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 +196 -47
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.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 +32 -2
- 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 +36 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +29 -21
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +33 -1
- 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 +115 -35
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/index.d.ts +8 -3
- package/dist/types/metrics/constants.d.ts +25 -1
- 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 +35 -1
- package/dist/types/services/config/index.d.ts +6 -9
- package/dist/types/services/config/types.d.ts +79 -58
- 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 +125 -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 +11 -10
- package/src/cc.ts +221 -52
- package/src/constants.ts +1 -0
- 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 +37 -1
- 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 +42 -2
- package/src/services/config/index.ts +30 -30
- package/src/services/config/types.ts +59 -58
- 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 +135 -0
- package/src/types.ts +180 -0
- package/src/utils/PageCache.ts +252 -0
- package/test/unit/spec/cc.ts +77 -84
- 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 +279 -65
- 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
|
@@ -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 */
|
|
@@ -1052,66 +1074,45 @@ export type CallDistributionGroup = {
|
|
|
1052
1074
|
};
|
|
1053
1075
|
|
|
1054
1076
|
/**
|
|
1055
|
-
*
|
|
1077
|
+
* Represents a single outdial ANI (Automatic Number Identification) entry
|
|
1056
1078
|
* @public
|
|
1057
1079
|
*/
|
|
1058
|
-
export type
|
|
1059
|
-
/** Unique identifier for the
|
|
1080
|
+
export type OutdialAniEntry = {
|
|
1081
|
+
/** Unique identifier for the ANI entry */
|
|
1060
1082
|
id: string;
|
|
1061
|
-
/**
|
|
1083
|
+
/** Display name for the ANI entry */
|
|
1062
1084
|
name: string;
|
|
1063
|
-
/**
|
|
1064
|
-
|
|
1065
|
-
/**
|
|
1066
|
-
|
|
1067
|
-
/**
|
|
1068
|
-
|
|
1069
|
-
/**
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
recordingPauseDuration: number;
|
|
1097
|
-
/** Control flow script URL */
|
|
1098
|
-
controlFlowScriptUrl: string;
|
|
1099
|
-
/** IVR requeue URL */
|
|
1100
|
-
ivrRequeueUrl: string;
|
|
1101
|
-
/** Type of routing strategy */
|
|
1102
|
-
routingType: string;
|
|
1103
|
-
/** Queue-specific routing type */
|
|
1104
|
-
queueRoutingType: string;
|
|
1105
|
-
/** Queue skill requirements for routing */
|
|
1106
|
-
queueSkillRequirements: object[];
|
|
1107
|
-
/** Associated agents */
|
|
1108
|
-
agents: object[];
|
|
1109
|
-
/** Call distribution group configurations */
|
|
1110
|
-
callDistributionGroups: CallDistributionGroup[];
|
|
1111
|
-
/** Associated resource links */
|
|
1112
|
-
links: Array<string>;
|
|
1113
|
-
/** Timestamp when queue was created */
|
|
1114
|
-
createdTime: string;
|
|
1115
|
-
/** Timestamp when queue was last updated */
|
|
1116
|
-
lastUpdatedTime: string;
|
|
1085
|
+
/** Phone number associated with this ANI entry */
|
|
1086
|
+
number: string;
|
|
1087
|
+
/** Related links for this ANI entry */
|
|
1088
|
+
links: string[];
|
|
1089
|
+
/** Timestamp when this entry was created (Unix timestamp in milliseconds) */
|
|
1090
|
+
createdTime: number;
|
|
1091
|
+
/** Timestamp when this entry was last updated (Unix timestamp in milliseconds) */
|
|
1092
|
+
lastUpdatedTime: number;
|
|
1093
|
+
};
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Response structure for outdial ANI entries API call
|
|
1097
|
+
* @public
|
|
1098
|
+
*/
|
|
1099
|
+
export type OutdialAniEntriesResponse = OutdialAniEntry[];
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* Parameters for fetching outdial ANI entries
|
|
1103
|
+
* @public
|
|
1104
|
+
*/
|
|
1105
|
+
export type OutdialAniParams = {
|
|
1106
|
+
/** Outdial ANI ID from agent profile */
|
|
1107
|
+
outdialANI: string;
|
|
1108
|
+
/** Page number for pagination (optional) */
|
|
1109
|
+
page?: number;
|
|
1110
|
+
/** Number of entries per page (optional) */
|
|
1111
|
+
pageSize?: number;
|
|
1112
|
+
/** Search string to filter entries (optional) */
|
|
1113
|
+
search?: string;
|
|
1114
|
+
/** Filter expression for advanced filtering (optional) */
|
|
1115
|
+
filter?: string;
|
|
1116
|
+
/** Comma-separated list of attributes to include in response (optional) */
|
|
1117
|
+
attributes?: string;
|
|
1117
1118
|
};
|
|
@@ -32,3 +32,30 @@ export type Failure = Msg<{
|
|
|
32
32
|
/** Human-readable description of the failure reason */
|
|
33
33
|
reason: string;
|
|
34
34
|
}>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Represents task API error details in a structured format
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export interface TaskError {
|
|
41
|
+
/** Original error object for throwing */
|
|
42
|
+
error: Error;
|
|
43
|
+
/** Unique tracking identifier for correlation */
|
|
44
|
+
trackingId: string;
|
|
45
|
+
/** Detailed error message from the API */
|
|
46
|
+
errorMessage: string;
|
|
47
|
+
/** Type/category of the error (e.g., "Bad Request") */
|
|
48
|
+
errorType: string;
|
|
49
|
+
/** Additional error context data */
|
|
50
|
+
errorData: string;
|
|
51
|
+
/** Numeric reason code */
|
|
52
|
+
reasonCode: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* An Error object augmented with a flexible data field for additional context.
|
|
57
|
+
* Use this to attach structured data to thrown errors without ts-ignore.
|
|
58
|
+
*/
|
|
59
|
+
export interface AugmentedError extends Error {
|
|
60
|
+
data?: Record<string, any>;
|
|
61
|
+
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import * as Err from './Err';
|
|
2
2
|
import {LoginOption, WebexRequestPayload} from '../../types';
|
|
3
|
-
import {Failure} from './GlobalTypes';
|
|
3
|
+
import {Failure, AugmentedError} from './GlobalTypes';
|
|
4
4
|
import LoggerProxy from '../../logger-proxy';
|
|
5
5
|
import WebexRequest from './WebexRequest';
|
|
6
|
+
import {
|
|
7
|
+
TaskData,
|
|
8
|
+
ConsultTransferPayLoad,
|
|
9
|
+
ConsultConferenceData,
|
|
10
|
+
consultConferencePayloadData,
|
|
11
|
+
CONSULT_TRANSFER_DESTINATION_TYPE,
|
|
12
|
+
Interaction,
|
|
13
|
+
} from '../task/types';
|
|
6
14
|
|
|
7
15
|
/**
|
|
8
16
|
* Extracts common error details from a Webex request payload.
|
|
@@ -19,6 +27,28 @@ const getCommonErrorDetails = (errObj: WebexRequestPayload) => {
|
|
|
19
27
|
};
|
|
20
28
|
};
|
|
21
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Checks if the destination type represents an entry point variant (EPDN or ENTRYPOINT).
|
|
32
|
+
*/
|
|
33
|
+
const isEntryPointOrEpdn = (destAgentType?: string): boolean => {
|
|
34
|
+
return destAgentType === 'EPDN' || destAgentType === 'ENTRYPOINT';
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Determines if the task involves dialing a number based on the destination type.
|
|
39
|
+
* Returns 'DIAL_NUMBER' for dial-related destinations, empty string otherwise.
|
|
40
|
+
*/
|
|
41
|
+
const getAgentActionTypeFromTask = (taskData?: TaskData): 'DIAL_NUMBER' | '' => {
|
|
42
|
+
const destAgentType = taskData?.destinationType;
|
|
43
|
+
|
|
44
|
+
// Check if destination requires dialing: direct dial number or entry point variants
|
|
45
|
+
const isDialNumber = destAgentType === 'DN';
|
|
46
|
+
const isEntryPointVariant = isEntryPointOrEpdn(destAgentType);
|
|
47
|
+
|
|
48
|
+
// If the destination type is a dial number or an entry point variant, return 'DIAL_NUMBER'
|
|
49
|
+
return isDialNumber || isEntryPointVariant ? 'DIAL_NUMBER' : '';
|
|
50
|
+
};
|
|
51
|
+
|
|
22
52
|
export const isValidDialNumber = (input: string): boolean => {
|
|
23
53
|
// This regex checks for a valid dial number format for only few countries such as US, Canada.
|
|
24
54
|
const regexForDn = /1[0-9]{3}[2-9][0-9]{6}([,]{1,10}[0-9]+){0,1}/;
|
|
@@ -115,6 +145,62 @@ export const getErrorDetails = (error: any, methodName: string, moduleName: stri
|
|
|
115
145
|
};
|
|
116
146
|
};
|
|
117
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Extracts error details from task API errors and logs them. Also uploads logs for the error.
|
|
150
|
+
* This handles the specific error format returned by task API calls.
|
|
151
|
+
*
|
|
152
|
+
* @param error - The error object from task API calls with structure: {id: string, details: {trackingId: string, msg: {...}}}
|
|
153
|
+
* @param methodName - The name of the method where the error occurred.
|
|
154
|
+
* @param moduleName - The name of the module where the error occurred.
|
|
155
|
+
* @returns AugmentedError containing structured error details on err.data for metrics and logging
|
|
156
|
+
* @public
|
|
157
|
+
* @example
|
|
158
|
+
* const taskError = generateTaskErrorObject(error, 'transfer', 'TaskModule');
|
|
159
|
+
* throw taskError.error;
|
|
160
|
+
* @ignore
|
|
161
|
+
*/
|
|
162
|
+
export const generateTaskErrorObject = (
|
|
163
|
+
error: any,
|
|
164
|
+
methodName: string,
|
|
165
|
+
moduleName: string
|
|
166
|
+
): AugmentedError => {
|
|
167
|
+
const trackingId = error?.details?.trackingId || error?.trackingId || '';
|
|
168
|
+
const errorMsg = error?.details?.msg;
|
|
169
|
+
|
|
170
|
+
const fallbackMessage =
|
|
171
|
+
(error && typeof error.message === 'string' && error.message) ||
|
|
172
|
+
`Error while performing ${methodName}`;
|
|
173
|
+
const errorMessage = errorMsg?.errorMessage || fallbackMessage;
|
|
174
|
+
const errorType =
|
|
175
|
+
errorMsg?.errorType ||
|
|
176
|
+
(error && typeof error.name === 'string' && error.name) ||
|
|
177
|
+
'Unknown Error';
|
|
178
|
+
const errorData = errorMsg?.errorData || '';
|
|
179
|
+
const reasonCode = errorMsg?.reasonCode || 0;
|
|
180
|
+
|
|
181
|
+
// Log and upload for Task API formatted errors
|
|
182
|
+
LoggerProxy.error(`${methodName} failed: ${errorMessage} (${errorType})`, {
|
|
183
|
+
module: moduleName,
|
|
184
|
+
method: methodName,
|
|
185
|
+
trackingId,
|
|
186
|
+
});
|
|
187
|
+
WebexRequest.getInstance().uploadLogs({
|
|
188
|
+
correlationId: trackingId,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const reason = `${errorType}: ${errorMessage}${errorData ? ` (${errorData})` : ''}`;
|
|
192
|
+
const err: AugmentedError = new Error(reason);
|
|
193
|
+
err.data = {
|
|
194
|
+
message: errorMessage,
|
|
195
|
+
errorType,
|
|
196
|
+
errorData,
|
|
197
|
+
reasonCode,
|
|
198
|
+
trackingId,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
return err;
|
|
202
|
+
};
|
|
203
|
+
|
|
118
204
|
/**
|
|
119
205
|
* Creates an error details object suitable for use with the Err.Details class.
|
|
120
206
|
*
|
|
@@ -130,3 +216,115 @@ export const createErrDetailsObject = (errObj: WebexRequestPayload) => {
|
|
|
130
216
|
|
|
131
217
|
return new Err.Details('Service.reqs.generic.failure', details);
|
|
132
218
|
};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Derives the consult transfer destination type based on the provided task data.
|
|
222
|
+
*
|
|
223
|
+
* Logic parity with desktop behavior:
|
|
224
|
+
* - If agent action is dialing a number (DN/EPDN/ENTRYPOINT):
|
|
225
|
+
* - ENTRYPOINT/EPDN map to ENTRYPOINT
|
|
226
|
+
* - DN maps to DIALNUMBER
|
|
227
|
+
* - Otherwise defaults to AGENT
|
|
228
|
+
*
|
|
229
|
+
* @param taskData - The task data used to infer the agent action and destination type
|
|
230
|
+
* @returns The normalized destination type to be used for consult transfer
|
|
231
|
+
*/
|
|
232
|
+
/**
|
|
233
|
+
* Checks if a participant type represents a non-customer participant.
|
|
234
|
+
* Non-customer participants include agents, dial numbers, entry point dial numbers,
|
|
235
|
+
* and entry points.
|
|
236
|
+
*/
|
|
237
|
+
const isNonCustomerParticipant = (participantType: string): boolean => {
|
|
238
|
+
return (
|
|
239
|
+
participantType === 'Agent' ||
|
|
240
|
+
participantType === 'DN' ||
|
|
241
|
+
participantType === 'EpDn' ||
|
|
242
|
+
participantType === 'entryPoint'
|
|
243
|
+
);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Gets the destination agent ID from participants data by finding the first
|
|
248
|
+
* non-customer participant that is not the current agent and is not in wrap-up state.
|
|
249
|
+
*
|
|
250
|
+
* @param participants - The participants data from the interaction
|
|
251
|
+
* @param agentId - The current agent's ID to exclude from the search
|
|
252
|
+
* @returns The destination agent ID, or empty string if none found
|
|
253
|
+
*/
|
|
254
|
+
export const getDestinationAgentId = (
|
|
255
|
+
participants: Interaction['participants'],
|
|
256
|
+
agentId: string
|
|
257
|
+
): string => {
|
|
258
|
+
let id = '';
|
|
259
|
+
|
|
260
|
+
if (participants) {
|
|
261
|
+
Object.keys(participants).forEach((participant) => {
|
|
262
|
+
const participantData = participants[participant];
|
|
263
|
+
if (
|
|
264
|
+
isNonCustomerParticipant(participantData.type) &&
|
|
265
|
+
participantData.id !== agentId &&
|
|
266
|
+
!participantData.isWrapUp
|
|
267
|
+
) {
|
|
268
|
+
id = participantData.id;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return id;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
export const deriveConsultTransferDestinationType = (
|
|
277
|
+
taskData?: TaskData
|
|
278
|
+
): ConsultTransferPayLoad['destinationType'] => {
|
|
279
|
+
const agentActionType = getAgentActionTypeFromTask(taskData);
|
|
280
|
+
|
|
281
|
+
if (agentActionType === 'DIAL_NUMBER') {
|
|
282
|
+
return isEntryPointOrEpdn(taskData?.destinationType)
|
|
283
|
+
? CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT
|
|
284
|
+
: CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
|
|
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
|
+
};
|
|
@@ -178,10 +178,6 @@ export class WebSocketManager extends EventEmitter {
|
|
|
178
178
|
issueReason = 'WebSocket auto close timed out. Forcefully closed websocket.';
|
|
179
179
|
} else {
|
|
180
180
|
const onlineStatus = navigator.onLine;
|
|
181
|
-
LoggerProxy.info(`[WebSocketStatus] | desktop online status is ${onlineStatus}`, {
|
|
182
|
-
module: WEB_SOCKET_MANAGER_FILE,
|
|
183
|
-
method: METHODS.WEB_SOCKET_ON_CLOSE_HANDLER,
|
|
184
|
-
});
|
|
185
181
|
issueReason = !onlineStatus
|
|
186
182
|
? 'network issue'
|
|
187
183
|
: 'missing keepalive from either desktop or notif service';
|
|
@@ -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 ||
|
|
@@ -270,6 +286,7 @@ export default class TaskManager extends EventEmitter {
|
|
|
270
286
|
break;
|
|
271
287
|
case CC_EVENTS.AGENT_CONSULTING:
|
|
272
288
|
// Received when agent is in an active consult state
|
|
289
|
+
// TODO: Check if we can use backend consult state instead of isConsulted
|
|
273
290
|
task = this.updateTaskData(task, payload.data);
|
|
274
291
|
if (task.data.isConsulted) {
|
|
275
292
|
// Fire only if you are the agent who received the consult request
|
|
@@ -323,6 +340,65 @@ export default class TaskManager extends EventEmitter {
|
|
|
323
340
|
task = this.updateTaskData(task, payload.data);
|
|
324
341
|
task.emit(TASK_EVENTS.TASK_RECORDING_RESUME_FAILED, task);
|
|
325
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;
|
|
326
402
|
default:
|
|
327
403
|
break;
|
|
328
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
|
}
|