@webex/contact-center 3.12.0-next.8 → 3.12.0-task-refactor.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/AGENTS.md +438 -0
  2. package/ai-docs/README.md +131 -0
  3. package/ai-docs/RULES.md +455 -0
  4. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  5. package/ai-docs/patterns/testing-patterns.md +480 -0
  6. package/ai-docs/patterns/typescript-patterns.md +365 -0
  7. package/ai-docs/templates/README.md +102 -0
  8. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  9. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  10. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  11. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  12. package/ai-docs/templates/new-method/00-master.md +80 -0
  13. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  14. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  15. package/ai-docs/templates/new-method/03-tests.md +201 -0
  16. package/ai-docs/templates/new-method/04-validation.md +141 -0
  17. package/ai-docs/templates/new-service/00-master.md +109 -0
  18. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  19. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  20. package/ai-docs/templates/new-service/03-integration.md +178 -0
  21. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  22. package/ai-docs/templates/new-service/05-validation.md +145 -0
  23. package/dist/cc.js +65 -123
  24. package/dist/cc.js.map +1 -1
  25. package/dist/constants.js +13 -2
  26. package/dist/constants.js.map +1 -1
  27. package/dist/index.js +13 -5
  28. package/dist/index.js.map +1 -1
  29. package/dist/metrics/behavioral-events.js +26 -13
  30. package/dist/metrics/behavioral-events.js.map +1 -1
  31. package/dist/metrics/constants.js +7 -6
  32. package/dist/metrics/constants.js.map +1 -1
  33. package/dist/services/ApiAiAssistant.js +0 -3
  34. package/dist/services/ApiAiAssistant.js.map +1 -1
  35. package/dist/services/config/Util.js +2 -3
  36. package/dist/services/config/Util.js.map +1 -1
  37. package/dist/services/config/types.js +16 -14
  38. package/dist/services/config/types.js.map +1 -1
  39. package/dist/services/constants.js +0 -1
  40. package/dist/services/constants.js.map +1 -1
  41. package/dist/services/core/Err.js.map +1 -1
  42. package/dist/services/core/Utils.js +79 -55
  43. package/dist/services/core/Utils.js.map +1 -1
  44. package/dist/services/core/aqm-reqs.js +17 -92
  45. package/dist/services/core/aqm-reqs.js.map +1 -1
  46. package/dist/services/core/websocket/WebSocketManager.js +5 -25
  47. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  48. package/dist/services/core/websocket/types.js.map +1 -1
  49. package/dist/services/index.js +1 -2
  50. package/dist/services/index.js.map +1 -1
  51. package/dist/services/task/Task.js +644 -0
  52. package/dist/services/task/Task.js.map +1 -0
  53. package/dist/services/task/TaskFactory.js +45 -0
  54. package/dist/services/task/TaskFactory.js.map +1 -0
  55. package/dist/services/task/TaskManager.js +556 -532
  56. package/dist/services/task/TaskManager.js.map +1 -1
  57. package/dist/services/task/TaskUtils.js +132 -28
  58. package/dist/services/task/TaskUtils.js.map +1 -1
  59. package/dist/services/task/constants.js +7 -6
  60. package/dist/services/task/constants.js.map +1 -1
  61. package/dist/services/task/dialer.js +0 -51
  62. package/dist/services/task/dialer.js.map +1 -1
  63. package/dist/services/task/digital/Digital.js +77 -0
  64. package/dist/services/task/digital/Digital.js.map +1 -0
  65. package/dist/services/task/state-machine/TaskStateMachine.js +634 -0
  66. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  67. package/dist/services/task/state-machine/actions.js +366 -0
  68. package/dist/services/task/state-machine/actions.js.map +1 -0
  69. package/dist/services/task/state-machine/constants.js +139 -0
  70. package/dist/services/task/state-machine/constants.js.map +1 -0
  71. package/dist/services/task/state-machine/guards.js +256 -0
  72. package/dist/services/task/state-machine/guards.js.map +1 -0
  73. package/dist/services/task/state-machine/index.js +53 -0
  74. package/dist/services/task/state-machine/index.js.map +1 -0
  75. package/dist/services/task/state-machine/types.js +54 -0
  76. package/dist/services/task/state-machine/types.js.map +1 -0
  77. package/dist/services/task/state-machine/uiControlsComputer.js +369 -0
  78. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  79. package/dist/services/task/taskDataNormalizer.js +99 -0
  80. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  81. package/dist/services/task/types.js +157 -18
  82. package/dist/services/task/types.js.map +1 -1
  83. package/dist/services/task/voice/Voice.js +1031 -0
  84. package/dist/services/task/voice/Voice.js.map +1 -0
  85. package/dist/services/task/voice/WebRTC.js +149 -0
  86. package/dist/services/task/voice/WebRTC.js.map +1 -0
  87. package/dist/types/cc.d.ts +4 -33
  88. package/dist/types/constants.d.ts +13 -2
  89. package/dist/types/index.d.ts +11 -5
  90. package/dist/types/metrics/constants.d.ts +5 -3
  91. package/dist/types/services/ApiAiAssistant.d.ts +1 -1
  92. package/dist/types/services/config/types.d.ts +97 -25
  93. package/dist/types/services/core/Err.d.ts +0 -2
  94. package/dist/types/services/core/Utils.d.ts +25 -23
  95. package/dist/types/services/core/aqm-reqs.d.ts +0 -49
  96. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -1
  97. package/dist/types/services/core/websocket/connection-service.d.ts +0 -1
  98. package/dist/types/services/core/websocket/types.d.ts +1 -1
  99. package/dist/types/services/index.d.ts +1 -1
  100. package/dist/types/services/task/Task.d.ts +146 -0
  101. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  102. package/dist/types/services/task/TaskUtils.d.ts +39 -8
  103. package/dist/types/services/task/constants.d.ts +5 -4
  104. package/dist/types/services/task/dialer.d.ts +0 -15
  105. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  106. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +906 -0
  107. package/dist/types/services/task/state-machine/actions.d.ts +8 -0
  108. package/dist/types/services/task/state-machine/constants.d.ts +91 -0
  109. package/dist/types/services/task/state-machine/guards.d.ts +78 -0
  110. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  111. package/dist/types/services/task/state-machine/types.d.ts +256 -0
  112. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  113. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  114. package/dist/types/services/task/types.d.ts +539 -88
  115. package/dist/types/services/task/voice/Voice.d.ts +183 -0
  116. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  117. package/dist/types/types.d.ts +68 -0
  118. package/dist/types/webex.d.ts +1 -0
  119. package/dist/types.js +70 -0
  120. package/dist/types.js.map +1 -1
  121. package/dist/webex.js +14 -2
  122. package/dist/webex.js.map +1 -1
  123. package/package.json +14 -11
  124. package/src/cc.ts +91 -177
  125. package/src/constants.ts +13 -2
  126. package/src/index.ts +14 -5
  127. package/src/metrics/ai-docs/AGENTS.md +348 -0
  128. package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
  129. package/src/metrics/behavioral-events.ts +28 -14
  130. package/src/metrics/constants.ts +7 -8
  131. package/src/services/ApiAiAssistant.ts +2 -4
  132. package/src/services/agent/ai-docs/AGENTS.md +238 -0
  133. package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
  134. package/src/services/ai-docs/AGENTS.md +384 -0
  135. package/src/services/config/Util.ts +2 -3
  136. package/src/services/config/ai-docs/AGENTS.md +253 -0
  137. package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
  138. package/src/services/config/types.ts +108 -20
  139. package/src/services/constants.ts +0 -1
  140. package/src/services/core/Err.ts +0 -1
  141. package/src/services/core/Utils.ts +90 -67
  142. package/src/services/core/ai-docs/AGENTS.md +379 -0
  143. package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
  144. package/src/services/core/aqm-reqs.ts +22 -100
  145. package/src/services/core/websocket/WebSocketManager.ts +4 -23
  146. package/src/services/core/websocket/types.ts +1 -1
  147. package/src/services/index.ts +1 -2
  148. package/src/services/task/Task.ts +785 -0
  149. package/src/services/task/TaskFactory.ts +55 -0
  150. package/src/services/task/TaskManager.ts +567 -633
  151. package/src/services/task/TaskUtils.ts +175 -31
  152. package/src/services/task/ai-docs/AGENTS.md +448 -0
  153. package/src/services/task/ai-docs/ARCHITECTURE.md +573 -0
  154. package/src/services/task/constants.ts +5 -4
  155. package/src/services/task/dialer.ts +1 -56
  156. package/src/services/task/digital/Digital.ts +95 -0
  157. package/src/services/task/state-machine/TaskStateMachine.ts +793 -0
  158. package/src/services/task/state-machine/actions.ts +409 -0
  159. package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
  160. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
  161. package/src/services/task/state-machine/constants.ts +150 -0
  162. package/src/services/task/state-machine/guards.ts +295 -0
  163. package/src/services/task/state-machine/index.ts +28 -0
  164. package/src/services/task/state-machine/types.ts +228 -0
  165. package/src/services/task/state-machine/uiControlsComputer.ts +529 -0
  166. package/src/services/task/taskDataNormalizer.ts +137 -0
  167. package/src/services/task/types.ts +641 -95
  168. package/src/services/task/voice/Voice.ts +1255 -0
  169. package/src/services/task/voice/WebRTC.ts +187 -0
  170. package/src/types.ts +88 -5
  171. package/src/utils/AGENTS.md +276 -0
  172. package/src/webex.js +2 -0
  173. package/test/unit/spec/cc.ts +59 -142
  174. package/test/unit/spec/logger-proxy.ts +70 -0
  175. package/test/unit/spec/services/ApiAiAssistant.ts +17 -0
  176. package/test/unit/spec/services/config/index.ts +26 -55
  177. package/test/unit/spec/services/core/Utils.ts +103 -52
  178. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +48 -112
  179. package/test/unit/spec/services/core/websocket/connection-service.ts +5 -4
  180. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  181. package/test/unit/spec/services/task/Task.ts +416 -0
  182. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  183. package/test/unit/spec/services/task/TaskManager.ts +781 -1735
  184. package/test/unit/spec/services/task/TaskUtils.ts +125 -0
  185. package/test/unit/spec/services/task/dialer.ts +112 -198
  186. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  187. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +473 -0
  188. package/test/unit/spec/services/task/state-machine/guards.ts +288 -0
  189. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  190. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +147 -0
  191. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  192. package/test/unit/spec/services/task/voice/Voice.ts +587 -0
  193. package/test/unit/spec/services/task/voice/WebRTC.ts +242 -0
  194. package/umd/contact-center.min.js +2 -2
  195. package/umd/contact-center.min.js.map +1 -1
  196. package/dist/services/task/index.js +0 -1525
  197. package/dist/services/task/index.js.map +0 -1
  198. package/dist/types/services/task/index.d.ts +0 -650
  199. package/src/services/task/index.ts +0 -1801
  200. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,573 @@
