@webex/contact-center 3.12.0-next.9 → 3.12.0-task-refactor.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.
Files changed (200) hide show
  1. package/AGENTS.md +438 -0
  2. package/ai-docs/README.md +131 -0
  3. package/ai-docs/RULES.md +455 -0
  4. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  5. package/ai-docs/patterns/testing-patterns.md +480 -0
  6. package/ai-docs/patterns/typescript-patterns.md +365 -0
  7. package/ai-docs/templates/README.md +102 -0
  8. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  9. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  10. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  11. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  12. package/ai-docs/templates/new-method/00-master.md +80 -0
  13. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  14. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  15. package/ai-docs/templates/new-method/03-tests.md +201 -0
  16. package/ai-docs/templates/new-method/04-validation.md +141 -0
  17. package/ai-docs/templates/new-service/00-master.md +109 -0
  18. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  19. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  20. package/ai-docs/templates/new-service/03-integration.md +178 -0
  21. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  22. package/ai-docs/templates/new-service/05-validation.md +145 -0
  23. package/dist/cc.js +65 -123
  24. package/dist/cc.js.map +1 -1
  25. package/dist/constants.js +13 -2
  26. package/dist/constants.js.map +1 -1
  27. package/dist/index.js +13 -5
  28. package/dist/index.js.map +1 -1
  29. package/dist/metrics/behavioral-events.js +26 -13
  30. package/dist/metrics/behavioral-events.js.map +1 -1
  31. package/dist/metrics/constants.js +7 -6
  32. package/dist/metrics/constants.js.map +1 -1
  33. package/dist/services/ApiAiAssistant.js +0 -3
  34. package/dist/services/ApiAiAssistant.js.map +1 -1
  35. package/dist/services/config/Util.js +2 -3
  36. package/dist/services/config/Util.js.map +1 -1
  37. package/dist/services/config/types.js +16 -14
  38. package/dist/services/config/types.js.map +1 -1
  39. package/dist/services/constants.js +0 -1
  40. package/dist/services/constants.js.map +1 -1
  41. package/dist/services/core/Err.js.map +1 -1
  42. package/dist/services/core/Utils.js +79 -55
  43. package/dist/services/core/Utils.js.map +1 -1
  44. package/dist/services/core/aqm-reqs.js +17 -92
  45. package/dist/services/core/aqm-reqs.js.map +1 -1
  46. package/dist/services/core/websocket/WebSocketManager.js +5 -25
  47. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  48. package/dist/services/core/websocket/types.js.map +1 -1
  49. package/dist/services/index.js +1 -2
  50. package/dist/services/index.js.map +1 -1
  51. package/dist/services/task/Task.js +644 -0
  52. package/dist/services/task/Task.js.map +1 -0
  53. package/dist/services/task/TaskFactory.js +45 -0
  54. package/dist/services/task/TaskFactory.js.map +1 -0
  55. package/dist/services/task/TaskManager.js +570 -535
  56. package/dist/services/task/TaskManager.js.map +1 -1
  57. package/dist/services/task/TaskUtils.js +132 -28
  58. package/dist/services/task/TaskUtils.js.map +1 -1
  59. package/dist/services/task/constants.js +7 -6
  60. package/dist/services/task/constants.js.map +1 -1
  61. package/dist/services/task/dialer.js +0 -51
  62. package/dist/services/task/dialer.js.map +1 -1
  63. package/dist/services/task/digital/Digital.js +77 -0
  64. package/dist/services/task/digital/Digital.js.map +1 -0
  65. package/dist/services/task/state-machine/TaskStateMachine.js +634 -0
  66. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  67. package/dist/services/task/state-machine/actions.js +372 -0
  68. package/dist/services/task/state-machine/actions.js.map +1 -0
  69. package/dist/services/task/state-machine/constants.js +139 -0
  70. package/dist/services/task/state-machine/constants.js.map +1 -0
  71. package/dist/services/task/state-machine/guards.js +263 -0
  72. package/dist/services/task/state-machine/guards.js.map +1 -0
  73. package/dist/services/task/state-machine/index.js +53 -0
  74. package/dist/services/task/state-machine/index.js.map +1 -0
  75. package/dist/services/task/state-machine/types.js +54 -0
  76. package/dist/services/task/state-machine/types.js.map +1 -0
  77. package/dist/services/task/state-machine/uiControlsComputer.js +377 -0
  78. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  79. package/dist/services/task/taskDataNormalizer.js +99 -0
  80. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  81. package/dist/services/task/types.js +157 -18
  82. package/dist/services/task/types.js.map +1 -1
  83. package/dist/services/task/voice/Voice.js +1031 -0
  84. package/dist/services/task/voice/Voice.js.map +1 -0
  85. package/dist/services/task/voice/WebRTC.js +149 -0
  86. package/dist/services/task/voice/WebRTC.js.map +1 -0
  87. package/dist/types/cc.d.ts +4 -33
  88. package/dist/types/constants.d.ts +13 -2
  89. package/dist/types/index.d.ts +11 -5
  90. package/dist/types/metrics/constants.d.ts +5 -3
  91. package/dist/types/services/ApiAiAssistant.d.ts +1 -1
  92. package/dist/types/services/config/types.d.ts +97 -25
  93. package/dist/types/services/core/Err.d.ts +0 -2
  94. package/dist/types/services/core/Utils.d.ts +25 -23
  95. package/dist/types/services/core/aqm-reqs.d.ts +0 -49
  96. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -1
  97. package/dist/types/services/core/websocket/connection-service.d.ts +0 -1
  98. package/dist/types/services/core/websocket/types.d.ts +1 -1
  99. package/dist/types/services/index.d.ts +1 -1
  100. package/dist/types/services/task/Task.d.ts +146 -0
  101. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  102. package/dist/types/services/task/TaskUtils.d.ts +39 -8
  103. package/dist/types/services/task/constants.d.ts +5 -4
  104. package/dist/types/services/task/dialer.d.ts +0 -15
  105. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  106. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +906 -0
  107. package/dist/types/services/task/state-machine/actions.d.ts +8 -0
  108. package/dist/types/services/task/state-machine/constants.d.ts +91 -0
  109. package/dist/types/services/task/state-machine/guards.d.ts +78 -0
  110. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  111. package/dist/types/services/task/state-machine/types.d.ts +256 -0
  112. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  113. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  114. package/dist/types/services/task/types.d.ts +539 -88
  115. package/dist/types/services/task/voice/Voice.d.ts +183 -0
  116. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  117. package/dist/types/types.d.ts +68 -0
  118. package/dist/types/webex.d.ts +1 -0
  119. package/dist/types.js +70 -0
  120. package/dist/types.js.map +1 -1
  121. package/dist/webex.js +14 -2
  122. package/dist/webex.js.map +1 -1
  123. package/package.json +14 -11
  124. package/src/cc.ts +91 -177
  125. package/src/constants.ts +13 -2
  126. package/src/index.ts +14 -5
  127. package/src/metrics/ai-docs/AGENTS.md +348 -0
  128. package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
  129. package/src/metrics/behavioral-events.ts +28 -14
  130. package/src/metrics/constants.ts +7 -8
  131. package/src/services/ApiAiAssistant.ts +2 -4
  132. package/src/services/agent/ai-docs/AGENTS.md +238 -0
  133. package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
  134. package/src/services/ai-docs/AGENTS.md +384 -0
  135. package/src/services/config/Util.ts +2 -3
  136. package/src/services/config/ai-docs/AGENTS.md +253 -0
  137. package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
  138. package/src/services/config/types.ts +108 -20
  139. package/src/services/constants.ts +0 -1
  140. package/src/services/core/Err.ts +0 -1
  141. package/src/services/core/Utils.ts +90 -67
  142. package/src/services/core/ai-docs/AGENTS.md +379 -0
  143. package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
  144. package/src/services/core/aqm-reqs.ts +22 -100
  145. package/src/services/core/websocket/WebSocketManager.ts +4 -23
  146. package/src/services/core/websocket/types.ts +1 -1
  147. package/src/services/index.ts +1 -2
  148. package/src/services/task/Task.ts +785 -0
  149. package/src/services/task/TaskFactory.ts +55 -0
  150. package/src/services/task/TaskManager.ts +579 -633
  151. package/src/services/task/TaskUtils.ts +175 -31
  152. package/src/services/task/ai-docs/AGENTS.md +448 -0
  153. package/src/services/task/ai-docs/ARCHITECTURE.md +573 -0
  154. package/src/services/task/constants.ts +5 -4
  155. package/src/services/task/dialer.ts +1 -56
  156. package/src/services/task/digital/Digital.ts +95 -0
  157. package/src/services/task/state-machine/TaskStateMachine.ts +793 -0
  158. package/src/services/task/state-machine/actions.ts +422 -0
  159. package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
  160. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
  161. package/src/services/task/state-machine/constants.ts +150 -0
  162. package/src/services/task/state-machine/guards.ts +303 -0
  163. package/src/services/task/state-machine/index.ts +28 -0
  164. package/src/services/task/state-machine/types.ts +228 -0
  165. package/src/services/task/state-machine/uiControlsComputer.ts +542 -0
  166. package/src/services/task/taskDataNormalizer.ts +137 -0
  167. package/src/services/task/types.ts +641 -95
  168. package/src/services/task/voice/Voice.ts +1255 -0
  169. package/src/services/task/voice/WebRTC.ts +187 -0
  170. package/src/types.ts +88 -5
  171. package/src/utils/AGENTS.md +276 -0
  172. package/src/webex.js +2 -0
  173. package/test/unit/spec/cc.ts +59 -142
  174. package/test/unit/spec/logger-proxy.ts +70 -0
  175. package/test/unit/spec/services/ApiAiAssistant.ts +17 -0
  176. package/test/unit/spec/services/config/index.ts +26 -55
  177. package/test/unit/spec/services/core/Utils.ts +103 -52
  178. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +48 -112
  179. package/test/unit/spec/services/core/websocket/connection-service.ts +5 -4
  180. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  181. package/test/unit/spec/services/task/Task.ts +416 -0
  182. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  183. package/test/unit/spec/services/task/TaskManager.ts +781 -1735
  184. package/test/unit/spec/services/task/TaskUtils.ts +125 -0
  185. package/test/unit/spec/services/task/dialer.ts +112 -198
  186. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  187. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +473 -0
  188. package/test/unit/spec/services/task/state-machine/guards.ts +288 -0
  189. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  190. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +147 -0
  191. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  192. package/test/unit/spec/services/task/voice/Voice.ts +587 -0
  193. package/test/unit/spec/services/task/voice/WebRTC.ts +242 -0
  194. package/umd/contact-center.min.js +2 -2
  195. package/umd/contact-center.min.js.map +1 -1
  196. package/dist/services/task/index.js +0 -1525
  197. package/dist/services/task/index.js.map +0 -1
  198. package/dist/types/services/task/index.d.ts +0 -650
  199. package/src/services/task/index.ts +0 -1801
  200. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,634 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createTaskStateMachine = createTaskStateMachine;
