@webex/contact-center 3.12.0-llmrefactor.1 → 3.12.0-llmrefactor.10

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 (198) hide show
  1. package/.sdd/manifest.json +7 -5
  2. package/ai-docs/ARCHITECTURE.md +1 -1
  3. package/ai-docs/CONTRACTS.md +8 -3
  4. package/ai-docs/SECURITY.md +1 -1
  5. package/ai-docs/contact-center-spec.md +22 -4
  6. package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
  7. package/dist/cc.js +544 -12
  8. package/dist/cc.js.map +1 -1
  9. package/dist/config.js +7 -0
  10. package/dist/config.js.map +1 -1
  11. package/dist/constants.js +10 -2
  12. package/dist/constants.js.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/metrics/MetricsManager.js +16 -0
  15. package/dist/metrics/MetricsManager.js.map +1 -1
  16. package/dist/metrics/behavioral-events.js +104 -0
  17. package/dist/metrics/behavioral-events.js.map +1 -1
  18. package/dist/metrics/constants.js +18 -0
  19. package/dist/metrics/constants.js.map +1 -1
  20. package/dist/services/AddressBook.js +18 -15
  21. package/dist/services/AddressBook.js.map +1 -1
  22. package/dist/services/AnswerCallOnWebexService.js +202 -0
  23. package/dist/services/AnswerCallOnWebexService.js.map +1 -0
  24. package/dist/services/EntryPoint.js +46 -68
  25. package/dist/services/EntryPoint.js.map +1 -1
  26. package/dist/services/Queue.js +27 -22
  27. package/dist/services/Queue.js.map +1 -1
  28. package/dist/services/WebexCrossClientService.js +222 -0
  29. package/dist/services/WebexCrossClientService.js.map +1 -0
  30. package/dist/services/WxAppTelephonyMercurySync.js +108 -0
  31. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  32. package/dist/services/config/Util.js +3 -0
  33. package/dist/services/config/Util.js.map +1 -1
  34. package/dist/services/config/constants.js +10 -6
  35. package/dist/services/config/constants.js.map +1 -1
  36. package/dist/services/config/types.js +4 -0
  37. package/dist/services/config/types.js.map +1 -1
  38. package/dist/services/core/Err.js.map +1 -1
  39. package/dist/services/core/WebexRequest.js +6 -2
  40. package/dist/services/core/WebexRequest.js.map +1 -1
  41. package/dist/services/core/aqm-reqs.js +28 -14
  42. package/dist/services/core/aqm-reqs.js.map +1 -1
  43. package/dist/services/core/types.js.map +1 -1
  44. package/dist/services/task/Task.js +73 -7
  45. package/dist/services/task/Task.js.map +1 -1
  46. package/dist/services/task/TaskFactory.js +8 -4
  47. package/dist/services/task/TaskFactory.js.map +1 -1
  48. package/dist/services/task/TaskManager.js +490 -21
  49. package/dist/services/task/TaskManager.js.map +1 -1
  50. package/dist/services/task/WebexCallingUtils.js +70 -0
  51. package/dist/services/task/WebexCallingUtils.js.map +1 -0
  52. package/dist/services/task/constants.js +4 -1
  53. package/dist/services/task/constants.js.map +1 -1
  54. package/dist/services/task/contact.js +29 -0
  55. package/dist/services/task/contact.js.map +1 -1
  56. package/dist/services/task/digital/Digital.js +3 -2
  57. package/dist/services/task/digital/Digital.js.map +1 -1
  58. package/dist/services/task/state-machine/TaskStateMachine.js +162 -53
  59. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
  60. package/dist/services/task/state-machine/actions.js +6 -1
  61. package/dist/services/task/state-machine/actions.js.map +1 -1
  62. package/dist/services/task/state-machine/guards.js +7 -10
  63. package/dist/services/task/state-machine/guards.js.map +1 -1
  64. package/dist/services/task/state-machine/types.js.map +1 -1
  65. package/dist/services/task/state-machine/uiControlsComputer.js +118 -18
  66. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
  67. package/dist/services/task/types.js +16 -1
  68. package/dist/services/task/types.js.map +1 -1
  69. package/dist/services/task/voice/Voice.js +456 -15
  70. package/dist/services/task/voice/Voice.js.map +1 -1
  71. package/dist/services/task/voice/WebRTC.js +4 -1
  72. package/dist/services/task/voice/WebRTC.js.map +1 -1
  73. package/dist/services/task/voice/wxAppVoiceMethods.js +354 -0
  74. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  75. package/dist/services/wxAppDiagnosticLogging.js +122 -0
  76. package/dist/services/wxAppDiagnosticLogging.js.map +1 -0
  77. package/dist/services/wxAppTelephonyUtils.js +19 -0
  78. package/dist/services/wxAppTelephonyUtils.js.map +1 -0
  79. package/dist/types/cc.d.ts +78 -4
  80. package/dist/types/config.d.ts +7 -0
  81. package/dist/types/constants.d.ts +8 -0
  82. package/dist/types/index.d.ts +3 -1
  83. package/dist/types/metrics/MetricsManager.d.ts +6 -0
  84. package/dist/types/metrics/constants.d.ts +17 -0
  85. package/dist/types/services/AddressBook.d.ts +2 -1
  86. package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
  87. package/dist/types/services/EntryPoint.d.ts +7 -5
  88. package/dist/types/services/Queue.d.ts +5 -3
  89. package/dist/types/services/WebexCrossClientService.d.ts +32 -0
  90. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  91. package/dist/types/services/config/constants.d.ts +8 -5
  92. package/dist/types/services/config/types.d.ts +17 -4
  93. package/dist/types/services/core/Err.d.ts +2 -0
  94. package/dist/types/services/core/WebexRequest.d.ts +1 -0
  95. package/dist/types/services/core/types.d.ts +2 -0
  96. package/dist/types/services/task/Task.d.ts +20 -2
  97. package/dist/types/services/task/TaskFactory.d.ts +2 -1
  98. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  99. package/dist/types/services/task/constants.d.ts +3 -0
  100. package/dist/types/services/task/contact.d.ts +4 -0
  101. package/dist/types/services/task/digital/Digital.d.ts +2 -2
  102. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +304 -56
  103. package/dist/types/services/task/state-machine/guards.d.ts +6 -5
  104. package/dist/types/services/task/state-machine/types.d.ts +9 -1
  105. package/dist/types/services/task/types.d.ts +81 -4
  106. package/dist/types/services/task/voice/Voice.d.ts +52 -9
  107. package/dist/types/services/task/voice/WebRTC.d.ts +2 -2
  108. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +55 -0
  109. package/dist/types/services/wxAppDiagnosticLogging.d.ts +51 -0
  110. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  111. package/dist/types/types.d.ts +14 -8
  112. package/dist/types/utils/PageCache.d.ts +20 -3
  113. package/dist/types.js +7 -2
  114. package/dist/types.js.map +1 -1
  115. package/dist/utils/PageCache.js +19 -5
  116. package/dist/utils/PageCache.js.map +1 -1
  117. package/dist/webex.js +1 -1
  118. package/package.json +8 -8
  119. package/src/cc.ts +657 -12
  120. package/src/config.ts +7 -0
  121. package/src/constants.ts +8 -0
  122. package/src/index.ts +2 -0
  123. package/src/metrics/MetricsManager.ts +16 -0
  124. package/src/metrics/ai-docs/metrics-spec.md +78 -10
  125. package/src/metrics/behavioral-events.ts +106 -0
  126. package/src/metrics/constants.ts +20 -0
  127. package/src/services/AddressBook.ts +17 -6
  128. package/src/services/AnswerCallOnWebexService.ts +239 -0
  129. package/src/services/EntryPoint.ts +59 -60
  130. package/src/services/Queue.ts +29 -12
  131. package/src/services/WebexCrossClientService.ts +293 -0
  132. package/src/services/WxAppTelephonyMercurySync.ts +142 -0
  133. package/src/services/agent/ai-docs/agent-spec.md +1 -0
  134. package/src/services/ai-docs/AGENTS.md +10 -10
  135. package/src/services/ai-docs/services-spec.md +6 -1
  136. package/src/services/config/Util.ts +3 -0
  137. package/src/services/config/ai-docs/AGENTS.md +1 -1
  138. package/src/services/config/ai-docs/ARCHITECTURE.md +2 -2
  139. package/src/services/config/ai-docs/config-spec.md +6 -0
  140. package/src/services/config/constants.ts +10 -6
  141. package/src/services/config/types.ts +16 -4
  142. package/src/services/core/Err.ts +1 -0
  143. package/src/services/core/WebexRequest.ts +3 -1
  144. package/src/services/core/ai-docs/core-spec.md +5 -1
  145. package/src/services/core/aqm-reqs.ts +30 -15
  146. package/src/services/core/types.ts +2 -0
  147. package/src/services/task/Task.ts +79 -8
  148. package/src/services/task/TaskFactory.ts +8 -3
  149. package/src/services/task/TaskManager.ts +716 -17
  150. package/src/services/task/WebexCallingUtils.ts +136 -0
  151. package/src/services/task/ai-docs/ARCHITECTURE.md +1 -0
  152. package/src/services/task/ai-docs/task-spec.md +156 -3
  153. package/src/services/task/constants.ts +3 -0
  154. package/src/services/task/contact.ts +30 -0
  155. package/src/services/task/digital/Digital.ts +4 -2
  156. package/src/services/task/state-machine/TaskStateMachine.ts +235 -81
  157. package/src/services/task/state-machine/actions.ts +5 -2
  158. package/src/services/task/state-machine/ai-docs/AGENTS.md +6 -4
  159. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +35 -16
  160. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +103 -33
  161. package/src/services/task/state-machine/guards.ts +7 -10
  162. package/src/services/task/state-machine/types.ts +16 -1
  163. package/src/services/task/state-machine/uiControlsComputer.ts +206 -32
  164. package/src/services/task/types.ts +114 -4
  165. package/src/services/task/voice/Voice.ts +595 -14
  166. package/src/services/task/voice/WebRTC.ts +5 -1
  167. package/src/services/task/voice/wxAppVoiceMethods.ts +516 -0
  168. package/src/services/wxAppDiagnosticLogging.ts +174 -0
  169. package/src/services/wxAppTelephonyUtils.ts +14 -0
  170. package/src/types.ts +33 -9
  171. package/src/utils/AGENTS.md +21 -10
  172. package/src/utils/PageCache.ts +38 -5
  173. package/src/utils/ai-docs/utils-spec.md +21 -11
  174. package/test/unit/spec/cc.ts +1522 -19
  175. package/test/unit/spec/metrics/MetricsManager.ts +25 -0
  176. package/test/unit/spec/metrics/behavioral-events.ts +60 -0
  177. package/test/unit/spec/services/AddressBook.ts +37 -6
  178. package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
  179. package/test/unit/spec/services/EntryPoint.ts +87 -40
  180. package/test/unit/spec/services/Queue.ts +123 -12
  181. package/test/unit/spec/services/WebexCrossClientService.ts +467 -0
  182. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
  183. package/test/unit/spec/services/config/Util.ts +85 -0
  184. package/test/unit/spec/services/core/WebexRequest.ts +3 -1
  185. package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
  186. package/test/unit/spec/services/task/Task.ts +274 -6
  187. package/test/unit/spec/services/task/TaskFactory.ts +39 -2
  188. package/test/unit/spec/services/task/TaskManager.ts +1717 -9
  189. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  190. package/test/unit/spec/services/task/contact.ts +33 -0
  191. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +1485 -109
  192. package/test/unit/spec/services/task/state-machine/guards.ts +210 -8
  193. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +445 -7
  194. package/test/unit/spec/services/task/voice/Voice.ts +1412 -0
  195. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +603 -0
  196. package/test/unit/spec/services/wxAppDiagnosticLogging.ts +143 -0
  197. package/umd/contact-center.min.js +2 -2
  198. package/umd/contact-center.min.js.map +1 -1
