@webex/contact-center 3.12.0-next.8 → 3.12.0-next.81

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 (205) 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 +265 -29
  24. package/dist/cc.js.map +1 -1
  25. package/dist/config.js +6 -0
  26. package/dist/config.js.map +1 -1
  27. package/dist/constants.js +16 -1
  28. package/dist/constants.js.map +1 -1
  29. package/dist/index.js +20 -5
  30. package/dist/index.js.map +1 -1
  31. package/dist/metrics/behavioral-events.js +101 -0
  32. package/dist/metrics/behavioral-events.js.map +1 -1
  33. package/dist/metrics/constants.js +23 -4
  34. package/dist/metrics/constants.js.map +1 -1
  35. package/dist/services/ApiAiAssistant.js +74 -3
  36. package/dist/services/ApiAiAssistant.js.map +1 -1
  37. package/dist/services/UserPreference.js +427 -0
  38. package/dist/services/UserPreference.js.map +1 -0
  39. package/dist/services/config/Util.js +3 -3
  40. package/dist/services/config/Util.js.map +1 -1
  41. package/dist/services/config/constants.js +23 -2
  42. package/dist/services/config/constants.js.map +1 -1
  43. package/dist/services/config/types.js +49 -9
  44. package/dist/services/config/types.js.map +1 -1
  45. package/dist/services/core/Err.js.map +1 -1
  46. package/dist/services/core/Utils.js +107 -32
  47. package/dist/services/core/Utils.js.map +1 -1
  48. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  49. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  50. package/dist/services/core/websocket/types.js.map +1 -1
  51. package/dist/services/index.js +1 -1
  52. package/dist/services/index.js.map +1 -1
  53. package/dist/services/task/Task.js +688 -0
  54. package/dist/services/task/Task.js.map +1 -0
  55. package/dist/services/task/TaskFactory.js +45 -0
  56. package/dist/services/task/TaskFactory.js.map +1 -0
  57. package/dist/services/task/TaskManager.js +725 -526
  58. package/dist/services/task/TaskManager.js.map +1 -1
  59. package/dist/services/task/TaskUtils.js +162 -26
  60. package/dist/services/task/TaskUtils.js.map +1 -1
  61. package/dist/services/task/constants.js +9 -2
  62. package/dist/services/task/constants.js.map +1 -1
  63. package/dist/services/task/dialer.js +78 -0
  64. package/dist/services/task/dialer.js.map +1 -1
  65. package/dist/services/task/digital/Digital.js +77 -0
  66. package/dist/services/task/digital/Digital.js.map +1 -0
  67. package/dist/services/task/state-machine/TaskStateMachine.js +837 -0
  68. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  69. package/dist/services/task/state-machine/actions.js +543 -0
  70. package/dist/services/task/state-machine/actions.js.map +1 -0
  71. package/dist/services/task/state-machine/constants.js +161 -0
  72. package/dist/services/task/state-machine/constants.js.map +1 -0
  73. package/dist/services/task/state-machine/guards.js +340 -0
  74. package/dist/services/task/state-machine/guards.js.map +1 -0
  75. package/dist/services/task/state-machine/index.js +53 -0
  76. package/dist/services/task/state-machine/index.js.map +1 -0
  77. package/dist/services/task/state-machine/types.js +54 -0
  78. package/dist/services/task/state-machine/types.js.map +1 -0
  79. package/dist/services/task/state-machine/uiControlsComputer.js +553 -0
  80. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  81. package/dist/services/task/taskDataNormalizer.js +99 -0
  82. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  83. package/dist/services/task/types.js +212 -4
  84. package/dist/services/task/types.js.map +1 -1
  85. package/dist/services/task/voice/Voice.js +1042 -0
  86. package/dist/services/task/voice/Voice.js.map +1 -0
  87. package/dist/services/task/voice/WebRTC.js +149 -0
  88. package/dist/services/task/voice/WebRTC.js.map +1 -0
  89. package/dist/types/cc.d.ts +94 -1
  90. package/dist/types/config.d.ts +6 -0
  91. package/dist/types/constants.d.ts +16 -1
  92. package/dist/types/index.d.ts +21 -6
  93. package/dist/types/metrics/constants.d.ts +19 -1
  94. package/dist/types/services/ApiAiAssistant.d.ts +11 -3
  95. package/dist/types/services/UserPreference.d.ts +118 -0
  96. package/dist/types/services/config/constants.d.ts +21 -0
  97. package/dist/types/services/config/types.d.ts +171 -10
  98. package/dist/types/services/core/Err.d.ts +4 -0
  99. package/dist/types/services/core/Utils.d.ts +33 -13
  100. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  101. package/dist/types/services/core/websocket/types.d.ts +1 -1
  102. package/dist/types/services/index.d.ts +1 -1
  103. package/dist/types/services/task/Task.d.ts +157 -0
  104. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  105. package/dist/types/services/task/TaskUtils.d.ts +46 -2
  106. package/dist/types/services/task/constants.d.ts +7 -0
  107. package/dist/types/services/task/dialer.d.ts +30 -0
  108. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  109. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1144 -0
  110. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  111. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  112. package/dist/types/services/task/state-machine/guards.d.ts +90 -0
  113. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  114. package/dist/types/services/task/state-machine/types.d.ts +267 -0
  115. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  116. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  117. package/dist/types/services/task/types.d.ts +603 -66
  118. package/dist/types/services/task/voice/Voice.d.ts +184 -0
  119. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  120. package/dist/types/types.d.ts +94 -0
  121. package/dist/types/webex.d.ts +1 -0
  122. package/dist/types.js +85 -0
  123. package/dist/types.js.map +1 -1
  124. package/dist/webex.js +14 -2
  125. package/dist/webex.js.map +1 -1
  126. package/package.json +15 -12
  127. package/src/cc.ts +329 -30
  128. package/src/config.ts +6 -0
  129. package/src/constants.ts +16 -1
  130. package/src/index.ts +23 -5
  131. package/src/metrics/ai-docs/AGENTS.md +348 -0
  132. package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
  133. package/src/metrics/behavioral-events.ts +106 -0
  134. package/src/metrics/constants.ts +23 -4
  135. package/src/services/ApiAiAssistant.ts +104 -3
  136. package/src/services/UserPreference.ts +509 -0
  137. package/src/services/agent/ai-docs/AGENTS.md +238 -0
  138. package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
  139. package/src/services/ai-docs/AGENTS.md +384 -0
  140. package/src/services/config/Util.ts +3 -3
  141. package/src/services/config/ai-docs/AGENTS.md +253 -0
  142. package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
  143. package/src/services/config/constants.ts +25 -1
  144. package/src/services/config/types.ts +174 -11
  145. package/src/services/core/Err.ts +2 -0
  146. package/src/services/core/Utils.ts +123 -37
  147. package/src/services/core/ai-docs/AGENTS.md +379 -0
  148. package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
  149. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  150. package/src/services/core/websocket/types.ts +1 -1
  151. package/src/services/index.ts +1 -1
  152. package/src/services/task/Task.ts +837 -0
  153. package/src/services/task/TaskFactory.ts +55 -0
  154. package/src/services/task/TaskManager.ts +738 -613
  155. package/src/services/task/TaskUtils.ts +205 -25
  156. package/src/services/task/ai-docs/AGENTS.md +455 -0
  157. package/src/services/task/ai-docs/ARCHITECTURE.md +585 -0
  158. package/src/services/task/constants.ts +7 -0
  159. package/src/services/task/dialer.ts +80 -0
  160. package/src/services/task/digital/Digital.ts +95 -0
  161. package/src/services/task/state-machine/TaskStateMachine.ts +1077 -0
  162. package/src/services/task/state-machine/actions.ts +685 -0
  163. package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
  164. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
  165. package/src/services/task/state-machine/constants.ts +172 -0
  166. package/src/services/task/state-machine/guards.ts +406 -0
  167. package/src/services/task/state-machine/index.ts +28 -0
  168. package/src/services/task/state-machine/types.ts +241 -0
  169. package/src/services/task/state-machine/uiControlsComputer.ts +867 -0
  170. package/src/services/task/taskDataNormalizer.ts +137 -0
  171. package/src/services/task/types.ts +710 -71
  172. package/src/services/task/voice/Voice.ts +1267 -0
  173. package/src/services/task/voice/WebRTC.ts +187 -0
  174. package/src/types.ts +122 -2
  175. package/src/utils/AGENTS.md +276 -0
  176. package/src/webex.js +2 -0
  177. package/test/unit/spec/cc.ts +343 -23
  178. package/test/unit/spec/logger-proxy.ts +70 -0
  179. package/test/unit/spec/services/ApiAiAssistant.ts +122 -17
  180. package/test/unit/spec/services/UserPreference.ts +401 -0
  181. package/test/unit/spec/services/WebCallingService.ts +7 -1
  182. package/test/unit/spec/services/config/index.ts +30 -30
  183. package/test/unit/spec/services/core/Utils.ts +425 -8
  184. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  185. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  186. package/test/unit/spec/services/task/Task.ts +477 -0
  187. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  188. package/test/unit/spec/services/task/TaskManager.ts +832 -1702
  189. package/test/unit/spec/services/task/TaskUtils.ts +206 -0
  190. package/test/unit/spec/services/task/dialer.ts +190 -0
  191. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  192. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +1825 -0
  193. package/test/unit/spec/services/task/state-machine/guards.ts +479 -0
  194. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  195. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2020 -0
  196. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  197. package/test/unit/spec/services/task/voice/Voice.ts +631 -0
  198. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  199. package/umd/contact-center.min.js +2 -2
  200. package/umd/contact-center.min.js.map +1 -1
  201. package/dist/services/task/index.js +0 -1525
  202. package/dist/services/task/index.js.map +0 -1
  203. package/dist/types/services/task/index.d.ts +0 -650
  204. package/src/services/task/index.ts +0 -1801
  205. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,585 @@
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
+ ### RTD / AI Assistant event routing
404
+
405
+ `TaskManager.handleRealtimeWebsocketEvent()` handles payloads arriving on the realtime subscription socket used for AI features. It:
406
+
407
+ 1. Normalizes the websocket envelope (`payload.data` vs direct payload form)
408
+ 2. Resolves the owning task via `conversationId`
409
+ 3. Emits `REAL_TIME_TRANSCRIPTION` on the task for transcript payloads
410
+ 4. Emits `SUGGESTED_RESPONSE` on the task only when the backend payload is a final suggestion (`data.type === 'SUGGESTION'`)
411
+ 5. Ignores `SUGGESTED_RESPONSE_ACKNOWLEDGE` for public SDK emission
412
+
413
+ This keeps transcript and suggestion delivery aligned on the same per-task event surface.
414
+
415
+ ---
416
+
417
+ ## WebRTC Integration
418
+
419
+ For BROWSER login, TaskManager integrates with WebCalling:
420
+
421
+ ```mermaid
422
+ flowchart TD
423
+ A[AgentOfferContact event] --> B[Determine media + loginOption]
424
+ B --> C[TaskFactory chooses Voice/WebRTC class]
425
+ C --> D[Create Task object]
426
+ D --> E[Store in taskCollection]
427
+ E --> F{BROWSER login?}
428
+ F -->|Yes| G[Wait for INCOMING_CALL]
429
+ G --> H[Map call to task]
430
+ H --> I[Emit task:incoming]
431
+ F -->|No| I
432
+ ```
433
+
434
+ ### Call Mapping
435
+
436
+ ```typescript
437
+ // WebCallingService maps call IDs to interaction IDs
438
+ this.webCallingService.mapCallToTask(callId, interactionId);
439
+
440
+ // Task uses call for media operations
441
+ this.webCallingService.answerCall(localAudioStream: LocalMicrophoneStream, taskId: string);
442
+ ```
443
+
444
+ ---
445
+
446
+ ## Auto Wrapup
447
+
448
+ AutoWrapup handles automatic task completion:
449
+
450
+ ```typescript
451
+ // AutoWrapup.ts
452
+ export default class AutoWrapup {
453
+ private timer: ReturnType<typeof setTimeout> | null = null;
454
+ private readonly interval: number;
455
+
456
+ start(onComplete: () => void) {
457
+ this.timer = setTimeout(onComplete, this.interval);
458
+ }
459
+
460
+ clear() {
461
+ if (this.timer) {
462
+ clearTimeout(this.timer);
463
+ this.timer = null;
464
+ }
465
+ }
466
+
467
+ getTimeLeft() {}
468
+ isRunning() {}
469
+ getTimeLeftSeconds() {}
470
+ }
471
+ ```
472
+
473
+ ---
474
+
475
+ ## Contact Service Operations
476
+
477
+ Each task operation maps to an AQM request:
478
+
479
+ ```typescript
480
+ // contact.ts
481
+ export default function routingContact(routing: AqmReqs) {
482
+ return {
483
+ accept: routing.req((p) => ({
484
+ url: '/v1/tasks/.../accept',
485
+ notifSuccess: { bind: { type: CC_EVENTS.AGENT_CONTACT_ASSIGNED }},
486
+ notifFail: { bind: { type: CC_EVENTS.AGENT_CONTACT_ASSIGN_FAILED }},
487
+ })),
488
+
489
+ hold: routing.req((p) => ({...})),
490
+ unHold: routing.req((p) => ({...})),
491
+ consultAccept: routing.req((p) => ({...})),
492
+ cancelTask: routing.req((p) => ({...})),
493
+ cancelCtq: routing.req((p) => ({...})),
494
+ end: routing.req((p) => ({...})),
495
+ wrapup: routing.req((p) => ({...})),
496
+ blindTransfer: routing.req((p) => ({...})),
497
+ consult: routing.req((p) => ({...})),
498
+ consultTransfer: routing.req((p) => ({...})),
499
+ // ... more operations
500
+ };
501
+ }
502
+ ```
503
+
504
+ ---
505
+
506
+ ## Task Utils
507
+
508
+ Helper functions for task state analysis:
509
+
510
+ ```typescript
511
+ // TaskUtils.ts
512
+
513
+ // Check if participant is in main interaction
514
+ isParticipantInMainInteraction(task, agentId);
515
+
516
+ // Check if conference is in progress
517
+ getIsConferenceInProgress(taskData);
518
+
519
+ // Check if agent is primary
520
+ isPrimary(task, agentId);
521
+
522
+ // Check if secondary EPDN agent
523
+ isSecondaryEpDnAgent(interaction);
524
+ ```
525
+
526
+ ---
527
+
528
+ ## Metrics Tracking
529
+
530
+ | Metric | Type | When Tracked |
531
+ | ----------------------- | -------------------- | ------------------ |
532
+ | `TASK_ACCEPT_SUCCESS` | behavioral, business | Task accepted |
533
+ | `TASK_HOLD_SUCCESS` | operational | Hold succeeded |
534
+ | `TASK_END_SUCCESS` | behavioral, business | Task ended |
535
+ | `TASK_WRAPUP_SUCCESS` | operational | Wrapup completed |
536
+ | `TASK_TRANSFER_SUCCESS` | behavioral, business | Transfer completed |
537
+ | `TASK_OUTDIAL_SUCCESS` | behavioral, business | Outdial completed |
538
+
539
+ ---
540
+
541
+ ## Troubleshooting
542
+
543
+ ### Issue: task:incoming not received
544
+
545
+ **Cause**: Agent not available or TaskManager not initialized
546
+
547
+ **Solution**:
548
+
549
+ 1. Ensure `cc.register()` completed
550
+ 2. Ensure `cc.stationLogin()` completed
551
+ 3. Ensure agent state is Available
552
+
553
+ ### Issue: Task operations fail
554
+
555
+ **Cause**: Task state doesn't allow operation
556
+
557
+ **Solution**: Check task state before operation:
558
+
559
+ ```typescript
560
+ if (task.uiControls.hold.isEnabled) {
561
+ await task.hold();
562
+ }
563
+ ```
564
+
565
+ ### Issue: WebRTC call not connecting
566
+
567
+ **Cause**: Call not mapped to task
568
+
569
+ **Solution**: Ensure BROWSER login and mercury connected:
570
+
571
+ ```typescript
572
+ await webex.internal.mercury.connect();
573
+ await cc.stationLogin({ loginOption: 'BROWSER', ... });
574
+ ```
575
+
576
+ ---
577
+
578
+ ## Related Files
579
+
580
+ - [cc.ts](../../../cc.ts) - Main plugin
581
+ - [TaskManager.ts](../TaskManager.ts) - Manager
582
+ - [contact.ts](../contact.ts) - Contact operations
583
+ - [types.ts](../types.ts) - Type definitions
584
+ - [../state-machine/ai-docs/AGENTS.md](../state-machine/ai-docs/AGENTS.md) - State machine guide
585
+ - [../state-machine/ai-docs/ARCHITECTURE.md](../state-machine/ai-docs/ARCHITECTURE.md) - State machine architecture
@@ -24,6 +24,8 @@ export const CONFERENCE_EXIT = '/conference/exit';
24
24
  export const CONFERENCE_TRANSFER = '/conference/transfer';