1
+ # Task Service - Architecture
2
+
3
+ > **Purpose**: Technical documentation for task lifecycle management.
4
+
5
+ ---
6
+
7
+ ## Component Overview
8
+
9
+ | Component | File | Responsibility |
10
+ | -------------------- | ---------------------------- | ---------------------------------------------------------- |
11
+ | `TaskManager` | `task/TaskManager.ts` | Task lifecycle coordination |
12
+ | `Task` | `task/Task.ts` | Individual task operations |
13
+ | `contact` | `task/contact.ts` | AQM request definitions |
14
+ | `dialer` | `task/dialer.ts` | Outbound call initiation |
15
+ | `AutoWrapup` | `task/AutoWrapup.ts` | Auto wrapup timer |
16
+ | `taskDataNormalizer` | `task/taskDataNormalizer.ts` | Normalizes backend task payloads |
17
+ | `TaskUtils` | `task/TaskUtils.ts` | Utility functions |
18
+ | `state-machine` | `task/state-machine/*` | Task state transitions, guards, and UI control computation |
19
+
20
+ ---
21
+
22
+ ## Task Module Design Overview
23
+
24
+ ### `Task` (abstract)
25
+
26
+ **File:** `Task.ts`
27
+
28
+ **Properties**
29
+
30
+ - `data: TaskData`
31
+ - `webCallMap: Record<TaskId, CallId>`
32
+ - `stateMachineService?: ActorRefFrom<TaskStateMachine>`
33
+ - `state?: SnapshotFrom<TaskStateMachine>`
34
+ - `autoWrapup?: AutoWrapup`
35
+ - `uiControls: TaskUIControls` (getter)
36
+
37
+ **Methods**
38
+
39
+ - `accept(): Promise<TaskResponse>` (abstract)
40
+ - `decline(): Promise<TaskResponse>` (default: unsupportedMethodError)
41
+ - `pauseRecording(): Promise<TaskResponse>` (default: unsupportedMethodError)
42
+ - `resumeRecording(resumeRecordingPayload: ResumeRecordingPayload): Promise<TaskResponse>` (default: unsupportedMethodError)
43
+ - `consult(consultPayload: ConsultPayload): Promise<TaskResponse>` (default: unsupportedMethodError)
44
+ - `endConsult(consultEndPayload?: ConsultEndPayload): Promise<TaskResponse>` (default: unsupportedMethodError)
45
+ - `consultTransfer(consultTransferPayload?: ConsultTransferPayLoad): Promise<TaskResponse>` (default: unsupportedMethodError)
46
+ - `consultConference(): Promise<TaskResponse>` (default: unsupportedMethodError)
47
+ - `exitConference(): Promise<TaskResponse>` (default: unsupportedMethodError)
48
+ - `transferConference(): Promise<TaskResponse>` (default: unsupportedMethodError)
49
+ - `switchCall(): Promise<TaskResponse>` (default: unsupportedMethodError)
50
+ - `toggleMute(): Promise<void>` (default: unsupportedMethodError)
51
+ - `unregisterWebCallListeners(): void` (default: no-op + log)
52
+ - `cancelAutoWrapupTimer(): void`
53
+ - `hold(mediaResourceId?: string): Promise<TaskResponse>` (default: unsupportedMethodError)
54
+ - `resume(mediaResourceId?: string): Promise<TaskResponse>` (default: unsupportedMethodError)
55
+ - `holdResume(): Promise<TaskResponse>` (default: unsupportedMethodError)
56
+ - `sendStateMachineEvent(event: TaskEventPayload): void`
57
+ - `updateTaskData(updatedData: TaskData, shouldOverwrite = false): ITask`
58
+ - `transfer(transferPayload: TransferPayLoad): Promise<TaskResponse>`
59
+ - `end(): Promise<TaskResponse>`
60
+ - `wrapup(wrapupPayload: WrapupPayLoad): Promise<TaskResponse>`
61
+
62
+ ### `Voice`
63
+
64
+ **File:** `voice/Voice.ts`
65
+
66
+ **Notes**
67
+
68
+ - Extends `Task`.
69
+ - Provides `hold()` and `resume()` that delegate to `holdResume()`.
70
+ - Explicitly overrides `accept()` and `decline()` to throw `unsupportedMethodError`.
71
+ - `WebRTC` then overrides these methods with concrete implementations.
72
+
73
+ ### `WebRTC`
74
+
75
+ **File:** `voice/WebRTC.ts`
76
+
77
+ **Notes**
78
+
79
+ - Extends `Voice`.
80
+ - Overrides `accept()` and `decline()` for WebRTC calls.
81
+ - Emits `TASK_EVENTS.TASK_MEDIA` on remote media (`CALL_EVENT_KEYS.REMOTE_MEDIA`).
82
+ - Overrides `unregisterWebCallListeners()`.
83
+
84
+ ### `Digital`
85
+
86
+ **File:** `digital/Digital.ts`
87
+
88
+ **Notes**
89
+
90
+ - Extends `Task`.
91
+ - Implements `accept()`.
92
+ - Overrides `updateTaskData()` to refresh digital task data and UI controls.
93
+
94
+ ### `TaskFactory`
95
+
96
+ **File:** `TaskFactory.ts`
97
+
98
+ **API**
99
+
100
+ - `createTask(contact, webCallingService, data, configFlags, wrapupData?, agentId?): Task`
101
+
102
+ **Behavior**
103
+
104
+ - Chooses `WebRTC` vs `Voice` for `MEDIA_CHANNEL.TELEPHONY` based on `webCallingService.loginOption`.
105
+ - Chooses `Digital` for `MEDIA_CHANNEL.CHAT`, `MEDIA_CHANNEL.EMAIL`, `MEDIA_CHANNEL.SOCIAL`.
106
+ - Throws `Error` for unknown media types.
107
+
108
+ ### Task Class Hierarchy Diagram
109
+
110
+ ```mermaid
111
+ classDiagram
112
+ class Task {
113
+ <<abstract>>
114
+ # contact
115
+ # metricsManager
116
+ + data: TaskData
117
+ + webCallMap: Record~TaskId, CallId~
118
+ + stateMachineService
119
+ + state
120
+ # currentUiControls: TaskUIControls
121
+ # uiControlConfig: UIControlConfig
122
+ + autoWrapup: AutoWrapup
123
+ + accept() TaskResponse
124
+ + transfer(payload) TaskResponse
125
+ + end() TaskResponse
126
+ + wrapup(payload) TaskResponse
127
+ + updateTaskData(updatedData, shouldOverwrite) ITask
128
+ + sendStateMachineEvent(event) void
129
+ + hold() TaskResponse
130
+ + resume() TaskResponse
131
+ + holdResume() TaskResponse
132
+ + consult(payload) TaskResponse
133
+ + endConsult(payload) TaskResponse
134
+ + consultTransfer(payload) TaskResponse
135
+ + consultConference() TaskResponse
136
+ + exitConference() TaskResponse
137
+ + transferConference() TaskResponse
138
+ + pauseRecording() TaskResponse
139
+ + resumeRecording(payload) TaskResponse
140
+ + toggleMute() void
141
+ + unregisterWebCallListeners() void
142
+ + cancelAutoWrapupTimer() void
143
+ }
144
+
145
+ class Voice {
146
+ + accept() TaskResponse
147
+ + decline() TaskResponse
148
+ + hold() TaskResponse
149
+ + resume() TaskResponse
150
+ + holdResume() TaskResponse
151
+ + pauseRecording() TaskResponse
152
+ + resumeRecording(payload) TaskResponse
153
+ + consult(payload) TaskResponse
154
+ + endConsult(payload) TaskResponse
155
+ + transfer(payload) TaskResponse
156
+ + consultConference() TaskResponse
157
+ + exitConference() TaskResponse
158
+ + transferConference() TaskResponse
159
+ }
160
+
161
+ class WebRTC {
162
+ - localAudioStream: LocalMicrophoneStream
163
+ - webCallingService: WebCallingService
164
+ + accept() TaskResponse
165
+ + decline() TaskResponse
166
+ + toggleMute() void
167
+ + unregisterWebCallListeners() void
168
+ }
169
+
170
+ class Digital {
171
+ + accept() TaskResponse
172
+ + updateTaskData(newData, shouldOverwrite) IDigital
173
+ }
174
+
175
+ class TaskFactory {
176
+ + createTask(contact, webCallingService, data, configFlags, wrapupData, agentId) Task
177
+ }
178
+
179
+ Task <|-- Voice
180
+ Voice <|-- WebRTC
181
+ Task <|-- Digital
182
+
183
+ TaskFactory ..> Task : creates
184
+ TaskFactory ..> Voice : creates
185
+ TaskFactory ..> WebRTC : creates
186
+ TaskFactory ..> Digital : creates
187
+ ```
188
+
189
+ ---
190
+
191
+ ## TaskManager Pattern
192
+
193
+ TaskManager is a singleton that:
194
+
195
+ 1. Listens for WebSocket task events
196
+ 2. Creates/manages Task objects
197
+ 3. Routes events to appropriate tasks
198
+ 4. Handles WebRTC call mapping
199
+
200
+ ```typescript
201
+ // Singleton access
202
+ const taskManager = TaskManager.getTaskManager(contact, webCallingService, webSocketManager);
203
+ ```
204
+
205
+ ---
206
+
207
+ ## AQM Request Modules
208
+
209
+ ### `routingContact(aqm: AqmReqs)` (`contact.ts`)
210
+
211
+ Returns an object of AQM request methods wired to `TASK_API` and `TASK_MESSAGE_TYPE`.
212
+
213
+ **Methods**
214
+
215
+ - `accept`
216
+ - `hold`
217
+ - `unHold`
218
+ - `pauseRecording`
219
+ - `resumeRecording`
220
+ - `consult`
221
+ - `consultEnd`
222
+ - `consultAccept`
223
+ - `blindTransfer`
224
+ - `vteamTransfer`
225
+ - `consultTransfer`
226
+ - `end`
227
+ - `wrapup`
228
+ - `cancelTask`
229
+ - `cancelCtq`
230
+ - `consultConference`
231
+ - `exitConference`
232
+ - `conferenceTransfer`
233
+
234
+ **Notes**
235
+
236
+ - Uses `WCC_API_GATEWAY`.
237
+ - Consult with `DESTINATION_TYPE.QUEUE` uses `TIMEOUT_REQ` = `'disabled'` for the request timeout.
238
+
239
+ ### `aqmDialer(aqm: AqmReqs)` (`dialer.ts`)
240
+
241
+ Returns an object of AQM request methods for outbound dialing.
242
+
243
+ **Methods**
244
+
245
+ - `startOutdial` (success: `CC_EVENTS.AGENT_OFFER_CONTACT`, failure: `CC_EVENTS.AGENT_OUTBOUND_FAILED`)
246
+
247
+ ---
248
+
249
+ ## Usage in Task Classes
250
+
251
+ ### `Task` (`Task.ts`)
252
+
253
+ - Constructor accepts `contact: ReturnType<typeof routingContact>`.
254
+ - Uses:
255
+ - `contact.vteamTransfer` / `contact.blindTransfer` in `transfer(...)`.
256
+ - While in consulting state, `transfer(...)` internally routes through consult-transfer behavior.
257
+ - `contact.end` in `end()`.
258
+ - `contact.wrapup` in `wrapup(...)`.
259
+
260
+ ### `Voice` (`voice/Voice.ts`)
261
+
262
+ Uses `contact` for:
263
+
264
+ - `hold`, `unHold`
265
+ - `pauseRecording`, `resumeRecording`
266
+ - `consult`, `consultEnd`, `consultTransfer`
267
+ - `consultConference`, `exitConference`, `conferenceTransfer`
268
+
269
+ ### `Digital` (`digital/Digital.ts`)
270
+
271
+ Uses `contact.accept` in `accept()`.
272
+
273
+ ---
274
+
275
+ ## State Machine Layer
276
+
277
+ `Task` delegates lifecycle transitions and control-state derivation to the state machine:
278
+
279
+ - Transition graph: `state-machine/TaskStateMachine.ts`
280
+ - Transition conditions: `state-machine/guards.ts`
281
+ - Context mutation and integration hooks: `state-machine/actions.ts`
282
+ - UI control derivation: `state-machine/uiControlsComputer.ts`
283
+
284
+ For state-machine-specific implementation guidance, use:
285
+
286
+ - `../state-machine/ai-docs/AGENTS.md`
287
+ - `../state-machine/ai-docs/ARCHITECTURE.md`
288
+
289
+ ### State Inventory (from `state-machine/constants.ts`)
290
+
291
+ - **Active lifecycle + intermediate states**:
292
+ - `IDLE`, `OFFERED`, `CONNECTED`
293
+ - `HOLD_INITIATING`, `HELD`, `RESUME_INITIATING`
294
+ - `CONSULT_INITIATING`, `CONSULTING`, `CONF_INITIATING`
295
+ - `CONFERENCING`, `WRAPPING_UP`, `COMPLETED`, `TERMINATED`
296
+ - **Future placeholders (defined, not currently implemented in transitions)**:
297
+ - `CONSULT_INITIATED`, `CONSULT_COMPLETED`, `POST_CALL`, `PARKED`, `MONITORING`
298
+
299
+ ---
300
+
301
+ ## Event Flow
302
+
303
+ ### Incoming Task Flow
304
+
305
+ ```mermaid
306
+ sequenceDiagram
307
+ participant BE as Backend
308
+ participant WS as WebSocket
309
+ participant TM as TaskManager
310
+ participant T as Task
311
+ participant CC as ContactCenter
312
+ participant App as Application
313
+
314
+ BE->>WS: AgentOfferContact event
315
+ WS->>TM: message event
316
+ TM->>TM: Check if telephony
317
+ alt BROWSER login
318
+ TM->>TM: Wait for INCOMING_CALL
319
+ WS->>TM: LINE_EVENTS.INCOMING_CALL
320
+ TM->>TM: Map call to task
321
+ end
322
+ TM->>T: new Task(data)
323
+ TM->>TM: Store in taskCollection
324
+ TM->>CC: emit task:incoming
325
+ CC->>App: trigger task:incoming
326
+ App->>T: task.accept()
327
+ ```
328
+
329
+ ### Task Operation Flow
330
+
331
+ ```mermaid
332
+ sequenceDiagram
333
+ participant App
334
+ participant T as Task
335
+ participant C as contact service
336
+ participant AQM as AqmReqs
337
+ participant WS as WebSocket
338
+ participant BE as Backend
339
+
340
+ App->>T: task.hold()
341
+ T->>T: Update local state
342
+ T->>C: contact.hold({data})
343
+ C->>AQM: req(config)
344
+ AQM->>BE: POST /v1/tasks/{interactionId}/hold (HTTP via WebexRequest)
345
+ BE-->>AQM: HTTP response (TaskResponse payload)
346
+ AQM-->>C: resolve Promise<TaskResponse>
347
+ C-->>T: return TaskResponse
348
+ T-->>App: Promise resolves
349
+ Note over WS,TM: WebSocket is notification channel, not request transport
350
+ BE-->>WS: AgentContactHeld
351
+ WS-->>TM: message event
352
+ TM-->>T: emit task:hold
353
+ ```
354
+
355
+ ---
356
+
357
+ ## Task Collection
358
+
359
+ TaskManager maintains a map of active tasks:
360
+
361
+ ```typescript
362
+ private taskCollection: Record<TaskId, ITask> = {};
363
+
364
+ // Tasks indexed by interactionId
365
+ this.taskCollection[interactionId] = task;
366
+
367
+ // Retrieve task
368
+ const task = this.taskCollection[interactionId];
369
+ ```
370
+
371
+ ---
372
+
373
+ ## WebSocket Event Handling
374
+
375
+ TaskManager uses a staged pipeline in `registerTaskListeners()`:
376
+
377
+ ```typescript
378
+ this.webSocketManager.on('message', (event) => {
379
+ // 1) Parse and validate message
380
+ const message = TaskManager.parseWebSocketMessage(event);
381
+ if (!message) return;
382
+
383
+ // 2) Build event context (task, payload, mapped state-machine event)
384
+ const eventContext = this.prepareEventContext(message);
385
+ if (!eventContext) return;
386
+
387
+ // 3) Handle lifecycle changes (create/update/remove task)
388
+ const actions = this.handleTaskLifecycleEvent(eventContext);
389
+ const {task} = actions;
390
+ if (!task) return;
391
+
392
+ // 4) Keep task.data synchronized
393
+ const {payload, stateMachineEvent} = eventContext;
394
+ if (payload) this.updateTaskData(task, payload);
395
+
396
+ // 5) Drive state machine (which emits TASK_EVENTS)
397
+ if (stateMachineEvent) {
398
+ task.sendStateMachineEvent(stateMachineEvent);
399
+ }
400
+ });
401
+ ```
402
+
403
+ ---
404
+
405
+ ## WebRTC Integration
406
+
407
+ For BROWSER login, TaskManager integrates with WebCalling:
408
+
409
+ ```mermaid
410
+ flowchart TD
411
+ A[AgentOfferContact event] --> B[Determine media + loginOption]
412
+ B --> C[TaskFactory chooses Voice/WebRTC class]
413
+ C --> D[Create Task object]
414
+ D --> E[Store in taskCollection]
415
+ E --> F{BROWSER login?}
416
+ F -->|Yes| G[Wait for INCOMING_CALL]
417
+ G --> H[Map call to task]
418
+ H --> I[Emit task:incoming]
419
+ F -->|No| I
420
+ ```
421
+
422
+ ### Call Mapping
423
+
424
+ ```typescript
425
+ // WebCallingService maps call IDs to interaction IDs
426
+ this.webCallingService.mapCallToTask(callId, interactionId);
427
+
428
+ // Task uses call for media operations
429
+ this.webCallingService.answerCall(localAudioStream: LocalMicrophoneStream, taskId: string);
430
+ ```
431
+
432
+ ---
433
+
434
+ ## Auto Wrapup
435
+
436
+ AutoWrapup handles automatic task completion:
437
+
438
+ ```typescript
439
+ // AutoWrapup.ts
440
+ export default class AutoWrapup {
441
+ private timer: ReturnType<typeof setTimeout> | null = null;
442
+ private readonly interval: number;
443
+
444
+ start(onComplete: () => void) {
445
+ this.timer = setTimeout(onComplete, this.interval);
446
+ }
447
+
448
+ clear() {
449
+ if (this.timer) {
450
+ clearTimeout(this.timer);
451
+ this.timer = null;
452
+ }
453
+ }
454
+
455
+ getTimeLeft() {}
456
+ isRunning() {}
457
+ getTimeLeftSeconds() {}
458
+ }
459
+ ```
460
+
461
+ ---
462
+
463
+ ## Contact Service Operations
464
+
465
+ Each task operation maps to an AQM request:
466
+
467
+ ```typescript
468
+ // contact.ts
469
+ export default function routingContact(routing: AqmReqs) {
470
+ return {
471
+ accept: routing.req((p) => ({
472
+ url: '/v1/tasks/.../accept',
473
+ notifSuccess: { bind: { type: CC_EVENTS.AGENT_CONTACT_ASSIGNED }},
474
+ notifFail: { bind: { type: CC_EVENTS.AGENT_CONTACT_ASSIGN_FAILED }},
475
+ })),
476
+
477
+ hold: routing.req((p) => ({...})),
478
+ unHold: routing.req((p) => ({...})),
479
+ consultAccept: routing.req((p) => ({...})),
480
+ cancelTask: routing.req((p) => ({...})),
481
+ cancelCtq: routing.req((p) => ({...})),
482
+ end: routing.req((p) => ({...})),
483
+ wrapup: routing.req((p) => ({...})),
484
+ blindTransfer: routing.req((p) => ({...})),
485
+ consult: routing.req((p) => ({...})),
486
+ consultTransfer: routing.req((p) => ({...})),
487
+ // ... more operations
488
+ };
489
+ }
490
+ ```
491
+
492
+ ---
493
+
494
+ ## Task Utils
495
+
496
+ Helper functions for task state analysis:
497
+
498
+ ```typescript
499
+ // TaskUtils.ts
500
+
501
+ // Check if participant is in main interaction
502
+ isParticipantInMainInteraction(task, agentId);
503
+
504
+ // Check if conference is in progress
505
+ getIsConferenceInProgress(taskData);
506
+
507
+ // Check if agent is primary
508
+ isPrimary(task, agentId);
509
+
510
+ // Check if secondary EPDN agent
511
+ isSecondaryEpDnAgent(interaction);
512
+ ```
513
+
514
+ ---
515
+
516
+ ## Metrics Tracking
517
+
518
+ | Metric | Type | When Tracked |
519
+ | ----------------------- | -------------------- | ------------------ |
520
+ | `TASK_ACCEPT_SUCCESS` | behavioral, business | Task accepted |
521
+ | `TASK_HOLD_SUCCESS` | operational | Hold succeeded |
522
+ | `TASK_END_SUCCESS` | behavioral, business | Task ended |
523
+ | `TASK_WRAPUP_SUCCESS` | operational | Wrapup completed |
524
+ | `TASK_TRANSFER_SUCCESS` | behavioral, business | Transfer completed |
525
+ | `TASK_OUTDIAL_SUCCESS` | behavioral, business | Outdial completed |
526
+
527
+ ---
528
+
529
+ ## Troubleshooting
530
+
531
+ ### Issue: task:incoming not received
532
+
533
+ **Cause**: Agent not available or TaskManager not initialized
534
+
535
+ **Solution**:
536
+
537
+ 1. Ensure `cc.register()` completed
538
+ 2. Ensure `cc.stationLogin()` completed
539
+ 3. Ensure agent state is Available
540
+
541
+ ### Issue: Task operations fail
542
+
543
+ **Cause**: Task state doesn't allow operation
544
+
545
+ **Solution**: Check task state before operation:
546
+
547
+ ```typescript
548
+ if (task.uiControls.hold.isEnabled) {
549
+ await task.hold();
550
+ }
551
+ ```
552
+
553
+ ### Issue: WebRTC call not connecting
554
+
555
+ **Cause**: Call not mapped to task
556
+
557
+ **Solution**: Ensure BROWSER login and mercury connected:
558
+
559
+ ```typescript
560
+ await webex.internal.mercury.connect();
561
+ await cc.stationLogin({ loginOption: 'BROWSER', ... });
562
+ ```
563
+
564
+ ---
565
+
566
+ ## Related Files
567
+
568
+ - [cc.ts](../../../cc.ts) - Main plugin
569
+ - [TaskManager.ts](../TaskManager.ts) - Manager
570
+ - [contact.ts](../contact.ts) - Contact operations
571
+ - [types.ts](../types.ts) - Type definitions
572
+ - [../state-machine/ai-docs/AGENTS.md](../state-machine/ai-docs/AGENTS.md) - State machine guide
573
+ - [../state-machine/ai-docs/ARCHITECTURE.md](../state-machine/ai-docs/ARCHITECTURE.md) - State machine architecture
@@ -22,10 +22,6 @@ export const END = '/end';
22
22
  export const CONSULT_CONFERENCE = '/consult/conference';