@@ -0,0 +1,136 @@
1
+ import {TaskState} from './state-machine/constants';
2
+
3
+ export type WebexCallingDeviceDetails = {
4
+ deviceType: string;
5
+ deviceId: string;
6
+ deviceCallId: string;
7
+ };
8
+
9
+ type WebexCallingParticipant = {
10
+ id?: unknown;
11
+ deviceType?: unknown;
12
+ deviceCallId?: unknown;
13
+ deviceId?: unknown;
14
+ };
15
+
16
+ const normalizeId = (id: unknown): string | undefined => {
17
+ if (typeof id !== 'string') {
18
+ return undefined;
19
+ }
20
+
21
+ const normalizedId = id.trim();
22
+
23
+ return normalizedId === '' ? undefined : normalizedId;
24
+ };
25
+
26
+ const isParticipantsById = (participants: unknown): participants is Record<string, unknown> =>
27
+ Boolean(participants) &&
28
+ typeof participants === 'object' &&
29
+ !Array.isArray(participants) &&
30
+ !(participants instanceof Map);
31
+
32
+ const hasWebexCallingDeviceDetails = (
33
+ participant: unknown
34
+ ): participant is WebexCallingParticipant &
35
+ Pick<WebexCallingDeviceDetails, 'deviceCallId' | 'deviceId'> => {
36
+ const participantDetails = participant as WebexCallingParticipant | undefined;
37
+
38
+ return (
39
+ typeof participantDetails?.deviceCallId === 'string' &&
40
+ participantDetails.deviceCallId.trim() !== '' &&
41
+ typeof participantDetails?.deviceId === 'string' &&
42
+ participantDetails.deviceId.trim() !== ''
43
+ );
44
+ };
45
+
46
+ const isWebexCallingParticipantForAgent = (
47
+ participant: unknown,
48
+ agentId: string
49
+ ): participant is WebexCallingParticipant &
50
+ Pick<WebexCallingDeviceDetails, 'deviceCallId' | 'deviceId'> => {
51
+ const participantDetails = participant as WebexCallingParticipant | undefined;
52
+
53
+ return (
54
+ normalizeId(participantDetails?.id) === agentId && hasWebexCallingDeviceDetails(participant)
55
+ );
56
+ };
57
+
58
+ const getWebexCallingDeviceDetails = (
59
+ participant: WebexCallingParticipant &
60
+ Pick<WebexCallingDeviceDetails, 'deviceCallId' | 'deviceId'>
61
+ ): WebexCallingDeviceDetails => ({
62
+ deviceType: typeof participant.deviceType === 'string' ? participant.deviceType : '',
63
+ deviceId: participant.deviceId,
64
+ deviceCallId: participant.deviceCallId,
65
+ });
66
+
67
+ export function getWebexCallingDeviceDetailsForAgent(
68
+ agentId: string | undefined,
69
+ participants: unknown
70
+ ): WebexCallingDeviceDetails | undefined {
71
+ const normalizedAgentId = normalizeId(agentId);
72
+ if (!normalizedAgentId || !isParticipantsById(participants)) {
73
+ return undefined;
74
+ }
75
+
76
+ const agentParticipant = participants[normalizedAgentId];
77
+ const matchingAgentParticipant = hasWebexCallingDeviceDetails(agentParticipant)
78
+ ? agentParticipant
79
+ : Object.values(participants).find((participant) =>
80
+ isWebexCallingParticipantForAgent(participant, normalizedAgentId)
81
+ );
82
+
83
+ if (!matchingAgentParticipant || !hasWebexCallingDeviceDetails(matchingAgentParticipant)) {
84
+ return undefined;
85
+ }
86
+
87
+ return getWebexCallingDeviceDetails(matchingAgentParticipant);
88
+ }
89
+
90
+ export function isWebexCallingCallForAgent(
91
+ agentId: string | undefined,
92
+ participants: unknown
93
+ ): boolean {
94
+ return Boolean(getWebexCallingDeviceDetailsForAgent(agentId, participants));
95
+ }
96
+
97
+ /** Matches wxAppVoiceMethods.getWebexCallingCallId engaged semantics for uiControls. */
98
+ export function isWxAppEngagedForControls(
99
+ enableWxBetterTogether: boolean,
100
+ agentId: string | undefined,
101
+ participants: unknown,
102
+ state: TaskState
103
+ ): boolean {
104
+ if (!enableWxBetterTogether) {
105
+ return false;
106
+ }
107
+
108
+ if (
109
+ !state ||
110
+ state === TaskState.OFFERED ||
111
+ state === TaskState.IDLE ||
112
+ state === TaskState.WRAPPING_UP ||
113
+ state === TaskState.TERMINATED ||
114
+ state === TaskState.COMPLETED
115
+ ) {
116
+ return false;
117
+ }
118
+
119
+ const details = getWebexCallingDeviceDetailsForAgent(agentId, participants);
120
+
121
+ return details?.deviceType === 'wxApp';
122
+ }
123
+
124
+ export function decodedLineOwnerId(lineOwnerId?: string): string | undefined {
125
+ if (!lineOwnerId) {
126
+ return undefined;
127
+ }
128
+
129
+ try {
130
+ const decoded = atob(lineOwnerId);
131
+
132
+ return decoded.split('/').pop();
133
+ } catch {
134
+ return undefined;
135
+ }
136
+ }
@@ -35,6 +35,7 @@
35
35
  - `state?: SnapshotFrom<TaskStateMachine>`