25
25
  export const DIALER_API = '/v1/dialer';
26
26
  export const CAMPAIGN_PREVIEW_ACCEPT = '/accept';
27
+ export const CAMPAIGN_PREVIEW_SKIP = '/skip';
28
+ export const CAMPAIGN_PREVIEW_REMOVE = '/remove';
27
29
  /** 80-second timeout for accepting preview contact (outbound call setup takes longer than default 20s) */
28
30
  export const TIMEOUT_PREVIEW_ACCEPT = 80000;
29
31
  export const TASK_MANAGER_FILE = 'taskManager';
@@ -50,6 +52,10 @@ export const PRESERVED_TASK_DATA_FIELDS = {
50
52
  */
51
53
  export const KEYS_TO_NOT_DELETE: string[] = Object.values(PRESERVED_TASK_DATA_FIELDS);
52
54
 
55
+ /**
56
+ * Consultation status constants derived from state machine
57
+ * These values are computed and available in task.data.consultStatus
58
+ */
53
59
  // METHOD NAMES
54
60
  export const METHODS = {
55
61
  // Task class methods
@@ -83,6 +89,7 @@ export const METHODS = {
83
89
  GET_TASK_MANAGER: 'getTaskManager',
84
90
  SETUP_AUTO_WRAPUP_TIMER: 'setupAutoWrapupTimer',
85
91
  CANCEL_AUTO_WRAPUP_TIMER: 'cancelAutoWrapupTimer',
92
+ REQUEST_REAL_TIME_TRANSCRIPTS: 'requestRealTimeTranscripts',
86
93
  };
87
94
 
88
95
  export const TRANSCRIPT_EVENT_MAP = {
@@ -7,6 +7,8 @@ import {
7
7
  TASK_API,
8
8
  DIALER_API,
9
9
  CAMPAIGN_PREVIEW_ACCEPT,
10
+ CAMPAIGN_PREVIEW_SKIP,
11
+ CAMPAIGN_PREVIEW_REMOVE,
10
12
  TIMEOUT_PREVIEW_ACCEPT,
11
13
  } from './constants';
12
14
  import * as Contact from './types';
@@ -103,5 +105,83 @@ export default function aqmDialer(aqm: AqmReqs) {
103
105
  errId: 'Service.aqm.dialer.acceptPreviewContact',
104
106
  },
105
107
  })),