23
23
  export const CONFERENCE_EXIT = '/conference/exit';
24
24
  export const CONFERENCE_TRANSFER = '/conference/transfer';
25
- export const DIALER_API = '/v1/dialer';
26
- export const CAMPAIGN_PREVIEW_ACCEPT = '/accept';
27
- /** 80-second timeout for accepting preview contact (outbound call setup takes longer than default 20s) */
28
- export const TIMEOUT_PREVIEW_ACCEPT = 80000;
29
25
  export const TASK_MANAGER_FILE = 'taskManager';
30
26
  export const TASK_FILE = 'task';
31
27
 
@@ -50,6 +46,10 @@ export const PRESERVED_TASK_DATA_FIELDS = {
50
46
  */
51
47
  export const KEYS_TO_NOT_DELETE: string[] = Object.values(PRESERVED_TASK_DATA_FIELDS);
52
48
 
49
+ /**
50
+ * Consultation status constants derived from state machine
51
+ * These values are computed and available in task.data.consultStatus
52
+ */
53
53
  // METHOD NAMES
54
54
  export const METHODS = {
55
55
  // Task class methods
@@ -83,6 +83,7 @@ export const METHODS = {
83
83
  GET_TASK_MANAGER: 'getTaskManager',
84
84
  SETUP_AUTO_WRAPUP_TIMER: 'setupAutoWrapupTimer',
85
85
  CANCEL_AUTO_WRAPUP_TIMER: 'cancelAutoWrapupTimer',
86
+ REQUEST_REAL_TIME_TRANSCRIPTS: 'requestRealTimeTranscripts',
86
87
  };
87
88
 
88
89
  export const TRANSCRIPT_EVENT_MAP = {
@@ -1,14 +1,7 @@
1
1
  import {CC_EVENTS} from '../config/types';
2
2
  import {WCC_API_GATEWAY} from '../constants';
3
- import {HTTP_METHODS} from '../../types';
4
3
  import {createErrDetailsObject as err} from '../core/Utils';
5
- import {
6
- TASK_MESSAGE_TYPE,
7
- TASK_API,
8
- DIALER_API,
9
- CAMPAIGN_PREVIEW_ACCEPT,
10
- TIMEOUT_PREVIEW_ACCEPT,
11
- } from './constants';
4
+ import {TASK_MESSAGE_TYPE, TASK_API} from './constants';
12
5
  import * as Contact from './types';
13
6
  import AqmReqs from '../core/aqm-reqs';
14
7
 
@@ -55,53 +48,5 @@ export default function aqmDialer(aqm: AqmReqs) {
55
48
  errId: 'Service.aqm.dialer.startOutdial',
56
49
  },
57
50
  })),