36
36
  - `autoWrapup?: AutoWrapup`
37
37
  - `uiControls: TaskUIControls` (getter)
38
+ - includes ordered, action-specific `consultTransferDestinations` computed from Task profile configuration and live interaction data
38
39
 
39
40
  **Methods**
40
41
 
@@ -33,7 +33,7 @@ Manage task lifecycle including inbound/outbound calls, hold/resume, consult, tr
33
33
 
34
34
  - **Event Emission and Public APIs**: Task objects register listeners, update context, emit SDK events (e.g., `task:*`), and expose public methods that delegate to `contact.ts` for call control and to the state machine for transition validation.
35
35
 
36
- - **AQM Contact Operations**: `contact.ts` builds the AQM request surface for call control (accept, hold, consult, transfer, wrapup, end) and is the primary bridge from `Task`/`Voice`/`WebRTC`/`Digital` methods to WCC task APIs.
36
+ - **AQM Contact Operations**: `contact.ts` builds the AQM request surface for call control (accept, hold, consult, transfer, participant Drop, wrapup, end) and is the primary bridge from `Task`/`Voice`/`WebRTC`/`Digital` methods to WCC task APIs.
37
37
 
38
38
  - **Outbound and Preview-Campaign Dialing**: `dialer.ts` exposes `startOutdial` plus `acceptPreviewContact`, `skipPreviewContact`, and `removePreviewContact`; ContactCenter publishes these operations through typed `cc` methods.
39
39
 
@@ -141,6 +141,8 @@ services/task/
141
141
  |---|---|---|---|---|---|---|
142
142
  | `task.surface` | SDK / event / internal API | Exported Task/types/events plus application-facing task instances and call-control methods. | Stable module consumption boundary. | Additive changes by default; breaking package exports require a major-version transition. | `src/services/task/Task.ts` | `../../../../ai-docs/CONTRACTS.md` |
