@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,1156 @@
1
+ # Task State Machine - Architecture
2
+
3
+ > **Legacy/reference-only.** Canonical SDD: [`task-state-machine-spec.md`](task-state-machine-spec.md). Use the package [manifest](../../../../../.sdd/manifest.json) and [`SPEC_INDEX.md`](../../../../../ai-docs/SPEC_INDEX.md) for routing; code and tests remain the behavioral referee.
4
+
5
+ ## Purpose
6
+
7
+ Technical reference for the complete state machine using XState to drive state transitions and UI control behavior. It orchestrates state transitions, guards, and actions for task lifecycle management.
8
+
9
+ ---
10
+
11
+ ## Architecture Overview
12
+
13
+ The task state machine is built with `xstate` and organized into:
14
+
15
+ - **State graph** (`TaskStateMachine.ts`)
16
+ - **Context mutators** (`actions.ts`)
17
+ - **Guard predicates** (`guards.ts`)
18
+ - **UI control derivation** (`uiControlsComputer.ts`)
19
+ - **Event/context contracts** (`types.ts`)
20
+
21
+ It is instantiated by `Task` and receives mapped backend/user events through `sendStateMachineEvent(...)`.
22
+
23
+ ---
24
+
25
+ ## Runtime Integration
26
+
27
+ `Task` bootstraps and owns the actor lifecycle:
28
+
29
+ 1. `createTaskStateMachine(uiControlConfig, {actions: overrides})`
30
+ 2. `createActor(machine).start()`
31
+ 3. `TaskManager` and task APIs map external signals to `TaskEvent`
32
+ 4. Actor transitions update context and execute action overrides
33
+ 5. `Task` recomputes per-leg controls plus ordered Consult/Transfer destination availability and emits task-level events when either changes
34
+
35
+ ---
36
+
37
+ ## States
38
+
39
+ ### IDLE
40
+
41
+ **Description**: Initial state before a task is offered or restored.
42
+
43
+ **How this state is reached (incoming transitions)**:
44
+
45
+ - Machine start -> `IDLE` (no event, no actions)
46
+
47
+ **Valid transitions from `IDLE` state**:
48
+
49
+ - `TASK_INCOMING` -> `OFFERED`
50
+ - Guard: none
51
+ - Actions: `initializeTask`, `emitTaskIncoming`
52
+ - `HYDRATE` -> `WRAPPING_UP`
53
+ - Guard: `guards.isInteractionTerminated`
54
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskHydrate`
55
+ - `HYDRATE` -> `CONSULTING`
56
+ - Guard: `guards.isInteractionConsulting`
57
+ - Actions: `updateTaskData`, `emitTaskHydrate`
58
+ - `HYDRATE` -> `HELD`
59
+ - Guard: `guards.isInteractionHeld`
60
+ - Actions: `updateTaskData`, `emitTaskHydrate`
61
+ - `HYDRATE` -> `CONNECTED`
62
+ - Guard: `guards.isInteractionConnected`
63
+ - Actions: `updateTaskData`, `emitTaskHydrate`
64
+ - `HYDRATE` -> `CONFERENCING`
65
+ - Guard: `guards.isConferencingByParticipants`
66
+ - Actions: `updateTaskData`, `emitTaskHydrate`
67
+ - `HYDRATE` -> stay `IDLE` (default hydrate branch)
68
+ - Guard: default
69
+ - Actions: `updateTaskData`, `emitTaskHydrate`
70
+
71
+ ---
72
+
73
+ ### OFFERED
74
+
75
+ **Description**: Task has been offered/reserved and is waiting for assignment or termination paths.
76
+
77
+ **How this state is reached (incoming transitions)**:
78
+
79
+ - `IDLE --TASK_INCOMING--> OFFERED`
80
+ - Guard: none
81
+ - Actions: `initializeTask`, `emitTaskIncoming`
82
+
83
+ **Valid transitions from `OFFERED`**:
84
+
85
+ - `TASK_OFFERED` -> Stay `OFFERED`
86
+ - Guard: none
87
+ - Actions: `updateTaskData`, `emitTaskOfferContact`, `requestAutoAnswer`
88
+ - `OFFER_CONSULT` -> Stay `OFFERED`
89
+ - Guard: none
90
+ - Actions: `updateTaskData`, `emitTaskOfferConsult`, `requestAutoAnswer`
91
+ - `ASSIGN` -> `CONNECTED`
92
+ - Guard: none
93
+ - Actions: `updateTaskData`, `emitTaskAssigned`
94
+ - `CONSULTING_ACTIVE` -> `CONSULTING`
95
+ - Guard: none
96
+ - Actions: `updateTaskData`, `setConsultAgentJoined`, `emitTaskConsultAccepted`, `emitTaskConsulting`
97
+ - `TASK_WRAPUP` -> `WRAPPING_UP`
98
+ - Guard: `guards.shouldWrapUp`
99
+ - Actions: `updateTaskData`, `markEnded`; `WRAPPING_UP` entry emits `task:wrapup`
100
+ - `TASK_WRAPUP` -> `TERMINATED` (default branch)
101
+ - Guard: default
102
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskEnd`
103
+ - `RONA` / `ASSIGN_FAILED` / `INVITE_FAILED` / `OUTBOUND_FAILED` -> `TERMINATED`
104
+ - Guard: none
105
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskReject`
106
+
107
+ ---
108
+
109
+ ### CONNECTED
110
+
111
+ **Description**: Agent is connected on the main customer interaction leg.
112
+
113
+ **How this state is reached (incoming transitions)**:
114
+
115
+ - `OFFERED --ASSIGN--> CONNECTED`
116
+ - Guard: none
117
+ - Actions: `updateTaskData`, `emitTaskAssigned`
118
+ - `IDLE --HYDRATE--> CONNECTED`
119
+ - Guard: `guards.isInteractionConnected`
120
+ - Actions: `updateTaskData`, `emitTaskHydrate`
121
+ - `RESUME_INITIATING --UNHOLD_SUCCESS--> CONNECTED`
122
+ - Guard: none
123
+ - Actions: `updateTaskData`, `setHoldState`, `emitTaskResume`
124
+ - `HELD --TRANSFER_SUCCESS--> CONNECTED` (receiver/default branch)
125
+ - Guard: default branch when `guards.shouldWrapUpOrIsInitiator` is false
126
+ - Actions: `updateTaskData`, `clearConsultState`
127
+ - `CONSULTING --ASSIGN--> CONNECTED`
128
+ - Guard: none
129
+ - Actions: `updateTaskData`, `emitTaskAssigned`
130
+
131
+ **Valid transitions from `CONNECTED`**:
132
+
133
+ - `ASSIGN` -> `CONNECTED` (self-transition)
134
+ - Guard: none
135
+ - Actions: `updateTaskData`, `emitTaskAssigned`
136
+ - `HOLD_INITIATED` -> `HOLD_INITIATING`
137
+ - Guard: none
138
+ - Actions: none
139
+ - `CONSULT` -> `CONSULT_INITIATING`
140
+ - Guard: none
141
+ - Actions: `setConsultInitiator`, `setConsultDestination`
142
+ - `CONSULTING_ACTIVE` -> `CONSULTING`
143
+ - Guard: none
144
+ - Actions: `updateTaskData`, `setConsultAgentJoined`, `emitTaskConsultAccepted`, `emitTaskConsulting`
145
+ - `TRANSFER_SUCCESS` -> `WRAPPING_UP`
146
+ - Guard: `guards.shouldWrapUpOrIsInitiator`
147
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskWrapup`
148
+ - `TRANSFER_SUCCESS` -> Stay `CONNECTED` (receiver/default branch)
149
+ - Guard: default
150
+ - Actions: `updateTaskData`, `clearConsultState`
151
+ - `TRANSFER_FAILED` -> Stay `CONNECTED`
152
+ - Guard: none
153
+ - Actions: `updateTaskData`
154
+ - `CONTACT_ENDED` -> `CONFERENCING`
155
+ - Guard: `guards.conferenceInProgressFromEvent`
156
+ - Actions: `updateTaskData`, `emitTaskConferenceStarted`, `requestCleanup`
157
+ - `CONTACT_ENDED` -> `WRAPPING_UP`
158
+ - Guard: `guards.shouldWrapUp`
159
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskWrapup`, `requestCleanup`
160
+ - `CONTACT_ENDED` -> `TERMINATED` (default branch)
161
+ - Guard: default
162
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskEnd`
163
+ - `TASK_WRAPUP` -> `WRAPPING_UP`
164
+ - Guard: none
165
+ - Actions: `updateTaskData`, `markEnded`; `WRAPPING_UP` entry emits `task:wrapup`
166
+ - `PAUSE_RECORDING` / `RESUME_RECORDING` -> Stay `CONNECTED`
167
+ - Guard: none
168
+ - Actions: `updateTaskData`, `setRecordingState`, `emitTaskRecordingPaused` / `emitTaskRecordingResumed`
169
+
170
+ ---
171
+
172
+ ### HELD
173
+
174
+ **Description**: Main call is on hold.
175
+
176
+ **How this state is reached (incoming transitions)**:
177
+
178
+ - `IDLE --HYDRATE--> HELD`
179
+ - Guard: `guards.isInteractionHeld`
180
+ - Actions: `updateTaskData`, `emitTaskHydrate`
181
+ - `HOLD_INITIATING --HOLD_SUCCESS--> HELD`
182
+ - Guard: none
183
+ - Actions: `updateTaskData`, `setHoldState`, `emitTaskHold`
184
+ - `RESUME_INITIATING --UNHOLD_FAILED--> HELD`
185
+ - Guard: none
186
+ - Actions: none
187
+ - `CONSULTING --CONSULT_END--> HELD`
188
+ - Guard: inline `context.consultInitiator === true`
189
+ - Actions: `updateTaskData`, `clearConsultState`, `emitTaskConsultEnd`
190
+ - `CONSULT_INITIATING --CONSULT_FAILED--> HELD`
191
+ - Guard: `guards.isPrimaryMediaOnHold`
192
+ - Actions: `updateTaskData`, `handleConsultFailed`
193
+ - `CONSULT_INITIATING --CTQ_CANCEL--> HELD`
194
+ - Guard: `guards.isPrimaryMediaOnHold`
195
+ - Actions: `updateTaskData`, `clearConsultState`
196
+
197
+ **Valid transitions from `HELD`**:
198
+
199
+ - `UNHOLD_INITIATED` -> `RESUME_INITIATING`
200
+ - Guard: none
201
+ - Actions: none
202
+ - `CONSULT` -> `CONSULT_INITIATING`
203
+ - Guard: none
204
+ - Actions: `setConsultInitiator`, `setConsultDestination`
205
+ - `TRANSFER_SUCCESS` -> `WRAPPING_UP`
206
+ - Guard: `guards.shouldWrapUpOrIsInitiator`
207
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskWrapup`
208
+ - `TRANSFER_SUCCESS` -> `CONNECTED` (receiver/default branch)
209
+ - Guard: default
210
+ - Actions: `updateTaskData`, `clearConsultState`
211
+ - `TRANSFER_FAILED` -> stay `HELD`
212
+ - Guard: none
213
+ - Actions: `updateTaskData`
214
+ - `CONTACT_ENDED` -> `CONFERENCING`
215
+ - Guard: `guards.conferenceInProgressFromEvent`
216
+ - Actions: `updateTaskData`, `emitTaskConferenceStarted`, `requestCleanup`
217
+ - `CONTACT_ENDED` -> `WRAPPING_UP`
218
+ - Guard: `guards.shouldWrapUp`
219
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskWrapup`, `requestCleanup`
220
+ - `CONTACT_ENDED` -> `TERMINATED` (default branch)
221
+ - Guard: default
222
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskEnd`
223
+ - `TASK_WRAPUP` -> `WRAPPING_UP`
224
+ - Guard: none
225
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskWrapup`
226
+
227
+ ---
228
+
229
+ ### HOLD_INITIATING
230
+
231
+ **Description**: Hold request has been sent and is awaiting backend confirmation.
232
+
233
+ **How this state is reached (incoming transitions)**:
234
+
235
+ - `CONNECTED --HOLD_INITIATED--> HOLD_INITIATING`
236
+ - Guard: none
237
+ - Actions: none
238
+
239
+ **Valid transitions from `HOLD_INITIATING`**:
240
+
241
+ - `HOLD_SUCCESS` -> `HELD`
242
+ - Guard: none
243
+ - Actions: `updateTaskData`, `setHoldState`, `emitTaskHold`
244
+ - `HOLD_FAILED` -> `CONNECTED`
245
+ - Guard: none
246
+ - Actions: `updateTaskData`
247
+
248
+ ---
249
+
250
+ ### RESUME_INITIATING
251
+
252
+ **Description**: Resume/unhold request has been sent and is awaiting backend confirmation.
253
+
254
+ **How this state is reached (incoming transitions)**:
255
+
256
+ - `HELD --UNHOLD_INITIATED--> RESUME_INITIATING`
257
+ - Guard: none
258
+ - Actions: none
259
+
260
+ **Valid transitions from `RESUME_INITIATING`**:
261
+
262
+ - `UNHOLD_SUCCESS` -> `CONNECTED`
263
+ - Guard: none
264
+ - Actions: `updateTaskData`, `setHoldState`, `emitTaskResume`
265
+ - `UNHOLD_FAILED` -> `HELD`
266
+ - Guard: none
267
+ - Actions: none
268
+
269
+ ---
270
+
271
+ ### CONSULT_INITIATING
272
+
273
+ **Description**: Consult request is in-flight.
274
+
275
+ **How this state is reached (incoming transitions)**:
276
+
277
+ - `CONNECTED --CONSULT--> CONSULT_INITIATING`
278
+ - Guard: none
279
+ - Actions: `setConsultInitiator`, `setConsultDestination`
280
+ - `HELD --CONSULT--> CONSULT_INITIATING`
281
+ - Guard: none
282
+ - Actions: `setConsultInitiator`, `setConsultDestination`
283
+ - `CONFERENCING --CONSULT--> CONSULT_INITIATING`
284
+ - Guard: none
285
+ - Actions: `setConsultInitiator`, `setConsultDestination`, `setConsultFromConference`
286
+
287
+ **Valid transitions from `CONSULT_INITIATING`**:
288
+
289
+ - `CONSULT_SUCCESS` -> `CONSULTING`
290
+ - Guard: none
291
+ - Actions: `updateTaskData`, `setConsultInitiator`
292
+ - `CONSULT_FAILED` -> `CONFERENCING`
293
+ - Guard: inline `context.consultFromConference === true`
294
+ - Actions: `updateTaskData`, `handleConsultFailed`
295
+ - `CONSULT_FAILED` -> `HELD`
296
+ - Guard: `guards.isPrimaryMediaOnHold`
297
+ - Actions: `updateTaskData`, `handleConsultFailed`
298
+ - `CONSULT_FAILED` -> `CONNECTED` (default branch)
299
+ - Guard: default
300
+ - Actions: `updateTaskData`, `handleConsultFailed`
301
+ - `CTQ_CANCEL` -> `HELD`
302
+ - Guard: `guards.isPrimaryMediaOnHold`
303
+ - Actions: `updateTaskData`, `clearConsultState`
304
+ - `CTQ_CANCEL` -> `CONNECTED` (default branch)
305
+ - Guard: default
306
+ - Actions: `updateTaskData`, `clearConsultState`
307
+ - `HOLD_SUCCESS` -> stay `CONSULT_INITIATING`
308
+ - Guard: none
309
+ - Actions: `updateTaskData`
310
+ - `HOLD_FAILED` -> `CONNECTED`
311
+ - Guard: none
312
+ - Actions: `updateTaskData`, `handleConsultFailed`
313
+
314
+ ---
315
+
316
+ ### CONSULTING
317
+
318
+ **Description**: Agent is in active consult leg.
319
+
320
+ **How this state is reached (incoming transitions)**:
321
+
322
+ - `IDLE --HYDRATE--> CONSULTING`
323
+ - Guard: `guards.isInteractionConsulting`
324
+ - Actions: `updateTaskData`, `emitTaskHydrate`
325
+ - `OFFERED --CONSULTING_ACTIVE--> CONSULTING`
326
+ - Guard: none
327
+ - Actions: `updateTaskData`, `setConsultAgentJoined`, `emitTaskConsultAccepted`, `emitTaskConsulting`
328
+ - `CONSULT_INITIATING --CONSULT_SUCCESS--> CONSULTING`
329
+ - Guard: none
330
+ - Actions: `updateTaskData`, `setConsultInitiator`
331
+ - `CONF_INITIATING --CONFERENCE_FAILED--> CONSULTING`
332
+ - Guard: none
333
+ - Actions: none
334
+
335
+ **Valid transitions from `CONSULTING`**:
336
+
337
+ - `CONSULTING_ACTIVE` -> stay `CONSULTING`
338
+ - Guard: none
339
+ - Actions: `updateTaskData`, `setConsultAgentJoined`, `emitTaskConsulting`
340
+ - `CONSULT_END` -> `CONFERENCING`
341
+ - Guard: inline `context.consultInitiator === true && context.consultFromConference === true`
342
+ - Actions: `updateTaskData`, `clearConsultState`, `emitTaskConsultEnd`
343
+ - `CONSULT_END` -> `HELD`
344
+ - Guard: inline `context.consultInitiator === true`
345
+ - Actions: `updateTaskData`, `clearConsultState`, `emitTaskConsultEnd`
346
+ - `CONSULT_END` -> `TERMINATED` (default branch)
347
+ - Guard: default
348
+ - Actions: `updateTaskData`
349
+ - `HOLD_SUCCESS` -> stay `CONSULTING`
350
+ - Guard: none
351
+ - Actions: `updateTaskData`, `setHoldState`, `setConsultCallHeld`
352
+ - `UNHOLD_SUCCESS` -> stay `CONSULTING`
353
+ - Guard: none
354
+ - Actions: `updateTaskData`, `setHoldState`, `clearConsultCallHeld`
355
+ - `TRANSFER_SUCCESS` -> `WRAPPING_UP`
356
+ - Guard: `guards.shouldWrapUpOrIsInitiator`
357
+ - Actions: `updateTaskData`, `markEnded`, `emitTaskWrapup`
358
+ - `TRANSFER_SUCCESS` -> `CONNECTED` (receiver/default branch)
359
+ - Guard: default
360
+ - Actions: `updateTaskData`, `clearConsultState`
361
+ - `TRANSFER_FAILED` -> stay `CONSULTING`
362
+ - Guard: none
363
+ - Actions: `updateTaskData`
364
+ - `TRANSFER_CONFERENCE` -> stay `CONSULTING`
365
+ - Guard: none
366
+ - Actions: `setTransferConferenceRequested`, `emitTaskTransferConference`
367
+ - `TRANSFER_CONFERENCE_SUCCESS` -> stay `CONSULTING`
368
+ - Guard: inline `context.transferConferenceRequested !== true`
369
+ - Actions: `updateTaskData`, `handleTransferConferenceSuccess`, `clearTransferConferenceRequested`
370
+ - `TRANSFER_CONFERENCE_SUCCESS` -> `WRAPPING_UP`
371
+ - Guard: `guards.shouldWrapUp`
372
+ - Actions: `updateTaskData`, `markEnded`, `clearConsultState`, `handleTransferConferenceSuccess`, `clearTransferConferenceRequested`; `WRAPPING_UP` entry emits `task:wrapup`
373
+ - `TRANSFER_CONFERENCE_SUCCESS` -> `CONFERENCING`
374
+ - Guard: inline `!context.consultInitiator`
375
+ - Actions: `updateTaskData`, `clearConsultState`, `handleTransferConferenceSuccess`, `clearTransferConferenceRequested`
376
+ - `TRANSFER_CONFERENCE_SUCCESS` -> `TERMINATED` (default branch)
377
+ - Guard: default
378
+ - Actions: `updateTaskData`, `markEnded`, `clearConsultState`, `handleTransferConferenceSuccess`, `clearTransferConferenceRequested`, `emitTaskEnd`
379
+ - `TRANSFER_CONFERENCE_FAILED` -> stay `CONSULTING`
380
+ - Guard: none
381
+ - Actions: `clearTransferConferenceRequested`
382
+ - `ASSIGN` -> `CONNECTED`
383
+ - Guard: none
384
+ - Actions: `updateTaskData`, `emitTaskAssigned`
385
+ - `CONTACT_ENDED` -> `WRAPPING_UP`
386
+ - Guard: none
387
+ - Actions: `updateTaskData`, `markEnded`, `clearConsultState`, `emitTaskWrapup`, `requestCleanup`
388
+ - `TASK_WRAPUP` -> `WRAPPING_UP`
389
+ - Guard: none
390
+ - Actions: `updateTaskData`, `markEnded`, `clearConsultState`; `WRAPPING_UP` entry emits `task:wrapup`
391
+ - `MERGE_TO_CONFERENCE` -> `CONF_INITIATING`
392
+ - Guard: none
393
+ - Actions: none
394
+ - `CONFERENCE_START` -> `CONFERENCING`
395
+ - Guard: none
396
+ - Actions: `handleConferenceStarted`, `clearConsultState`
397
+
398
+ ---
399
+
400
+ ### CONF_INITIATING
401
+
402
+ **Description**: Conference merge is being established.
403
+
404
+ **How this state is reached (incoming transitions)**:
405
+
406
+ - `CONSULTING --MERGE_TO_CONFERENCE--> CONF_INITIATING`
407
+ - Guard: none
408
+ - Actions: none
409
+
410
+ **Valid transitions from `CONF_INITIATING`**:
411
+
412
+ - `CONFERENCE_START` -> `CONFERENCING`
413
+ - Guard: none
414
+ - Actions: `handleConferenceStarted`
415
+ - `CONFERENCE_FAILED` -> `CONSULTING`
416
+ - Guard: none
417
+ - Actions: none
418
+
419
+ ---
420
+
421
+ ### CONFERENCING
422
+
423
+ **Description**: Active conference call state.
424
+
425
+ **How this state is reached (incoming transitions)**:
426
+
427
+ - `IDLE --HYDRATE--> CONFERENCING`
428
+ - Guard: `guards.isConferencingByParticipants`
429
+ - Actions: `updateTaskData`, `emitTaskHydrate`
430
+ - `CONNECTED --CONTACT_ENDED--> CONFERENCING`
431
+ - Guard: `guards.conferenceInProgressFromEvent`
432
+ - Actions: `updateTaskData`, `emitTaskConferenceStarted`, `requestCleanup`
433
+ - `HELD --CONTACT_ENDED--> CONFERENCING`
434
+ - Guard: `guards.conferenceInProgressFromEvent`
435
+ - Actions: `updateTaskData`, `emitTaskConferenceStarted`, `requestCleanup`
436
+ - `CONSULTING --CONFERENCE_START--> CONFERENCING`
437
+ - Guard: none
438
+ - Actions: `handleConferenceStarted`, `clearConsultState`
439
+ - `CONF_INITIATING --CONFERENCE_START--> CONFERENCING`
440
+ - Guard: none
441
+ - Actions: `handleConferenceStarted`
442
+ - `CONSULTING --TRANSFER_CONFERENCE_SUCCESS--> CONFERENCING`
443
+ - Guard: inline `!context.consultInitiator`
444
+ - Actions: `updateTaskData`, `clearConsultState`, `handleTransferConferenceSuccess`, `clearTransferConferenceRequested`
445
+
446
+ **Valid transitions from `CONFERENCING`**:
447
+
448
+ - `CONSULT` -> `CONSULT_INITIATING`
449
+ - Guard: none
450
+ - Actions: `setConsultInitiator`, `setConsultDestination`, `setConsultFromConference`
451
+ - `CONFERENCE_START` -> stay `CONFERENCING`
452
+ - Guard: none
453
+ - Actions: `updateTaskData`, `clearConsultState`, `emitTaskConferenceStarted`
454
+ - `CONSULT_END` -> stay `CONFERENCING`
455
+ - Guard: none
456
+ - Actions: `updateTaskData`, `clearConsultState`
457
+ - `HOLD_SUCCESS` / `UNHOLD_SUCCESS` -> stay `CONFERENCING`
458
+ - Guard: none
459
+ - Actions: `updateTaskData`, `setHoldState`, `emitTaskHold` / `emitTaskResume`
460
+ - `TRANSFER_CONFERENCE` -> stay `CONFERENCING`
461
+ - Guard: none
462
+ - Actions: `setTransferConferenceRequested`, `emitTaskTransferConference`
463
+ - `TRANSFER_CONFERENCE_SUCCESS` -> stay `CONFERENCING`
464
+ - Guard: inline `context.transferConferenceRequested !== true`
465
+ - Actions: `updateTaskData`, `handleTransferConferenceSuccess`, `clearTransferConferenceRequested`
466
+ - `TRANSFER_CONFERENCE_FAILED` -> stay `CONFERENCING`
467
+ - Guard: none
468
+ - Actions: `clearTransferConferenceRequested`
469
+ - `PARTICIPANT_LEAVE` -> `WRAPPING_UP`
470
+ - Guard: `guards.didCurrentAgentLeaveMainInteraction && guards.shouldWrapUp`
471
+ - Actions: `updateTaskData`, `handleParticipantLeft`, `markEnded`, `clearConsultState`, `emitTaskParticipantLeft` (entry emits `task:wrapup`)
472
+ - `PARTICIPANT_LEAVE` -> `TERMINATED`
473
+ - Guard: `guards.didCurrentAgentLeaveMainInteraction`
474
+ - Actions: `updateTaskData`, `handleParticipantLeft`, `markEnded`, `clearConsultState`, `emitTaskParticipantLeft`, `emitTaskEnd`
475
+ - `PARTICIPANT_LEAVE` -> `CONNECTED`
476
+ - Guard: `guards.shouldDowngradeConferenceToConnected`
477
+ - Actions: `updateTaskData`, `handleParticipantLeft`, `clearConsultState`, `emitTaskParticipantLeft`, `emitTaskConferenceEnded`
478
+ - `PARTICIPANT_LEAVE` -> stay `CONFERENCING` (default)
479
+ - Guard: default
480
+ - Actions: `updateTaskData`, `handleParticipantLeft`, `emitTaskParticipantLeft`
481
+
482
+ `didCurrentAgentLeaveMainInteraction` treats an explicit self participant ID
483
+ or absence from the updated participants map as terminal (EP-DN removal).
484
+ Remaining in the map with `hasLeft`, or disappearing only from `mainCall` media,
485
+ is not treated as departure. `PARTICIPANT_LEAVE` is handled in `HELD`,
486
+ `RESUME_INITIATING`, `CONSULTING`, `CONSULT_INITIATING`, and `CONFERENCING`;
487
+ `CONNECTED`, `HOLD_INITIATING`, and `CONF_INITIATING` ignore the event.
488
+
489
+ - `EXIT_CONFERENCE_SUCCESS` -> `WRAPPING_UP` or `TERMINATED`
490
+ - Guard: `guards.shouldWrapUp` or default
491
+ - Actions: `updateTaskData`, `markEnded`, `clearConsultState`, or `emitTaskEnd` on terminate; `WRAPPING_UP` entry emits `task:wrapup` (shared helper on `CONNECTED`, `HELD`, and `CONFERENCING` for Voice HTTP exit)
492
+ - `CONFERENCE_END` -> `WRAPPING_UP`
493
+ - Guard: `guards.shouldWrapUp`
494
+ - Actions: `updateTaskData`, `markEnded`, `clearConsultState`; `WRAPPING_UP` entry emits `task:wrapup`
495
+ - `CONFERENCE_END` -> `CONNECTED`
496
+ - Guard: inline `!context.exitingConference && customerInCall`
497
+ - Actions: `updateTaskData`, `clearConsultState`, `emitTaskConferenceEnded`
498
+ - `CONFERENCE_END` -> `TERMINATED` (default branch)
499
+ - Guard: default
500
+ - Actions: `updateTaskData`, `markEnded`, `clearConsultState`, `emitTaskEnd`
501
+ - `TASK_WRAPUP` -> `WRAPPING_UP`
502
+ - Guard: `guards.shouldWrapUp`
503
+ - Actions: `updateTaskData`, `markEnded`, `clearConsultState`; `WRAPPING_UP` entry emits `task:wrapup`
504
+ - `CONTACT_ENDED` -> stay `CONFERENCING`
505
+ - Guard: none
506
+ - Actions: `updateTaskData`, `requestCleanup`
507
+
508
+ ---
509
+
510
+ ### WRAPPING_UP
511
+
512
+ **Description**: Post-interaction work (ACW) is in progress.
513
+
514
+ **How this state is reached (incoming transitions)**:
515
+
516
+ - Reached from `CONNECTED`, `HELD`, `CONSULTING`, or `CONFERENCING` via `CONTACT_ENDED`, `TASK_WRAPUP`, `TRANSFER_SUCCESS`, `TRANSFER_CONFERENCE_SUCCESS`, `PARTICIPANT_LEAVE`, or `CONFERENCE_END` branches
517
+ - Entry always emits wrapup event after transition
518
+
519
+ **Entry Actions**:
520
+
521
+ - `emitTaskWrapup`
522
+
523
+ **Valid transitions from `WRAPPING_UP`**:
524
+
525
+ - `TASK_WRAPUP` -> stay `WRAPPING_UP`
526
+ - Guard: if `context.taskData.wrapUpRequired === true`, `updateTaskData` only; else `updateTaskData`, `emitTaskWrapup`
527
+ - `WRAPUP_COMPLETE` -> `COMPLETED`
528
+ - Guard: none
529
+ - Actions: `updateTaskData`
530
+
531
+ **Guards**: None
532
+
533
+ ### COMPLETED
534
+
535
+ **Description**: Final wrapped-up terminal state.
536
+
537
+ **Entry Actions**:
538
+
539
+ - `emitTaskWrappedup`
540
+ - `cleanupResources`
541
+
542
+ **How this state is reached (incoming transitions)**:
543
+
544
+ - `WRAPPING_UP --WRAPUP_COMPLETE--> COMPLETED`
545
+ - Guard: none
546
+ - Actions: `updateTaskData`
547
+
548
+ **Valid transitions from `COMPLETED`**: None (final state)
549
+
550
+ **Guards**: None
551
+
552
+ ---
553
+
554
+ ### TERMINATED
555
+
556
+ **Description**: Final terminated terminal state.
557
+
558
+ **Entry Actions**:
559
+
560
+ - `cleanupResources`
561
+
562
+ **How this state is reached (incoming transitions)**:
563
+
564
+ - Reached from `OFFERED`, `CONNECTED`, `HELD`, `CONSULTING`, and `CONFERENCING` via terminating branches (`TASK_WRAPUP`, failure paths, and default end-of-contact/conference branches)
565
+
566
+ **Valid transitions from `TERMINATED`**: None (final state)
567
+
568
+ **Guards**: None
569
+
570
+ ---
571
+
572
+ ## Events
573
+
574
+ Event names below are from `TaskEvent` in `constants.ts`.
575
+
576
+ ### Core lifecycle and sync
577
+
578
+ - `TASK_INCOMING`, `TASK_OFFERED`, `HYDRATE`
579
+ - `CONTACT_UPDATED`, `CONTACT_OWNER_CHANGED`
580
+ - `ASSIGN`, `CONTACT_ENDED`, `TASK_WRAPUP`, `WRAPUP_COMPLETE`
581
+
582
+ ### Hold/resume
583
+
584
+ - `HOLD_INITIATED`, `HOLD_SUCCESS`, `HOLD_FAILED`
585
+ - `UNHOLD_INITIATED`, `UNHOLD_SUCCESS`, `UNHOLD_FAILED`
586
+
587
+ ### Consult
588
+
589
+ - `OFFER_CONSULT`, `CONSULT`, `CONSULT_SUCCESS`, `CONSULT_CREATED`
590
+ - `CONSULTING_ACTIVE`, `CONSULT_END`, `CONSULT_FAILED`
591
+ - `CTQ_CANCEL`, `CTQ_CANCEL_FAILED`
592
+
593
+ ### Conference and conference-transfer
594
+
595
+ - `MERGE_TO_CONFERENCE`, `CONFERENCE_START`, `CONFERENCE_FAILED`, `CONFERENCE_END`
596
+ - `PARTICIPANT_LEAVE`
597
+ - `TRANSFER_CONFERENCE`, `TRANSFER_CONFERENCE_SUCCESS`, `TRANSFER_CONFERENCE_FAILED`
598
+ - `EXIT_CONFERENCE`, `EXIT_CONFERENCE_SUCCESS`, `EXIT_CONFERENCE_FAILED`
599
+
600
+ ### Transfer
601
+
602
+ - `TRANSFER_SUCCESS`, `TRANSFER_FAILED`
603
+
604
+ ### Recording
605
+
606
+ - `RECORDING_STARTED`, `PAUSE_RECORDING`, `RESUME_RECORDING`
607
+
608
+ ### Failure/end events
609
+
610
+ - `RONA`, `INVITE_FAILED`, `ASSIGN_FAILED`, `OUTBOUND_FAILED`
611
+
612
+ ---
613
+
614
+ ## Single Transition Flow
615
+
616
+ The flow below shows a single transition in the requested form:
617
+
618
+ ```mermaid
619
+ flowchart LR
620
+ A[User Action/CC Event Mapping] --> B[State Machine Event Trigger]
621
+ B --> C{Check against Current State: Valid Transition?}
622
+ C -- No --> X[Ignore/No-op]
623
+ C -- Yes --> D[StateMachine evaluates guards]
624
+ D -- No --> Y[Blocked by Guard]
625
+ D -- Yes --> E[Execute Associated Actions]
626
+ E --> F[Context updated]
627
+ F --> G[UI Controls Recomputed]
628
+ G --> H[Transition to Target State]
629
+ ```
630
+
631
+ ### Example: Hold Flow (Concrete)
632
+
633
+ ```mermaid
634
+ flowchart LR
635
+ A[User invoked hold API] --> B[Event Trigger: HOLD_INITIATED]
636
+ B --> C{State = CONNECTED?}
637
+ C -- No --> X[Ignore/No-op]
638
+ C -- Yes --> D[Guards: none]
639
+ D -- Yes --> E[Actions: setHoldInitiated + updateTaskData]
640
+ E --> F[Context updated]
641
+ F --> G[UI controls recomputed]
642
+ G --> H[Transition: CONNECTED -> HOLD_INITIATING]
643
+ H --> I[CC Event: AGENT_CONTACT_HELD]
644
+ I --> J[Mapped: HOLD_SUCCESS]
645
+ J --> K{State = HOLD_INITIATING?}
646
+ K -- No --> X
647
+ K -- Yes --> L[Guards: none]
648
+ L -- Yes --> M[Actions: setHoldSuccess + updateTaskData]
649
+ M --> N[Context updated]
650
+ N --> O[UI controls recomputed]
651
+ O --> P[Transition: HOLD_INITIATING -> HELD]
652
+ ```
653
+
654
+ ---
655
+
656
+ ## State Pattern (via XState)
657
+
658
+ ### Purpose
659
+
660
+ Manage complex task lifecycle with clear states, transitions, guards, and actions.
661
+
662
+ ### Implementation
663
+
664
+ ```typescript
665
+ // Task.ts
666
+ export default abstract class Task extends EventEmitter {
667
+ public stateMachineService?: ActorRefFrom<TaskStateMachine>;
668
+
669
+ private initializeStateMachine(): void {
670
+ const machine: TaskStateMachine = createTaskStateMachine(this.uiControlConfig, {
671
+ actions: this.getStateMachineActionOverrides(),
672
+ });
673
+
674
+ this.stateMachineService = createActor(machine);
675
+
676
+ // Subscribe to state changes
677
+ this.stateMachineService.subscribe((snapshot) => {
678
+ const currentState = snapshot.value as TaskState;
679
+ this.state = snapshot;
680
+ this.updateUiControls(previousState !== currentState);
681
+ });
682
+
683
+ this.stateMachineService.start();
684
+ }
685
+
686
+ public sendStateMachineEvent(event: TaskEventPayload): void {
687
+ this.stateMachineService?.send(event);
688
+ }
689
+ }
690
+ ```
691
+
692
+ ### State Machine Architecture
693
+
694
+ ```typescript
695
+ // state-machine/TaskStateMachine.ts
696
+ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
697
+ return {
698
+ id: 'taskStateMachine',
699
+ initial: TaskState.IDLE,
700
+ context: createInitialContext(uiControlConfig, TaskState.IDLE),
701
+ states: {
702
+ [TaskState.IDLE]: {
703
+ on: {
704
+ [TaskEvent.TASK_INCOMING]: {
705
+ target: TaskState.OFFERED,
706
+ actions: ['initializeTask', 'emitTaskIncoming'],
707
+ },
708
+ },
709
+ },
710
+ [TaskState.OFFERED]: {
711
+ on: {
712
+ [TaskEvent.ASSIGN]: {
713
+ target: TaskState.CONNECTED,
714
+ actions: ['updateTaskData', 'emitTaskAssigned'],
715
+ },
716
+ [TaskEvent.TASK_WRAPUP]: {
717
+ target: TaskState.TERMINATED,
718
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd'],
719
+ },
720
+ },
721
+ },
722
+ // ... more states
723
+ },
724
+ };
725
+ }
726
+ ```
727
+
728
+ ## Backend CC Event Mapping Reference (CC_EVENTS -> TaskEvent -> Transition)
729
+
730
+ Complete mapping from backend CC_EVENTS to internal TaskEvent types.
731
+
732
+ | Backend CC Event | TaskEvent | Typical From State(s) | Target State | Notes / Guards |
733
+ | ---------------------------------- | ----------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------- |
734
+ | `AGENT_CONTACT_RESERVED` | `TASK_INCOMING` | `IDLE` | `OFFERED` | Incoming task entry |
735
+ | `AGENT_OFFER_CONTACT` | `TASK_OFFERED` | `OFFERED` | `OFFERED` | Offer payload refresh |
736
+ | `AGENT_CONTACT` | `HYDRATE` | `IDLE` | `WRAPPING_UP` / `CONSULTING` / `HELD` / `CONNECTED` / `CONFERENCING` / `IDLE` | Guard-based restore |
737
+ | `CONTACT_UPDATED` | `CONTACT_UPDATED` | any | same | Context sync |
738
+ | `CONTACT_OWNER_CHANGED` | `CONTACT_OWNER_CHANGED` | any | same | Context sync |
739
+ | `AGENT_OFFER_CONSULT` | `OFFER_CONSULT` | `OFFERED` | `OFFERED` | Receiver-side consult offer |
740
+ | `AGENT_CONTACT_ASSIGNED` | `ASSIGN` | `OFFERED` / `CONNECTED` / `CONSULTING` | `CONNECTED` | Assign/reassign |
741
+ | `AGENT_CONTACT_HELD` | `HOLD_SUCCESS` | `HOLD_INITIATING` | `HELD` | Includes `mediaResourceId` |
742
+ | `AGENT_CONTACT_UNHELD` | `UNHOLD_SUCCESS` | `RESUME_INITIATING` | `CONNECTED` | Includes `mediaResourceId` |
743
+ | `AGENT_CONSULT_CREATED` | `CONSULT_CREATED` | varies | same | Context + emitter action |
744
+ | `AGENT_CONSULTING` | `CONSULTING_ACTIVE` | `OFFERED` / `CONSULTING` | `CONSULTING` | Sets consult joined flag |
745
+ | `AGENT_CONSULT_ENDED` | `CONSULT_END` | `CONSULTING` | `CONFERENCING` / `HELD` / `TERMINATED` | Depends on initiator flags |
746
+ | `AGENT_CONSULT_FAILED` | `CONSULT_FAILED` | `CONSULT_INITIATING` | `CONFERENCING` / `HELD` / `CONNECTED` | Guard-based fallback |
747
+ | `AGENT_CTQ_FAILED` | `CONSULT_FAILED` | `CONSULT_INITIATING` | `CONFERENCING` / `HELD` / `CONNECTED` | Same as consult failed |
748
+ | `AGENT_CTQ_CANCELLED` | `CTQ_CANCEL` | `CONSULT_INITIATING` | `HELD` / `CONNECTED` | Guarded by hold state |
749
+ | `AGENT_CTQ_CANCEL_FAILED` | `CTQ_CANCEL_FAILED` | varies | same | No transition mapping |
750
+ | `AGENT_BLIND_TRANSFERRED` | `TRANSFER_SUCCESS` | `CONNECTED` / `HELD` / `CONSULTING` | `WRAPPING_UP` / `CONNECTED` | `shouldWrapUpOrIsInitiator` |
751
+ | `AGENT_CONSULT_TRANSFERRED` | `TRANSFER_SUCCESS` | `CONNECTED` / `HELD` / `CONSULTING` | `WRAPPING_UP` / `CONNECTED` | Same path |
752
+ | `AGENT_VTEAM_TRANSFERRED` | `TRANSFER_SUCCESS` | `CONNECTED` / `HELD` / `CONSULTING` | `WRAPPING_UP` / `CONNECTED` | Same path |
753
+ | `AGENT_WRAPUP` | `TASK_WRAPUP` | `OFFERED` / `CONNECTED` / `HELD` / `CONSULTING` | `TERMINATED` / `WRAPPING_UP` | `OFFERED` terminates; others wrap |
754
+ | `AGENT_BLIND_TRANSFER_FAILED` | `TRANSFER_FAILED` | `CONNECTED` / `HELD` / `CONSULTING` | same | Context update |
755
+ | `AGENT_VTEAM_TRANSFER_FAILED` | `TRANSFER_FAILED` | `CONNECTED` / `HELD` / `CONSULTING` | same | Context update |
756
+ | `AGENT_CONSULT_TRANSFER_FAILED` | `TRANSFER_FAILED` | `CONNECTED` / `HELD` / `CONSULTING` | same | Context update |
757
+ | `AGENT_CONFERENCE_TRANSFER_FAILED` | `TRANSFER_FAILED` | `CONNECTED` / `HELD` / `CONSULTING` | same | Context update |
758
+ | `CONTACT_ENDED` | `CONTACT_ENDED` | `CONNECTED` / `HELD` / `CONSULTING` / `CONFERENCING` | `CONFERENCING` / `WRAPPING_UP` / `TERMINATED` / same | Guard-driven branch |
759
+ | `AGENT_INVITE_FAILED` | `INVITE_FAILED` | `OFFERED` | `TERMINATED` | Reject path |
760
+ | `AGENT_CONTACT_ASSIGN_FAILED` | `ASSIGN_FAILED` | `OFFERED` | `TERMINATED` | Reject path |
761
+ | `AGENT_CONTACT_OFFER_RONA` | `RONA` | `OFFERED` | `TERMINATED` | Timeout path |
762
+ | `AGENT_OUTBOUND_FAILED` | `OUTBOUND_FAILED` | `OFFERED` | `TERMINATED` | Outbound failure |
763
+ | `CONTACT_RECORDING_STARTED` | `RECORDING_STARTED` | any | same | Recording state update |
764
+ | `CONTACT_RECORDING_PAUSED` | `PAUSE_RECORDING` | `CONNECTED` | same | Recording state update |
765
+ | `CONTACT_RECORDING_RESUMED` | `RESUME_RECORDING` | `CONNECTED` | same | Recording state update |
766
+ | `AGENT_WRAPPEDUP` | `WRAPUP_COMPLETE` | `WRAPPING_UP` | `COMPLETED` | Final completion |
767
+ | `AGENT_CONSULT_CONFERENCED` | `CONFERENCE_START` | `CONSULTING` / `CONF_INITIATING` / `CONFERENCING` | `CONFERENCING` / same | Conference established |
768
+ | `PARTICIPANT_JOINED_CONFERENCE` | `CONFERENCE_START` | `CONSULTING` / `CONF_INITIATING` / `CONFERENCING` | `CONFERENCING` / same | Conference participant joined |
769
+ | `AGENT_CONSULT_CONFERENCE_FAILED` | `CONFERENCE_FAILED` | `CONF_INITIATING` | `CONSULTING` | Merge fail fallback |
770
+ | `AGENT_CONSULT_CONFERENCE_ENDED` | `CONFERENCE_END` | `CONFERENCING` | `WRAPPING_UP` / `CONNECTED` / `TERMINATED` | Guard-driven |
771
+ | `PARTICIPANT_LEFT_CONFERENCE` | `PARTICIPANT_LEAVE` | `HELD` / `RESUME_INITIATING` / `CONSULTING` / `CONSULT_INITIATING` / `CONFERENCING` | `WRAPPING_UP` / `TERMINATED` / `CONNECTED` / same | Named self or omitted from participant map; `CONNECTED` / `HOLD_INITIATING` / `CONF_INITIATING` ignore |
772
+ | `AGENT_CONFERENCE_TRANSFERRED` | `TRANSFER_CONFERENCE_SUCCESS` | `CONSULTING` / `CONFERENCING` | `WRAPPING_UP` / `CONFERENCING` / `TERMINATED` / same | Initiator/receiver dependent |
773
+
774
+ ### Explicitly not mapped to state machine
775
+
776
+ - `AGENT_CONTACT_UNASSIGNED` -> returns `null` in mapper (`TaskManager.mapEventToTaskStateMachineEvent`)
777
+
778
+ ### Contact Lifecycle Mappings
779
+
780
+ | Backend Event | TaskEvent | State Transition | Notes |
781
+ | ------------------------ | ----------------------- | ------------------------------------------------------------- | ---------------------------------------------- |
782
+ | `AgentContactReserved` | `TASK_INCOMING` | IDLE → OFFERED | New task offered |
783
+ | `AgentOfferContact` | `TASK_OFFERED` | Stay in OFFERED | Offer confirmation |
784
+ | `AgentContact` | `HYDRATE` | Various | State restoration |
785
+ | `AgentContactAssigned` | `ASSIGN` | OFFERED → CONNECTED (also CONNECTED/CONSULTING refresh paths) | Task accepted/reassigned |
786
+ | `ContactUpdated` | `CONTACT_UPDATED` | No change | Data update only |
787
+ | `ContactOwnerChanged` | `CONTACT_OWNER_CHANGED` | No change | Owner update only |
788
+ | `ContactEnded` | `CONTACT_ENDED` | Guard-based branch | CONFERENCING / WRAPPING_UP / TERMINATED / stay |
789
+ | `AgentContactUnassigned` | None | N/A | Handled by other events |
790
+
791
+ ### Hold/Resume Mappings
792
+
793
+ | Backend Event | TaskEvent | State Transition | Context Update |
794
+ | -------------------------- | ---------------- | ----------------------------- | ----------------------------------------------------------------------------------- |
795
+ | `AgentContactHeld` | `HOLD_SUCCESS` | HOLD_INITIATING → HELD | `setHoldState` updates `taskData.interaction.media[mediaResourceId].isHold = true` |
796
+ | `AgentContactUnheld` | `UNHOLD_SUCCESS` | RESUME_INITIATING → CONNECTED | `setHoldState` updates `taskData.interaction.media[mediaResourceId].isHold = false` |
797
+ | `AgentContactHoldFailed` | `HOLD_FAILED` | HOLD_INITIATING → CONNECTED | Context refreshed |
798
+ | `AgentContactUnholdFailed` | `UNHOLD_FAILED` | RESUME_INITIATING → HELD | No transition action |
799
+
800
+ ### Consult Mappings
801
+
802
+ | Backend Event / API | TaskEvent | State Transition | Context Update |
803
+ | --------------------------------------- | ------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------- |
804
+ | API `task.consult(...)` | `CONSULT` | CONNECTED/HELD/CONFERENCING → CONSULT_INITIATING | Sets consult initiator + destination (and `consultFromConference` in conference flow) |
805
+ | `AgentOfferConsult` | `OFFER_CONSULT` | OFFERED → OFFERED | Offer-only path |
806
+ | `AgentConsultCreated` | `CONSULT_CREATED` | No state transition wiring | Event exists but not consumed by transition table |
807
+ | `AgentConsulting` | `CONSULTING_ACTIVE` | OFFERED → CONSULTING, CONSULTING → CONSULTING | Sets `consultDestinationAgentJoined` |
808
+ | `AgentConsultEnded` | `CONSULT_END` | CONSULTING → CONFERENCING / HELD / TERMINATED | Depends on initiator and consult-from-conference |
809
+ | `AgentConsultFailed` / `AgentCtqFailed` | `CONSULT_FAILED` | CONSULT_INITIATING → CONFERENCING / HELD / CONNECTED | Guard-based fallback |
810
+ | `AgentCtqCancelled` | `CTQ_CANCEL` | CONSULT_INITIATING → HELD / CONNECTED | Guarded by `isPrimaryMediaOnHold` |
811
+ | `AgentCtqCancelFailed` | `CTQ_CANCEL_FAILED` | No state transition wiring | Event mapped but not consumed |
812
+
813
+ ### Transfer Mappings
814
+
815
+ | Backend Event | TaskEvent | State Transition | Wrapup Logic |
816
+ | ---------------------------- | ------------------ | ---------------------------------- | ------------------------------------------------------------------------- |
817
+ | `AgentBlindTransferred` | `TRANSFER_SUCCESS` | → WRAPPING_UP/CONNECTED | Guard `shouldWrapUpOrIsInitiator` decides wrapup vs receiver/default path |
818
+ | `AgentVTeamTransferred` | `TRANSFER_SUCCESS` | → WRAPPING_UP/CONNECTED | Same transition logic as blind transfer |
819
+ | `AgentConsultTransferred` | `TRANSFER_SUCCESS` | CONSULTING → WRAPPING_UP/CONNECTED | Initiator/wrapup path vs receiver/default path |
820
+ | `AgentBlindTransferFailed` | `TRANSFER_FAILED` | No change | Emit failure, stay in current state |
821
+ | `AgentVTeamTransferFailed` | `TRANSFER_FAILED` | No change | Queue transfer failed |
822
+ | `AgentConsultTransferFailed` | `TRANSFER_FAILED` | No change | Consult transfer failed |
823
+
824
+ ### Conference Mappings
825
+
826
+ | Backend Event / API | TaskEvent | State Transition | Context Update |
827
+ | -------------------------------- | ----------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
828
+ | API `task.consultConference()` | `MERGE_TO_CONFERENCE` | CONSULTING → CONF_INITIATING | Starts merge flow |
829
+ | `AgentConsultConferenced` | `CONFERENCE_START` | CONSULTING/CONF_INITIATING → CONFERENCING | `handleConferenceStarted` path |
830
+ | `ParticipantJoinedConference` | `CONFERENCE_START` | CONFERENCING → CONFERENCING | Refresh + emit conference started |
831
+ | `ParticipantLeftConference` | `PARTICIPANT_LEAVE` | HELD / RESUME_INITIATING / CONSULTING / CONSULT_INITIATING / CONFERENCING → WRAPPING_UP / TERMINATED / CONNECTED / stay; CONNECTED / HOLD_INITIATING / CONF_INITIATING ignore | Uses `didCurrentAgentLeaveMainInteraction` (named self or omitted from participant map), `shouldWrapUp`, `shouldDowngradeConferenceToConnected` |
832
+ | `AgentConsultConferenceEnded` | `CONFERENCE_END` | CONFERENCING → WRAPPING_UP / CONNECTED / TERMINATED | Guard-based branch |
833
+ | `AgentConsultConferenceFailed` | `CONFERENCE_FAILED` | CONF_INITIATING → CONSULTING | Merge failed fallback |
834
+ | `AgentConferenceTransferred` | `TRANSFER_CONFERENCE_SUCCESS` | CONSULTING/CONFERENCING branch logic | Initiator/receiver dependent |
835
+ | API/SDK conference transfer fail | `TRANSFER_CONFERENCE_FAILED` | CONSULTING/CONFERENCING stay | Clears transfer request flag |
836
+
837
+ ### Recording Mappings
838
+
839
+ | Backend Event | TaskEvent | State Transition | Context Update |
840
+ | ------------------------- | ------------------- | ---------------- | ---------------------- |
841
+ | `ContactRecordingStarted` | `RECORDING_STARTED` | No change | Update recording state |
842
+ | `ContactRecordingPaused` | `PAUSE_RECORDING` | No change | Mark recording paused |
843
+ | `ContactRecordingResumed` | `RESUME_RECORDING` | No change | Mark recording active |
844
+
845
+ ### Wrapup Mappings
846
+
847
+ | Backend Event | TaskEvent | State Transition | Notes |
848
+ | ---------------- | ----------------- | ----------------------- | --------------- |
849
+ | `AgentWrapup` | `TASK_WRAPUP` | → WRAPPING_UP | Enter ACW |
850
+ | `AgentWrappedup` | `WRAPUP_COMPLETE` | WRAPPING_UP → COMPLETED | Complete wrapup |
851
+
852
+ ### Error Mappings
853
+
854
+ | Backend Event | TaskEvent | State Transition | Notes |
855
+ | -------------------------- | ----------------- | -------------------- | ------------------------ |
856
+ | `AgentContactOfferRona` | `RONA` | OFFERED → TERMINATED | Redirection on no answer |
857
+ | `AgentInviteFailed` | `INVITE_FAILED` | OFFERED → TERMINATED | Invite failed |
858
+ | `AgentContactAssignFailed` | `ASSIGN_FAILED` | OFFERED → TERMINATED | Assignment failed |
859
+ | `AgentOutboundFailed` | `OUTBOUND_FAILED` | OFFERED → TERMINATED | Outdial failed |
860
+
861
+ ---
862
+
863
+ ## State Transition Diagrams
864
+
865
+ This diagram represents state-to-state lifecycle transitions for the task state machine.
866
+
867
+ ```mermaid
868
+ stateDiagram-v2
869
+ [*] --> IDLE
870
+
871
+ %% IDLE
872
+ IDLE --> OFFERED: AGENT_CONTACT_RESERVED (CC Event) -> TASK_INCOMING (State Machine Event)
873
+
874
+ %% OFFERED
875
+ OFFERED --> OFFERED: AGENT_OFFER_CONTACT (CC Event) -> TASK_OFFERED (State Machine Event)
876
+ OFFERED --> OFFERED: AGENT_OFFER_CONSULT (CC Event) -> OFFER_CONSULT (State Machine Event)
877
+ OFFERED --> CONNECTED: AGENT_CONTACT_ASSIGNED (CC Event) -> ASSIGN (State Machine Event)
878
+ OFFERED --> CONSULTING: AGENT_CONSULTING (CC Event) -> CONSULTING_ACTIVE (State Machine Event)
879
+ OFFERED --> TERMINATED: AGENT_CONTACT_OFFER_RONA (CC Event) -> RONA (State Machine Event)
880
+ OFFERED --> TERMINATED: AGENT_CONTACT_ASSIGN_FAILED (CC Event) -> ASSIGN_FAILED (State Machine Event)
881
+ OFFERED --> TERMINATED: AGENT_INVITE_FAILED (CC Event) -> INVITE_FAILED (State Machine Event)
882
+ OFFERED --> TERMINATED: AGENT_OUTBOUND_FAILED (CC Event) -> OUTBOUND_FAILED (State Machine Event)
883
+ OFFERED --> TERMINATED: AGENT_WRAPUP (CC Event) -> TASK_WRAPUP (State Machine Event)
884
+
885
+ %% CONNECTED
886
+ CONNECTED --> HOLD_INITIATING: API hold() -> HOLD_INITIATED (State Machine Event)
887
+ CONNECTED --> CONSULT_INITIATING: API consult() -> CONSULT (State Machine Event)
888
+ CONNECTED --> WRAPPING_UP: AGENT_*TRANSFERRED (CC Event) -> TRANSFER_SUCCESS (State Machine Event) [shouldWrapUpOrIsInitiator]
889
+ CONNECTED --> CONNECTED: AGENT_*TRANSFERRED (CC Event) -> TRANSFER_SUCCESS (State Machine Event) [receiver]
890
+ CONNECTED --> CONNECTED: AGENT_*TRANSFER_FAILED (CC Event) -> TRANSFER_FAILED (State Machine Event)
891
+ CONNECTED --> CONFERENCING: CONTACT_ENDED (CC Event) -> CONTACT_ENDED (State Machine Event) [conferenceInProgressFromEvent]
892
+ CONNECTED --> WRAPPING_UP: CONTACT_ENDED (CC Event) -> CONTACT_ENDED (State Machine Event) [shouldWrapUp]
893
+ CONNECTED --> TERMINATED: CONTACT_ENDED (CC Event) -> CONTACT_ENDED (State Machine Event) [default]
894
+ CONNECTED --> WRAPPING_UP: AGENT_WRAPUP (CC Event) -> TASK_WRAPUP (State Machine Event)
895
+
896
+ %% HOLD_INITIATING
897
+ HOLD_INITIATING --> HELD: HOLD_SUCCESS (State Machine Event)
898
+ HOLD_INITIATING --> CONNECTED: HOLD_FAILED (State Machine Event)
899
+
900
+ %% HELD
901
+ HELD --> RESUME_INITIATING: UNHOLD_INITIATED (State Machine Event)
902
+ HELD --> CONSULT_INITIATING: CONSULT (State Machine Event)
903
+ HELD --> WRAPPING_UP: TRANSFER_SUCCESS (State Machine Event) [shouldWrapUpOrIsInitiator]
904
+ HELD --> CONNECTED: TRANSFER_SUCCESS (State Machine Event) [receiver]
905
+ HELD --> CONFERENCING: CONTACT_ENDED (CC Event) -> CONTACT_ENDED (State Machine Event) [conferenceInProgressFromEvent]
906
+ HELD --> WRAPPING_UP: CONTACT_ENDED (CC Event) -> CONTACT_ENDED (State Machine Event) [shouldWrapUp]
907
+ HELD --> TERMINATED: CONTACT_ENDED (CC Event) -> CONTACT_ENDED (State Machine Event) [default]
908
+ HELD --> WRAPPING_UP: TASK_WRAPUP (State Machine Event)
909
+ HELD --> HELD: TRANSFER_FAILED (State Machine Event)
910
+
911
+ %% RESUME_INITIATING
912
+ RESUME_INITIATING --> CONNECTED: UNHOLD_SUCCESS (State Machine Event)
913
+ RESUME_INITIATING --> HELD: UNHOLD_FAILED (State Machine Event)
914
+
915
+ %% CONSULT_INITIATING
916
+ CONSULT_INITIATING --> CONSULTING: CONSULT_SUCCESS (State Machine Event)
917
+ CONSULT_INITIATING --> CONFERENCING: CONSULT_FAILED (State Machine Event) [consultFromConference]
918
+ CONSULT_INITIATING --> HELD: CONSULT_FAILED / CTQ_CANCEL (State Machine Event) [isPrimaryMediaOnHold]
919
+ CONSULT_INITIATING --> CONNECTED: HOLD_FAILED / CONSULT_FAILED / CTQ_CANCEL (State Machine Event) [default]
920
+ CONSULT_INITIATING --> CONSULT_INITIATING: HOLD_SUCCESS (State Machine Event)
921
+
922
+ %% CONSULTING
923
+ CONSULTING --> CONFERENCING: CONSULT_END (State Machine Event) [consultInitiator && consultFromConference]
924
+ CONSULTING --> HELD: CONSULT_END (State Machine Event) [consultInitiator]
925
+ CONSULTING --> TERMINATED: CONSULT_END (State Machine Event) [consulted agent]
926
+ CONSULTING --> WRAPPING_UP: TRANSFER_SUCCESS (State Machine Event) [shouldWrapUpOrIsInitiator]
927
+ CONSULTING --> CONNECTED: TRANSFER_SUCCESS (State Machine Event) [receiver]
928
+ CONSULTING --> WRAPPING_UP: CONTACT_ENDED (CC Event) -> CONTACT_ENDED (State Machine Event) / TASK_WRAPUP (State Machine Event)
929
+ CONSULTING --> CONNECTED: ASSIGN (State Machine Event)
930
+ CONSULTING --> CONF_INITIATING: MERGE_TO_CONFERENCE (State Machine Event)
931
+ CONSULTING --> CONFERENCING: CONFERENCE_START (State Machine Event)
932
+ CONSULTING --> CONFERENCING: TRANSFER_CONFERENCE_SUCCESS (State Machine Event) [!consultInitiator]
933
+ CONSULTING --> WRAPPING_UP: TRANSFER_CONFERENCE_SUCCESS (State Machine Event) [shouldWrapUp]
934
+ CONSULTING --> TERMINATED: TRANSFER_CONFERENCE_SUCCESS (State Machine Event) [default]
935
+ CONSULTING --> CONSULTING: CONSULTING_ACTIVE / HOLD_SUCCESS / UNHOLD_SUCCESS / TRANSFER_FAILED / TRANSFER_CONFERENCE / TRANSFER_CONFERENCE_FAILED (State Machine Event)
936
+
937
+ %% CONF_INITIATING
938
+ CONF_INITIATING --> CONFERENCING: CONFERENCE_START (State Machine Event)
939
+ CONF_INITIATING --> CONSULTING: CONFERENCE_FAILED (State Machine Event)
940
+
941
+ %% CONFERENCING
942
+ CONFERENCING --> CONSULT_INITIATING: CONSULT (State Machine Event)
943
+ CONFERENCING --> WRAPPING_UP: PARTICIPANT_LEAVE (CC Event) -> PARTICIPANT_LEAVE (State Machine Event) [didCurrentAgentLeaveMainInteraction && shouldWrapUp]
944
+ CONFERENCING --> TERMINATED: PARTICIPANT_LEAVE (CC Event) -> PARTICIPANT_LEAVE (State Machine Event) [didCurrentAgentLeaveMainInteraction]
945
+ CONFERENCING --> CONNECTED: PARTICIPANT_LEAVE (CC Event) -> PARTICIPANT_LEAVE (State Machine Event) [shouldDowngradeConferenceToConnected]
946
+ CONFERENCING --> WRAPPING_UP: CONFERENCE_END (CC Event) -> CONFERENCE_END (State Machine Event) [shouldWrapUp]
947
+ CONFERENCING --> CONNECTED: CONFERENCE_END (CC Event) -> CONFERENCE_END (State Machine Event) [customerInCall]
948
+ CONFERENCING --> TERMINATED: CONFERENCE_END (CC Event) -> CONFERENCE_END (State Machine Event) [default]
949
+ CONFERENCING --> CONFERENCING: CONFERENCE_START / CONSULT_END / HOLD_SUCCESS / UNHOLD_SUCCESS / PARTICIPANT_LEAVE(other) / TRANSFER_CONFERENCE / TRANSFER_CONFERENCE_SUCCESS / TRANSFER_CONFERENCE_FAILED / CONTACT_ENDED (State Machine Event)
950
+
951
+ %% WRAPPING_UP / FINAL
952
+ WRAPPING_UP --> COMPLETED: WRAPUP_COMPLETE (State Machine Event)
953
+ COMPLETED --> [*]
954
+ TERMINATED --> [*]
955
+ ```
956
+
957
+ ---
958
+
959
+ ## Focused Transition Diagrams
960
+
961
+ The full diagram above is the source of truth. The diagrams below split above flows based on each feature.
962
+
963
+ ### 1) Initial Task Assign Flow
964
+
965
+ ```mermaid
966
+ stateDiagram-v2
967
+ [*] --> IDLE
968
+ IDLE --> OFFERED: AGENT_CONTACT_RESERVED -> TASK_INCOMING
969
+ OFFERED --> OFFERED: AGENT_CONTACT_OFFER -> TASK_OFFERED
970
+ OFFERED --> OFFERED: AGENT_CONSULT_OFFER -> OFFER_CONSULT
971
+ OFFERED --> CONNECTED: AGENT_CONTACT_ASSIGNED -> ASSIGN
972
+ OFFERED --> TERMINATED: AGENT_CONTACT_OFFER_RONA/AGENT_CONTACT_ASSIGN_FAILED/AGENT_INVITE_FAILED/AGENT_OUTBOUND_FAILED/AGENT_WRAPUP -> RONA/ASSIGN_FAILED/INVITE_FAILED/OUTBOUND_FAILED/TASK_WRAPUP
973
+
974
+ CONNECTED --> HOLD_INITIATING: task.hold() -> HOLD_INITIATED
975
+ CONNECTED --> CONSULT_INITIATING: task.consult() -> CONSULT
976
+
977
+ CONNECTED --> CONNECTED: PAUSE_RECORDING/RESUME_RECORDING
978
+ CONNECTED --> CONNECTED: AGENT_BLIND_TRANSFER_FAILED/AGENT_VTEAM_TRANSFER_FAILED -> TRANSFER_FAILED
979
+
980
+ CONNECTED --> WRAPPING_UP: AGENT_BLIND_TRANSFERRED/AGENT_VTEAM_TRANSFERRED -> TRANSFER_SUCCESS [shouldWrapUpOrIsInitiator]
981
+ CONNECTED --> WRAPPING_UP: CONTACT_ENDED -> CONTACT_ENDED [shouldWrapUp]
982
+ CONNECTED --> WRAPPING_UP: AGENT_WRAPUP -> TASK_WRAPUP
983
+ CONNECTED --> TERMINATED: CONTACT_ENDED -> CONTACT_ENDED [default]
984
+
985
+ WRAPPING_UP --> COMPLETED: AGENT_WRAPPEDUP -> WRAPUP_COMPLETE
986
+ COMPLETED --> [*]
987
+ TERMINATED --> [*]
988
+ ```
989
+
990
+ ### 2) Hold/Resume Flow
991
+
992
+ ```mermaid
993
+ stateDiagram-v2
994
+ [*] --> CONNECTED
995
+ CONNECTED --> HOLD_INITIATING: task.hold() -> HOLD_INITIATED
996
+ HOLD_INITIATING --> HELD: AGENT_CONTACT_HELD -> HOLD_SUCCESS
997
+ HOLD_INITIATING --> CONNECTED: AGENT_CONTACT_HOLD_FAILED -> HOLD_FAILED
998
+ HELD --> RESUME_INITIATING: task.resume() -> UNHOLD_INITIATED
999
+ RESUME_INITIATING --> CONNECTED: AGENT_CONTACT_UNHELD -> UNHOLD_SUCCESS
1000
+ RESUME_INITIATING --> HELD: AGENT_CONTACT_UNHOLD_FAILED -> UNHOLD_FAILED
1001
+ HELD --> CONSULT_INITIATING: task.consult() -> Consult
1002
+ CONSULT_INITIATING --> HELD: CONSULT_FAILED / CTQ_CANCEL [isPrimaryMediaOnHold]
1003
+ HELD --> WRAPPING_UP: CONTACT_ENDED -> CONTACT_ENDED [shouldWrapUp]
1004
+ HELD --> TERMINATED: CONTACT_ENDED -> CONTACT_ENDED [default]
1005
+
1006
+ WRAPPING_UP --> COMPLETED: AGENT_WRAPPEDUP -> WRAPUP_COMPLETE
1007
+ COMPLETED --> [*]
1008
+ TERMINATED --> [*]
1009
+ ```
1010
+
1011
+ ### 3) Consult Flow
1012
+
1013
+ ```mermaid
1014
+ stateDiagram-v2
1015
+ stateDiagram-v2
1016
+ [*] --> CONNECTED
1017
+ CONNECTED --> CONSULT_INITIATING: task.consult() -> CONSULT
1018
+ HELD --> CONSULT_INITIATING: task.consult() -> CONSULT
1019
+ CONFERENCING --> CONSULT_INITIATING: task.consult() -> CONSULT
1020
+
1021
+ CONSULT_INITIATING --> CONSULT_INITIATING: AGENT_CONTACT_HELD -> HOLD_SUCCESS
1022
+ CONSULT_INITIATING --> CONNECTED: AGENT_CONTACT_HOLD_FAILED -> HOLD_FAILED
1023
+ CONSULT_INITIATING --> CONSULTING: API consult success -> CONSULT_SUCCESS
1024
+ CONSULT_INITIATING --> HELD: AGENT_CONSULT_FAILED/AGENT_CTQ_FAILED -> CONSULT_FAILED [isPrimaryMediaOnHold]
1025
+ CONSULT_INITIATING --> CONNECTED: AGENT_CONSULT_FAILED/AGENT_CTQ_FAILED -> CONSULT_FAILED [default]
1026
+ CONSULT_INITIATING --> CONFERENCING: AGENT_CONSULT_FAILED -> CONSULT_FAILED [consultFromConference]
1027
+ CONSULT_INITIATING --> HELD: AGENT_CTQ_CANCELLED -> CTQ_CANCEL [isPrimaryMediaOnHold]
1028
+ CONSULT_INITIATING --> CONNECTED: AGENT_CTQ_CANCELLED -> CTQ_CANCEL [default]
1029
+
1030
+ CONSULTING --> HELD: AGENT_CONSULT_ENDED -> CONSULT_END [consultInitiator]
1031
+ CONSULTING --> TERMINATED: AGENT_CONSULT_ENDED -> CONSULT_END [consulted agent]
1032
+ CONSULTING --> CONFERENCING: AGENT_CONSULT_ENDED -> CONSULT_END [consultInitiator && consultFromConference]
1033
+ CONSULTING --> CONNECTED: AGENT_CONSULT_TRANSFERRED/AGENT_CONTACT_ASSIGNED -> TRANSFER_SUCCESS/ASSIGN
1034
+ CONSULTING --> WRAPPING_UP: AGENT_CONSULT_TRANSFERRED -> TRANSFER_SUCCESS [shouldWrapUpOrIsInitiator]
1035
+ CONSULTING --> CONSULTING: AGENT_CONSULT_TRANSFER_FAILED -> TRANSFER_FAILED
1036
+ CONSULTING --> CONF_INITIATING: task.consultConference() -> MERGE_TO_CONFERENCE
1037
+ CONSULTING --> WRAPPING_UP: AGENT_CONTACT_ENDED -> CONTACT_ENDED
1038
+
1039
+ WRAPPING_UP --> COMPLETED: AGENT_WRAPPEDUP -> WRAPUP_COMPLETE
1040
+ COMPLETED --> [*]
1041
+ TERMINATED --> [*]
1042
+ ```
1043
+
1044
+ ### 4) Conference Flow
1045
+
1046
+ ```mermaid
1047
+ stateDiagram-v2
1048
+ [*] --> CONSULTING
1049
+ CONSULTING --> CONF_INITIATING: task.consultConference() -> MERGE_TO_CONFERENCE
1050
+ CONF_INITIATING --> CONFERENCING: AGENT_CONSULT_CONFERENCED -> CONFERENCE_START
1051
+ CONF_INITIATING --> CONSULTING: AGENT_CONSULT_CONFERENCE_FAILED -> CONFERENCE_FAILED
1052
+ CONFERENCING --> CONSULT_INITIATING: task.consult() -> CONSULT
1053
+ CONSULTING --> CONFERENCING: AGENT_CONFERENCE_TRANSFERRED -> TRANSFER_CONFERENCE_SUCCESS [!consultInitiator]
1054
+ CONSULTING --> WRAPPING_UP: AGENT_CONFERENCE_TRANSFERRED -> TRANSFER_CONFERENCE_SUCCESS [shouldWrapUp]
1055
+ CONSULTING --> TERMINATED: AGENT_CONFERENCE_TRANSFERRED -> TRANSFER_CONFERENCE_SUCCESS [default]
1056
+ CONSULTING --> CONSULTING: AGENT_CONFERENCE_TRANSFER_FAILED -> TRANSFER_CONFERENCE_FAILED
1057
+ CONFERENCING --> CONFERENCING: AGENT_CONFERENCE_TRANSFERRED -> TRANSFER_CONFERENCE_SUCCESS
1058
+ CONFERENCING --> CONFERENCING: AGENT_CONFERENCE_TRANSFER_FAILED-> TRANSFER_CONFERENCE_FAILED
1059
+
1060
+ CONFERENCING --> WRAPPING_UP: PARTICIPANT_LEFT_CONFERENCE -> PARTICIPANT_LEAVE [didCurrentAgentLeaveMainInteraction && shouldWrapUp]
1061
+ CONFERENCING --> TERMINATED: PARTICIPANT_LEFT_CONFERENCE -> PARTICIPANT_LEAVE [didCurrentAgentLeaveMainInteraction]
1062
+ CONFERENCING --> CONNECTED: PARTICIPANT_LEFT_CONFERENCE -> PARTICIPANT_LEAVE [shouldDowngradeConferenceToConnected]
1063
+ CONFERENCING --> WRAPPING_UP: AGENT_CONSULT_CONFERENCE_ENDED -> CONFERENCE_END [shouldWrapUp]
1064
+ CONFERENCING --> CONNECTED: AGENT_CONSULT_CONFERENCE_ENDED -> CONFERENCE_END [customerInCall]
1065
+ CONFERENCING --> TERMINATED: AGENT_CONSULT_CONFERENCE_ENDED -> CONFERENCE_END [default]
1066
+ WRAPPING_UP --> COMPLETED: WRAPUP_COMPLETE
1067
+ COMPLETED --> [*]
1068
+ TERMINATED --> [*]
1069
+ ```
1070
+
1071
+ ---
1072
+
1073
+ ## State Machine Configuration Example
1074
+
1075
+ ```typescript
1076
+ import {setup} from 'xstate';
1077
+ import {actions} from './actions';
1078
+ import {guards} from './guards';
1079
+
1080
+ const taskStateMachine = setup({
1081
+ types: {
1082
+ context: {} as TaskContext,
1083
+ events: {} as TaskEventPayload,
1084
+ },
1085
+ })
1086
+ .createMachine({
1087
+ id: 'taskStateMachine',
1088
+ initial: TaskState.IDLE,
1089
+ context: createInitialContext(uiControlConfig, TaskState.IDLE),
1090
+ states: {
1091
+ [TaskState.IDLE]: {
1092
+ on: {
1093
+ [TaskEvent.TASK_INCOMING]: {
1094
+ target: TaskState.OFFERED,
1095
+ actions: ['initializeTask', 'emitTaskIncoming'],
1096
+ },
1097
+ [TaskEvent.HYDRATE]: [
1098
+ {
1099
+ guard: guards.isInteractionTerminated,
1100
+ target: TaskState.WRAPPING_UP,
1101
+ actions: ['updateTaskData', 'markEnded', 'emitTaskHydrate'],
1102
+ },
1103
+ // ... more hydrate cases
1104
+ ],
1105
+ },
1106
+ },
1107
+ [TaskState.OFFERED]: {
1108
+ on: {
1109
+ [TaskEvent.ASSIGN]: {
1110
+ target: TaskState.CONNECTED,
1111
+ actions: ['updateTaskData', 'emitTaskAssigned'],
1112
+ },
1113
+ [TaskEvent.TASK_WRAPUP]: {
1114
+ target: TaskState.TERMINATED,
1115
+ actions: ['updateTaskData', 'markEnded', 'emitTaskEnd'],
1116
+ },
1117
+ // ... more transitions
1118
+ },
1119
+ },
1120
+ // ... more states
1121
+ },
1122
+ })
1123
+ .provide({actions});
1124
+ ```
1125
+
1126
+ ---
1127
+
1128
+ ## State Restoration (HYDRATE)
1129
+
1130
+ The HYDRATE event restores state machine state after page refresh or reconnection.
1131
+
1132
+ **Algorithm**:
1133
+
1134
+ 1. Receive HYDRATE event with full task data
1135
+ 2. Check interaction state and flags in order of precedence:
1136
+ - If `taskData.interaction.isTerminated === true` -> WRAPPING_UP
1137
+ - If `taskData.interaction.state === 'consulting'` -> CONSULTING
1138
+ - If `taskData.interaction.state === 'hold'` -> HELD
1139
+ - If `taskData.interaction.state === 'connected'` -> CONNECTED
1140
+ - If conferencing-by-participants guard passes (`agentCount >= 2` in main call) -> CONFERENCING
1141
+ - Default → Stay in IDLE
1142
+ 3. Update context with hydrated data
1143
+ 4. Emit TASK_HYDRATE event
1144
+
1145
+ ---
1146
+
1147
+ ## Related Files
1148
+
1149
+ - `../Task.ts` - actor lifecycle, action overrides, event emission
1150
+ - `../TaskManager.ts` - maps backend events to state-machine events
1151
+ - `../types.ts` - shared task data structures
1152
+ - `../../ai-docs/ARCHITECTURE.md` - broader task service architecture
1153
+ - [TaskStateMachine.ts](../TaskStateMachine.ts) - Implementation
1154
+ - [guards.ts](../guards.ts) - Guard functions
1155
+ - [actions.ts](../actions.ts) - Action functions
1156
+ - [constants.ts](../constants.ts) - State and event enums