58
-
59
- /**
60
- * Accepts a campaign preview contact, initiating the outbound call.
61
- *
62
- * @param {Object} p - Parameters object.
63
- * @param {Contact.PreviewContactPayload} p.data - Payload containing interactionId and campaignId.
64
- * @returns {Promise<Contact.AgentContact>} A promise that resolves with agent contact on success.
65
- *
66
- * Emits:
67
- * - `CC_EVENTS.AGENT_CONTACT_ASSIGNED` on success
68
- * - `CC_EVENTS.CAMPAIGN_PREVIEW_ACCEPT_FAILED` on failure
69
- * @ignore
70
- */
71
- acceptPreviewContact: aqm.req((p: {data: Contact.PreviewContactPayload}) => ({
72
- url: `${DIALER_API}/campaign/${encodeURIComponent(p.data.campaignId)}/preview-task/${
73
- p.data.interactionId
74
- }${CAMPAIGN_PREVIEW_ACCEPT}`,
75
- host: WCC_API_GATEWAY,
76
- data: {},
77
- method: HTTP_METHODS.POST,
78
- timeout: TIMEOUT_PREVIEW_ACCEPT,
79
- err,
80
- notifSuccess: {
81
- bind: {
82
- type: TASK_MESSAGE_TYPE,
83
- data: {
84
- type: [CC_EVENTS.AGENT_CONTACT_ASSIGNED, CC_EVENTS.CONTACT_ENDED],
85
- __typeMap: {
86
- typeField: 'type',
87
- conditions: {
88
- [CC_EVENTS.AGENT_CONTACT_ASSIGNED]: {
89
- reservationInteractionId: p.data.interactionId,
90
- },
91
- [CC_EVENTS.CONTACT_ENDED]: {interactionId: p.data.interactionId},
92
- },
93
- },
94
- },
95
- },
96
- msg: {} as Contact.AgentContact,
97
- },
98
- notifFail: {
99
- bind: {
100
- type: TASK_MESSAGE_TYPE,
101
- data: {type: CC_EVENTS.CAMPAIGN_PREVIEW_ACCEPT_FAILED, campaignId: p.data.campaignId},
102
- },
103
- errId: 'Service.aqm.dialer.acceptPreviewContact',
104
- },
105
- })),
106
51
  };
107
52
  }