143
143
  | `task.preview-campaign` | SDK/AQM API | `acceptPreviewContact`, `skipPreviewContact`, `removePreviewContact`, and `PreviewContactPayload`. | Accept, skip, or remove a reserved campaign preview contact; each method returns `Promise<TaskResponse>`. | Additive semver-public methods; removals or signature changes are breaking. | `src/cc.ts`, `src/services/task/dialer.ts`, `src/services/task/types.ts` | `../../../../ai-docs/CONTRACTS.md` |
144
+ | `task.consult-transfer-controls` | SDK task controls | `TaskUIControls.consultTransferDestinations` with ordered `consult` and `transfer` arrays. | Surface default destination availability on every Task without an extra policy method. | Additive semver-public field/types; array order is meaningful and the first item is the default. | `src/services/task/types.ts`, `src/services/task/state-machine/uiControlsComputer.ts` | `../../../../ai-docs/CONTRACTS.md` |
145
+ | `task.conference-participant-drop` | SDK/AQM API | `task.dropConferenceParticipant(payload: DropConferenceParticipantPayload): Promise<TaskResponse>`. | Remove a supported target from a voice conference after correlated routing completion. | Additive semver-public method and payload; removals or signature changes are breaking. | `src/services/task/voice/Voice.ts`, `src/services/task/contact.ts`, `src/services/task/types.ts` | `../../../../ai-docs/CONTRACTS.md` |
144
146
 
145
147
  Compatibility notes:
146
148
  - Do not remove or reinterpret exported symbols/events without a documented consumer migration.
@@ -151,6 +153,8 @@ Compatibility notes:
151
153
 
152
154
  - `PreviewContactPayload` (`types.ts`) with `interactionId` and campaign-name `campaignId`
153
155
 
156
+ - `DropConferenceParticipantPayload` (`types.ts`) with a runtime-validated non-empty `participantId`
157
+
154
158
  - `ITask`, `IVoice`, `IWebRTC`, `IDigital` (`types.ts`)
155
159
 
156
160
  - `MEDIA_CHANNEL`, `TASK_CHANNEL_TYPE`, `VOICE_VARIANT` (`types.ts`)
@@ -346,6 +350,20 @@ End consultation without transfer.
346
350
 
347
351
  **Returns**: `Promise<TaskResponse>`
348
352
 
353
+ Remove another participant from a voice conference.
354
+
355
+ **Parameters**:
356
+
357
+ - `participantId` (string, required): backend participant target identifier; blank and non-string values reject before AQM registration or telemetry.
358
+
359
+ **Returns**: `Promise<TaskResponse>` after `ParticipantLeftConference` is received for the latest `interaction.mainInteractionId || task.data.interactionId`.
360
+
361
+ **Failure**: `ParticipantDropConferenceFailed`, HTTP rejection, or the default 20-second AQM timeout rejects the promise. The operation does not add a task state-machine event or optimistically change the roster.
362
+
363
+ ```typescript
364
+ await task.dropConferenceParticipant({participantId});
365
+ ```
366
+
349
367
  ### Complete TASK_EVENTS inventory
350
368
 
351
369
  The public `TASK_EVENTS` enum contains 49 members; every member is listed below from `src/services/task/types.ts`.