108
+
109
+ /**
110
+ * Skips a campaign preview contact, requesting the next contact from the campaign.
111
+ *
112
+ * @param {Object} p - Parameters object.
113
+ * @param {Contact.PreviewContactPayload} p.data - Payload containing interactionId and campaignId.
114
+ * @returns {Promise<Contact.AgentContact>} A promise that resolves with agent contact on success.
115
+ *
116
+ * Emits:
117
+ * - `CC_EVENTS.CAMPAIGN_CONTACT_UPDATED` or `CC_EVENTS.CONTACT_ENDED` on success
118
+ * - `CC_EVENTS.CAMPAIGN_PREVIEW_SKIP_FAILED` on failure
119
+ * @ignore
120
+ */
121
+ skipPreviewContact: aqm.req((p: {data: Contact.PreviewContactPayload}) => ({
122
+ url: `${DIALER_API}/campaign/${encodeURIComponent(p.data.campaignId)}/preview-task/${
123
+ p.data.interactionId
124
+ }${CAMPAIGN_PREVIEW_SKIP}`,
125
+ host: WCC_API_GATEWAY,
126
+ data: {},
127
+ method: HTTP_METHODS.POST,
128
+ err,
129
+ notifSuccess: {
130
+ bind: {
131
+ type: TASK_MESSAGE_TYPE,
132
+ data: {
133
+ type: [CC_EVENTS.CAMPAIGN_CONTACT_UPDATED, CC_EVENTS.CONTACT_ENDED],
134
+ interactionId: p.data.interactionId,
135
+ },
136
+ },
137
+ msg: {} as Contact.AgentContact,
138
+ },
139
+ notifFail: {
140
+ bind: {
141
+ type: TASK_MESSAGE_TYPE,
142
+ data: {type: CC_EVENTS.CAMPAIGN_PREVIEW_SKIP_FAILED, campaignId: p.data.campaignId},
143
+ },
144
+ errId: 'Service.aqm.dialer.skipPreviewContact',
145
+ },
146
+ })),
147
+
148
+ /**
149
+ * Removes a campaign preview contact from the campaign list entirely.
150
+ *
151
+ * @param {Object} p - Parameters object.
152
+ * @param {Contact.PreviewContactPayload} p.data - Payload containing interactionId and campaignId.
153
+ * @returns {Promise<Contact.AgentContact>} A promise that resolves with agent contact on success.
154
+ *
155
+ * Emits:
156
+ * - `CC_EVENTS.CAMPAIGN_CONTACT_UPDATED` or `CC_EVENTS.CONTACT_ENDED` on success
157
+ * - `CC_EVENTS.CAMPAIGN_PREVIEW_REMOVE_FAILED` on failure
158
+ * @ignore
159
+ */
160
+ removePreviewContact: aqm.req((p: {data: Contact.PreviewContactPayload}) => ({
161
+ url: `${DIALER_API}/campaign/${encodeURIComponent(p.data.campaignId)}/preview-task/${
162
+ p.data.interactionId
163
+ }${CAMPAIGN_PREVIEW_REMOVE}`,
164
+ host: WCC_API_GATEWAY,
165
+ data: {},
166
+ method: HTTP_METHODS.POST,
167
+ err,
168
+ notifSuccess: {
169
+ bind: {
170
+ type: TASK_MESSAGE_TYPE,
171
+ data: {
172
+ type: [CC_EVENTS.CAMPAIGN_CONTACT_UPDATED, CC_EVENTS.CONTACT_ENDED],
173
+ interactionId: p.data.interactionId,
174
+ },
175
+ },
176
+ msg: {} as Contact.AgentContact,
177
+ },
178
+ notifFail: {
179
+ bind: {
180
+ type: TASK_MESSAGE_TYPE,
181
+ data: {type: CC_EVENTS.CAMPAIGN_PREVIEW_REMOVE_FAILED, campaignId: p.data.campaignId},
182
+ },
183
+ errId: 'Service.aqm.dialer.removePreviewContact',
184
+ },
185
+ })),
106
186
  };
107
187
  }