@webex/contact-center 3.12.0-next.9 → 3.12.0-task-refactor.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/AGENTS.md +438 -0
- package/ai-docs/README.md +131 -0
- package/ai-docs/RULES.md +455 -0
- package/ai-docs/patterns/event-driven-patterns.md +485 -0
- package/ai-docs/patterns/testing-patterns.md +480 -0
- package/ai-docs/patterns/typescript-patterns.md +365 -0
- package/ai-docs/templates/README.md +102 -0
- package/ai-docs/templates/documentation/create-agents-md.md +240 -0
- package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
- package/ai-docs/templates/existing-service/bug-fix.md +254 -0
- package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
- package/ai-docs/templates/new-method/00-master.md +80 -0
- package/ai-docs/templates/new-method/01-requirements.md +232 -0
- package/ai-docs/templates/new-method/02-implementation.md +295 -0
- package/ai-docs/templates/new-method/03-tests.md +201 -0
- package/ai-docs/templates/new-method/04-validation.md +141 -0
- package/ai-docs/templates/new-service/00-master.md +109 -0
- package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
- package/ai-docs/templates/new-service/02-code-generation.md +346 -0
- package/ai-docs/templates/new-service/03-integration.md +178 -0
- package/ai-docs/templates/new-service/04-test-generation.md +205 -0
- package/ai-docs/templates/new-service/05-validation.md +145 -0
- package/dist/cc.js +65 -123
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +13 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +26 -13
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +7 -6
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +0 -3
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/config/Util.js +2 -3
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/types.js +16 -14
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +0 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +79 -55
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +17 -92
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +5 -25
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +1 -2
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +644 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +45 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +556 -532
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +132 -28
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +7 -6
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/dialer.js +0 -51
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/digital/Digital.js +77 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +634 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +366 -0
- package/dist/services/task/state-machine/actions.js.map +1 -0
- package/dist/services/task/state-machine/constants.js +139 -0
- package/dist/services/task/state-machine/constants.js.map +1 -0
- package/dist/services/task/state-machine/guards.js +256 -0
- package/dist/services/task/state-machine/guards.js.map +1 -0
- package/dist/services/task/state-machine/index.js +53 -0
- package/dist/services/task/state-machine/index.js.map +1 -0
- package/dist/services/task/state-machine/types.js +54 -0
- package/dist/services/task/state-machine/types.js.map +1 -0
- package/dist/services/task/state-machine/uiControlsComputer.js +369 -0
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
- package/dist/services/task/taskDataNormalizer.js +99 -0
- package/dist/services/task/taskDataNormalizer.js.map +1 -0
- package/dist/services/task/types.js +157 -18
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1031 -0
- package/dist/services/task/voice/Voice.js.map +1 -0
- package/dist/services/task/voice/WebRTC.js +149 -0
- package/dist/services/task/voice/WebRTC.js.map +1 -0
- package/dist/types/cc.d.ts +4 -33
- package/dist/types/constants.d.ts +13 -2
- package/dist/types/index.d.ts +11 -5
- package/dist/types/metrics/constants.d.ts +5 -3
- package/dist/types/services/ApiAiAssistant.d.ts +1 -1
- package/dist/types/services/config/types.d.ts +97 -25
- package/dist/types/services/core/Err.d.ts +0 -2
- package/dist/types/services/core/Utils.d.ts +25 -23
- package/dist/types/services/core/aqm-reqs.d.ts +0 -49
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -1
- package/dist/types/services/core/websocket/connection-service.d.ts +0 -1
- package/dist/types/services/core/websocket/types.d.ts +1 -1
- package/dist/types/services/index.d.ts +1 -1
- package/dist/types/services/task/Task.d.ts +146 -0
- package/dist/types/services/task/TaskFactory.d.ts +12 -0
- package/dist/types/services/task/TaskUtils.d.ts +39 -8
- package/dist/types/services/task/constants.d.ts +5 -4
- package/dist/types/services/task/dialer.d.ts +0 -15
- package/dist/types/services/task/digital/Digital.d.ts +22 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +906 -0
- package/dist/types/services/task/state-machine/actions.d.ts +8 -0
- package/dist/types/services/task/state-machine/constants.d.ts +91 -0
- package/dist/types/services/task/state-machine/guards.d.ts +78 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +256 -0
- package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
- package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
- package/dist/types/services/task/types.d.ts +539 -88
- package/dist/types/services/task/voice/Voice.d.ts +183 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/types.d.ts +68 -0
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +70 -0
- package/dist/types.js.map +1 -1
- package/dist/webex.js +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +14 -11
- package/src/cc.ts +91 -177
- package/src/constants.ts +13 -2
- package/src/index.ts +14 -5
- package/src/metrics/ai-docs/AGENTS.md +348 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
- package/src/metrics/behavioral-events.ts +28 -14
- package/src/metrics/constants.ts +7 -8
- package/src/services/ApiAiAssistant.ts +2 -4
- package/src/services/agent/ai-docs/AGENTS.md +238 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
- package/src/services/ai-docs/AGENTS.md +384 -0
- package/src/services/config/Util.ts +2 -3
- package/src/services/config/ai-docs/AGENTS.md +253 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
- package/src/services/config/types.ts +108 -20
- package/src/services/constants.ts +0 -1
- package/src/services/core/Err.ts +0 -1
- package/src/services/core/Utils.ts +90 -67
- package/src/services/core/ai-docs/AGENTS.md +379 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
- package/src/services/core/aqm-reqs.ts +22 -100
- package/src/services/core/websocket/WebSocketManager.ts +4 -23
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +1 -2
- package/src/services/task/Task.ts +785 -0
- package/src/services/task/TaskFactory.ts +55 -0
- package/src/services/task/TaskManager.ts +567 -633
- package/src/services/task/TaskUtils.ts +175 -31
- package/src/services/task/ai-docs/AGENTS.md +448 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +573 -0
- package/src/services/task/constants.ts +5 -4
- package/src/services/task/dialer.ts +1 -56
- package/src/services/task/digital/Digital.ts +95 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +793 -0
- package/src/services/task/state-machine/actions.ts +409 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
- package/src/services/task/state-machine/constants.ts +150 -0
- package/src/services/task/state-machine/guards.ts +295 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +228 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +529 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +641 -95
- package/src/services/task/voice/Voice.ts +1255 -0
- package/src/services/task/voice/WebRTC.ts +187 -0
- package/src/types.ts +88 -5
- package/src/utils/AGENTS.md +276 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +59 -142
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +17 -0
- package/test/unit/spec/services/config/index.ts +26 -55
- package/test/unit/spec/services/core/Utils.ts +103 -52
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +48 -112
- package/test/unit/spec/services/core/websocket/connection-service.ts +5 -4
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +416 -0
- package/test/unit/spec/services/task/TaskFactory.ts +62 -0
- package/test/unit/spec/services/task/TaskManager.ts +781 -1735
- package/test/unit/spec/services/task/TaskUtils.ts +125 -0
- package/test/unit/spec/services/task/dialer.ts +112 -198
- package/test/unit/spec/services/task/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +473 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +288 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +147 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +587 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +242 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/index.js +0 -1525
- package/dist/services/task/index.js.map +0 -1
- package/dist/types/services/task/index.d.ts +0 -650
- package/src/services/task/index.ts +0 -1801
- package/test/unit/spec/services/task/index.ts +0 -2184
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for the task state machine.
|
|
3
|
+
* These enums define the allowed states, events, and built-in action identifiers.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ============================================
|
|
7
|
+
// Conference Constants
|
|
8
|
+
// ============================================
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Maximum number of participants allowed in a multi-party conference.
|
|
12
|
+
* Max 7 counted agents + 1 customer.
|
|
13
|
+
*/
|
|
14
|
+
export const MAX_PARTICIPANTS_IN_MULTIPARTY_CONFERENCE = 7;
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// Participant Type Constants
|
|
18
|
+
// ============================================
|
|
19
|
+
|
|
20
|
+
/** Participant types for conference filtering */
|
|
21
|
+
export const PARTICIPANT_TYPE = {
|
|
22
|
+
CUSTOMER: 'Customer',
|
|
23
|
+
SUPERVISOR: 'Supervisor',
|
|
24
|
+
VVA: 'VVA',
|
|
25
|
+
} as const;
|
|
26
|
+
|
|
27
|
+
export type ParticipantType = (typeof PARTICIPANT_TYPE)[keyof typeof PARTICIPANT_TYPE];
|
|
28
|
+
|
|
29
|
+
// ============================================
|
|
30
|
+
// Media Type Constants
|
|
31
|
+
// ============================================
|
|
32
|
+
|
|
33
|
+
/** Media type for consult calls */
|
|
34
|
+
export const MEDIA_TYPE_CONSULT = 'consult';
|
|
35
|
+
|
|
36
|
+
/** Media type for main calls */
|
|
37
|
+
export const MEDIA_TYPE_MAIN_CALL = 'mainCall';
|
|
38
|
+
|
|
39
|
+
// ============================================
|
|
40
|
+
// State Machine Enums
|
|
41
|
+
// ============================================
|
|
42
|
+
|
|
43
|
+
export enum TaskState {
|
|
44
|
+
IDLE = 'IDLE',
|
|
45
|
+
OFFERED = 'OFFERED',
|
|
46
|
+
CONNECTED = 'CONNECTED',
|
|
47
|
+
|
|
48
|
+
// Intermediate states for async operations
|
|
49
|
+
HOLD_INITIATING = 'HOLD_INITIATING',
|
|
50
|
+
HELD = 'HELD',
|
|
51
|
+
RESUME_INITIATING = 'RESUME_INITIATING',
|
|
52
|
+
CONSULT_INITIATING = 'CONSULT_INITIATING',
|
|
53
|
+
CONSULTING = 'CONSULTING',
|
|
54
|
+
CONF_INITIATING = 'CONF_INITIATING',
|
|
55
|
+
|
|
56
|
+
CONFERENCING = 'CONFERENCING',
|
|
57
|
+
WRAPPING_UP = 'WRAPPING_UP',
|
|
58
|
+
COMPLETED = 'COMPLETED',
|
|
59
|
+
TERMINATED = 'TERMINATED',
|
|
60
|
+
|
|
61
|
+
// NOT IMPLEMENTED: MPC (Multi-Party Conference) states
|
|
62
|
+
CONSULT_INITIATED = 'CONSULT_INITIATED',
|
|
63
|
+
CONSULT_COMPLETED = 'CONSULT_COMPLETED',
|
|
64
|
+
// NOT IMPLEMENTED: Post-call state (isWxccPostCallEnabled feature flag)
|
|
65
|
+
POST_CALL = 'POST_CALL',
|
|
66
|
+
// NOT IMPLEMENTED: Parked state
|
|
67
|
+
PARKED = 'PARKED',
|
|
68
|
+
// NOT IMPLEMENTED: Monitoring/Supervisory states
|
|
69
|
+
MONITORING = 'MONITORING',
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export enum TaskEvent {
|
|
73
|
+
TASK_INCOMING = 'TASK_INCOMING',
|
|
74
|
+
TASK_OFFERED = 'TASK_OFFERED',
|
|
75
|
+
|
|
76
|
+
// Offer events
|
|
77
|
+
OFFER_CONSULT = 'OFFER_CONSULT',
|
|
78
|
+
HYDRATE = 'HYDRATE',
|
|
79
|
+
|
|
80
|
+
// Internal "data refresh" events
|
|
81
|
+
CONTACT_UPDATED = 'CONTACT_UPDATED',
|
|
82
|
+
CONTACT_OWNER_CHANGED = 'CONTACT_OWNER_CHANGED',
|
|
83
|
+
|
|
84
|
+
// Assignment events
|
|
85
|
+
ASSIGN = 'ASSIGN',
|
|
86
|
+
|
|
87
|
+
// Hold/Resume events
|
|
88
|
+
HOLD_SUCCESS = 'HOLD_SUCCESS',
|
|
89
|
+
HOLD_FAILED = 'HOLD_FAILED',
|
|
90
|
+
UNHOLD_SUCCESS = 'UNHOLD_SUCCESS',
|
|
91
|
+
UNHOLD_FAILED = 'UNHOLD_FAILED',
|
|
92
|
+
HOLD_INITIATED = 'HOLD_INITIATED',
|
|
93
|
+
UNHOLD_INITIATED = 'UNHOLD_INITIATED',
|
|
94
|
+
|
|
95
|
+
// Consult events
|
|
96
|
+
CONSULT = 'CONSULT',
|
|
97
|
+
CONSULT_SUCCESS = 'CONSULT_SUCCESS',
|
|
98
|
+
CONSULT_CREATED = 'CONSULT_CREATED',
|
|
99
|
+
CONSULTING_ACTIVE = 'CONSULTING_ACTIVE',
|
|
100
|
+
CONSULT_END = 'CONSULT_END',
|
|
101
|
+
CONSULT_FAILED = 'CONSULT_FAILED',
|
|
102
|
+
|
|
103
|
+
// Conference events
|
|
104
|
+
MERGE_TO_CONFERENCE = 'MERGE_TO_CONFERENCE',
|
|
105
|
+
CONFERENCE_START = 'CONFERENCE_START',
|
|
106
|
+
CONFERENCE_FAILED = 'CONFERENCE_FAILED',
|
|
107
|
+
CONFERENCE_END = 'CONFERENCE_END',
|
|
108
|
+
TRANSFER_CONFERENCE = 'TRANSFER_CONFERENCE',
|
|
109
|
+
TRANSFER_CONFERENCE_SUCCESS = 'TRANSFER_CONFERENCE_SUCCESS',
|
|
110
|
+
TRANSFER_CONFERENCE_FAILED = 'TRANSFER_CONFERENCE_FAILED',
|
|
111
|
+
PARTICIPANT_LEAVE = 'PARTICIPANT_LEAVE',
|
|
112
|
+
EXIT_CONFERENCE = 'EXIT_CONFERENCE',
|
|
113
|
+
EXIT_CONFERENCE_SUCCESS = 'EXIT_CONFERENCE_SUCCESS',
|
|
114
|
+
EXIT_CONFERENCE_FAILED = 'EXIT_CONFERENCE_FAILED',
|
|
115
|
+
|
|
116
|
+
// Recording events
|
|
117
|
+
RECORDING_STARTED = 'RECORDING_STARTED',
|
|
118
|
+
PAUSE_RECORDING = 'PAUSE_RECORDING',
|
|
119
|
+
RESUME_RECORDING = 'RESUME_RECORDING',
|
|
120
|
+
|
|
121
|
+
// Transfer events
|
|
122
|
+
TRANSFER_SUCCESS = 'TRANSFER_SUCCESS',
|
|
123
|
+
TRANSFER_FAILED = 'TRANSFER_FAILED',
|
|
124
|
+
|
|
125
|
+
// Wrapup events
|
|
126
|
+
WRAPUP_COMPLETE = 'WRAPUP_COMPLETE',
|
|
127
|
+
|
|
128
|
+
// End events
|
|
129
|
+
TASK_WRAPUP = 'TASK_WRAPUP',
|
|
130
|
+
RONA = 'RONA', // Ring On No Answer
|
|
131
|
+
CONTACT_ENDED = 'CONTACT_ENDED',
|
|
132
|
+
|
|
133
|
+
// Failure events
|
|
134
|
+
ASSIGN_FAILED = 'ASSIGN_FAILED',
|
|
135
|
+
INVITE_FAILED = 'INVITE_FAILED',
|
|
136
|
+
OUTBOUND_FAILED = 'OUTBOUND_FAILED',
|
|
137
|
+
|
|
138
|
+
// Switch events (toggle between consult and main call)
|
|
139
|
+
SWITCH_TO_MAIN_CALL = 'SWITCH_TO_MAIN_CALL',
|
|
140
|
+
SWITCH_TO_CONSULT = 'SWITCH_TO_CONSULT',
|
|
141
|
+
|
|
142
|
+
// Accept/Decline (WebRTC)
|
|
143
|
+
ACCEPT = 'ACCEPT',
|
|
144
|
+
DECLINE = 'DECLINE',
|
|
145
|
+
END = 'END',
|
|
146
|
+
|
|
147
|
+
// Queue events
|
|
148
|
+
CTQ_CANCEL = 'CTQ_CANCEL', // Cancel To Queue
|
|
149
|
+
CTQ_CANCEL_FAILED = 'CTQ_CANCEL_FAILED',
|
|
150
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task State Machine Guards
|
|
3
|
+
*
|
|
4
|
+
* Guard functions that determine if a state transition is allowed.
|
|
5
|
+
* These functions validate the current context before allowing transitions.
|
|
6
|
+
*
|
|
7
|
+
* All guards are consolidated here for:
|
|
8
|
+
* - Single source of truth
|
|
9
|
+
* - Easy testing
|
|
10
|
+
* - Reusability across state machine transitions
|
|
11
|
+
*
|
|
12
|
+
* Guards are organized by category:
|
|
13
|
+
* 1. Helper Functions - Extract data from events/context
|
|
14
|
+
* 2. Hydrate Guards - For state restoration on page refresh
|
|
15
|
+
* 3. Conference Guards - Conference state checks
|
|
16
|
+
* 4. Customer Guards - Customer presence checks
|
|
17
|
+
* 5. Consult Guards - Consult flow checks
|
|
18
|
+
* 6. Wrapup Guards - End-of-call flow checks
|
|
19
|
+
* 7. Server State Guards - Check backend-reported state
|
|
20
|
+
* 8. Recording Guards - Recording state checks
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import {TaskContext, TaskEventPayload} from './types';
|
|
24
|
+
import {TaskData} from '../types';
|
|
25
|
+
import {
|
|
26
|
+
getIsCustomerInCall,
|
|
27
|
+
getConferenceParticipantsCount,
|
|
28
|
+
getIsConferenceInProgress,
|
|
29
|
+
} from '../TaskUtils';
|
|
30
|
+
import {TaskEvent} from './constants';
|
|
31
|
+
|
|
32
|
+
export const getTaskDataFromEvent = (event?: TaskEventPayload): TaskData | undefined =>
|
|
33
|
+
event && typeof event === 'object' && 'taskData' in event
|
|
34
|
+
? (event as {taskData?: TaskData}).taskData
|
|
35
|
+
: undefined;
|
|
36
|
+
|
|
37
|
+
export const getSelfAgentId = (context: TaskContext, taskData?: TaskData): string | undefined =>
|
|
38
|
+
context.uiControlConfig?.agentId ?? context.taskData?.agentId ?? taskData?.agentId;
|
|
39
|
+
|
|
40
|
+
export const isSelfConsultingAgent = (context: TaskContext, taskData?: TaskData): boolean => {
|
|
41
|
+
const selfAgentId = getSelfAgentId(context, taskData);
|
|
42
|
+
if (!selfAgentId) return false;
|
|
43
|
+
|
|
44
|
+
return taskData?.consultingAgentId === selfAgentId;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Determines if this agent should enter WRAPPING_UP state.
|
|
49
|
+
* Priority: agentsPendingWrapUp > wrapUpRequired / participant.isWrapUp > ownership > !isConsulted
|
|
50
|
+
*/
|
|
51
|
+
export const shouldWrapUpForThisAgent = (context: TaskContext, taskData: TaskData): boolean => {
|
|
52
|
+
const selfAgentId = getSelfAgentId(context, taskData);
|
|
53
|
+
if (!selfAgentId) return false;
|
|
54
|
+
|
|
55
|
+
const pending = taskData?.agentsPendingWrapUp;
|
|
56
|
+
if (Array.isArray(pending) && pending.length > 0) {
|
|
57
|
+
return pending.includes(selfAgentId);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const participantWrapUp = taskData?.interaction?.participants?.[selfAgentId]?.isWrapUp === true;
|
|
61
|
+
const wrapUpRequired = taskData?.wrapUpRequired === true;
|
|
62
|
+
if (wrapUpRequired || participantWrapUp) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const owner = taskData?.interaction?.owner;
|
|
67
|
+
if (owner && owner === selfAgentId) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (taskData?.isConsulted === false) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return false;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export interface GuardParams {
|
|
79
|
+
context: TaskContext;
|
|
80
|
+
event?: TaskEventPayload;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type GuardFunction = (params: GuardParams) => boolean;
|
|
84
|
+
|
|
85
|
+
export const guards = {
|
|
86
|
+
// Hydrate Guards
|
|
87
|
+
isInteractionTerminated: ({context, event}: GuardParams): boolean => {
|
|
88
|
+
const taskData = getTaskDataFromEvent(event);
|
|
89
|
+
|
|
90
|
+
if (taskData?.interaction?.isTerminated === true) return true;
|
|
91
|
+
|
|
92
|
+
const selfAgentId = getSelfAgentId(context, taskData);
|
|
93
|
+
if (selfAgentId && taskData?.interaction?.participants?.[selfAgentId]?.isWrapUp === true) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return false;
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
isInteractionConsulting: ({event}: GuardParams): boolean => {
|
|
101
|
+
const taskData = getTaskDataFromEvent(event);
|
|
102
|
+
|
|
103
|
+
return taskData?.interaction?.state === 'consulting';
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
isInteractionHeld: ({event}: GuardParams): boolean => {
|
|
107
|
+
const taskData = getTaskDataFromEvent(event);
|
|
108
|
+
|
|
109
|
+
if (taskData?.interaction?.state === 'hold') return true;
|
|
110
|
+
|
|
111
|
+
const mainMediaId = taskData?.interaction?.mainInteractionId || taskData?.interactionId;
|
|
112
|
+
if (mainMediaId && taskData?.interaction?.media?.[mainMediaId]?.isHold === true) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return false;
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
isInteractionConnected: ({event}: GuardParams): boolean => {
|
|
120
|
+
const taskData = getTaskDataFromEvent(event);
|
|
121
|
+
|
|
122
|
+
return taskData?.interaction?.state === 'connected';
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
isConferencingByParticipants: ({event}: GuardParams): boolean => {
|
|
126
|
+
const taskData = getTaskDataFromEvent(event);
|
|
127
|
+
if (!taskData) return false;
|
|
128
|
+
const mainCallId = taskData.interaction?.mainInteractionId || taskData.interactionId;
|
|
129
|
+
const media = taskData.interaction?.media?.[mainCallId];
|
|
130
|
+
const participants = taskData.interaction?.participants;
|
|
131
|
+
if (!media?.participants || !participants) return false;
|
|
132
|
+
let agentCount = 0;
|
|
133
|
+
for (const pId of media.participants) {
|
|
134
|
+
const p = participants[pId];
|
|
135
|
+
if (p && p.pType !== 'Customer' && p.pType !== 'Supervisor' && !p.hasLeft) {
|
|
136
|
+
agentCount += 1;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return agentCount >= 2;
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Conference Guards
|
|
144
|
+
conferenceInProgressFromEvent: ({event}: GuardParams): boolean => {
|
|
145
|
+
const taskData = getTaskDataFromEvent(event);
|
|
146
|
+
if (!taskData?.interaction) return false;
|
|
147
|
+
|
|
148
|
+
return getIsConferenceInProgress(taskData);
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Conference downgrade check specifically for transitioning back to CONNECTED.
|
|
153
|
+
*
|
|
154
|
+
* Returns true only when:
|
|
155
|
+
* - conference has downgraded (fewer than 2 active agent participants in main call)
|
|
156
|
+
* - customer is still in the call
|
|
157
|
+
* - current agent is still in the main call
|
|
158
|
+
*/
|
|
159
|
+
shouldDowngradeConferenceToConnected: ({context, event}: GuardParams): boolean => {
|
|
160
|
+
const eventTaskData = getTaskDataFromEvent(event);
|
|
161
|
+
const taskData = eventTaskData ?? context.taskData;
|
|
162
|
+
if (!taskData?.interaction) return false;
|
|
163
|
+
|
|
164
|
+
const selfAgentId = getSelfAgentId(context, taskData);
|
|
165
|
+
if (!selfAgentId) return false;
|
|
166
|
+
|
|
167
|
+
const mainCallId = taskData.interaction.mainInteractionId || taskData.interactionId;
|
|
168
|
+
if (!mainCallId) return false;
|
|
169
|
+
|
|
170
|
+
// Don't downgrade while backend still reports conference.
|
|
171
|
+
if (taskData.interaction.state === 'conference') return false;
|
|
172
|
+
|
|
173
|
+
const agentParticipantsCount = getConferenceParticipantsCount(taskData.interaction, mainCallId);
|
|
174
|
+
if (agentParticipantsCount >= 2) return false;
|
|
175
|
+
|
|
176
|
+
const customerInCall = getIsCustomerInCall(taskData.interaction, mainCallId);
|
|
177
|
+
if (!customerInCall) return false;
|
|
178
|
+
|
|
179
|
+
const selfInMainCall = Boolean(
|
|
180
|
+
taskData.interaction.media?.[mainCallId]?.participants?.includes(selfAgentId)
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
return selfInMainCall;
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// Consult Guards
|
|
187
|
+
/**
|
|
188
|
+
* Check if this agent initiated the consult (using event data)
|
|
189
|
+
* Handles both consultingAgentId and fallback to context flag
|
|
190
|
+
*/
|
|
191
|
+
didInitiateConsult: ({context, event}: GuardParams): boolean => {
|
|
192
|
+
const taskData = getTaskDataFromEvent(event);
|
|
193
|
+
if (taskData?.isConsulted === true) return false;
|
|
194
|
+
|
|
195
|
+
return taskData?.consultingAgentId
|
|
196
|
+
? isSelfConsultingAgent(context, taskData)
|
|
197
|
+
: context.consultInitiator === true;
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* EP-DN / consulted consult legs can arrive as AGENT_CONTACT_ASSIGNED without a preceding
|
|
202
|
+
* AgentConsulting event. When that happens, we should enter CONSULTING (not CONNECTED).
|
|
203
|
+
*/
|
|
204
|
+
isConsultingAssignment: ({event}: GuardParams): boolean => {
|
|
205
|
+
const taskData = getTaskDataFromEvent(event);
|
|
206
|
+
if (!taskData) return false;
|
|
207
|
+
|
|
208
|
+
const relationshipType = taskData.interaction?.callProcessingDetails?.relationshipType;
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
taskData.isConsulted === true ||
|
|
212
|
+
relationshipType === 'consult' ||
|
|
213
|
+
taskData.interaction?.state === 'consulting'
|
|
214
|
+
);
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
// Wrapup Guards
|
|
218
|
+
shouldWrapUp: ({context, event}: GuardParams): boolean => {
|
|
219
|
+
const taskData = getTaskDataFromEvent(event);
|
|
220
|
+
if (!taskData) return false;
|
|
221
|
+
|
|
222
|
+
if (event?.type === TaskEvent.CONFERENCE_END) {
|
|
223
|
+
const selfAgentId = getSelfAgentId(context, taskData);
|
|
224
|
+
if (!selfAgentId) return false;
|
|
225
|
+
|
|
226
|
+
const pending = taskData?.agentsPendingWrapUp;
|
|
227
|
+
if (Array.isArray(pending) && pending.length > 0) {
|
|
228
|
+
return pending.includes(selfAgentId);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const participantWrapUp =
|
|
232
|
+
taskData?.interaction?.participants?.[selfAgentId]?.isWrapUp === true;
|
|
233
|
+
const wrapUpRequired = taskData?.wrapUpRequired === true;
|
|
234
|
+
|
|
235
|
+
return wrapUpRequired || participantWrapUp;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return shouldWrapUpForThisAgent(context, taskData);
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Check if wrapUpRequired in payload OR is consult initiator
|
|
243
|
+
*/
|
|
244
|
+
shouldWrapUpOrIsInitiator: ({context, event}: GuardParams): boolean => {
|
|
245
|
+
const taskData = getTaskDataFromEvent(event);
|
|
246
|
+
|
|
247
|
+
return Boolean(taskData?.wrapUpRequired || context.consultInitiator);
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* True if PARTICIPANT_LEAVE indicates that *this* agent left the conference.
|
|
252
|
+
*
|
|
253
|
+
* Important: PARTICIPANT_LEAVE is broadcast to all agents in the conference.
|
|
254
|
+
* Only the agent whose id matches the leaving participant should transition to
|
|
255
|
+
* TERMINATED / WRAPPING_UP based on wrapup rules.
|
|
256
|
+
*/
|
|
257
|
+
didCurrentAgentLeaveConference: ({context, event}: GuardParams): boolean => {
|
|
258
|
+
const taskData = getTaskDataFromEvent(event);
|
|
259
|
+
const selfAgentId = getSelfAgentId(context, taskData);
|
|
260
|
+
if (!selfAgentId) return false;
|
|
261
|
+
|
|
262
|
+
const participantIdFromEvent =
|
|
263
|
+
event && typeof event === 'object' && 'participantId' in event
|
|
264
|
+
? (event as {participantId?: string}).participantId
|
|
265
|
+
: undefined;
|
|
266
|
+
const participantId = participantIdFromEvent ?? taskData?.participantId;
|
|
267
|
+
|
|
268
|
+
if (Boolean(participantId) && participantId === selfAgentId) {
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// For EP-DN agents the backend removes the leaving participant entirely
|
|
273
|
+
// from the participants map (rather than setting hasLeft). If this task
|
|
274
|
+
// is in CONFERENCING (implied by the guard being evaluated here) but the
|
|
275
|
+
// agent is absent from the updated participants, they have left.
|
|
276
|
+
const participants = taskData?.interaction?.participants;
|
|
277
|
+
if (participants && !(selfAgentId in participants)) {
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return false;
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
// Server State Guards
|
|
285
|
+
isPrimaryMediaOnHold: ({event}: GuardParams): boolean => {
|
|
286
|
+
const taskData = getTaskDataFromEvent(event);
|
|
287
|
+
if (!taskData) return false;
|
|
288
|
+
const mediaId = taskData.mediaResourceId;
|
|
289
|
+
if (!mediaId) return false;
|
|
290
|
+
|
|
291
|
+
return taskData.interaction?.media?.[mediaId]?.isHold === true;
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export type GuardName = keyof typeof guards;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task State Machine
|
|
3
|
+
*
|
|
4
|
+
* Export all state machine components for easy importing
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Main state machine
|
|
8
|
+
export {createTaskStateMachine} from './TaskStateMachine';
|
|
9
|
+
export type {TaskStateMachine} from './TaskStateMachine';
|
|
10
|
+
|
|
11
|
+
// Types & enums
|
|
12
|
+
export {TaskState, TaskEvent} from './constants';
|
|
13
|
+
export {isEventOfType} from './types';
|
|
14
|
+
export type {
|
|
15
|
+
TaskContext,
|
|
16
|
+
TaskEventPayload,
|
|
17
|
+
TaskStateMachineConfig,
|
|
18
|
+
UIControlConfig,
|
|
19
|
+
TaskActionsMap,
|
|
20
|
+
TaskActionArgs,
|
|
21
|
+
} from './types';
|
|
22
|
+
|
|
23
|
+
// Guards
|
|
24
|
+
export {guards} from './guards';
|
|
25
|
+
export type {GuardParams, GuardFunction} from './guards';
|
|
26
|
+
|
|
27
|
+
// Actions
|
|
28
|
+
export {actions, createInitialContext} from './actions';
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task State Machine Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the XState-based task state machine.
|
|
5
|
+
* These types define states, events, context, and schemas for task lifecycle management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {AnyStateNodeConfig, ActionFunctionMap, EventObject, ActionArgs} from 'xstate';
|
|
9
|
+
import {DestinationType, TaskChannelType, TaskData, TaskUIControls, VoiceVariant} from '../types';
|
|
10
|
+
import {TaskEvent, TaskState} from './constants';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Represents a participant in a conference call
|
|
14
|
+
*/
|
|
15
|
+
export interface ConferenceParticipant {
|
|
16
|
+
/** Unique identifier for the participant */
|
|
17
|
+
id: string;
|
|
18
|
+
/** Type of participant (agent, customer, or external party) */
|
|
19
|
+
type: 'AGENT' | 'CUSTOMER' | 'EXTERNAL';
|
|
20
|
+
/** Display name of the participant */
|
|
21
|
+
name?: string;
|
|
22
|
+
/** Timestamp when participant joined the conference */
|
|
23
|
+
joinedAt: Date;
|
|
24
|
+
/** Whether this participant initiated the conference */
|
|
25
|
+
isInitiator: boolean;
|
|
26
|
+
/** Whether this participant can be removed from the conference */
|
|
27
|
+
canBeRemoved: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* UI Control configuration for the task
|
|
32
|
+
*/
|
|
33
|
+
export interface UIControlConfig {
|
|
34
|
+
/** Whether end call button is enabled (config option) */
|
|
35
|
+
isEndTaskEnabled: boolean;
|
|
36
|
+
/** Whether end consult button is enabled (config option) */
|
|
37
|
+
isEndConsultEnabled: boolean;
|
|
38
|
+
/** Channel type determines which controls are available */
|
|
39
|
+
channelType: TaskChannelType;
|
|
40
|
+
/** Optional voice channel variant to toggle WebRTC-specific controls */
|
|
41
|
+
voiceVariant?: VoiceVariant;
|
|
42
|
+
/** Whether recording controls should be shown for this task */
|
|
43
|
+
isRecordingEnabled: boolean;
|
|
44
|
+
/** Current agent ID for ownership checks (transfer conference) */
|
|
45
|
+
agentId?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Task state machine context.
|
|
50
|
+
* Only stores data that cannot be derived from state machine state.
|
|
51
|
+
*/
|
|
52
|
+
export interface TaskContext {
|
|
53
|
+
taskData: TaskData | null;
|
|
54
|
+
|
|
55
|
+
// Consult tracking
|
|
56
|
+
consultInitiator: boolean;
|
|
57
|
+
exitingConference: boolean;
|
|
58
|
+
consultFromConference: boolean;
|
|
59
|
+
transferConferenceRequested: boolean;
|
|
60
|
+
consultDestinationType: DestinationType | null;
|
|
61
|
+
consultDestinationAgentId: string | null;
|
|
62
|
+
consultDestinationAgentJoined: boolean;
|
|
63
|
+
consultCallHeld: boolean;
|
|
64
|
+
|
|
65
|
+
// Recording
|
|
66
|
+
recordingControlsAvailable: boolean;
|
|
67
|
+
recordingInProgress: boolean;
|
|
68
|
+
|
|
69
|
+
// UI
|
|
70
|
+
uiControlConfig: UIControlConfig;
|
|
71
|
+
uiControls: TaskUIControls;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type RecordingStateUpdate = Partial<
|
|
75
|
+
Pick<TaskContext, 'recordingControlsAvailable' | 'recordingInProgress'>
|
|
76
|
+
>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Base event type - all events have a type property
|
|
80
|
+
*/
|
|
81
|
+
type BaseEvent<T extends TaskEvent> = {type: T};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Event payload mapping - defines the payload for each event type
|
|
85
|
+
*/
|
|
86
|
+
interface TaskEventPayloadMap {
|
|
87
|
+
[TaskEvent.TASK_INCOMING]: BaseEvent<TaskEvent.TASK_INCOMING> & {taskData: TaskData};
|
|
88
|
+
[TaskEvent.TASK_OFFERED]: BaseEvent<TaskEvent.TASK_OFFERED> & {taskData: TaskData};
|
|
89
|
+
[TaskEvent.OFFER_CONSULT]: BaseEvent<TaskEvent.OFFER_CONSULT> & {taskData: TaskData};
|
|
90
|
+
[TaskEvent.HYDRATE]: BaseEvent<TaskEvent.HYDRATE> & {taskData: TaskData; agentId?: string};
|
|
91
|
+
[TaskEvent.CONTACT_UPDATED]: BaseEvent<TaskEvent.CONTACT_UPDATED> & {taskData: TaskData};
|
|
92
|
+
[TaskEvent.CONTACT_OWNER_CHANGED]: BaseEvent<TaskEvent.CONTACT_OWNER_CHANGED> & {
|
|
93
|
+
taskData: TaskData;
|
|
94
|
+
};
|
|
95
|
+
[TaskEvent.ASSIGN]: BaseEvent<TaskEvent.ASSIGN> & {taskData: TaskData};
|
|
96
|
+
[TaskEvent.HOLD_INITIATED]: BaseEvent<TaskEvent.HOLD_INITIATED> & {mediaResourceId: string};
|
|
97
|
+
[TaskEvent.HOLD_SUCCESS]: BaseEvent<TaskEvent.HOLD_SUCCESS> & {
|
|
98
|
+
mediaResourceId: string;
|
|
99
|
+
taskData?: TaskData;
|
|
100
|
+
};
|
|
101
|
+
[TaskEvent.HOLD_FAILED]: BaseEvent<TaskEvent.HOLD_FAILED> & {
|
|
102
|
+
reason?: string;
|
|
103
|
+
mediaResourceId: string;
|
|
104
|
+
};
|
|
105
|
+
[TaskEvent.UNHOLD_INITIATED]: BaseEvent<TaskEvent.UNHOLD_INITIATED> & {mediaResourceId: string};
|
|
106
|
+
[TaskEvent.UNHOLD_SUCCESS]: BaseEvent<TaskEvent.UNHOLD_SUCCESS> & {
|
|
107
|
+
mediaResourceId: string;
|
|
108
|
+
taskData?: TaskData;
|
|
109
|
+
};
|
|
110
|
+
[TaskEvent.UNHOLD_FAILED]: BaseEvent<TaskEvent.UNHOLD_FAILED> & {
|
|
111
|
+
reason?: string;
|
|
112
|
+
mediaResourceId: string;
|
|
113
|
+
};
|
|
114
|
+
[TaskEvent.CONSULT]: BaseEvent<TaskEvent.CONSULT> & {
|
|
115
|
+
destination: string;
|
|
116
|
+
destAgentId?: string;
|
|
117
|
+
destinationType: DestinationType;
|
|
118
|
+
};
|
|
119
|
+
[TaskEvent.CONSULT_SUCCESS]: BaseEvent<TaskEvent.CONSULT_SUCCESS> & {taskData?: TaskData};
|
|
120
|
+
[TaskEvent.CONSULT_CREATED]: BaseEvent<TaskEvent.CONSULT_CREATED> & {taskData: TaskData};
|
|
121
|
+
[TaskEvent.CONSULTING_ACTIVE]: BaseEvent<TaskEvent.CONSULTING_ACTIVE> & {
|
|
122
|
+
consultDestinationAgentJoined: boolean;
|
|
123
|
+
taskData?: TaskData;
|
|
124
|
+
};
|
|
125
|
+
[TaskEvent.CONSULT_END]: BaseEvent<TaskEvent.CONSULT_END> & {taskData?: TaskData};
|
|
126
|
+
[TaskEvent.CONSULT_FAILED]: BaseEvent<TaskEvent.CONSULT_FAILED> & {
|
|
127
|
+
reason?: string;
|
|
128
|
+
taskData?: TaskData;
|
|
129
|
+
};
|
|
130
|
+
[TaskEvent.MERGE_TO_CONFERENCE]: BaseEvent<TaskEvent.MERGE_TO_CONFERENCE>;
|
|
131
|
+
[TaskEvent.CONFERENCE_START]: BaseEvent<TaskEvent.CONFERENCE_START> & {
|
|
132
|
+
participants?: ConferenceParticipant[];
|
|
133
|
+
taskData?: TaskData;
|
|
134
|
+
};
|
|
135
|
+
[TaskEvent.CONFERENCE_FAILED]: BaseEvent<TaskEvent.CONFERENCE_FAILED> & {
|
|
136
|
+
reason?: string;
|
|
137
|
+
taskData?: TaskData;
|
|
138
|
+
};
|
|
139
|
+
[TaskEvent.CONFERENCE_END]: BaseEvent<TaskEvent.CONFERENCE_END> & {taskData: TaskData};
|
|
140
|
+
[TaskEvent.TRANSFER_CONFERENCE]: BaseEvent<TaskEvent.TRANSFER_CONFERENCE> & {agentId?: string};
|
|
141
|
+
[TaskEvent.PARTICIPANT_LEAVE]: BaseEvent<TaskEvent.PARTICIPANT_LEAVE> & {
|
|
142
|
+
participantId?: string;
|
|
143
|
+
taskData: TaskData;
|
|
144
|
+
};
|
|
145
|
+
[TaskEvent.EXIT_CONFERENCE]: BaseEvent<TaskEvent.EXIT_CONFERENCE> & {agentId?: string};
|
|
146
|
+
[TaskEvent.EXIT_CONFERENCE_SUCCESS]: BaseEvent<TaskEvent.EXIT_CONFERENCE_SUCCESS> & {
|
|
147
|
+
taskData: TaskData;
|
|
148
|
+
};
|
|
149
|
+
[TaskEvent.EXIT_CONFERENCE_FAILED]: BaseEvent<TaskEvent.EXIT_CONFERENCE_FAILED> & {
|
|
150
|
+
reason?: string;
|
|
151
|
+
};
|
|
152
|
+
[TaskEvent.TRANSFER_CONFERENCE_SUCCESS]: BaseEvent<TaskEvent.TRANSFER_CONFERENCE_SUCCESS> & {
|
|
153
|
+
taskData: TaskData;
|
|
154
|
+
};
|
|
155
|
+
[TaskEvent.TRANSFER_CONFERENCE_FAILED]: BaseEvent<TaskEvent.TRANSFER_CONFERENCE_FAILED> & {
|
|
156
|
+
reason?: string;
|
|
157
|
+
};
|
|
158
|
+
[TaskEvent.RECORDING_STARTED]: BaseEvent<TaskEvent.RECORDING_STARTED> & {taskData: TaskData};
|
|
159
|
+
[TaskEvent.PAUSE_RECORDING]: BaseEvent<TaskEvent.PAUSE_RECORDING> & {taskData: TaskData};
|
|
160
|
+
[TaskEvent.RESUME_RECORDING]: BaseEvent<TaskEvent.RESUME_RECORDING> & {taskData: TaskData};
|
|
161
|
+
[TaskEvent.TRANSFER_SUCCESS]: BaseEvent<TaskEvent.TRANSFER_SUCCESS> & {taskData?: TaskData};
|
|
162
|
+
[TaskEvent.TRANSFER_FAILED]: BaseEvent<TaskEvent.TRANSFER_FAILED> & {
|
|
163
|
+
reason?: string;
|
|
164
|
+
taskData?: TaskData;
|
|
165
|
+
};
|
|
166
|
+
[TaskEvent.WRAPUP_COMPLETE]: BaseEvent<TaskEvent.WRAPUP_COMPLETE> & {taskData?: TaskData};
|
|
167
|
+
[TaskEvent.TASK_WRAPUP]: BaseEvent<TaskEvent.TASK_WRAPUP> & {taskData?: TaskData};
|
|
168
|
+
[TaskEvent.RONA]: BaseEvent<TaskEvent.RONA> & {taskData?: TaskData; reason?: string};
|
|
169
|
+
[TaskEvent.CONTACT_ENDED]: BaseEvent<TaskEvent.CONTACT_ENDED> & {taskData: TaskData};
|
|
170
|
+
[TaskEvent.ASSIGN_FAILED]: BaseEvent<TaskEvent.ASSIGN_FAILED> & {reason?: string};
|
|
171
|
+
[TaskEvent.INVITE_FAILED]: BaseEvent<TaskEvent.INVITE_FAILED> & {reason?: string};
|
|
172
|
+
[TaskEvent.OUTBOUND_FAILED]: BaseEvent<TaskEvent.OUTBOUND_FAILED> & {
|
|
173
|
+
reason?: string;
|
|
174
|
+
taskData?: TaskData;
|
|
175
|
+
};
|
|
176
|
+
[TaskEvent.SWITCH_TO_MAIN_CALL]: BaseEvent<TaskEvent.SWITCH_TO_MAIN_CALL>;
|
|
177
|
+
[TaskEvent.SWITCH_TO_CONSULT]: BaseEvent<TaskEvent.SWITCH_TO_CONSULT>;
|
|
178
|
+
[TaskEvent.ACCEPT]: BaseEvent<TaskEvent.ACCEPT>;
|
|
179
|
+
[TaskEvent.DECLINE]: BaseEvent<TaskEvent.DECLINE>;
|
|
180
|
+
[TaskEvent.END]: BaseEvent<TaskEvent.END> & {taskData?: TaskData};
|
|
181
|
+
[TaskEvent.CTQ_CANCEL]: BaseEvent<TaskEvent.CTQ_CANCEL> & {taskData: TaskData};
|
|
182
|
+
[TaskEvent.CTQ_CANCEL_FAILED]: BaseEvent<TaskEvent.CTQ_CANCEL_FAILED> & {taskData: TaskData};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Union of all possible event payloads
|
|
187
|
+
*/
|
|
188
|
+
export type TaskEventPayload = TaskEventPayloadMap[TaskEvent];
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Type guard to check event type
|
|
192
|
+
*/
|
|
193
|
+
export function isEventOfType<T extends TaskEvent>(
|
|
194
|
+
event: TaskEventPayload | undefined,
|
|
195
|
+
type: T
|
|
196
|
+
): event is TaskEventPayloadMap[T] {
|
|
197
|
+
return Boolean(event && event.type === type);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Recording control state for UI controls computer
|
|
202
|
+
*/
|
|
203
|
+
export interface RecordingControlState {
|
|
204
|
+
available: boolean;
|
|
205
|
+
inProgress: boolean;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* State machine configuration type
|
|
210
|
+
*/
|
|
211
|
+
export interface TaskStateMachineConfig {
|
|
212
|
+
id: string;
|
|
213
|
+
initial: TaskState;
|
|
214
|
+
context: TaskContext;
|
|
215
|
+
states: Record<string, AnyStateNodeConfig>;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export type TaskActionsMap = ActionFunctionMap<
|
|
219
|
+
TaskContext,
|
|
220
|
+
TaskEventPayload,
|
|
221
|
+
never,
|
|
222
|
+
{type: string; params: undefined},
|
|
223
|
+
never,
|
|
224
|
+
never,
|
|
225
|
+
EventObject
|
|
226
|
+
>;
|
|
227
|
+
|
|
228
|
+
export type TaskActionArgs = ActionArgs<TaskContext, TaskEventPayload, TaskEventPayload>;
|