@@ -417,6 +435,10 @@ The public `TASK_EVENTS` enum contains 49 members; every member is listed below
417
435
  | TASK-R-005 | The contact dependency belongs to Task/TaskFactory-created tasks; dialer is an AqmReqs request factory without that constructor. | Misattributing constructor dependencies causes invalid instantiation examples. | `src/services/task/TaskFactory.ts` | `test/unit/spec/services/task/dialer.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
418
436
  | TASK-R-006 | Keep credentials and authentication outside Task; remote operations delegate through contact/dialer routing, AqmReqs, and Core/WebexRequest. | Task lifecycle objects should never duplicate host token handling or leak authentication state into interaction data. | `src/services/task/Task.ts`, `src/services/task/contact.ts`, `src/services/core/WebexRequest.ts` | `test/unit/spec/services/task/Task.ts`, `test/unit/spec/services/task/contact.ts` | None; authentication ownership is explicit. | PRESENT |
419
437
  | TASK-R-007 | Route enabled preview-campaign accept, skip, and remove operations through the dialer AQM factory using `PreviewContactPayload`, returning `Promise<TaskResponse>` from the public ContactCenter methods. Before routing skip/remove, reject the operation when the matching task's disable flag is `'true'`. | Preview reservations require typed payloads and correlated backend completion, while campaign controls must block prohibited skip/remove requests before transport begins. | `src/cc.ts`, `src/services/task/dialer.ts`, `src/services/task/types.ts` | `test/unit/spec/cc.ts`, `test/unit/spec/services/task/dialer.ts` | Public delegation and dialer requests are covered; the `campaignPreviewSkipDisabled` and `campaignPreviewRemoveDisabled` early-exit guards lack direct unit coverage. Independent review identified this gap on 2026-07-15. | PRESENT |
438
+ | TASK-R-008 | Voice `dropConferenceParticipant` must validate the public target, resolve the latest main interaction, POST an empty body to the encoded participant-drop route, and settle only from `ParticipantLeftConference`, `ParticipantDropConferenceFailed`, HTTP failure, or the existing AQM timeout. | Participant removal is backend-authoritative and must preserve event-driven roster/state synchronization without exposing participant identifiers through telemetry or logs. | `src/services/task/voice/Voice.ts`, `src/services/task/contact.ts`, `src/services/task/types.ts` | `test/unit/spec/services/task/voice/Voice.ts`, `test/unit/spec/services/task/contact.ts`, `test/unit/spec/services/core/aqm-reqs.ts` | Backend authorization and media removal are remote-service responsibilities. | PRESENT |
439
+ | TASK-R-009 | ContactCenter must inject Desktop Profile collaboration policy into TaskFactory, and every created voice/digital Task must expose ordered Consult and Transfer destination categories through `TaskUIControls.consultTransferDestinations`. | Task consumers need one already-computed policy surface and must not fetch profile flags or duplicate destination decisions. | `src/cc.ts`, `src/services/task/TaskFactory.ts`, `src/services/task/types.ts` | `test/unit/spec/cc.ts`, `test/unit/spec/services/task/TaskFactory.ts` | Host-specific UI options may only further hide an SDK-allowed category. | PRESENT |
440
+ | TASK-R-010 | TaskManager must propagate backend owner promotion without electing an owner locally. `ContactOwnerChanged` resolves an exact task first, then one unique related task whose existing snapshot proves that the current Agent is active on `mainCall`, or whose incoming snapshot both names that Agent as `interaction.owner` and proves the same active-main-leg membership. Active membership requires a participant entry with `hasLeft !== true`. If no task exists, recovery is limited to that incoming owner=current-Agent proof: create the normal Task under the stable main interaction ID, silently HYDRATE its actor before listener installation, then process the original owner-change event so consumers receive one `task:hydrate` and no `task:incoming`. An owner-changing `ContactUpdated` uses the existing owner-change hydrate path only for an existing task, and a late `ParticipantLeftConference` cannot replace a confirmed active owner with the departed participant. | Every surviving agent must observe the backend-selected primary Agent immediately, including stale child-keyed and narrowly recoverable desynchronization cases, without duplicating tasks or exposing an uninitialized actor. | `src/services/task/TaskManager.ts` | `test/unit/spec/services/task/TaskManager.ts`, `test/unit/spec/services/task/Task.ts` | Backend owner selection and delivery of a complete owner-bearing `ContactOwnerChanged` payload remain remote responsibilities; missing-task `ContactUpdated` remains update-only. | PRESENT |
441
+ | TASK-R-011 | TaskManager must stamp `wrapUpRequired` once in `prepareEventContext` on `AGENT_WRAPUP`, `AGENT_CONSULT_CONFERENCE_ENDED`, `PARTICIPANT_LEFT_CONFERENCE`, and `AGENT_CONFERENCE_TRANSFERRED` before `updateTaskData` / mapper (mapper passes the already-stamped payload through). Voice `exitConference` stamps the same flag on `EXIT_CONFERENCE_SUCCESS` (that HTTP path skips TaskManager) using `shouldWrapUpForThisAgent`, then the same empty-pending self-exit fallback as leave (true unless this agent is a consulted non-owner). Voice pending-list precedence uses the correlated HTTP response only (a cached `agentsPendingWrapUp` is ignored when the response omits the list). `AGENT_WRAPUP` is always `true`. Conference-end uses explicit signals only (`agentsPendingWrapUp`, then `wrapUpRequired` / `isWrapUp`). A nonempty `agentsPendingWrapUp` is authoritative and wins over initiator fallback: `consultingAgentId === self` and actor `transferConferenceRequested` are honored only when the list is empty or absent. On participant leave: do not stamp when the actor ignores `PARTICIPANT_LEAVE` (`CONNECTED`, `HOLD_INITIATING`, `CONF_INITIATING`); stamp only in `HELD`, `RESUME_INITIATING`, `CONSULTING`, `CONSULT_INITIATING`, or `CONFERENCING` (or when no actor snapshot exists). A named other `participantId` is never self-leave (do not infer leave from a partial `participants` map); missing-map fallback applies only when `participantId` is absent (EP-DN), and when a previous task map exists it must have contained self. Remaining agents use explicit signals only; this agent left + nonempty pending uses `includes(self)`; this agent left + empty/absent pending stamps `true` unless this agent is a consulted non-owner. Remaining conference agents stay `false`. `setupAutoWrapupTimer()` still requires profile `autoWrapup !== false`, a valid interval, and a default reason. `PARTICIPANT_LEAVE` and Voice `EXIT_CONFERENCE_SUCCESS` into `WRAPPING_UP` do not transition-emit; the `WRAPPING_UP` entry still emits `task:wrapup`. `EXIT_CONFERENCE_SUCCESS` is handled in `CONNECTED`, `HELD`, and `CONFERENCING`. `TASK_WRAPUP` is handled in `HOLD_INITIATING`, `RESUME_INITIATING`, `CONSULT_INITIATING`, and `CONF_INITIATING` (transition `updateTaskData` + `markEnded` only). Late `TASK_WRAPUP` in `WRAPPING_UP` always runs `updateTaskData` and runs `emitTaskWrapup` only when `context.taskData.wrapUpRequired` was not already `true`. | Consumers rely on `task:wrapup` and `task.autoWrapup` when wrap-up starts; those surfaces only activate when ingress task data already has `wrapUpRequired === true`. | `src/services/task/TaskManager.ts`, `src/services/task/voice/Voice.ts`, `src/services/task/Task.ts`, `src/services/task/state-machine/TaskStateMachine.ts` | `test/unit/spec/services/task/TaskManager.ts`, `test/unit/spec/services/task/voice/Voice.ts`, `test/unit/spec/services/task/Task.ts`, `test/unit/spec/services/task/state-machine/TaskStateMachine.ts` | Profile auto wrap-up, interval, and default reason remain agent-config responsibilities. | PRESENT |
420
442
 
421
443
  ## Design Overview
422
444
  Task separates its stable consumption boundary from collaborators so ownership and failure behavior stay explicit. A shared Task base preserves a stable API while media-specific subclasses and a separate state engine enforce capability differences.
@@ -431,7 +453,7 @@ Task separates its stable consumption boundary from collaborators so ownership a
431
453
  | `facebook` | Unsupported by TaskFactory; throws `Unknown media type` |
432
454
  | `whatsapp` | Unsupported by TaskFactory; throws `Unknown media type` |
433
455
 
434
- If enabled in agent profile, wrapup completes automatically after timeout:
456
+ If enabled in agent profile, wrapup completes automatically after timeout. The timer starts only when ingress task data has `wrapUpRequired === true` (TASK-R-011).
435
457
 
436
458
  > **Host-application example:** `updateWrapupStatus` is a consumer-owned UI callback, not SDK package logging.
437
459
 
@@ -494,6 +516,8 @@ Returns an object of AQM request methods wired to `TASK_API` and `TASK_MESSAGE_T
494
516
 
495
517
  - `consultConference`
496
518
 
519
+ - `dropConferenceParticipant`
520
+
497
521
  - `exitConference`
498
522
 
499
523
  - `conferenceTransfer`
@@ -532,6 +556,8 @@ Uses `contact` for:
532
556
 
533
557
  - `consultConference`, `exitConference`, `conferenceTransfer`
534
558
 
559
+ - `dropConferenceParticipant` (Voice only; base Task rejects as unsupported)
560
+
535
561
  Uses `contact.accept` in `accept()`.
536
562
 