7
+ exports.getTaskStateMachineConfig = getTaskStateMachineConfig;
8
+ var _xstate = require("xstate");
9
+ var _constants = require("./constants");
10
+ var _actions = require("./actions");
11
+ var _guards = require("./guards");
12
+ var _TaskUtils = require("../TaskUtils");
13
+ /**
14
+ * Task State Machine Configuration
15
+ *
16
+ * This file defines the XState state machine configuration for contact center tasks.
17
+ * It orchestrates state transitions, guards, and actions for task lifecycle management.
18
+ *
19
+ * GUARD FUNCTIONS: All guard logic is centralized in guards.ts for reusability and testing.
20
+ * This file imports and uses those guards via the `guards` object.
21
+ */
22
+
23
+ const taskStateMachineSetup = (0, _xstate.setup)({
24
+ actors: {},
25
+ types: {
26
+ context: {},
27
+ events: {}
28
+ }
29
+ });
30
+
31
+ /**
32
+ * Get task state machine configuration with UI control config
33
+ * Defines all states, transitions, guards, and actions for task management
34
+ *
35
+ * @param uiControlConfig - UI control configuration
36
+ * @returns State machine configuration object
37
+ */
38
+ function getTaskStateMachineConfig(uiControlConfig) {
39
+ /**
40
+ * Event mapping reference (CC WebSocket -> TaskEvent)
41
+ *
42
+ * AgentContactReserved -> TaskEvent.TASK_INCOMING
43
+ * AgentOfferContact -> TaskEvent.TASK_OFFERED
44
+ * AgentOfferConsult -> TaskEvent.OFFER_CONSULT
45
+ * AgentConsulting -> TaskEvent.CONSULTING_ACTIVE
46
+ * AgentConsultCreated -> TaskEvent.CONSULT_CREATED
47
+ * AgentConsultTransferred -> TaskEvent.TRANSFER_SUCCESS
48
+ * AgentContactAssigned -> TaskEvent.ASSIGN
49
+ * AgentContactHeld -> TaskEvent.HOLD_SUCCESS
50
+ * AgentContactUnheld -> TaskEvent.UNHOLD_SUCCESS
51
+ * AgentConsultEnded -> TaskEvent.CONSULT_END
52
+ * AgentContactEnded -> TaskEvent.CONTACT_ENDED
53
+ * AgentWrapup -> TaskEvent.TASK_WRAPUP (wrapUpRequired)
54
+ * AgentWrappedup -> TaskEvent.WRAPUP_COMPLETE
55
+ *
56
+ * (See TaskManager.mapEventToTaskStateMachineEvent for the full mapping table.)
57
+ */
58
+ return {
59
+ id: 'taskStateMachine',
60
+ initial: _constants.TaskState.IDLE,
61
+ context: (0, _actions.createInitialContext)(uiControlConfig, _constants.TaskState.IDLE),
62
+ on: {
63
+ [_constants.TaskEvent.RECORDING_STARTED]: {
64
+ actions: ['updateTaskData', 'emitTaskRecordingStarted']
65
+ },
66
+ [_constants.TaskEvent.CONTACT_UPDATED]: {
67
+ actions: ['updateTaskData', 'syncTaskDataFromEvent']
68
+ },
69
+ [_constants.TaskEvent.CONTACT_OWNER_CHANGED]: {
70
+ actions: ['updateTaskData', 'syncTaskDataFromEvent']
71
+ },
72
+ // HYDRATE: Update task data from AgentContact event
73
+ // Note: State restoration with transitions is handled in IDLE state.
74
+ // This root-level handler is for when task is already in another state (just updates data).
75
+ [_constants.TaskEvent.HYDRATE]: {
76
+ actions: ['updateTaskData', 'emitTaskHydrate']
77
+ }
78
+ },
79
+ states: {
80
+ [_constants.TaskState.IDLE]: {
81
+ on: {
82
+ // HYDRATE: Restore state machine to correct state based on hydrated task data
83
+ // This handles page refresh/reconnection scenarios where task needs to be restored
84
+ // IMPORTANT: This MUST be in IDLE state (not root) because root-level events cannot
85
+ // transition to child states in XState
86
+ [_constants.TaskEvent.HYDRATE]: [{
87
+ guard: _guards.guards.isInteractionTerminated,
88
+ target: _constants.TaskState.WRAPPING_UP,
89
+ actions: ['updateTaskData', 'markEnded', 'emitTaskHydrate']
90
+ }, {
91
+ guard: _guards.guards.isInteractionConsulting,
92
+ target: _constants.TaskState.CONSULTING,
93
+ actions: ['updateTaskData', 'emitTaskHydrate']
94
+ }, {
95
+ guard: _guards.guards.isInteractionHeld,
96
+ target: _constants.TaskState.HELD,
97
+ actions: ['updateTaskData', 'emitTaskHydrate']
98
+ }, {
99
+ guard: _guards.guards.isInteractionConnected,
100
+ target: _constants.TaskState.CONNECTED,
101
+ actions: ['updateTaskData', 'emitTaskHydrate']
102
+ }, {
103
+ guard: _guards.guards.isConferencingByParticipants,
104
+ target: _constants.TaskState.CONFERENCING,
105
+ actions: ['updateTaskData', 'emitTaskHydrate']
106
+ }, {
107
+ // Default: just update data, stay in IDLE
108
+ actions: ['updateTaskData', 'emitTaskHydrate']
109
+ }],
110
+ // AgentContactReserved (applicable for direct incoming/consult/transfer/outdial)
111
+ [_constants.TaskEvent.TASK_INCOMING]: {
112
+ target: _constants.TaskState.OFFERED,
113
+ actions: ['initializeTask', 'emitTaskIncoming']
114
+ },
115
+ // EP-DN split-leg ordering can deliver AgentConsulting before HYDRATE/TASK_INCOMING.
116
+ // Do not drop it in IDLE; bootstrap to CONSULTING using event taskData.
117
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
118
+ target: _constants.TaskState.CONSULTING,
119
+ actions: ['updateTaskData', 'setConsultInitiator', 'setConsultDestination', 'setConsultFromConference', 'setConsultAgentJoined', 'emitTaskConsultAccepted', 'emitTaskConsulting']
120
+ }
121
+ }
122
+ },
123
+ [_constants.TaskState.OFFERED]: {
124
+ on: {
125
+ // AgentContactOffer
126
+ [_constants.TaskEvent.TASK_OFFERED]: {
127
+ actions: ['updateTaskData', 'emitTaskOfferContact', 'requestAutoAnswer']
128
+ },
129
+ // AgentContactAssigned
130
+ [_constants.TaskEvent.ASSIGN]: [{
131
+ guard: _guards.guards.isConsultingAssignment,
132
+ target: _constants.TaskState.CONSULTING,
133
+ actions: ['updateTaskData', 'emitTaskConsultAccepted', 'emitTaskConsulting']
134
+ }, {
135
+ target: _constants.TaskState.CONNECTED,
136
+ actions: ['updateTaskData', 'emitTaskAssigned']
137
+ }],
138
+ // AgentOfferContactRONA
139
+ [_constants.TaskEvent.RONA]: {
140
+ target: _constants.TaskState.TERMINATED,
141
+ actions: ['updateTaskData', 'markEnded', 'emitTaskReject']
142
+ },
143
+ [_constants.TaskEvent.TASK_WRAPUP]: {
144
+ target: _constants.TaskState.TERMINATED,
145
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
146
+ },
147
+ [_constants.TaskEvent.CONTACT_ENDED]: {
148
+ target: _constants.TaskState.TERMINATED,
149
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
150
+ },
151
+ // This needs to be handled for all assign failed scenarios (contact, buddy)
152
+ // [AgentContactAssignFailed, AgentCtqFailed, AgentBlindTransferFailed,
153
+ // AgentVTeamTransferFailed, AgentConsultTransferFailed]
154
+ [_constants.TaskEvent.ASSIGN_FAILED]: {
155
+ target: _constants.TaskState.TERMINATED,
156
+ actions: ['updateTaskData', 'markEnded', 'emitTaskReject']
157
+ },
158
+ [_constants.TaskEvent.INVITE_FAILED]: {
159
+ target: _constants.TaskState.TERMINATED,
160
+ actions: ['updateTaskData', 'markEnded', 'emitTaskReject']
161
+ },
162
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
163
+ guard: _guards.guards.shouldWrapUp,
164
+ target: _constants.TaskState.WRAPPING_UP,
165
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
166
+ }, {
167
+ target: _constants.TaskState.TERMINATED,
168
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskReject']
169
+ }],
170
+ // AgentConsulting comes for received after the initial consult is accepted
171
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: [{
172
+ target: _constants.TaskState.CONSULTING,
173
+ actions: ['updateTaskData', 'setConsultAgentJoined', 'emitTaskConsultAccepted', 'emitTaskConsulting']
174
+ }],
175
+ // agentOfferConsult happens only on the receiver side of consult
176
+ [_constants.TaskEvent.OFFER_CONSULT]: {
177
+ actions: ['updateTaskData', 'emitTaskOfferConsult', 'requestAutoAnswer']
178
+ },
179
+ // AgentConsultFailed - when consulted agent (Agent 2) doesn't answer (RONA or decline)
180
+ // Clears the incoming consult notification by transitioning to TERMINATED
181
+ [_constants.TaskEvent.CONSULT_FAILED]: {
182
+ target: _constants.TaskState.TERMINATED,
183
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskReject']
184
+ },
185
+ // AgentConsultEnded - when consult initiator (Agent 1) ends the consult before
186
+ // the consulted agent (Agent 2) accepts. Clears the incoming notification.
187
+ [_constants.TaskEvent.CONSULT_END]: {
188
+ target: _constants.TaskState.TERMINATED,
189
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskReject']
190
+ }
191
+ }
192
+ },
193
+ [_constants.TaskState.CONNECTED]: {
194
+ on: {
195
+ // AgentConsulting may arrive while machine is CONNECTED (EP-DN/event ordering).
196
+ // Derive consultInitiator from payload so controls are set correctly.
197
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
198
+ target: _constants.TaskState.CONSULTING,
199
+ actions: ['updateTaskData', 'setConsultInitiator', 'setConsultDestination', 'setConsultAgentJoined', 'emitTaskConsultAccepted', 'emitTaskConsulting']
200
+ },
201
+ // AgentContactAssigned can be resent after consult transfers; keep context in sync
202
+ [_constants.TaskEvent.ASSIGN]: {
203
+ target: _constants.TaskState.CONNECTED,
204
+ actions: ['updateTaskData', 'emitTaskAssigned']
205
+ },
206
+ // Click of hold button
207
+ [_constants.TaskEvent.HOLD_INITIATED]: {
208
+ target: _constants.TaskState.HOLD_INITIATING
209
+ },
210
+ // Remote hold from another login session (multi-login)
211
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
212
+ target: _constants.TaskState.HELD,
213
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
214
+ },
215
+ // Click of the consult button
216
+ [_constants.TaskEvent.CONSULT]: {
217
+ target: _constants.TaskState.CONSULT_INITIATING,
218
+ actions: ['setConsultInitiator', 'setConsultDestination']
219
+ },
220
+ // AgentConsultTransferred / AgentVTeamTransferred / AgentBlindTransferred
221
+ [_constants.TaskEvent.TRANSFER_SUCCESS]: [{
222
+ guard: _guards.guards.shouldWrapUpOrIsInitiator,
223
+ target: _constants.TaskState.WRAPPING_UP,
224
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
225
+ }, {
226
+ // Receiver goes to connected as he receives transferSuccess event
227
+ actions: ['updateTaskData', 'clearConsultState']
228
+ }],
229
+ [_constants.TaskEvent.TRANSFER_FAILED]: {
230
+ actions: ['updateTaskData']
231
+ },
232
+ // AgentContactEnded Event
233
+ [_constants.TaskEvent.CONTACT_ENDED]: [{
234
+ // Conference still active → CONFERENCING
235
+ guard: _guards.guards.conferenceInProgressFromEvent,
236
+ target: _constants.TaskState.CONFERENCING,
237
+ actions: ['updateTaskData', 'emitTaskConferenceStarted', 'requestCleanup']
238
+ }, {
239
+ // Agent should wrap up → WRAPPING_UP
240
+ guard: _guards.guards.shouldWrapUp,
241
+ target: _constants.TaskState.WRAPPING_UP,
242
+ actions: ['updateTaskData', 'markEnded', 'emitTaskWrapup', 'requestCleanup']
243
+ }, {
244
+ // Consulted agent → TERMINATED
245
+ target: _constants.TaskState.TERMINATED,
246
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
247
+ }],
248
+ [_constants.TaskEvent.TASK_WRAPUP]: {
249
+ target: _constants.TaskState.WRAPPING_UP,
250
+ actions: ['updateTaskData', 'markEnded', 'emitTaskWrapup']
251
+ },
252
+ [_constants.TaskEvent.PAUSE_RECORDING]: {
253
+ actions: ['updateTaskData', 'setRecordingState', 'emitTaskRecordingPaused']
254
+ },
255
+ [_constants.TaskEvent.RESUME_RECORDING]: {
256
+ actions: ['updateTaskData', 'setRecordingState', 'emitTaskRecordingResumed']
257
+ }
258
+ }
259
+ },
260
+ [_constants.TaskState.HOLD_INITIATING]: {
261
+ on: {
262
+ // AgentContactHeld Event
263
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
264
+ target: _constants.TaskState.HELD,
265
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
266
+ },
267
+ // AgentContactHoldFailed Event
268
+ [_constants.TaskEvent.HOLD_FAILED]: {
269
+ target: _constants.TaskState.CONNECTED,
270
+ actions: ['updateTaskData']
271
+ }
272
+ }
273
+ },
274
+ [_constants.TaskState.HELD]: {
275
+ on: {
276
+ // Click of the unhold button
277
+ [_constants.TaskEvent.UNHOLD_INITIATED]: {
278
+ target: _constants.TaskState.RESUME_INITIATING
279
+ },
280
+ // Remote resume from another login session (multi-login)
281
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: {
282
+ target: _constants.TaskState.CONNECTED,
283
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskResume']
284
+ },
285
+ // Click of the consult button
286
+ [_constants.TaskEvent.CONSULT]: {
287
+ target: _constants.TaskState.CONSULT_INITIATING,
288
+ actions: ['setConsultInitiator', 'setConsultDestination']
289
+ },
290
+ // TODO: This may not be a valid transition, need to be removed
291
+ // AgentConsultTransferred / AgentVTeamTransferred / AgentBlindTransferred
292
+ [_constants.TaskEvent.TRANSFER_SUCCESS]: [{
293
+ guard: _guards.guards.shouldWrapUpOrIsInitiator,
294
+ target: _constants.TaskState.WRAPPING_UP,
295
+ actions: ['updateTaskData', 'markEnded', 'emitTaskWrapup']
296
+ }, {
297
+ target: _constants.TaskState.CONNECTED,
298
+ actions: ['updateTaskData', 'clearConsultState']
299
+ }],
300
+ [_constants.TaskEvent.TRANSFER_FAILED]: {
301
+ actions: ['updateTaskData']
302
+ },
303
+ [_constants.TaskEvent.CONTACT_ENDED]: [{
304
+ guard: _guards.guards.conferenceInProgressFromEvent,
305
+ target: _constants.TaskState.CONFERENCING,
306
+ actions: ['updateTaskData', 'emitTaskConferenceStarted', 'requestCleanup']
307
+ }, {
308
+ guard: _guards.guards.shouldWrapUp,
309
+ target: _constants.TaskState.WRAPPING_UP,
310
+ actions: ['updateTaskData', 'markEnded', 'emitTaskWrapup', 'requestCleanup']
311
+ }, {
312
+ target: _constants.TaskState.TERMINATED,
313
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
314
+ }],
315
+ // TODO: This may not be a valid transition, this needs to be checked as well
316
+ [_constants.TaskEvent.TASK_WRAPUP]: {
317
+ target: _constants.TaskState.WRAPPING_UP,
318
+ actions: ['updateTaskData', 'markEnded', 'emitTaskWrapup']
319
+ }
320
+ }
321
+ },
322
+ [_constants.TaskState.RESUME_INITIATING]: {
323
+ on: {
324
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: {
325
+ target: _constants.TaskState.CONNECTED,
326
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskResume']
327
+ },
328
+ [_constants.TaskEvent.UNHOLD_FAILED]: {
329
+ target: _constants.TaskState.HELD
330
+ }
331
+ }
332
+ },
333
+ [_constants.TaskState.CONSULT_INITIATING]: {
334
+ on: {
335
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
336
+ actions: ['updateTaskData']
337
+ },
338
+ [_constants.TaskEvent.HOLD_FAILED]: {
339
+ target: _constants.TaskState.CONNECTED,
340
+ actions: ['updateTaskData', 'handleConsultFailed']
341
+ },
342
+ // AgentConsulting
343
+ // NOTE: Don't set consultDestinationAgentJoined here - wait for CONSULTING_ACTIVE
344
+ [_constants.TaskEvent.CONSULT_SUCCESS]: {
345
+ target: _constants.TaskState.CONSULTING,
346
+ actions: ['updateTaskData', 'setConsultInitiator']
347
+ },
348
+ // AgentConsultFailed, API Failures, AgentCtqFailed
349
+ [_constants.TaskEvent.CONSULT_FAILED]: [{
350
+ // Consult from conference → back to CONFERENCING
351
+ guard: ({
352
+ context
353
+ }) => context.consultFromConference === true,
354
+ target: _constants.TaskState.CONFERENCING,
355
+ actions: ['updateTaskData', 'handleConsultFailed']
356
+ }, {
357
+ guard: _guards.guards.isPrimaryMediaOnHold,
358
+ target: _constants.TaskState.HELD,
359
+ actions: ['updateTaskData', 'handleConsultFailed']
360
+ }, {
361
+ target: _constants.TaskState.CONNECTED,
362
+ actions: ['updateTaskData', 'handleConsultFailed']
363
+ }],
364
+ // AgentCtqCancelled Event
365
+ [_constants.TaskEvent.CTQ_CANCEL]: [{
366
+ guard: _guards.guards.isPrimaryMediaOnHold,
367
+ target: _constants.TaskState.HELD,
368
+ actions: ['updateTaskData', 'clearConsultState']
369
+ }, {
370
+ target: _constants.TaskState.CONNECTED,
371
+ actions: ['updateTaskData', 'clearConsultState']
372
+ }]
373
+ }
374
+ },
375
+ [_constants.TaskState.CONSULTING]: {
376
+ on: {
377
+ // AgentConsulting updates consulted agent arrival
378
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
379
+ actions: ['updateTaskData', 'setConsultAgentJoined', 'setConsultDestination', 'emitTaskConsulting']
380
+ },
381
+ // AgentConsultEnded
382
+ [_constants.TaskEvent.CONSULT_END]: [{
383
+ // Initiator returning to conference (flag set OR backend still shows conference)
384
+ guard: ({
385
+ context,
386
+ event
387
+ }) => context.consultInitiator === true && (context.consultFromConference === true || _guards.guards.conferenceInProgressFromEvent({
388
+ context,
389
+ event
390
+ })),
391
+ target: _constants.TaskState.CONFERENCING,
392
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
393
+ }, {
394
+ // Initiator already switched back to the main/customer leg
395
+ guard: ({
396
+ context
397
+ }) => context.consultInitiator === true && context.consultCallHeld === true,
398
+ target: _constants.TaskState.CONNECTED,
399
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
400
+ }, {
401
+ // Initiator (no conference) → HELD
402
+ guard: ({
403
+ context
404
+ }) => context.consultInitiator === true,
405
+ target: _constants.TaskState.HELD,
406
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
407
+ }, {
408
+ // Consulted agent → TERMINATED
409
+ target: _constants.TaskState.TERMINATED,
410
+ actions: ['updateTaskData']
411
+ }],
412
+ // Switch between consult and main call (UI-driven toggle)
413
+ [_constants.TaskEvent.SWITCH_TO_MAIN_CALL]: {
414
+ actions: ['handleSwitchToMainCall', 'emitTaskSwitchCall']
415
+ },
416
+ [_constants.TaskEvent.SWITCH_TO_CONSULT]: {
417
+ actions: ['handleSwitchToConsult', 'emitTaskSwitchCall']
418
+ },
419
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
420
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
421
+ },
422
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: {
423
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskResume']
424
+ },
425
+ [_constants.TaskEvent.TRANSFER_SUCCESS]: [{
426
+ guard: _guards.guards.shouldWrapUpOrIsInitiator,
427
+ target: _constants.TaskState.WRAPPING_UP,
428
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
429
+ }, {
430
+ target: _constants.TaskState.CONNECTED,
431
+ actions: ['updateTaskData', 'clearConsultState']
432
+ }],
433
+ [_constants.TaskEvent.TRANSFER_FAILED]: {
434
+ actions: ['updateTaskData']
435
+ },
436
+ [_constants.TaskEvent.TRANSFER_CONFERENCE]: {
437
+ // Track that this agent initiated the conference transfer so we can
438
+ // apply the correct lifecycle transition when success arrives.
439
+ actions: ['setTransferConferenceRequested', 'emitTaskTransferConference']
440
+ },
441
+ [_constants.TaskEvent.TRANSFER_CONFERENCE_SUCCESS]: [{
442
+ guard: ({
443
+ context
444
+ }) => context.transferConferenceRequested !== true,
445
+ actions: ['updateTaskData', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested']
446
+ }, {
447
+ guard: _guards.guards.shouldWrapUp,
448
+ target: _constants.TaskState.WRAPPING_UP,
449
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested', 'emitTaskWrapup']
450
+ }, {
451
+ // Non-initiator (consulted agent) stays in CONFERENCING
452
+ guard: ({
453
+ context
454
+ }) => !context.consultInitiator,
455
+ target: _constants.TaskState.CONFERENCING,
456
+ actions: ['updateTaskData', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested']
457
+ }, {
458
+ target: _constants.TaskState.TERMINATED,
459
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested', 'emitTaskEnd']
460
+ }],
461
+ [_constants.TaskEvent.TRANSFER_CONFERENCE_FAILED]: {
462
+ actions: ['clearTransferConferenceRequested', 'emitTaskTransferConferenceFailed']
463
+ },
464
+ // AgentContactAssigned - receiver side becomes connected to customer
465
+ [_constants.TaskEvent.ASSIGN]: {
466
+ target: _constants.TaskState.CONNECTED,
467
+ actions: ['updateTaskData', 'emitTaskAssigned']
468
+ },
469
+ // AgentContactEnded
470
+ [_constants.TaskEvent.CONTACT_ENDED]: {
471
+ target: _constants.TaskState.WRAPPING_UP,
472
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup', 'requestCleanup']
473
+ },
474
+ [_constants.TaskEvent.TASK_WRAPUP]: {
475
+ target: _constants.TaskState.WRAPPING_UP,
476
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
477
+ },
478
+ [_constants.TaskEvent.MERGE_TO_CONFERENCE]: {
479
+ target: _constants.TaskState.CONF_INITIATING
480
+ },
481
+ // AgentConsultConferenced, ParticipantJoinedConference
482
+ [_constants.TaskEvent.CONFERENCE_START]: {
483
+ target: _constants.TaskState.CONFERENCING,
484
+ actions: ['handleConferenceStarted', 'clearConsultState']
485
+ }
486
+ }
487
+ },
488
+ [_constants.TaskState.CONF_INITIATING]: {
489
+ on: {
490
+ // AgentConsultConferenced, ParticipantJoinedConference
491
+ [_constants.TaskEvent.CONFERENCE_START]: {
492
+ target: _constants.TaskState.CONFERENCING,
493
+ actions: ['handleConferenceStarted']
494
+ },
495
+ // AgentConsultConferenceFailed
496
+ [_constants.TaskEvent.CONFERENCE_FAILED]: {
497
+ target: _constants.TaskState.CONSULTING,
498
+ actions: ['handleConferenceFailed', 'emitTaskConferenceFailed']
499
+ }
500
+ }
501
+ },
502
+ [_constants.TaskState.CONFERENCING]: {
503
+ on: {
504
+ [_constants.TaskEvent.CONFERENCE_START]: {
505
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConferenceStarted']
506
+ },
507
+ [_constants.TaskEvent.EXIT_CONFERENCE_SUCCESS]: [{
508
+ guard: _guards.guards.shouldWrapUp,
509
+ target: _constants.TaskState.WRAPPING_UP,
510
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
511
+ }, {
512
+ target: _constants.TaskState.TERMINATED,
513
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskEnd']
514
+ }],
515
+ // Needed as all agents in conference get this event, hence we need to clear the consult state
516
+ [_constants.TaskEvent.CONSULT_END]: {
517
+ actions: ['updateTaskData', 'clearConsultState']
518
+ },
519
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
520
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
521
+ },
522
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: {
523
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskResume']
524
+ },
525
+ // Start a new consult from within an active conference
526
+ [_constants.TaskEvent.CONSULT]: {
527
+ target: _constants.TaskState.CONSULT_INITIATING,
528
+ actions: ['setConsultInitiator', 'setConsultDestination', 'setConsultFromConference']
529
+ },
530
+ // Participant leaves - handle conference downgrade scenarios
531
+ [_constants.TaskEvent.PARTICIPANT_LEAVE]: [{
532
+ // Only the leaving agent should wrap up → WRAPPING_UP
533
+ guard: params => _guards.guards.didCurrentAgentLeaveConference(params) && _guards.guards.shouldWrapUp(params),
534
+ target: _constants.TaskState.WRAPPING_UP,
535
+ actions: ['updateTaskData', 'handleParticipantLeft', 'markEnded', 'clearConsultState', 'emitTaskParticipantLeft', 'emitTaskWrapup']
536
+ }, {
537
+ // Only the leaving agent (no wrapup) → TERMINATED
538
+ guard: _guards.guards.didCurrentAgentLeaveConference,
539
+ target: _constants.TaskState.TERMINATED,
540
+ actions: ['updateTaskData', 'handleParticipantLeft', 'markEnded', 'clearConsultState', 'emitTaskParticipantLeft', 'emitTaskEnd']
541
+ }, {
542
+ // Conference downgraded, customer present → CONNECTED
543
+ guard: params => !_guards.guards.didCurrentAgentLeaveConference(params) && _guards.guards.shouldDowngradeConferenceToConnected(params),
544
+ target: _constants.TaskState.CONNECTED,
545
+ actions: ['updateTaskData', 'handleParticipantLeft', 'clearConsultState', 'emitTaskParticipantLeft', 'emitTaskConferenceEnded']
546
+ }, {
547
+ actions: ['updateTaskData', 'handleParticipantLeft', 'emitTaskParticipantLeft']
548
+ }],
549
+ [_constants.TaskEvent.TRANSFER_CONFERENCE]: {
550
+ actions: ['setTransferConferenceRequested', 'emitTaskTransferConference']
551
+ },
552
+ [_constants.TaskEvent.TRANSFER_CONFERENCE_SUCCESS]: [{
553
+ // Not initiated by this agent → just refresh backend state.
554
+ guard: ({
555
+ context
556
+ }) => context.transferConferenceRequested !== true,
557
+ actions: ['updateTaskData', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested']
558
+ }],
559
+ [_constants.TaskEvent.TRANSFER_CONFERENCE_FAILED]: {
560
+ actions: ['clearTransferConferenceRequested', 'emitTaskTransferConferenceFailed']
561
+ },
562
+ // Conference ends explicitly
563
+ [_constants.TaskEvent.CONFERENCE_END]: [{
564
+ // Agent who should wrap up → WRAPPING_UP
565
+ guard: _guards.guards.shouldWrapUp,
566
+ target: _constants.TaskState.WRAPPING_UP,
567
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
568
+ }, {
569
+ // Customer still in call → CONNECTED
570
+ guard: ({
571
+ context,
572
+ event
573
+ }) => {
574
+ if (context.exitingConference === true) return false;
575
+ const taskData = event?.taskData ?? context.taskData;
576
+ if (!taskData?.interaction) return false;
577
+ const mainCallId = taskData.interaction.mainInteractionId || taskData.interactionId;
578
+ if (!mainCallId) return false;
579
+ return (0, _TaskUtils.getIsCustomerInCall)(taskData.interaction, mainCallId);
580
+ },
581
+ target: _constants.TaskState.CONNECTED,
582
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConferenceEnded']
583
+ }, {
584
+ // Otherwise → TERMINATED
585
+ target: _constants.TaskState.TERMINATED,
586
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskEnd']
587
+ }],
588
+ // CONTACT_ENDED in conference
589
+ [_constants.TaskEvent.CONTACT_ENDED]: [{
590
+ // Conference still active → stay
591
+ actions: ['updateTaskData', 'requestCleanup']
592
+ }]
593
+ }
594
+ },
595
+ [_constants.TaskState.WRAPPING_UP]: {
596
+ // Only emit wrapup event on entry - task:end should only be emitted when COMPLETED
597
+ entry: ['emitTaskWrapup'],
598
+ on: {
599
+ // AgentWrappedup Event
600
+ [_constants.TaskEvent.WRAPUP_COMPLETE]: {
601
+ target: _constants.TaskState.COMPLETED,
602
+ actions: ['updateTaskData']
603
+ }
604
+ }
605
+ },
606
+ [_constants.TaskState.COMPLETED]: {
607
+ type: 'final',
608
+ entry: ['emitTaskWrappedup', 'cleanupResources']
609
+ },
610
+ [_constants.TaskState.TERMINATED]: {
611
+ type: 'final',
612
+ entry: ['cleanupResources']
613
+ }
614
+ }
615
+ };
616
+ }
617
+
618
+ /**
619
+ * Create a task state machine instance using only the built-in actions.
620
+ * The resulting machine is ready for most consumers that rely on the default
621
+ * context mutators declared in actions.ts.
622
+ *
623
+ * @param uiControlConfig - UI control configuration
624
+ * @returns StateMachine instance for task management
625
+ */
626
+ function createTaskStateMachine(uiControlConfig, options) {
627
+ return taskStateMachineSetup.createMachine(getTaskStateMachineConfig(uiControlConfig)).provide({
628
+ actions: {
629
+ ..._actions.actions,
630
+ ...(options?.actions ?? {})
631
+ }
632
+ });
633
+ }
634
+ //# sourceMappingURL=TaskStateMachine.js.map