@webex/contact-center 3.12.0-next.13 → 3.12.0-next.130

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 (312) hide show
  1. package/.sdd/manifest.json +884 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +53 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +52 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +382 -0
  17. package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
  18. package/ai-docs/features/contact-owner-change-refactor.md +78 -0
  19. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  20. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  21. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  22. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  23. package/ai-docs/patterns/testing-patterns.md +480 -0
  24. package/ai-docs/patterns/typescript-patterns.md +365 -0
  25. package/ai-docs/templates/README.md +102 -0
  26. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  27. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  28. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  29. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  30. package/ai-docs/templates/new-method/00-master.md +80 -0
  31. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  32. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  33. package/ai-docs/templates/new-method/03-tests.md +201 -0
  34. package/ai-docs/templates/new-method/04-validation.md +141 -0
  35. package/ai-docs/templates/new-service/00-master.md +109 -0
  36. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  37. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  38. package/ai-docs/templates/new-service/03-integration.md +178 -0
  39. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  40. package/ai-docs/templates/new-service/05-validation.md +145 -0
  41. package/dist/cc.js +971 -42
  42. package/dist/cc.js.map +1 -1
  43. package/dist/config.js +13 -0
  44. package/dist/config.js.map +1 -1
  45. package/dist/constants.js +31 -3
  46. package/dist/constants.js.map +1 -1
  47. package/dist/index.js +45 -15
  48. package/dist/index.js.map +1 -1
  49. package/dist/metrics/MetricsManager.js +16 -0
  50. package/dist/metrics/MetricsManager.js.map +1 -1
  51. package/dist/metrics/behavioral-events.js +205 -0
  52. package/dist/metrics/behavioral-events.js.map +1 -1
  53. package/dist/metrics/constants.js +48 -4
  54. package/dist/metrics/constants.js.map +1 -1
  55. package/dist/services/AddressBook.js +18 -15
  56. package/dist/services/AddressBook.js.map +1 -1
  57. package/dist/services/AnswerCallOnWebexService.js +202 -0
  58. package/dist/services/AnswerCallOnWebexService.js.map +1 -0
  59. package/dist/services/ApiAiAssistant.js +269 -9
  60. package/dist/services/ApiAiAssistant.js.map +1 -1
  61. package/dist/services/EntryPoint.js +46 -68
  62. package/dist/services/EntryPoint.js.map +1 -1
  63. package/dist/services/Queue.js +27 -22
  64. package/dist/services/Queue.js.map +1 -1
  65. package/dist/services/UserPreference.js +427 -0
  66. package/dist/services/UserPreference.js.map +1 -0
  67. package/dist/services/WebexCrossClientService.js +222 -0
  68. package/dist/services/WebexCrossClientService.js.map +1 -0
  69. package/dist/services/WxAppTelephonyMercurySync.js +108 -0
  70. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  71. package/dist/services/config/Util.js +11 -4
  72. package/dist/services/config/Util.js.map +1 -1
  73. package/dist/services/config/constants.js +41 -7
  74. package/dist/services/config/constants.js.map +1 -1
  75. package/dist/services/config/index.js +51 -0
  76. package/dist/services/config/index.js.map +1 -1
  77. package/dist/services/config/types.js +57 -12
  78. package/dist/services/config/types.js.map +1 -1
  79. package/dist/services/core/Err.js.map +1 -1
  80. package/dist/services/core/Utils.js +111 -32
  81. package/dist/services/core/Utils.js.map +1 -1
  82. package/dist/services/core/WebexRequest.js +6 -2
  83. package/dist/services/core/WebexRequest.js.map +1 -1
  84. package/dist/services/core/aqm-reqs.js +28 -14
  85. package/dist/services/core/aqm-reqs.js.map +1 -1
  86. package/dist/services/core/types.js.map +1 -1
  87. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  88. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  89. package/dist/services/core/websocket/types.js.map +1 -1
  90. package/dist/services/index.js +1 -1
  91. package/dist/services/index.js.map +1 -1
  92. package/dist/services/task/Task.js +754 -0
  93. package/dist/services/task/Task.js.map +1 -0
  94. package/dist/services/task/TaskFactory.js +49 -0
  95. package/dist/services/task/TaskFactory.js.map +1 -0
  96. package/dist/services/task/TaskManager.js +1172 -521
  97. package/dist/services/task/TaskManager.js.map +1 -1
  98. package/dist/services/task/TaskUtils.js +211 -27
  99. package/dist/services/task/TaskUtils.js.map +1 -1
  100. package/dist/services/task/WebexCallingUtils.js +70 -0
  101. package/dist/services/task/WebexCallingUtils.js.map +1 -0
  102. package/dist/services/task/constants.js +12 -2
  103. package/dist/services/task/constants.js.map +1 -1
  104. package/dist/services/task/contact.js +29 -0
  105. package/dist/services/task/contact.js.map +1 -1
  106. package/dist/services/task/dialer.js +78 -0
  107. package/dist/services/task/dialer.js.map +1 -1
  108. package/dist/services/task/digital/Digital.js +78 -0
  109. package/dist/services/task/digital/Digital.js.map +1 -0
  110. package/dist/services/task/state-machine/TaskStateMachine.js +982 -0
  111. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  112. package/dist/services/task/state-machine/actions.js +572 -0
  113. package/dist/services/task/state-machine/actions.js.map +1 -0
  114. package/dist/services/task/state-machine/constants.js +161 -0
  115. package/dist/services/task/state-machine/constants.js.map +1 -0
  116. package/dist/services/task/state-machine/guards.js +379 -0
  117. package/dist/services/task/state-machine/guards.js.map +1 -0
  118. package/dist/services/task/state-machine/index.js +53 -0
  119. package/dist/services/task/state-machine/index.js.map +1 -0
  120. package/dist/services/task/state-machine/types.js +54 -0
  121. package/dist/services/task/state-machine/types.js.map +1 -0
  122. package/dist/services/task/state-machine/uiControlsComputer.js +703 -0
  123. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  124. package/dist/services/task/taskDataNormalizer.js +99 -0
  125. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  126. package/dist/services/task/types.js +228 -5
  127. package/dist/services/task/types.js.map +1 -1
  128. package/dist/services/task/voice/Voice.js +1485 -0
  129. package/dist/services/task/voice/Voice.js.map +1 -0
  130. package/dist/services/task/voice/WebRTC.js +152 -0
  131. package/dist/services/task/voice/WebRTC.js.map +1 -0
  132. package/dist/services/task/voice/wxAppVoiceMethods.js +354 -0
  133. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  134. package/dist/services/wxAppDiagnosticLogging.js +122 -0
  135. package/dist/services/wxAppDiagnosticLogging.js.map +1 -0
  136. package/dist/services/wxAppTelephonyUtils.js +19 -0
  137. package/dist/services/wxAppTelephonyUtils.js.map +1 -0
  138. package/dist/types/cc.d.ts +193 -6
  139. package/dist/types/config.d.ts +13 -0
  140. package/dist/types/constants.d.ts +29 -1
  141. package/dist/types/index.d.ts +35 -8
  142. package/dist/types/metrics/MetricsManager.d.ts +6 -0
  143. package/dist/types/metrics/constants.d.ts +43 -1
  144. package/dist/types/services/AddressBook.d.ts +2 -1
  145. package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
  146. package/dist/types/services/ApiAiAssistant.d.ts +56 -5
  147. package/dist/types/services/EntryPoint.d.ts +7 -5
  148. package/dist/types/services/Queue.d.ts +5 -3
  149. package/dist/types/services/UserPreference.d.ts +118 -0
  150. package/dist/types/services/WebexCrossClientService.d.ts +32 -0
  151. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  152. package/dist/types/services/config/constants.d.ts +34 -5
  153. package/dist/types/services/config/types.d.ts +197 -12
  154. package/dist/types/services/core/Err.d.ts +6 -0
  155. package/dist/types/services/core/Utils.d.ts +35 -13
  156. package/dist/types/services/core/WebexRequest.d.ts +1 -0
  157. package/dist/types/services/core/types.d.ts +2 -0
  158. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  159. package/dist/types/services/core/websocket/types.d.ts +1 -1
  160. package/dist/types/services/index.d.ts +1 -1
  161. package/dist/types/services/task/Task.d.ts +175 -0
  162. package/dist/types/services/task/TaskFactory.d.ts +13 -0
  163. package/dist/types/services/task/TaskUtils.d.ts +48 -2
  164. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  165. package/dist/types/services/task/constants.d.ts +10 -0
  166. package/dist/types/services/task/contact.d.ts +4 -0
  167. package/dist/types/services/task/dialer.d.ts +30 -0
  168. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  169. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1442 -0
  170. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  171. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  172. package/dist/types/services/task/state-machine/guards.d.ts +103 -0
  173. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  174. package/dist/types/services/task/state-machine/types.d.ts +277 -0
  175. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  176. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  177. package/dist/types/services/task/types.d.ts +680 -66
  178. package/dist/types/services/task/voice/Voice.d.ts +227 -0
  179. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  180. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +55 -0
  181. package/dist/types/services/wxAppDiagnosticLogging.d.ts +51 -0
  182. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  183. package/dist/types/types.d.ts +205 -9
  184. package/dist/types/utils/PageCache.d.ts +20 -3
  185. package/dist/types/webex.d.ts +1 -0
  186. package/dist/types.js +162 -4
  187. package/dist/types.js.map +1 -1
  188. package/dist/utils/PageCache.js +19 -5
  189. package/dist/utils/PageCache.js.map +1 -1
  190. package/dist/webex.js +22 -2
  191. package/dist/webex.js.map +1 -1
  192. package/package.json +16 -12
  193. package/src/cc.ts +1289 -112
  194. package/src/config.ts +13 -0
  195. package/src/constants.ts +29 -1
  196. package/src/index.ts +36 -5
  197. package/src/metrics/MetricsManager.ts +16 -0
  198. package/src/metrics/ai-docs/AGENTS.md +350 -0
  199. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  200. package/src/metrics/ai-docs/metrics-spec.md +921 -0
  201. package/src/metrics/behavioral-events.ts +212 -0
  202. package/src/metrics/constants.ts +52 -4
  203. package/src/services/AddressBook.ts +17 -6
  204. package/src/services/AnswerCallOnWebexService.ts +239 -0
  205. package/src/services/ApiAiAssistant.ts +356 -9
  206. package/src/services/EntryPoint.ts +59 -60
  207. package/src/services/Queue.ts +29 -12
  208. package/src/services/UserPreference.ts +509 -0
  209. package/src/services/WebexCrossClientService.ts +293 -0
  210. package/src/services/WxAppTelephonyMercurySync.ts +142 -0
  211. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  212. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  213. package/src/services/agent/ai-docs/agent-spec.md +505 -0
  214. package/src/services/ai-docs/AGENTS.md +386 -0
  215. package/src/services/ai-docs/services-spec.md +505 -0
  216. package/src/services/config/Util.ts +12 -3
  217. package/src/services/config/ai-docs/AGENTS.md +255 -0
  218. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  219. package/src/services/config/ai-docs/config-spec.md +686 -0
  220. package/src/services/config/constants.ts +46 -6
  221. package/src/services/config/index.ts +65 -0
  222. package/src/services/config/types.ts +197 -13
  223. package/src/services/core/Err.ts +3 -0
  224. package/src/services/core/Utils.ts +127 -37
  225. package/src/services/core/WebexRequest.ts +3 -1
  226. package/src/services/core/ai-docs/AGENTS.md +381 -0
  227. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  228. package/src/services/core/ai-docs/core-spec.md +787 -0
  229. package/src/services/core/aqm-reqs.ts +30 -15
  230. package/src/services/core/types.ts +2 -0
  231. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  232. package/src/services/core/websocket/types.ts +1 -1
  233. package/src/services/index.ts +1 -1
  234. package/src/services/task/Task.ts +908 -0
  235. package/src/services/task/TaskFactory.ts +60 -0
  236. package/src/services/task/TaskManager.ts +1419 -608
  237. package/src/services/task/TaskUtils.ts +303 -25
  238. package/src/services/task/WebexCallingUtils.ts +136 -0
  239. package/src/services/task/ai-docs/AGENTS.md +457 -0
  240. package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
  241. package/src/services/task/ai-docs/task-spec.md +1474 -0
  242. package/src/services/task/constants.ts +10 -0
  243. package/src/services/task/contact.ts +30 -0
  244. package/src/services/task/dialer.ts +80 -0
  245. package/src/services/task/digital/Digital.ts +97 -0
  246. package/src/services/task/state-machine/TaskStateMachine.ts +1320 -0
  247. package/src/services/task/state-machine/actions.ts +741 -0
  248. package/src/services/task/state-machine/ai-docs/AGENTS.md +460 -0
  249. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1156 -0
  250. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2247 -0
  251. package/src/services/task/state-machine/constants.ts +172 -0
  252. package/src/services/task/state-machine/guards.ts +442 -0
  253. package/src/services/task/state-machine/index.ts +28 -0
  254. package/src/services/task/state-machine/types.ts +258 -0
  255. package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
  256. package/src/services/task/taskDataNormalizer.ts +137 -0
  257. package/src/services/task/types.ts +819 -70
  258. package/src/services/task/voice/Voice.ts +1851 -0
  259. package/src/services/task/voice/WebRTC.ts +191 -0
  260. package/src/services/task/voice/wxAppVoiceMethods.ts +516 -0
  261. package/src/services/wxAppDiagnosticLogging.ts +174 -0
  262. package/src/services/wxAppTelephonyUtils.ts +14 -0
  263. package/src/types.ts +262 -11
  264. package/src/utils/AGENTS.md +289 -0
  265. package/src/utils/PageCache.ts +38 -5
  266. package/src/utils/ai-docs/utils-spec.md +391 -0
  267. package/src/webex.js +10 -0
  268. package/test/unit/spec/cc.ts +2210 -119
  269. package/test/unit/spec/logger-proxy.ts +70 -0
  270. package/test/unit/spec/metrics/MetricsManager.ts +25 -0
  271. package/test/unit/spec/metrics/behavioral-events.ts +60 -0
  272. package/test/unit/spec/services/AddressBook.ts +37 -6
  273. package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
  274. package/test/unit/spec/services/ApiAiAssistant.ts +311 -21
  275. package/test/unit/spec/services/EntryPoint.ts +87 -40
  276. package/test/unit/spec/services/Queue.ts +123 -12
  277. package/test/unit/spec/services/UserPreference.ts +401 -0
  278. package/test/unit/spec/services/WebCallingService.ts +7 -1
  279. package/test/unit/spec/services/WebexCrossClientService.ts +467 -0
  280. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
  281. package/test/unit/spec/services/config/Util.ts +129 -0
  282. package/test/unit/spec/services/config/index.ts +97 -29
  283. package/test/unit/spec/services/core/Utils.ts +425 -8
  284. package/test/unit/spec/services/core/WebexRequest.ts +3 -1
  285. package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
  286. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  287. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  288. package/test/unit/spec/services/task/Task.ts +745 -0
  289. package/test/unit/spec/services/task/TaskFactory.ts +99 -0
  290. package/test/unit/spec/services/task/TaskManager.ts +2518 -1494
  291. package/test/unit/spec/services/task/TaskUtils.ts +235 -0
  292. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  293. package/test/unit/spec/services/task/contact.ts +33 -0
  294. package/test/unit/spec/services/task/dialer.ts +190 -0
  295. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  296. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +4060 -0
  297. package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
  298. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  299. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
  300. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  301. package/test/unit/spec/services/task/voice/Voice.ts +2061 -0
  302. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  303. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +603 -0
  304. package/test/unit/spec/services/wxAppDiagnosticLogging.ts +143 -0
  305. package/test/unit/spec/wellnessSampleUtils.ts +288 -0
  306. package/umd/contact-center.min.js +2 -2
  307. package/umd/contact-center.min.js.map +1 -1
  308. package/dist/services/task/index.js +0 -1525
  309. package/dist/services/task/index.js.map +0 -1
  310. package/dist/types/services/task/index.d.ts +0 -650
  311. package/src/services/task/index.ts +0 -1801
  312. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,982 @@
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
+ * ParticipantLeftConference -> TaskEvent.PARTICIPANT_LEAVE
53
+ * AgentContactEnded -> TaskEvent.CONTACT_ENDED
54
+ * AgentWrapup -> TaskEvent.TASK_WRAPUP (wrapUpRequired)
55
+ * AgentWrappedup -> TaskEvent.WRAPUP_COMPLETE
56
+ *
57
+ * (See TaskManager.mapEventToTaskStateMachineEvent for the full mapping table.)
58
+ */
59
+ // XState evaluates these guarded transition arrays in order. Each returned entry is a
60
+ // complete transition with its own target and actions; sharing them keeps lifecycle-event
61
+ // handling consistent across active states where ParticipantLeftConference can arrive.
62
+ const currentAgentParticipantLeaveTransitions = () => [{
63
+ guard: params => _guards.guards.didCurrentAgentLeaveMainInteraction(params) && _guards.guards.shouldWrapUp(params),
64
+ target: _constants.TaskState.WRAPPING_UP,
65
+ actions: ['updateTaskData', 'handleParticipantLeft', 'markEnded', 'clearConsultState', 'emitTaskParticipantLeft']
66
+ }, {
67
+ guard: _guards.guards.didCurrentAgentLeaveMainInteraction,
68
+ target: _constants.TaskState.TERMINATED,
69
+ actions: ['updateTaskData', 'handleParticipantLeft', 'markEnded', 'clearConsultState', 'emitTaskParticipantLeft', 'emitTaskEnd']
70
+ }];
71
+ const exitConferenceSuccessTransitions = () => [{
72
+ guard: _guards.guards.shouldWrapUp,
73
+ target: _constants.TaskState.WRAPPING_UP,
74
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState']
75
+ }, {
76
+ target: _constants.TaskState.TERMINATED,
77
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskEnd']
78
+ }];
79
+ const currentAgentConsultEndTransitions = () => [{
80
+ guard: params => _guards.guards.didCurrentAgentLeaveMainInteraction(params) && _guards.guards.shouldWrapUp(params),
81
+ target: _constants.TaskState.WRAPPING_UP,
82
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskConsultEnd', 'emitTaskWrapup']
83
+ }, {
84
+ guard: _guards.guards.didCurrentAgentLeaveMainInteraction,
85
+ target: _constants.TaskState.TERMINATED,
86
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskConsultEnd', 'emitTaskEnd']
87
+ }];
88
+ return {
89
+ id: 'taskStateMachine',
90
+ initial: _constants.TaskState.IDLE,
91
+ context: (0, _actions.createInitialContext)(uiControlConfig, _constants.TaskState.IDLE),
92
+ on: {
93
+ [_constants.TaskEvent.RECORDING_STARTED]: {
94
+ actions: ['updateTaskData', 'emitTaskRecordingStarted']
95
+ },
96
+ [_constants.TaskEvent.CONTACT_UPDATED]: {
97
+ actions: ['updateTaskData', 'syncTaskDataFromEvent']
98
+ },
99
+ [_constants.TaskEvent.CONTACT_OWNER_CHANGED]: {
100
+ actions: ['updateTaskData', 'syncTaskDataFromEvent', 'emitTaskHydrate']
101
+ },
102
+ // HYDRATE: Update task data from AgentContact event
103
+ // Note: State restoration with transitions is handled in IDLE state.
104
+ // This root-level handler is for when task is already in another state (just updates data).
105
+ [_constants.TaskEvent.HYDRATE]: {
106
+ actions: ['updateTaskData', 'emitTaskHydrate']
107
+ },
108
+ // AgentConsultCreated from Stable Prod while already HELD/CONNECTED (external consult).
109
+ // Child states do not handle CONSULT_CREATED; wire here so updateTaskData + setConsultInitiator run.
110
+ [_constants.TaskEvent.CONSULT_CREATED]: {
111
+ actions: ['updateTaskData', 'setConsultInitiator']
112
+ },
113
+ // AgentConsultFailed (RONA) while HELD/CONNECTED without passing through CONSULT_INITIATING.
114
+ [_constants.TaskEvent.CONSULT_FAILED]: {
115
+ actions: ['updateTaskData', 'handleConsultFailed']
116
+ }
117
+ },
118
+ states: {
119
+ [_constants.TaskState.IDLE]: {
120
+ on: {
121
+ // HYDRATE: Restore state machine to correct state based on hydrated task data
122
+ // This handles page refresh/reconnection scenarios where task needs to be restored
123
+ // IMPORTANT: This MUST be in IDLE state (not root) because root-level events cannot
124
+ // transition to child states in XState
125
+ [_constants.TaskEvent.HYDRATE]: [{
126
+ guard: _guards.guards.isInteractionTerminated,
127
+ target: _constants.TaskState.WRAPPING_UP,
128
+ actions: ['updateTaskData', 'markEnded', 'emitTaskHydrate']
129
+ }, {
130
+ guard: _guards.guards.isEpDnPendingConferenceMergeHydrate,
131
+ target: _constants.TaskState.CONFERENCING,
132
+ actions: ['updateTaskData', 'emitTaskHydrate']
133
+ }, {
134
+ guard: _guards.guards.isInteractionConsulting,
135
+ target: _constants.TaskState.CONSULTING,
136
+ actions: ['updateTaskData', 'emitTaskHydrate']
137
+ }, {
138
+ guard: _guards.guards.isInteractionHeld,
139
+ target: _constants.TaskState.HELD,
140
+ actions: ['updateTaskData', 'emitTaskHydrate']
141
+ }, {
142
+ guard: _guards.guards.isInteractionConnected,
143
+ target: _constants.TaskState.CONNECTED,
144
+ actions: ['updateTaskData', 'emitTaskHydrate']
145
+ }, {
146
+ guard: _guards.guards.isConferencingByParticipants,
147
+ target: _constants.TaskState.CONFERENCING,
148
+ actions: ['updateTaskData', 'emitTaskHydrate']
149
+ }, {
150
+ // Default: just update data, stay in IDLE
151
+ actions: ['updateTaskData', 'emitTaskHydrate']
152
+ }],
153
+ // AgentContactReserved (direct incoming/consult/transfer/outdial, or campaign preview accept)
154
+ [_constants.TaskEvent.TASK_INCOMING]: [{
155
+ guard: _guards.guards.isCampaignReservationAccept,
156
+ target: _constants.TaskState.OFFERED,
157
+ actions: ['initializeTask', 'emitTaskCampaignPreviewReservation']
158
+ }, {
159
+ target: _constants.TaskState.OFFERED,
160
+ actions: ['initializeTask', 'emitTaskIncoming']
161
+ }],
162
+ // AgentOutboundFailed can arrive before TASK_INCOMING due to race conditions
163
+ [_constants.TaskEvent.OUTBOUND_FAILED]: {
164
+ target: _constants.TaskState.TERMINATED,
165
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
166
+ },
167
+ // EP-DN split-leg ordering can deliver AgentConsulting before HYDRATE/TASK_INCOMING.
168
+ // Do not drop it in IDLE; bootstrap to CONSULTING using event taskData.
169
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
170
+ target: _constants.TaskState.CONSULTING,
171
+ actions: ['setConsultInitiator', 'setConsultDestination', 'setConsultFromConference', 'setConsultAgentJoined', 'updateTaskData', 'emitTaskConsultAccepted', 'emitTaskConsulting']
172
+ }
173
+ }
174
+ },
175
+ [_constants.TaskState.OFFERED]: {
176
+ on: {
177
+ // AgentContactOffer
178
+ [_constants.TaskEvent.TASK_OFFERED]: {
179
+ actions: ['updateTaskData', 'emitTaskOfferContact', 'requestAutoAnswer']
180
+ },
181
+ // AgentContactAssigned
182
+ [_constants.TaskEvent.ASSIGN]: [{
183
+ guard: _guards.guards.isConsultingAssignment,
184
+ target: _constants.TaskState.CONSULTING,
185
+ actions: ['updateTaskData', 'emitTaskConsultAccepted', 'emitTaskConsulting']
186
+ }, {
187
+ target: _constants.TaskState.CONNECTED,
188
+ actions: ['updateTaskData', 'emitTaskAssigned']
189
+ }],
190
+ // AgentOfferContactRONA
191
+ [_constants.TaskEvent.RONA]: {
192
+ target: _constants.TaskState.TERMINATED,
193
+ actions: ['updateTaskData', 'markEnded', 'emitTaskReject']
194
+ },
195
+ [_constants.TaskEvent.TASK_WRAPUP]: [{
196
+ guard: _guards.guards.shouldWrapUp,
197
+ target: _constants.TaskState.WRAPPING_UP,
198
+ actions: ['updateTaskData', 'markEnded']
199
+ }, {
200
+ target: _constants.TaskState.TERMINATED,
201
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
202
+ }],
203
+ [_constants.TaskEvent.CONTACT_ENDED]: {
204
+ target: _constants.TaskState.TERMINATED,
205
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
206
+ },
207
+ // This needs to be handled for all assign failed scenarios (contact, buddy)
208
+ // [AgentContactAssignFailed, AgentCtqFailed, AgentBlindTransferFailed,
209
+ // AgentVTeamTransferFailed, AgentConsultTransferFailed]
210
+ [_constants.TaskEvent.ASSIGN_FAILED]: {
211
+ target: _constants.TaskState.TERMINATED,
212
+ actions: ['updateTaskData', 'markEnded', 'emitTaskReject']
213
+ },
214
+ [_constants.TaskEvent.INVITE_FAILED]: {
215
+ target: _constants.TaskState.TERMINATED,
216
+ actions: ['updateTaskData', 'markEnded', 'emitTaskReject']
217
+ },
218
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
219
+ guard: _guards.guards.shouldWrapUp,
220
+ target: _constants.TaskState.WRAPPING_UP,
221
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
222
+ }, {
223
+ target: _constants.TaskState.TERMINATED,
224
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
225
+ }],
226
+ [_constants.TaskEvent.CAMPAIGN_PREVIEW_ACCEPT_FAILED]: {
227
+ actions: ['updateTaskData', 'emitTaskCampaignPreviewAcceptFailed']
228
+ },
229
+ [_constants.TaskEvent.CAMPAIGN_PREVIEW_SKIP_FAILED]: {
230
+ actions: ['updateTaskData', 'emitTaskCampaignPreviewSkipFailed']
231
+ },
232
+ [_constants.TaskEvent.CAMPAIGN_PREVIEW_REMOVE_FAILED]: {
233
+ actions: ['updateTaskData', 'emitTaskCampaignPreviewRemoveFailed']
234
+ },
235
+ // AgentConsulting comes for received after the initial consult is accepted
236
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: [{
237
+ target: _constants.TaskState.CONSULTING,
238
+ actions: ['setConsultAgentJoined', 'setConsultDestination', 'updateTaskData', 'emitTaskConsultAccepted', 'emitTaskConsulting']
239
+ }],
240
+ // agentOfferConsult happens only on the receiver side of consult
241
+ [_constants.TaskEvent.OFFER_CONSULT]: {
242
+ actions: ['updateTaskData', 'emitTaskOfferConsult', 'requestAutoAnswer']
243
+ },
244
+ // AgentConsultFailed - when consulted agent (Agent 2) doesn't answer (RONA or decline)
245
+ // Clears the incoming consult notification by transitioning to TERMINATED
246
+ [_constants.TaskEvent.CONSULT_FAILED]: {
247
+ target: _constants.TaskState.TERMINATED,
248
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskReject']
249
+ },
250
+ // AgentConsultEnded - when consult initiator (Agent 1) ends the consult before
251
+ // the consulted agent (Agent 2) accepts. Clears the incoming notification.
252
+ [_constants.TaskEvent.CONSULT_END]: {
253
+ target: _constants.TaskState.TERMINATED,
254
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
255
+ }
256
+ }
257
+ },
258
+ [_constants.TaskState.CONNECTED]: {
259
+ on: {
260
+ // AgentConsultConferenced / ParticipantJoinedConference can arrive while connected.
261
+ [_constants.TaskEvent.CONFERENCE_START]: {
262
+ target: _constants.TaskState.CONFERENCING,
263
+ actions: ['updateTaskData', 'syncTaskDataFromEvent', 'clearConsultState', 'emitTaskConferenceStarted']
264
+ },
265
+ // AgentConsulting may arrive while machine is CONNECTED (EP-DN/event ordering).
266
+ // Derive consultInitiator from payload so controls are set correctly.
267
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
268
+ target: _constants.TaskState.CONSULTING,
269
+ actions: ['setConsultInitiator', 'setConsultDestination', 'setConsultAgentJoined', 'updateTaskData', 'emitTaskConsultAccepted', 'emitTaskConsulting']
270
+ },
271
+ // AgentContactAssigned can be resent after consult transfers; keep context in sync
272
+ /* TODO: This transition needs to be checked if this is even needed as receiver will
273
+ * be in Consult Accept state which can be consulting state and ASSIGNED will be only
274
+ * for the receiver. So receuving ASSIGNED in Connected state is highly unlikely.
275
+ */
276
+ [_constants.TaskEvent.ASSIGN]: {
277
+ target: _constants.TaskState.CONNECTED,
278
+ actions: ['updateTaskData', 'emitTaskAssigned']
279
+ },
280
+ // Click of hold button
281
+ [_constants.TaskEvent.HOLD_INITIATED]: {
282
+ target: _constants.TaskState.HOLD_INITIATING
283
+ },
284
+ // Remote hold from another login session (multi-login)
285
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
286
+ target: _constants.TaskState.HELD,
287
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
288
+ },
289
+ [_constants.TaskEvent.UNHOLD_INITIATED]: {
290
+ target: _constants.TaskState.RESUME_INITIATING
291
+ },
292
+ // Resume while machine is CONNECTED but main media is still on hold (stale state after consult RONA/decline).
293
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: {
294
+ target: _constants.TaskState.CONNECTED,
295
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskResume']
296
+ },
297
+ // Click of the consult button
298
+ [_constants.TaskEvent.CONSULT]: {
299
+ target: _constants.TaskState.CONSULT_INITIATING,
300
+ actions: ['setConsultInitiator', 'setConsultDestination']
301
+ },
302
+ // AgentConsultTransferred / AgentVTeamTransferred / AgentBlindTransferred
303
+ [_constants.TaskEvent.TRANSFER_SUCCESS]: [{
304
+ guard: _guards.guards.shouldWrapUpOrIsInitiator,
305
+ target: _constants.TaskState.WRAPPING_UP,
306
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
307
+ }, {
308
+ // Receiver goes to connected as he receives transferSuccess event
309
+ actions: ['updateTaskData', 'clearConsultState']
310
+ }],
311
+ [_constants.TaskEvent.TRANSFER_FAILED]: {
312
+ actions: ['updateTaskData']
313
+ },
314
+ // AgentConsultEnded from Stable Prod while on connected leg (external end consult).
315
+ [_constants.TaskEvent.CONSULT_END]: [...currentAgentConsultEndTransitions(), {
316
+ guard: ({
317
+ context,
318
+ event
319
+ }) => {
320
+ if (context.consultInitiator !== true) return false;
321
+ const taskData = (0, _guards.getTaskDataFromEvent)(event);
322
+ const mainId = taskData?.interaction?.mainInteractionId || taskData?.interactionId;
323
+ return Boolean(mainId && taskData?.interaction?.media?.[mainId]?.isHold === true);
324
+ },
325
+ target: _constants.TaskState.HELD,
326
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
327
+ }, {
328
+ guard: ({
329
+ context
330
+ }) => context.consultInitiator === true,
331
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
332
+ }],
333
+ // AgentContactEnded Event
334
+ [_constants.TaskEvent.CONTACT_ENDED]: [{
335
+ // Campaign preview ContactEnded is terminal cleanup; never enter wrapup.
336
+ guard: _guards.guards.isCampaignPreviewContactEnded,
337
+ target: _constants.TaskState.TERMINATED,
338
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
339
+ }, {
340
+ // Conference still active → CONFERENCING
341
+ guard: _guards.guards.conferenceInProgressFromEvent,
342
+ target: _constants.TaskState.CONFERENCING,
343
+ actions: ['updateTaskData', 'emitTaskConferenceStarted', 'requestCleanup']
344
+ }, {
345
+ // Agent should wrap up → WRAPPING_UP
346
+ guard: _guards.guards.shouldWrapUp,
347
+ target: _constants.TaskState.WRAPPING_UP,
348
+ actions: ['updateTaskData', 'markEnded', 'emitTaskWrapup', 'requestCleanup']
349
+ }, {
350
+ // Consulted agent → TERMINATED
351
+ target: _constants.TaskState.TERMINATED,
352
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
353
+ }],
354
+ [_constants.TaskEvent.TASK_WRAPUP]: {
355
+ target: _constants.TaskState.WRAPPING_UP,
356
+ actions: ['updateTaskData', 'markEnded']
357
+ },
358
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
359
+ guard: _guards.guards.shouldWrapUp,
360
+ target: _constants.TaskState.WRAPPING_UP,
361
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
362
+ }, {
363
+ target: _constants.TaskState.TERMINATED,
364
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
365
+ }],
366
+ [_constants.TaskEvent.PAUSE_RECORDING]: {
367
+ actions: ['updateTaskData', 'setRecordingState', 'emitTaskRecordingPaused']
368
+ },
369
+ [_constants.TaskEvent.RESUME_RECORDING]: {
370
+ actions: ['updateTaskData', 'setRecordingState', 'emitTaskRecordingResumed']
371
+ },
372
+ [_constants.TaskEvent.EXIT_CONFERENCE_SUCCESS]: exitConferenceSuccessTransitions()
373
+ }
374
+ },
375
+ [_constants.TaskState.HOLD_INITIATING]: {
376
+ on: {
377
+ // AgentContactHeld Event
378
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
379
+ target: _constants.TaskState.HELD,
380
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
381
+ },
382
+ // AgentContactHoldFailed Event
383
+ [_constants.TaskEvent.HOLD_FAILED]: {
384
+ target: _constants.TaskState.CONNECTED,
385
+ actions: ['updateTaskData']
386
+ },
387
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
388
+ guard: _guards.guards.shouldWrapUp,
389
+ target: _constants.TaskState.WRAPPING_UP,
390
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
391
+ }, {
392
+ target: _constants.TaskState.TERMINATED,
393
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
394
+ }],
395
+ [_constants.TaskEvent.TASK_WRAPUP]: {
396
+ target: _constants.TaskState.WRAPPING_UP,
397
+ actions: ['updateTaskData', 'markEnded']
398
+ }
399
+ }
400
+ },
401
+ [_constants.TaskState.HELD]: {
402
+ on: {
403
+ // Conference can be merged while this agent is in held state after refresh/recovery.
404
+ [_constants.TaskEvent.CONFERENCE_START]: {
405
+ target: _constants.TaskState.CONFERENCING,
406
+ actions: ['updateTaskData', 'syncTaskDataFromEvent', 'clearConsultState', 'emitTaskConferenceStarted']
407
+ },
408
+ [_constants.TaskEvent.PAUSE_RECORDING]: {
409
+ actions: ['updateTaskData', 'setRecordingState', 'emitTaskRecordingPaused']
410
+ },
411
+ [_constants.TaskEvent.RESUME_RECORDING]: {
412
+ actions: ['updateTaskData', 'setRecordingState', 'emitTaskRecordingResumed']
413
+ },
414
+ // Click of the unhold button
415
+ [_constants.TaskEvent.UNHOLD_INITIATED]: {
416
+ target: _constants.TaskState.RESUME_INITIATING
417
+ },
418
+ // Remote resume from another login session (multi-login)
419
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: {
420
+ target: _constants.TaskState.CONNECTED,
421
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskResume']
422
+ },
423
+ // Click of the consult button
424
+ [_constants.TaskEvent.CONSULT]: {
425
+ target: _constants.TaskState.CONSULT_INITIATING,
426
+ actions: ['setConsultInitiator', 'setConsultDestination']
427
+ },
428
+ // AgentConsulting while main leg is held (Task Refactor / Stable Prod consult accept).
429
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
430
+ target: _constants.TaskState.CONSULTING,
431
+ actions: ['setConsultInitiator', 'setConsultDestination', 'setConsultAgentJoined', 'updateTaskData', 'emitTaskConsultAccepted', 'emitTaskConsulting']
432
+ },
433
+ // TODO: This may not be a valid transition, need to be removed
434
+ // AgentConsultTransferred / AgentVTeamTransferred / AgentBlindTransferred
435
+ [_constants.TaskEvent.TRANSFER_SUCCESS]: [{
436
+ guard: _guards.guards.shouldWrapUpOrIsInitiator,
437
+ target: _constants.TaskState.WRAPPING_UP,
438
+ actions: ['updateTaskData', 'markEnded', 'emitTaskWrapup']
439
+ }, {
440
+ target: _constants.TaskState.CONNECTED,
441
+ actions: ['updateTaskData', 'clearConsultState']
442
+ }],
443
+ [_constants.TaskEvent.TRANSFER_FAILED]: {
444
+ actions: ['updateTaskData']
445
+ },
446
+ [_constants.TaskEvent.CONTACT_ENDED]: [{
447
+ // Campaign preview ContactEnded is terminal cleanup; never enter wrapup.
448
+ guard: _guards.guards.isCampaignPreviewContactEnded,
449
+ target: _constants.TaskState.TERMINATED,
450
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
451
+ }, {
452
+ guard: _guards.guards.conferenceInProgressFromEvent,
453
+ target: _constants.TaskState.CONFERENCING,
454
+ actions: ['updateTaskData', 'emitTaskConferenceStarted', 'requestCleanup']
455
+ }, {
456
+ guard: _guards.guards.shouldWrapUp,
457
+ target: _constants.TaskState.WRAPPING_UP,
458
+ actions: ['updateTaskData', 'markEnded', 'emitTaskWrapup', 'requestCleanup']
459
+ }, {
460
+ target: _constants.TaskState.TERMINATED,
461
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd']
462
+ }],
463
+ // AgentConsultEnded from Stable Prod while main leg is held (external end consult).
464
+ [_constants.TaskEvent.CONSULT_END]: [...currentAgentConsultEndTransitions(), {
465
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
466
+ }],
467
+ [_constants.TaskEvent.PARTICIPANT_LEAVE]: [...currentAgentParticipantLeaveTransitions(), {
468
+ actions: ['updateTaskData', 'handleParticipantLeft', 'emitTaskParticipantLeft']
469
+ }],
470
+ // TODO: This may not be a valid transition, this needs to be checked as well
471
+ [_constants.TaskEvent.TASK_WRAPUP]: {
472
+ target: _constants.TaskState.WRAPPING_UP,
473
+ actions: ['updateTaskData', 'markEnded']
474
+ },
475
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
476
+ guard: _guards.guards.shouldWrapUp,
477
+ target: _constants.TaskState.WRAPPING_UP,
478
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
479
+ }, {
480
+ target: _constants.TaskState.TERMINATED,
481
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
482
+ }],
483
+ [_constants.TaskEvent.EXIT_CONFERENCE_SUCCESS]: exitConferenceSuccessTransitions()
484
+ }
485
+ },
486
+ [_constants.TaskState.RESUME_INITIATING]: {
487
+ on: {
488
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: {
489
+ target: _constants.TaskState.CONNECTED,
490
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskResume']
491
+ },
492
+ [_constants.TaskEvent.UNHOLD_FAILED]: {
493
+ target: _constants.TaskState.HELD
494
+ },
495
+ [_constants.TaskEvent.PARTICIPANT_LEAVE]: [...currentAgentParticipantLeaveTransitions(), {
496
+ actions: ['updateTaskData', 'handleParticipantLeft', 'emitTaskParticipantLeft']
497
+ }],
498
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
499
+ guard: _guards.guards.shouldWrapUp,
500
+ target: _constants.TaskState.WRAPPING_UP,
501
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
502
+ }, {
503
+ target: _constants.TaskState.TERMINATED,
504
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
505
+ }],
506
+ [_constants.TaskEvent.TASK_WRAPUP]: {
507
+ target: _constants.TaskState.WRAPPING_UP,
508
+ actions: ['updateTaskData', 'markEnded']
509
+ }
510
+ }
511
+ },
512
+ [_constants.TaskState.CONSULT_INITIATING]: {
513
+ on: {
514
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
515
+ actions: ['updateTaskData']
516
+ },
517
+ [_constants.TaskEvent.HOLD_FAILED]: {
518
+ target: _constants.TaskState.CONNECTED,
519
+ actions: ['updateTaskData', 'handleConsultFailed']
520
+ },
521
+ // AgentConsulting
522
+ // NOTE: Don't set consultDestinationAgentJoined here - wait for CONSULTING_ACTIVE
523
+ [_constants.TaskEvent.CONSULT_SUCCESS]: {
524
+ target: _constants.TaskState.CONSULTING,
525
+ actions: ['updateTaskData', 'setConsultInitiator']
526
+ },
527
+ // AgentConsulting (Task Refactor: AgentConsulting event, not CONSULT_SUCCESS)
528
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
529
+ target: _constants.TaskState.CONSULTING,
530
+ actions: ['setConsultInitiator', 'setConsultDestination', 'setConsultAgentJoined', 'updateTaskData', 'emitTaskConsultAccepted', 'emitTaskConsulting']
531
+ },
532
+ // AgentConsultFailed, API Failures, AgentCtqFailed
533
+ [_constants.TaskEvent.CONSULT_FAILED]: [{
534
+ // Consult from conference → back to CONFERENCING
535
+ guard: ({
536
+ context
537
+ }) => context.consultFromConference === true,
538
+ target: _constants.TaskState.CONFERENCING,
539
+ actions: ['updateTaskData', 'handleConsultFailed']
540
+ }, {
541
+ guard: _guards.guards.isPrimaryMediaOnHold,
542
+ target: _constants.TaskState.HELD,
543
+ actions: ['updateTaskData', 'handleConsultFailed']
544
+ }, {
545
+ target: _constants.TaskState.CONNECTED,
546
+ actions: ['updateTaskData', 'handleConsultFailed']
547
+ }],
548
+ // AgentCtqCancelled Event
549
+ [_constants.TaskEvent.CTQ_CANCEL]: [{
550
+ guard: _guards.guards.isPrimaryMediaOnHold,
551
+ target: _constants.TaskState.HELD,
552
+ actions: ['updateTaskData', 'clearConsultState']
553
+ }, {
554
+ target: _constants.TaskState.CONNECTED,
555
+ actions: ['updateTaskData', 'clearConsultState']
556
+ }],
557
+ // AgentConsultEnded from Stable Prod during consult initiation (external end consult).
558
+ [_constants.TaskEvent.CONSULT_END]: [...currentAgentConsultEndTransitions(), {
559
+ guard: _guards.guards.isPrimaryMediaOnHold,
560
+ target: _constants.TaskState.HELD,
561
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
562
+ }, {
563
+ target: _constants.TaskState.CONNECTED,
564
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
565
+ }],
566
+ [_constants.TaskEvent.PARTICIPANT_LEAVE]: [...currentAgentParticipantLeaveTransitions(), {
567
+ actions: ['updateTaskData', 'handleParticipantLeft', 'emitTaskParticipantLeft']
568
+ }],
569
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
570
+ guard: _guards.guards.shouldWrapUp,
571
+ target: _constants.TaskState.WRAPPING_UP,
572
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
573
+ }, {
574
+ target: _constants.TaskState.TERMINATED,
575
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
576
+ }],
577
+ [_constants.TaskEvent.TASK_WRAPUP]: {
578
+ target: _constants.TaskState.WRAPPING_UP,
579
+ actions: ['updateTaskData', 'markEnded']
580
+ }
581
+ }
582
+ },
583
+ [_constants.TaskState.CONSULTING]: {
584
+ on: {
585
+ // AgentConsulting updates consulted agent arrival
586
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
587
+ actions: ['setConsultAgentJoined', 'setConsultDestination', 'updateTaskData', 'emitTaskConsulting']
588
+ },
589
+ // AgentConsultFailed (RONA / consultee declined) while the initiator is already in
590
+ // CONSULTING (AgentConsulting arrived during ringing). Mirror CONSULT_INITIATING so the
591
+ // initiator returns to their own leg (HELD when main is on hold, else CONNECTED) instead
592
+ // of staying in CONSULTING. Without this, handleConsultFailed clears consultInitiator but
593
+ // the machine stays in CONSULTING, so the trailing AgentConsultEnded falls through the
594
+ // CONSULT_END "consulted agent" branch to TERMINATED and wrongly clears the task.
595
+ [_constants.TaskEvent.CONSULT_FAILED]: [{
596
+ guard: ({
597
+ context
598
+ }) => context.consultFromConference === true,
599
+ target: _constants.TaskState.CONFERENCING,
600
+ actions: ['updateTaskData', 'handleConsultFailed']
601
+ }, {
602
+ guard: _guards.guards.isPrimaryMediaOnHold,
603
+ target: _constants.TaskState.HELD,
604
+ actions: ['updateTaskData', 'handleConsultFailed']
605
+ }, {
606
+ target: _constants.TaskState.CONNECTED,
607
+ actions: ['updateTaskData', 'handleConsultFailed']
608
+ }],
609
+ // AgentConsultEnded
610
+ [_constants.TaskEvent.CONSULT_END]: [...currentAgentConsultEndTransitions(), {
611
+ // Initiator returning to conference only while conference is still active.
612
+ guard: ({
613
+ context,
614
+ event
615
+ }) => context.consultInitiator === true && _guards.guards.conferenceInProgressFromEvent({
616
+ context,
617
+ event
618
+ }),
619
+ target: _constants.TaskState.CONFERENCING,
620
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
621
+ }, {
622
+ // Conference consult ended after conference downgrade while main leg is held.
623
+ guard: ({
624
+ context,
625
+ event
626
+ }) => context.consultInitiator === true && context.consultFromConference === true && !_guards.guards.conferenceInProgressFromEvent({
627
+ context,
628
+ event
629
+ }) && _guards.guards.isConferenceHoldParticipantFromEvent({
630
+ context,
631
+ event
632
+ }),
633
+ target: _constants.TaskState.HELD,
634
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
635
+ }, {
636
+ // Conference consult ended after conference downgrade while main leg is connected.
637
+ guard: ({
638
+ context,
639
+ event
640
+ }) => context.consultInitiator === true && context.consultFromConference === true && !_guards.guards.conferenceInProgressFromEvent({
641
+ context,
642
+ event
643
+ }) && !_guards.guards.isConferenceHoldParticipantFromEvent({
644
+ context,
645
+ event
646
+ }),
647
+ target: _constants.TaskState.CONNECTED,
648
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
649
+ }, {
650
+ // Initiator already switched back to the main/customer leg
651
+ guard: ({
652
+ context
653
+ }) => context.consultInitiator === true && context.consultCallHeld === true,
654
+ target: _constants.TaskState.CONNECTED,
655
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
656
+ }, {
657
+ // Interaction terminated during consult (customer left) → WRAPPING_UP
658
+ guard: ({
659
+ context,
660
+ event
661
+ }) => {
662
+ // if (context.consultInitiator !== true) return false;
663
+ // const taskData = getTaskDataFromEvent(event);
664
+ const taskData = (0, _guards.getTaskDataFromEvent)(event);
665
+ const cpd = taskData?.interaction?.callProcessingDetails;
666
+ if (cpd?.hasCustomerLeft !== 'true') return false;
667
+ return taskData?.interaction?.isTerminated === true && (0, _guards.shouldWrapUpForThisAgent)(context, taskData);
668
+ },
669
+ target: _constants.TaskState.WRAPPING_UP,
670
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup', 'requestCleanup']
671
+ }, {
672
+ // Initiator (no conference) → HELD
673
+ guard: ({
674
+ context
675
+ }) => context.consultInitiator === true,
676
+ target: _constants.TaskState.HELD,
677
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd']
678
+ }, {
679
+ // Consulted agent → TERMINATED
680
+ target: _constants.TaskState.TERMINATED,
681
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskConsultEnd', 'emitTaskEnd']
682
+ }],
683
+ // Switch between consult and main call (UI-driven toggle)
684
+ [_constants.TaskEvent.SWITCH_TO_MAIN_CALL]: {
685
+ actions: ['handleSwitchToMainCall', 'emitTaskSwitchCall']
686
+ },
687
+ [_constants.TaskEvent.SWITCH_TO_CONSULT]: {
688
+ actions: ['handleSwitchToConsult', 'emitTaskSwitchCall']
689
+ },
690
+ [_constants.TaskEvent.HOLD_SUCCESS]: {
691
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
692
+ },
693
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: {
694
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskResume']
695
+ },
696
+ [_constants.TaskEvent.PARTICIPANT_LEAVE]: [...currentAgentParticipantLeaveTransitions(), {
697
+ guard: params => !_guards.guards.didCurrentAgentLeaveMainInteraction(params) && _guards.guards.shouldDowngradeConferenceToConnected(params),
698
+ target: _constants.TaskState.CONNECTED,
699
+ actions: ['updateTaskData', 'handleParticipantLeft', 'clearConsultState', 'emitTaskParticipantLeft', 'emitTaskConferenceEnded']
700
+ }, {
701
+ actions: ['updateTaskData', 'handleParticipantLeft', 'emitTaskParticipantLeft']
702
+ }],
703
+ [_constants.TaskEvent.TRANSFER_SUCCESS]: [{
704
+ guard: _guards.guards.shouldWrapUpOrIsInitiator,
705
+ target: _constants.TaskState.WRAPPING_UP,
706
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
707
+ }, {
708
+ target: _constants.TaskState.CONNECTED,
709
+ actions: ['updateTaskData', 'clearConsultState']
710
+ }],
711
+ [_constants.TaskEvent.TRANSFER_FAILED]: {
712
+ actions: ['updateTaskData']
713
+ },
714
+ [_constants.TaskEvent.TRANSFER_CONFERENCE]: {
715
+ // Track that this agent initiated the conference transfer so we can
716
+ // apply the correct lifecycle transition when success arrives.
717
+ actions: ['setTransferConferenceRequested', 'emitTaskTransferConference']
718
+ },
719
+ [_constants.TaskEvent.TRANSFER_CONFERENCE_SUCCESS]: [{
720
+ guard: _guards.guards.shouldWrapUp,
721
+ target: _constants.TaskState.WRAPPING_UP,
722
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested']
723
+ }, {
724
+ // Non-initiator (e.g. consultee receiving transfer) moves to CONFERENCING
725
+ guard: params => !_guards.guards.isSelfConferenceTransferInitiator(params),
726
+ target: _constants.TaskState.CONFERENCING,
727
+ actions: ['updateTaskData', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested']
728
+ }, {
729
+ target: _constants.TaskState.TERMINATED,
730
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested', 'emitTaskEnd']
731
+ }],
732
+ [_constants.TaskEvent.TRANSFER_CONFERENCE_FAILED]: {
733
+ actions: ['clearTransferConferenceRequested', 'emitTaskTransferConferenceFailed']
734
+ },
735
+ // AgentContactAssigned - receiver side becomes connected to customer
736
+ [_constants.TaskEvent.ASSIGN]: {
737
+ target: _constants.TaskState.CONNECTED,
738
+ actions: ['updateTaskData', 'emitTaskAssigned']
739
+ },
740
+ // AgentContactEnded
741
+ [_constants.TaskEvent.CONTACT_ENDED]: {
742
+ target: _constants.TaskState.WRAPPING_UP,
743
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup', 'requestCleanup']
744
+ },
745
+ [_constants.TaskEvent.TASK_WRAPUP]: {
746
+ target: _constants.TaskState.WRAPPING_UP,
747
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState']
748
+ },
749
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
750
+ guard: _guards.guards.shouldWrapUp,
751
+ target: _constants.TaskState.WRAPPING_UP,
752
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
753
+ }, {
754
+ target: _constants.TaskState.TERMINATED,
755
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
756
+ }],
757
+ [_constants.TaskEvent.MERGE_TO_CONFERENCE]: {
758
+ target: _constants.TaskState.CONF_INITIATING
759
+ },
760
+ // AgentConsultConferenced, ParticipantJoinedConference
761
+ [_constants.TaskEvent.CONFERENCE_START]: {
762
+ target: _constants.TaskState.CONFERENCING,
763
+ actions: ['updateTaskData', 'syncTaskDataFromEvent', 'handleConferenceStarted', 'clearConsultState']
764
+ }
765
+ }
766
+ },
767
+ [_constants.TaskState.CONF_INITIATING]: {
768
+ on: {
769
+ // AgentConsultConferenced, AgentConsultConferencing, ParticipantJoinedConference
770
+ [_constants.TaskEvent.CONFERENCE_START]: {
771
+ target: _constants.TaskState.CONFERENCING,
772
+ actions: ['updateTaskData', 'syncTaskDataFromEvent', 'handleConferenceStarted', 'clearConsultState']
773
+ },
774
+ // AgentConsultConferenceFailed
775
+ [_constants.TaskEvent.CONFERENCE_FAILED]: {
776
+ target: _constants.TaskState.CONSULTING,
777
+ actions: ['handleConferenceFailed', 'emitTaskConferenceFailed']
778
+ },
779
+ // AgentConsultEnded while conference is initiating (end call before conference completes)
780
+ [_constants.TaskEvent.CONSULT_END]: [...currentAgentConsultEndTransitions(), {
781
+ guard: ({
782
+ event
783
+ }) => {
784
+ const taskData = (0, _guards.getTaskDataFromEvent)(event);
785
+ return taskData?.interaction?.isTerminated === true;
786
+ },
787
+ target: _constants.TaskState.WRAPPING_UP,
788
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
789
+ }, {
790
+ target: _constants.TaskState.CONNECTED,
791
+ actions: ['updateTaskData', 'clearConsultState']
792
+ }],
793
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
794
+ guard: _guards.guards.shouldWrapUp,
795
+ target: _constants.TaskState.WRAPPING_UP,
796
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
797
+ }, {
798
+ target: _constants.TaskState.TERMINATED,
799
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
800
+ }],
801
+ [_constants.TaskEvent.TASK_WRAPUP]: {
802
+ target: _constants.TaskState.WRAPPING_UP,
803
+ actions: ['updateTaskData', 'markEnded']
804
+ }
805
+ }
806
+ },
807
+ [_constants.TaskState.CONFERENCING]: {
808
+ on: {
809
+ [_constants.TaskEvent.CONFERENCE_START]: {
810
+ actions: ['updateTaskData', 'syncTaskDataFromEvent', 'clearConsultState', 'emitTaskConferenceStarted']
811
+ },
812
+ [_constants.TaskEvent.EXIT_CONFERENCE_SUCCESS]: exitConferenceSuccessTransitions(),
813
+ // Needed as all agents in conference get this event, hence we need to clear the consult state
814
+ [_constants.TaskEvent.CONSULT_END]: [...currentAgentConsultEndTransitions(), {
815
+ guard: ({
816
+ context,
817
+ event
818
+ }) => {
819
+ const taskData = (0, _guards.getTaskDataFromEvent)(event);
820
+ return taskData?.interaction?.isTerminated === true && (0, _guards.shouldWrapUpForThisAgent)(context, taskData);
821
+ },
822
+ target: _constants.TaskState.WRAPPING_UP,
823
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskWrapup']
824
+ }, {
825
+ actions: ['updateTaskData', 'clearConsultState']
826
+ }],
827
+ [_constants.TaskEvent.HOLD_SUCCESS]: [{
828
+ // Conference already downgraded (no other agents) and backend hold arrives.
829
+ // Move to HELD so the UI renders resume action.
830
+ guard: _guards.guards.shouldDowngradeConferenceToConnected,
831
+ target: _constants.TaskState.HELD,
832
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
833
+ }, {
834
+ actions: ['updateTaskData', 'setHoldState', 'emitTaskHold']
835
+ }],
836
+ [_constants.TaskEvent.UNHOLD_SUCCESS]: [{
837
+ // Conference already downgraded (no other agents) and backend unhold arrives.
838
+ // Move to CONNECTED so hold action is available again.
839
+ guard: _guards.guards.shouldDowngradeConferenceToConnected,
840
+ target: _constants.TaskState.CONNECTED,
841
+ actions: ['updateTaskData', 'syncTaskDataFromEvent', 'setHoldState', 'emitTaskResume']
842
+ }, {
843
+ actions: ['updateTaskData', 'syncTaskDataFromEvent', 'setHoldState', 'emitTaskResume']
844
+ }],
845
+ // Start a new consult from within an active conference
846
+ [_constants.TaskEvent.CONSULT]: {
847
+ target: _constants.TaskState.CONSULT_INITIATING,
848
+ actions: ['setConsultInitiator', 'setConsultDestination', 'setConsultFromConference']
849
+ },
850
+ // AgentConsulting while still in conference (EP-DN/external ordering).
851
+ [_constants.TaskEvent.CONSULTING_ACTIVE]: {
852
+ target: _constants.TaskState.CONSULTING,
853
+ actions: ['setConsultInitiator', 'setConsultDestination', 'setConsultFromConference', 'setConsultAgentJoined', 'updateTaskData', 'emitTaskConsultAccepted', 'emitTaskConsulting']
854
+ },
855
+ // Participant leaves - handle conference downgrade scenarios
856
+ [_constants.TaskEvent.PARTICIPANT_LEAVE]: [...currentAgentParticipantLeaveTransitions(), {
857
+ // Conference downgraded, customer present → CONNECTED
858
+ guard: params => !_guards.guards.didCurrentAgentLeaveMainInteraction(params) && _guards.guards.shouldDowngradeConferenceToConnected(params),
859
+ target: _constants.TaskState.CONNECTED,
860
+ actions: ['updateTaskData', 'handleParticipantLeft', 'clearConsultState', 'emitTaskParticipantLeft', 'emitTaskConferenceEnded']
861
+ }, {
862
+ actions: ['updateTaskData', 'handleParticipantLeft', 'emitTaskParticipantLeft']
863
+ }],
864
+ [_constants.TaskEvent.TRANSFER_CONFERENCE]: {
865
+ actions: ['setTransferConferenceRequested', 'emitTaskTransferConference']
866
+ },
867
+ [_constants.TaskEvent.TRANSFER_CONFERENCE_SUCCESS]: [{
868
+ guard: _guards.guards.isPassiveConferenceTransferObserver,
869
+ actions: ['updateTaskData', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested']
870
+ }, {
871
+ guard: _guards.guards.shouldWrapUp,
872
+ target: _constants.TaskState.WRAPPING_UP,
873
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested']
874
+ }, {
875
+ guard: params => !_guards.guards.isSelfConferenceTransferInitiator(params),
876
+ target: _constants.TaskState.CONFERENCING,
877
+ actions: ['updateTaskData', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested']
878
+ }, {
879
+ target: _constants.TaskState.TERMINATED,
880
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'handleTransferConferenceSuccess', 'clearTransferConferenceRequested', 'emitTaskEnd']
881
+ }],
882
+ [_constants.TaskEvent.TRANSFER_CONFERENCE_FAILED]: {
883
+ actions: ['clearTransferConferenceRequested', 'emitTaskTransferConferenceFailed']
884
+ },
885
+ // Conference ends explicitly
886
+ [_constants.TaskEvent.CONFERENCE_END]: [{
887
+ // Agent who should wrap up → WRAPPING_UP
888
+ guard: _guards.guards.shouldWrapUp,
889
+ target: _constants.TaskState.WRAPPING_UP,
890
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState']
891
+ }, {
892
+ // Customer still in call → CONNECTED
893
+ guard: ({
894
+ context,
895
+ event
896
+ }) => {
897
+ if (context.exitingConference === true) return false;
898
+ const taskData = event?.taskData ?? context.taskData;
899
+ if (!taskData?.interaction) return false;
900
+ const mainCallId = taskData.interaction.mainInteractionId || taskData.interactionId;
901
+ if (!mainCallId) return false;
902
+ return (0, _TaskUtils.getIsCustomerInCall)(taskData.interaction, mainCallId);
903
+ },
904
+ target: _constants.TaskState.CONNECTED,
905
+ actions: ['updateTaskData', 'clearConsultState', 'emitTaskConferenceEnded']
906
+ }, {
907
+ // Otherwise → TERMINATED
908
+ target: _constants.TaskState.TERMINATED,
909
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState', 'emitTaskEnd']
910
+ }],
911
+ // CONTACT_ENDED in conference
912
+ [_constants.TaskEvent.CONTACT_ENDED]: [{
913
+ // Conference still active → stay
914
+ actions: ['updateTaskData', 'requestCleanup']
915
+ }],
916
+ [_constants.TaskEvent.CONSULT_FAILED]: {
917
+ actions: ['updateTaskData', 'handleConsultFailed']
918
+ },
919
+ [_constants.TaskEvent.TASK_WRAPUP]: {
920
+ guard: _guards.guards.shouldWrapUp,
921
+ target: _constants.TaskState.WRAPPING_UP,
922
+ actions: ['updateTaskData', 'markEnded', 'clearConsultState']
923
+ },
924
+ [_constants.TaskEvent.OUTBOUND_FAILED]: [{
925
+ guard: _guards.guards.shouldWrapUp,
926
+ target: _constants.TaskState.WRAPPING_UP,
927
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskWrapup']
928
+ }, {
929
+ target: _constants.TaskState.TERMINATED,
930
+ actions: ['updateTaskData', 'markEnded', 'emitTaskOutdialFailed', 'emitTaskEnd']
931
+ }]
932
+ }
933
+ },
934
+ [_constants.TaskState.WRAPPING_UP]: {
935
+ // Only emit wrapup event on entry - task:end should only be emitted when COMPLETED
936
+ entry: ['emitTaskWrapup'],
937
+ on: {
938
+ // Late AgentWrapup after conference exit already entered WRAPPING_UP
939
+ [_constants.TaskEvent.TASK_WRAPUP]: [{
940
+ guard: ({
941
+ context
942
+ }) => context.taskData?.wrapUpRequired === true,
943
+ actions: ['updateTaskData']
944
+ }, {
945
+ actions: ['updateTaskData', 'emitTaskWrapup']
946
+ }],
947
+ // AgentWrappedup Event
948
+ [_constants.TaskEvent.WRAPUP_COMPLETE]: {
949
+ target: _constants.TaskState.COMPLETED,
950
+ actions: ['updateTaskData']
951
+ }
952
+ }
953
+ },
954
+ [_constants.TaskState.COMPLETED]: {
955
+ type: 'final',
956
+ entry: ['emitTaskWrappedup', 'cleanupResources']
957
+ },
958
+ [_constants.TaskState.TERMINATED]: {
959
+ type: 'final',
960
+ entry: ['cleanupResources']
961
+ }
962
+ }
963
+ };
964
+ }
965
+
966
+ /**
967
+ * Create a task state machine instance using only the built-in actions.
968
+ * The resulting machine is ready for most consumers that rely on the default
969
+ * context mutators declared in actions.ts.
970
+ *
971
+ * @param uiControlConfig - UI control configuration
972
+ * @returns StateMachine instance for task management
973
+ */
974
+ function createTaskStateMachine(uiControlConfig, options) {
975
+ return taskStateMachineSetup.createMachine(getTaskStateMachineConfig(uiControlConfig)).provide({
976
+ actions: {
977
+ ..._actions.actions,
978
+ ...(options?.actions ?? {})
979
+ }
980
+ });
981
+ }
982
+ //# sourceMappingURL=TaskStateMachine.js.map