537
563
  TaskManager maintains a map of active tasks:
@@ -588,6 +614,16 @@ this.webSocketManager.on('message', (event) => {
588
614
 
589
615
  This keeps transcript and suggestion delivery aligned on the same per-task event surface.
590
616
 
617
+ **wxApp outdial `ContactEnded` / `AgentOutboundFailed` mapping:** Applies only when the current agent is a **wxApp-managed** outdial (`enableWxBetterTogether` + agent participant `deviceType: wxApp`). Pre-accept decline maps to `CONTACT_ENDED` when `wxAppAnswerPending` is false and `agentsPendingWrapUp` is empty — even if the backend sends misleading `interaction.state: wrapUp`. Post-accept wxApp agent end remaps to `OUTBOUND_FAILED` / `AGENT_ENDS` when `wxAppAnswerPending`, `agentsPendingWrapUp`, or `interaction.state === 'wrapUp'` indicates wrapup. **Non-wxApp** agent-terminated `AgentOutboundFailed` (`AGENT_ENDS` / `terminatingParty: Agent`) stays on `OUTBOUND_FAILED` so the OFFERED-state `shouldWrapUp` path runs; `suppressOutdialFailedPopup` on `taskData` skips the outdial-failed modal only. Non-wxApp `ContactEnded` keeps the legacy path. Other failure reasons (`CUSTOMER_BUSY`, etc.) still use `OUTBOUND_FAILED` with the popup. See `TaskManager.isWxAppManagedOutdialTask`, `isAgentTerminatedOutdialWrapup`, and `task-state-machine-spec.md`.
618
+
619
+ **wxApp consumer contract (WXCC-6026):** Hosts enable `enableWxBetterTogether` at init (Phase 1 init-only; re-init to change), bind UI to `task.uiControls` (including optional `main.keypad`), and call **`task.accept()`**, **`task.decline()`**, **`task.toggleMute({ muted? })`**, **`task.transmitDtmf({ dtmf })`**. SDK routes wxApp telephony internally on `Voice`. Shared-line `lineOwnerId` defaults from the wxApp agent participant when omitted.
620
+
621
+ **wxApp offer UI (`uiControlsComputer`):** `wxAppAcceptInFlight` disables accept/decline during the accept REST call. `wxAppAnswerPending` additionally disables accept and decline for **inbound** offers until ASSIGN; wxApp **outdial** keeps decline enabled during the post-accept "Calling…" phase so `cancelTask` remains available.
622
+
623
+ **wxApp decline observability:** Inbound wxApp offers decline via telephony `rejectCall` (`runWxAppReject` → `WXAPP_TASK_DECLINE_*`). wxApp outdial cancellations use CC routing `cancelTask` (`runWxAppOutdialDecline` → additive `WXAPP_TASK_DECLINE_*` plus existing `TASK_DECLINE_*`).
624
+
625
+ **wxApp mute backfill guard (`Voice.syncWxAppMuteFromCallDetails`):** Skips telephony `GET /calls/{callId}` when the interaction is terminated or the task is a pre-accept wxApp OFFERED offer (`wxAppAnswerPending` false). Post-accept OFFERED and engaged CONNECTED sync still run. `isWxAppEngagedForControls` and `getWebexCallingCallId` exclude `TERMINATED` and `COMPLETED`. Expected 400 / "Call not found" / `101002` responses are not logged as errors.
626
+
591
627
  For BROWSER login, TaskManager integrates with WebCalling:
592
628
 
593
629
  ```mermaid
@@ -689,6 +725,7 @@ isSecondaryEpDnAgent(interaction);
689
725
  | `TASK_WRAPUP_SUCCESS` | operational | Wrapup completed |
690
726
  | `TASK_TRANSFER_SUCCESS` | behavioral, business | Transfer completed |
691
727
  | `TASK_OUTDIAL_SUCCESS` | behavioral, business | Outdial completed |
728
+ | `TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS` | operational, behavioral, business | Participant Drop completed |
692
729
 
693
730
  ## Data Flow
694
731
  1. **WebSocket event arrives** → `TaskManager` maps CC event to `TaskEvent`.
@@ -727,6 +764,7 @@ Sequence coverage:
727
764
  | Incoming task creation | Incoming task | Unsupported media or incomplete event context prevents publication of a partial task. |
728
765
  | Voice hold/resume | Hold or resume | Invalid state rejects before transport; failure notification/HTTP error/timeout sends the matching failure event and throws. |
729
766
  | Consult/transfer/conference | Consult and transfer | Backend failure notifications drive explicit failure actions and preserve stable call context. |
767
+ | Participant Drop | Participant Drop | Validation rejects locally; AQM success/failure/HTTP/timeout paths settle and clean up without optimistic state changes. |
730
768
  | Wrapup/end | Wrapup or end | Validation and backend failures throw; backend events retain distinct WRAPPING_UP/COMPLETED/TERMINATED outcomes. |
731
769
  | WebRTC and digital accept | Channel-specific accept | WebRTC media/calling failure and Digital AQM failure follow different rejection paths. |
732
770
 
@@ -820,6 +858,117 @@ sequenceDiagram
820
858
  end
821
859
  ```
822
860
 
861
+ ### Participant Drop
862
+
863
+ ```mermaid
864
+ sequenceDiagram
865
+ participant App
866
+ participant Voice
867
+ participant Contact as routingContact
868
+ participant AQM as AqmReqs
869
+ participant Backend
870
+ participant WS as Primary WebSocket
871
+ participant TM as TaskManager/state machine
872
+ App->>Voice: dropConferenceParticipant({participantId})
873
+ alt participantId is invalid
874
+ Voice-->>App: reject before metrics, HTTP, or bind registration
875
+ else valid target
876
+ Voice->>Voice: select latest main interaction ID
877
+ Voice->>Contact: participant Drop request
878
+ Contact->>AQM: POST encoded path with empty body and sensitive-log redaction
879
+ AQM->>Backend: authenticated HTTP initiation
880
+ alt ParticipantLeftConference
881
+ Backend-->>WS: ParticipantLeftConference
882
+ WS-->>AQM: correlated success
883
+ AQM-->>Voice: TaskResponse
884
+ WS-->>TM: existing PARTICIPANT_LEAVE mapping updates roster/conference state
885
+ Voice-->>App: resolve
886
+ else ParticipantDropConferenceFailed, HTTP failure, or timeout
887
+ AQM-->>Voice: structured rejection
888
+ Voice-->>App: reject without participant data in logs/metrics
889
+ end
890
+ end
891
+ ```
892
+
893
+ `ParticipantLeftConference` is authoritative for both a customer hangup and an
894
+ agent-initiated customer Drop. The task removes only participants absent from
895
+ the latest interaction snapshot. TaskManager first uses the exact interaction
896
+ key, then the existing reservation fallback, and finally one unique task whose
897
+ `interaction.mainInteractionId`, interaction-level `parentInteractionId`, or
898
+ `callProcessingDetails.parentInteractionId` matches an identifier carried by the
899
+ lifecycle event. Object aliases are deduplicated and all aliases are removed
900
+ during terminal cleanup; ambiguous related-interaction matches are ignored
901
+ without logging participant data. Events carrying none of those correlation
902
+ identifiers are not routed. `ContactMerged` removes the EP-DN child task,
903
+ hydrates the main-interaction task, and publishes the existing `task:merged`
904
+ event so consumers can rebind to the surviving task object.
905
+
906
+ Dropping an Agent while that Agent is consulting continues through the existing
907
+ `PARTICIPANT_LEAVE` transition, which clears consult state and emits the normal
908
+ participant-left and task-end lifecycle. `PARTICIPANT_LEAVE` is handled in
909
+ `HELD`, `RESUME_INITIATING`, `CONSULTING`, `CONSULT_INITIATING`, and
910
+ `CONFERENCING`; `CONNECTED`, `HOLD_INITIATING`, and `CONF_INITIATING` ignore the
911
+ event. The current Agent is treated as departed only when the event names that
912
+ Agent or the updated participants map omits that Agent (EP-DN removal). Remaining
913
+ in the map with `hasLeft`, or disappearing only from `mainCall` media, is
914
+ non-terminal. A consulted Agent receiving `AgentConsultEnded` continues through
915
+ `CONSULT_END`; current-agent departure is evaluated before consult-initiator
916
+ recovery and does not use mainCall membership as self-departure evidence.
917
+ Accepted consultees emit `task:consultEnd` and `task:end`, while an unaccepted
918
+ OFFERED consultee retains the existing consult-end-only signal. A surviving
919
+ consult initiator still returns to the main-call state selected by the existing
920
+ guards. The state-machine transition table lives in
921
+ `src/services/task/state-machine/ai-docs/task-state-machine-spec.md`
922
+ `TASK_STATE_MACHINE-R-008`.
923
+
924
+ Primary-Agent promotion remains backend-authoritative and follows the two-event
925
+ desktop contract. `ContactOwnerChanged` updates the promoted Agent; TaskManager
926
+ prefers an exact task, then one unique related task resolved through nested
927
+ main/parent identifiers or the `mainCall` media-map identity. A related
928
+ candidate is eligible when its current
929
+ snapshot contains the current Agent's participant entry with `hasLeft !== true`
930
+ and membership on the `mType: mainCall` leg. The incoming snapshot can provide
931
+ that evidence only when it also names the current Agent as `interaction.owner`;
932
+ this permits an authoritative promotion payload to repair a stale child-keyed
933
+ snapshot while still excluding consult-only tasks. The update keeps the
934
+ surviving main interaction identity even when the notification names a
935
+ promoted-Agent child interaction.
936
+
937
+ If no related task exists, TaskManager recovers only the promoted current Agent
938
+ from a non-terminal telephony `ContactOwnerChanged` payload that provides the same
939
+ active-main-leg evidence. It creates the normal Task through TaskFactory under the
940
+ stable main interaction ID, sends an internal HYDRATE before installing external
941
+ listeners, and then processes the original owner-change event. Consumers
942
+ therefore receive one `task:hydrate`, never a synthetic `task:incoming`, and a
943
+ later canonical contact or merge event reuses the same task rather than creating
944
+ an alias. Missing, partial, departed, consult-only, non-promoted, and ambiguous
945
+ payloads are ignored for recovery.
946
+
947
+ For other surviving Agents, a `ContactUpdated` whose non-empty
948
+ `interaction.owner` differs from the current owner is delivered through the
949
+ existing `CONTACT_OWNER_CHANGED`/`task:hydrate` path; same-owner or owner-less
950
+ updates remain data-only, and a missing task is not created from `ContactUpdated`.
951
+ If a later `ParticipantLeftConference` still names the departed participant as
952
+ owner, an already confirmed owner is retained only when the new roster proves
953
+ that confirmed owner remains active on `mainCall` and explicitly names the
954
+ incoming owner as `participantId` or marks it `hasLeft`. Main-call omission alone
955
+ is not departure evidence. The SDK never chooses the successor locally.
956
+
957
+ In the Contact Center sample roster, non-owner and Supervisor targets remain
958
+ visible but non-actionable; the UI does not display a separate read-only label.
959
+ The roster is visible whenever the viewing agent remains active on the main leg
960
+ and at least one supported non-customer participant (Agent, EP-DN, or Supervisor)
961
+ is visible. Consequently, Customer-only calls use the original 1-to-1 UI, while
962
+ a single Agent remains visible after the Customer leaves. Dropping the last
963
+ non-customer participant while the Customer remains restores the 1-to-1 UI.
964
+ Terminated tasks and viewing-agent departure hide the roster immediately.
965
+
966
+ The current consult leg may additionally contribute a pending EP-DN row before
967
+ conference merge. The sample displays its `dn`, then its participant/media key
968
+ as a fallback, and deduplicates the row once it joins the main leg. The owner can
969
+ see a disabled Drop action until merge; other active main-call agents see the
970
+ same row without an action. Consult-only Agent targets remain excluded.
971
+
823
972
  ### Wrapup or end
824
973
 
825
974
  ```mermaid
@@ -1270,7 +1419,7 @@ await cc.stationLogin({ loginOption: 'BROWSER', ... });
1270
1419
  - A shared Task base preserves a stable API while media-specific subclasses and a separate state engine enforce capability differences.
1271
1420
 
1272
1421
  ## Test-Case Strategy (module)
1273
- Use `test/unit/spec/services/task/Task.ts`, `TaskFactory.ts`, `TaskManager.ts`, media-specific suites, contact/dialer suites, and state-machine suites. Cover concrete-versus-interface method signatures, every TASK_EVENTS group, unsupported media rejection, primary/RTD event ownership, injected state actions, preview-campaign accept/skip/remove payloads and failure paths, the disabled skip/remove pre-guards, and success/failure/timeout paths.
1422
+ Use `test/unit/spec/services/task/Task.ts`, `TaskFactory.ts`, `TaskManager.ts`, media-specific suites, contact/dialer suites, and state-machine suites. Cover concrete-versus-interface method signatures, every TASK_EVENTS group, unsupported media rejection, primary/RTD event ownership, injected state actions, preview-campaign accept/skip/remove payloads and failure paths, the disabled skip/remove pre-guards, Participant Drop validation/correlation/privacy, primary-owner promotion propagation, and success/failure/timeout paths.
1274
1423
 
1275
1424
  | Behavior / Requirement | Existing test evidence | Gap |
1276
1425
  |---|---|---|
@@ -1281,6 +1430,10 @@ Use `test/unit/spec/services/task/Task.ts`, `TaskFactory.ts`, `TaskManager.ts`,
1281
1430
  | `TASK-R-005` | `test/unit/spec/services/task/TaskFactory.ts`, `test/unit/spec/services/task/dialer.ts` | None. |
1282
1431
  | `TASK-R-006` | `test/unit/spec/services/task/contact.ts`, `test/unit/spec/services/core/WebexRequest.ts` | Authentication ownership is verified across routing/Core boundaries. |
1283
1432
  | `TASK-R-007` | `test/unit/spec/cc.ts`, `test/unit/spec/services/task/dialer.ts` | Add direct tests proving disabled skip/remove flags throw before dialer invocation; keep public signatures, metrics/error handling, and AQM request contracts synchronized. |
1433
+ | `TASK-R-008` | `test/unit/spec/services/task/Task.ts`, `test/unit/spec/services/task/voice/Voice.ts`, `test/unit/spec/services/task/contact.ts`, `test/unit/spec/services/core/aqm-reqs.ts`, `test/unit/spec/services/task/TaskManager.ts` | None. |
1434
+ | `TASK-R-009` | `test/unit/spec/cc.ts`, `test/unit/spec/services/task/TaskFactory.ts`, `test/unit/spec/services/task/state-machine/uiControlsComputer.ts` | None. |
1435
+ | `TASK-R-010` | `test/unit/spec/services/task/TaskManager.ts`, `test/unit/spec/services/task/Task.ts` | None. |
1436
+ | `TASK-R-011` | `test/unit/spec/services/task/TaskManager.ts`, `test/unit/spec/services/task/voice/Voice.ts`, `test/unit/spec/services/task/Task.ts`, `test/unit/spec/services/task/state-machine/TaskStateMachine.ts` | None. |
1284
1437
 
1285
1438
  ## Traceability
1286
1439
  - Repo architecture: `../../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../../ai-docs/SPEC_INDEX.md`
@@ -14,6 +14,8 @@ export const CONSULT = '/consult';
14
14
  export const CONSULT_ACCEPT = '/consult/accept';
15
15
  export const CONSULT_END = '/consult/end';
16
16
  export const TRANSFER = '/transfer';
17
+ /** Backend destination value for direct entry-point transfers through the vteam endpoint. */
18
+ export const ENTRY_POINT_TRANSFER_DESTINATION_TYPE = 'entrypointDialNumber';
17
19
  export const CONSULT_TRANSFER = '/consult/transfer';
18
20
  export const PAUSE = '/record/pause';
19
21
  export const RESUME = '/record/resume';
@@ -73,6 +75,7 @@ export const METHODS = {
73
75
  TRANSFER: 'transfer',
74
76
  CONSULT_TRANSFER: 'consultTransfer',
75
77
  CONSULT_CONFERENCE: 'consultConference',
78
+ DROP_CONFERENCE_PARTICIPANT: 'dropConferenceParticipant',
76
79
  EXIT_CONFERENCE: 'exitConference',
77
80
  TRANSFER_CONFERENCE: 'transferConference',
78
81
  UPDATE_TASK_DATA: 'updateTaskData',
@@ -458,6 +458,36 @@ export default function routingContact(aqm: AqmReqs) {
458
458
  })
459
459
  ),
460
460
 
461
+ /*
462
+ * Drop another participant from an active conference
463
+ */
464
+ dropConferenceParticipant: aqm.req((p: {interactionId: string; participantId: string}) => ({
465
+ url: `${TASK_API}${p.interactionId}/conference/participants/${encodeURIComponent(
466
+ p.participantId
467
+ )}/drop`,
468
+ data: {},
469
+ host: WCC_API_GATEWAY,
470
+ err,
471
+ redactSensitiveLogs: true,
472
+ notifSuccess: {
473
+ bind: {
474
+ type: TASK_MESSAGE_TYPE,
475
+ data: {
476
+ type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
477
+ interactionId: p.interactionId,
478
+ },
479
+ },
480
+ msg: {} as Contact.AgentContact,
481
+ },
482
+ notifFail: {
483
+ bind: {
484
+ type: TASK_MESSAGE_TYPE,
485
+ data: {type: CC_EVENTS.PARTICIPANT_DROP_CONFERENCE_FAILED},
486
+ },
487
+ errId: 'Service.aqm.task.dropConferenceParticipant',
488
+ },
489
+ })),
490
+
461
491
  /*
462
492
  * Exit conference
463
493
  */
@@ -1,6 +1,6 @@
1
1
  import {CC_FILE, METHODS} from '../../../constants';
2
2
  import {getErrorDetails} from '../../core/Utils';
3
- import {IDigital, TaskResponse, TaskData} from '../types';
3
+ import {ConsultTransferDestinationConfig, IDigital, TaskResponse, TaskData} from '../types';
4
4
  import {WrapupData} from '../../config/types';
5
5
  import Task from '../Task';
6
6
  import routingContact from '../contact';
@@ -13,7 +13,8 @@ export default class Digital extends Task implements IDigital {
13
13
  contact: ReturnType<typeof routingContact>,
14
14
  data: TaskData,
15
15
  wrapupData?: WrapupData,
16
- agentId?: string
16
+ agentId?: string,
17
+ consultTransferConfig?: ConsultTransferDestinationConfig
17
18
  ) {
18
19
  super(
19
20
  contact,
@@ -22,6 +23,7 @@ export default class Digital extends Task implements IDigital {
22
23
  isEndTaskEnabled: true,
23
24
  isEndConsultEnabled: false,
24
25
  isRecordingEnabled: false,
26
+ consultTransferConfig,
25
27
  },
26
28
  wrapupData,
27
29
  agentId