@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,1031 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _constants = require("../../../constants");
8
+ var _Utils = require("../../core/Utils");
9
+ var _types = require("../types");
10
+ var _Task = _interopRequireDefault(require("../Task"));
11
+ var _loggerProxy = _interopRequireDefault(require("../../../logger-proxy"));
12
+ var _MetricsManager = _interopRequireDefault(require("../../../metrics/MetricsManager"));
13
+ var _constants2 = require("../../../metrics/constants");
14
+ var _stateMachine = require("../state-machine");
15
+ var _TaskUtils = require("../TaskUtils");
16
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
+ class Voice extends _Task.default {
18
+ constructor(contact, data, callOptions, wrapupData, agentId) {
19
+ const resolvedOptions = {
20
+ isEndTaskEnabled: callOptions?.isEndTaskEnabled ?? true,
21
+ isEndConsultEnabled: callOptions?.isEndConsultEnabled ?? true,
22
+ voiceVariant: callOptions?.voiceVariant ?? _types.VOICE_VARIANT.PSTN,
23
+ isRecordingEnabled: callOptions?.isRecordingEnabled ?? true
24
+ };
25
+ super(contact, data, {
26
+ ...resolvedOptions
27
+ }, wrapupData, agentId);
28
+ }
29
+ getStateMachineSnapshot() {
30
+ return this.stateMachineService?.getSnapshot?.();
31
+ }
32
+
33
+ /**
34
+ * This method is used to accept the task.
35
+ * It is expected to be overridden by child classes.
36
+ * @returns Promise<TaskResponse>
37
+ * @throws Error
38
+ */
39
+ async accept() {
40
+ super.unsupportedMethodError(_constants.METHODS.ACCEPT);
41
+ }
42
+
43
+ /**
44
+ * This method is used to decline the task.
45
+ * It is expected to be overridden by child classes.
46
+ * @returns Promise<TaskResponse>
47
+ * @throws Error
48
+ */
49
+ async decline() {
50
+ super.unsupportedMethodError(_constants.METHODS.REJECT);
51
+ }
52
+
53
+ /**
54
+ * This is used to hold the task.
55
+ * @returns Promise<TaskResponse>
56
+ * @throws Error
57
+ * @example
58
+ * ```typescript
59
+ * task.hold().then(()=>{}).catch(()=>{})
60
+ * ```
61
+ * */
62
+ async hold() {
63
+ return this.holdResume();
64
+ }
65
+
66
+ /**
67
+ * This is used to resume the task.
68
+ * @returns Promise<TaskResponse>
69
+ * @throws Error
70
+ * @example
71
+ * ```typescript
72
+ * task.resume().then(()=>{}).catch(()=>{})
73
+ * ```
74
+ * */
75
+ async resume() {
76
+ return this.holdResume();
77
+ }
78
+
79
+ /**
80
+ * This is used to hold or resume the task.
81
+ * @param isHeld: boolean - true to hold the task, false to resume it
82
+ * @returns Promise<TaskResponse>
83
+ * @throws Error
84
+ * @example
85
+ * ```typescript
86
+ * task.holdResume(isHeld: true).then(()=>{}).catch(()=>{})
87
+ * ```
88
+ * */
89
+ async holdResume() {
90
+ /*
91
+ Determine if the task is being held or resumed based on the media resource state
92
+ If the media resource is not found, default to resuming the task
93
+ */
94
+ const snapshot = this.getStateMachineSnapshot();
95
+ const snapshotState = snapshot?.value;
96
+ const mainInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
97
+ const mainMediaResource = this.data.interaction?.media?.[mainInteractionId]?.mediaResourceId || this.data.mediaResourceId;
98
+ const mediaHoldState = this.data.interaction?.media?.[mainInteractionId]?.isHold ?? this.data.interaction.media?.[mainMediaResource]?.isHold;
99
+ let shouldHold = !(mediaHoldState ?? false);
100
+ if (snapshotState === _stateMachine.TaskState.HELD) {
101
+ shouldHold = false;
102
+ } else if (snapshotState === _stateMachine.TaskState.CONNECTED) {
103
+ shouldHold = true;
104
+ }
105
+
106
+ // Validate operation is allowed in current state
107
+ const state = snapshot;
108
+ if (state) {
109
+ const currentState = state.value;
110
+ if (shouldHold) {
111
+ if (!state.matches(_stateMachine.TaskState.CONNECTED)) {
112
+ const error = new Error(`Cannot hold call in current state: ${currentState}`);
113
+ _loggerProxy.default.error('Hold operation not allowed', {
114
+ module: _constants.CC_FILE,
115
+ method: _constants.METHODS.HOLD_RESUME,
116
+ interactionId: this.data.interactionId
117
+ });
118
+ throw error;
119
+ }
120
+ } else if (!state.matches(_stateMachine.TaskState.HELD)) {
121
+ const error = new Error(`Cannot resume call in current state: ${currentState}`);
122
+ _loggerProxy.default.error('Resume operation not allowed', {
123
+ module: _constants.CC_FILE,
124
+ method: _constants.METHODS.HOLD_RESUME,
125
+ interactionId: this.data.interactionId
126
+ });
127
+ throw error;
128
+ }
129
+ }
130
+
131
+ // Send initiating event to transition to intermediate state
132
+ if (this.stateMachineService) {
133
+ const initiatingEvent = shouldHold ? _stateMachine.TaskEvent.HOLD_INITIATED : _stateMachine.TaskEvent.UNHOLD_INITIATED;
134
+ this.stateMachineService.send({
135
+ type: initiatingEvent,
136
+ mediaResourceId: mainMediaResource
137
+ });
138
+ }
139
+ _loggerProxy.default.info(`${shouldHold ? 'Holding' : 'Resuming'} task`, {
140
+ module: _constants.CC_FILE,
141
+ method: _constants.METHODS.HOLD_RESUME,
142
+ interactionId: this.data.interactionId
143
+ });
144
+ const [successEvt, failedEvt] = shouldHold ? [_constants2.METRIC_EVENT_NAMES.TASK_HOLD_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_HOLD_FAILED] : [_constants2.METRIC_EVENT_NAMES.TASK_RESUME_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_RESUME_FAILED];
145
+ this.metricsManager.timeEvent([successEvt, failedEvt]);
146
+ try {
147
+ let response;
148
+ if (shouldHold) {
149
+ response = await this.contact.hold({
150
+ interactionId: this.data.interactionId,
151
+ data: {
152
+ mediaResourceId: mainMediaResource
153
+ }
154
+ });
155
+
156
+ // Send success event to complete the transition
157
+ if (this.stateMachineService) {
158
+ this.stateMachineService.send({
159
+ type: _stateMachine.TaskEvent.HOLD_SUCCESS,
160
+ mediaResourceId: mainMediaResource
161
+ });
162
+ }
163
+ this.metricsManager.trackEvent(successEvt, {
164
+ taskId: this.data.interactionId,
165
+ mediaResourceId: mainMediaResource,
166
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
167
+ }, ['operational', 'behavioral']);
168
+ _loggerProxy.default.log(`Task placed on hold successfully`, {
169
+ module: _constants.CC_FILE,
170
+ method: _constants.METHODS.HOLD_RESUME,
171
+ trackingId: response.trackingId,
172
+ interactionId: this.data.interactionId
173
+ });
174
+ } else {
175
+ response = await this.contact.unHold({
176
+ interactionId: this.data.interactionId,
177
+ data: {
178
+ mediaResourceId: mainMediaResource
179
+ }
180
+ });
181
+
182
+ // Send success event to complete the transition
183
+ if (this.stateMachineService) {
184
+ this.stateMachineService.send({
185
+ type: _stateMachine.TaskEvent.UNHOLD_SUCCESS,
186
+ mediaResourceId: mainMediaResource
187
+ });
188
+ }
189
+ this.metricsManager.trackEvent(successEvt, {
190
+ taskId: this.data.interactionId,
191
+ mainInteractionId,
192
+ mediaResourceId: mainMediaResource,
193
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
194
+ }, ['operational', 'behavioral']);
195
+ _loggerProxy.default.log(`Task resumed successfully`, {
196
+ module: _constants.CC_FILE,
197
+ method: _constants.METHODS.HOLD_RESUME,
198
+ trackingId: response.trackingId,
199
+ interactionId: this.data.interactionId
200
+ });
201
+ }
202
+ return response;
203
+ } catch (error) {
204
+ const failureEvent = shouldHold ? _stateMachine.TaskEvent.HOLD_FAILED : _stateMachine.TaskEvent.UNHOLD_FAILED;
205
+ this.stateMachineService.send({
206
+ type: failureEvent,
207
+ reason: error.toString(),
208
+ mediaResourceId: this.data.mediaResourceId
209
+ });
210
+ const {
211
+ error: detailedError
212
+ } = (0, _Utils.getErrorDetails)(error, 'holdResume', _constants.CC_FILE);
213
+ this.metricsManager.trackEvent(failedEvt, shouldHold ? {
214
+ taskId: this.data.interactionId,
215
+ mediaResourceId: this.data.mediaResourceId,
216
+ error: error.toString(),
217
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
218
+ } : {
219
+ taskId: this.data.interactionId,
220
+ error: error.toString(),
221
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
222
+ }, ['operational', 'behavioral']);
223
+ throw detailedError;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * This is used to pause the call recording
229
+ * @returns Promise<TaskResponse>
230
+ * @throws Error
231
+ * @example
232
+ * ```typescript
233
+ * task.pauseRecording().then(()=>{}).catch(()=>{});
234
+ * ```
235
+ */
236
+ async pauseRecording() {
237
+ // Validate recording is active
238
+ const state = this.getStateMachineSnapshot();
239
+ if (state) {
240
+ const {
241
+ recordingControlsAvailable,
242
+ recordingInProgress
243
+ } = state.context;
244
+ const recordingActive = Boolean(recordingControlsAvailable && recordingInProgress);
245
+ if (!recordingActive) {
246
+ const error = new Error('Recording is not active or already paused');
247
+ _loggerProxy.default.error('Pause recording operation not allowed', {
248
+ module: _constants.CC_FILE,
249
+ method: 'pauseRecording',
250
+ interactionId: this.data.interactionId
251
+ });
252
+ throw error;
253
+ }
254
+ }
255
+ try {
256
+ _loggerProxy.default.info(`Pausing recording`, {
257
+ module: _constants.CC_FILE,
258
+ method: 'pauseRecording',
259
+ interactionId: this.data.interactionId
260
+ });
261
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_FAILED]);
262
+ const result = await this.contact.pauseRecording({
263
+ interactionId: this.data.interactionId
264
+ });
265
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_SUCCESS, {
266
+ taskId: this.data.interactionId,
267
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
268
+ }, ['operational', 'behavioral', 'business']);
269
+ _loggerProxy.default.log(`Recording paused successfully`, {
270
+ module: _constants.CC_FILE,
271
+ method: 'pauseRecording',
272
+ trackingId: result.trackingId,
273
+ interactionId: this.data.interactionId
274
+ });
275
+ return result;
276
+ } catch (error) {
277
+ const {
278
+ error: detailedError
279
+ } = (0, _Utils.getErrorDetails)(error, 'pauseRecording', _constants.CC_FILE);
280
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_FAILED, {
281
+ taskId: this.data.interactionId,
282
+ error: error.toString(),
283
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
284
+ }, ['operational', 'behavioral', 'business']);
285
+ throw detailedError;
286
+ }
287
+ }
288
+
289
+ /**
290
+ * This is used to pause the call recording
291
+ * @param resumeRecordingPayload
292
+ * @returns Promise<TaskResponse>
293
+ * @throws Error
294
+ * @example
295
+ * ```typescript
296
+ * task.resumeRecording(resumeRecordingPayload).then(()=>{}).catch(()=>{});
297
+ * ```
298
+ */
299
+ async resumeRecording(resumeRecordingPayload) {
300
+ // Validate recording is paused
301
+ const state = this.getStateMachineSnapshot();
302
+ if (state) {
303
+ const {
304
+ recordingControlsAvailable,
305
+ recordingInProgress
306
+ } = state.context;
307
+ const recordingPaused = Boolean(recordingControlsAvailable && !recordingInProgress);
308
+ if (!recordingPaused) {
309
+ const error = new Error('Recording is not paused');
310
+ _loggerProxy.default.error('Resume recording operation not allowed', {
311
+ module: _constants.CC_FILE,
312
+ method: 'resumeRecording',
313
+ interactionId: this.data.interactionId
314
+ });
315
+ throw error;
316
+ }
317
+ }
318
+ try {
319
+ _loggerProxy.default.info(`Resuming recording`, {
320
+ module: _constants.CC_FILE,
321
+ method: 'resumeRecording',
322
+ interactionId: this.data.interactionId
323
+ });
324
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_FAILED]);
325
+ resumeRecordingPayload ??= {
326
+ autoResumed: false
327
+ };
328
+ const result = await this.contact.resumeRecording({
329
+ interactionId: this.data.interactionId,
330
+ data: resumeRecordingPayload
331
+ });
332
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_SUCCESS, {
333
+ taskId: this.data.interactionId,
334
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
335
+ }, ['operational', 'behavioral', 'business']);
336
+ _loggerProxy.default.log(`Recording resumed successfully`, {
337
+ module: _constants.CC_FILE,
338
+ method: 'resumeRecording',
339
+ trackingId: result.trackingId,
340
+ interactionId: this.data.interactionId
341
+ });
342
+ return result;
343
+ } catch (error) {
344
+ const {
345
+ error: detailedError
346
+ } = (0, _Utils.getErrorDetails)(error, 'resumeRecording', _constants.CC_FILE);
347
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_FAILED, {
348
+ taskId: this.data.interactionId,
349
+ error: error.toString(),
350
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
351
+ }, ['operational', 'behavioral', 'business']);
352
+ throw detailedError;
353
+ }
354
+ }
355
+
356
+ /**
357
+ * This is used to consult the task
358
+ * @param consultPayload
359
+ * @returns Promise<TaskResponse>
360
+ * @throws Error
361
+ * @example
362
+ * ```typescript
363
+ * const consultPayload = {
364
+ * destination: 'myBuddyAgentId',
365
+ * destinationType: DESTINATION_TYPE.AGENT,
366
+ * }
367
+ * task.consult(consultPayload).then(()=>{}).catch(()=>{});
368
+ * ```
369
+ * */
370
+ async consult(consultPayload) {
371
+ // Validate consult is allowed
372
+ const state = this.getStateMachineSnapshot();
373
+ const canConsult = state && (state.matches(_stateMachine.TaskState.CONNECTED) || state.matches(_stateMachine.TaskState.HELD) || state.matches(_stateMachine.TaskState.CONFERENCING));
374
+ if (!canConsult) {
375
+ const currentState = state?.value;
376
+ const error = new Error(`Cannot initiate consult in ${currentState} state`);
377
+ _loggerProxy.default.error('Consult operation not allowed', {
378
+ module: _constants.CC_FILE,
379
+ method: 'consult',
380
+ interactionId: this.data.interactionId
381
+ });
382
+ throw error;
383
+ }
384
+
385
+ // Send initiating event to transition to CONSULT_INITIATING state
386
+ if (this.stateMachineService) {
387
+ this.stateMachineService.send({
388
+ type: _stateMachine.TaskEvent.CONSULT,
389
+ destination: consultPayload.to,
390
+ destinationType: consultPayload.destinationType
391
+ });
392
+ }
393
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
394
+ try {
395
+ _loggerProxy.default.info(`Starting consult`, {
396
+ module: _constants.CC_FILE,
397
+ method: 'consult',
398
+ interactionId: requestInteractionId
399
+ });
400
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_START_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONSULT_START_FAILED]);
401
+ const result = await this.contact.consult({
402
+ interactionId: requestInteractionId,
403
+ data: consultPayload
404
+ });
405
+
406
+ // Send success event to transition to CONSULTING state
407
+ if (this.stateMachineService) {
408
+ this.stateMachineService.send({
409
+ type: _stateMachine.TaskEvent.CONSULT_SUCCESS,
410
+ taskData: result.data
411
+ });
412
+ }
413
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_START_SUCCESS, {
414
+ taskId: this.data.interactionId,
415
+ requestInteractionId,
416
+ destination: consultPayload.to,
417
+ destinationType: consultPayload.destinationType,
418
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
419
+ }, ['operational', 'behavioral', 'business']);
420
+ _loggerProxy.default.log(`Consult successfully initiated to ${consultPayload.to}`, {
421
+ module: _constants.CC_FILE,
422
+ method: 'consult',
423
+ trackingId: result.trackingId,
424
+ interactionId: requestInteractionId
425
+ });
426
+ return result;
427
+ } catch (error) {
428
+ this.stateMachineService.send({
429
+ type: _stateMachine.TaskEvent.CONSULT_FAILED,
430
+ reason: error.toString()
431
+ });
432
+ const {
433
+ error: detailedError
434
+ } = (0, _Utils.getErrorDetails)(error, 'consult', _constants.CC_FILE);
435
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_START_FAILED, {
436
+ taskId: this.data.interactionId,
437
+ requestInteractionId,
438
+ destination: consultPayload.to,
439
+ destinationType: consultPayload.destinationType,
440
+ error: error.toString(),
441
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
442
+ }, ['operational', 'behavioral', 'business']);
443
+ throw detailedError;
444
+ }
445
+ }
446
+
447
+ /**
448
+ * This is used to end the consult session on the task.
449
+ * @param consultEndPayload - Payload indicating consult end flags and identifiers
450
+ * @returns Promise<TaskResponse>
451
+ * @throws Error
452
+ * @example
453
+ * ```typescript
454
+ * task.endConsult({
455
+ * isConsult: true,
456
+ * queueId: 'myQueueId',
457
+ * taskId: 'taskId',
458
+ * });
459
+ * ```
460
+ */
461
+ async endConsult(consultEndPayload) {
462
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
463
+ try {
464
+ _loggerProxy.default.info(`Ending consult`, {
465
+ module: _constants.CC_FILE,
466
+ method: 'endConsult',
467
+ interactionId: requestInteractionId
468
+ });
469
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_END_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONSULT_END_FAILED]);
470
+ const result = await this.contact.consultEnd({
471
+ interactionId: requestInteractionId,
472
+ data: consultEndPayload
473
+ });
474
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_END_SUCCESS, {
475
+ taskId: this.data.interactionId,
476
+ requestInteractionId,
477
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
478
+ }, ['operational', 'behavioral', 'business']);
479
+ _loggerProxy.default.log(`Consult ended successfully`, {
480
+ module: _constants.CC_FILE,
481
+ method: 'endConsult',
482
+ trackingId: result.trackingId,
483
+ interactionId: this.data.interactionId
484
+ });
485
+ return result;
486
+ } catch (error) {
487
+ const {
488
+ error: detailedError
489
+ } = (0, _Utils.getErrorDetails)(error, 'endConsult', _constants.CC_FILE);
490
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_END_FAILED, {
491
+ taskId: this.data.interactionId,
492
+ requestInteractionId,
493
+ error: error.toString(),
494
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
495
+ }, ['operational', 'behavioral', 'business']);
496
+ throw detailedError;
497
+ }
498
+ }
499
+
500
+ /**
501
+ * This is used to transfer the task.
502
+ * @param payload - Transfer payload
503
+ * @returns Promise<TaskResponse>
504
+ * @throws Error
505
+ * @example
506
+ * ```typescript
507
+ * task.transfer({
508
+ * to: 'destinationId',
509
+ * destinationType: DESTINATION_TYPE.AGENT,
510
+ * consult: true, // Optional, if true will perform a consult transfer else blind transfer
511
+ * });
512
+ * ```
513
+ */
514
+ async transfer(payload) {
515
+ try {
516
+ _loggerProxy.default.info(`Transferring task to ${payload.to}`, {
517
+ module: _constants.CC_FILE,
518
+ method: _constants.METHODS.TRANSFER_CALL,
519
+ interactionId: this.data.interactionId
520
+ });
521
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED]);
522
+
523
+ // consult transfer path
524
+ if (this.data.interaction.state === 'consulting') {
525
+ const normalizedDestinationType = payload.destinationType === 'Agent' || payload.destinationType === 'Queue' ? payload.destinationType.toLowerCase() : payload.destinationType;
526
+ let consultPayload = {
527
+ to: payload.to,
528
+ destinationType: normalizedDestinationType
529
+ };
530
+ if (normalizedDestinationType === _types.CONSULT_TRANSFER_DESTINATION_TYPE.QUEUE) {
531
+ const consultContext = this.getStateMachineSnapshot()?.context;
532
+ const destAgent = consultContext?.consultDestinationAgentId || this.data.destAgentId;
533
+ if (!destAgent) {
534
+ throw new Error('No agent has accepted this queue consult yet');
535
+ }
536
+ consultPayload = {
537
+ to: destAgent,
538
+ destinationType: _types.CONSULT_TRANSFER_DESTINATION_TYPE.AGENT
539
+ };
540
+ }
541
+ const result = await this.contact.consultTransfer({
542
+ interactionId: this.data.interactionId,
543
+ data: consultPayload
544
+ });
545
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS, {
546
+ taskId: this.data.interactionId,
547
+ destination: consultPayload.to,
548
+ destinationType: consultPayload.destinationType,
549
+ isConsultTransfer: true,
550
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
551
+ }, ['operational', 'behavioral', 'business']);
552
+ _loggerProxy.default.log(`Consult transfer completed successfully to ${consultPayload.to}`, {
553
+ module: _constants.CC_FILE,
554
+ method: _constants.METHODS.TRANSFER_CALL,
555
+ trackingId: result.trackingId,
556
+ interactionId: this.data.interactionId
557
+ });
558
+ return result;
559
+ }
560
+
561
+ // standard blind transfer
562
+ return await super.transfer({
563
+ to: payload.to,
564
+ destinationType: payload.destinationType
565
+ });
566
+ } catch (err) {
567
+ const {
568
+ error: detailedError
569
+ } = (0, _Utils.getErrorDetails)(err, _constants.METHODS.TRANSFER_CALL, _constants.CC_FILE);
570
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED, {
571
+ taskId: this.data.interactionId,
572
+ destination: payload.to,
573
+ destinationType: payload.destinationType,
574
+ isConsultTransfer: this.data.interaction.state === 'consulting',
575
+ error: err.toString(),
576
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(err.details || {})
577
+ }, ['operational', 'behavioral', 'business']);
578
+ throw detailedError;
579
+ }
580
+ }
581
+
582
+ /**
583
+ * Start a consult conference, merging main and consult calls.
584
+ */
585
+ async consultConference() {
586
+ const derivedDestAgentId = this.data.interaction && this.data.agentId ? (0, _Utils.calculateDestAgentId)(this.data.interaction, this.data.agentId) : '';
587
+ const derivedDestType = this.data.interaction && this.data.agentId ? (0, _Utils.calculateDestType)(this.data.interaction, this.data.agentId) : '';
588
+ const consultationData = {
589
+ agentId: this.data.agentId,
590
+ destinationType: this.getStateMachineSnapshot()?.context?.consultDestinationType || this.data.destinationType || derivedDestType || 'agent',
591
+ destAgentId: this.getStateMachineSnapshot()?.context?.consultDestinationAgentId || this.data.destAgentId || derivedDestAgentId
592
+ };
593
+
594
+ // Send state machine event to transition to CONF_INITIATING
595
+ if (this.stateMachineService) {
596
+ this.stateMachineService.send({
597
+ type: _stateMachine.TaskEvent.MERGE_TO_CONFERENCE
598
+ });
599
+ }
600
+ try {
601
+ if (!consultationData.destAgentId) {
602
+ throw new Error('Unable to determine consult destination for conference');
603
+ }
604
+ _loggerProxy.default.info(`Initiating consult conference to ${consultationData.destAgentId}`, {
605
+ module: _constants.CC_FILE,
606
+ method: _constants.METHODS.CONSULT_CONFERENCE,
607
+ interactionId: this.data.interactionId
608
+ });
609
+ const paramsDataForConferenceV2 = (0, _Utils.buildConsultConferenceParamData)(consultationData, this.data.interactionId);
610
+ const response = await this.contact.consultConference({
611
+ interactionId: paramsDataForConferenceV2.interactionId,
612
+ data: paramsDataForConferenceV2.data
613
+ });
614
+
615
+ // Send success event to transition to CONFERENCING
616
+ if (this.stateMachineService) {
617
+ this.stateMachineService.send({
618
+ type: _stateMachine.TaskEvent.CONFERENCE_START
619
+ });
620
+ }
621
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_START_SUCCESS, {
622
+ taskId: this.data.interactionId,
623
+ destination: paramsDataForConferenceV2.data.to,
624
+ destinationType: paramsDataForConferenceV2.data.destinationType,
625
+ agentId: paramsDataForConferenceV2.data.agentId,
626
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
627
+ }, ['operational', 'behavioral', 'business']);
628
+ _loggerProxy.default.log(`Consult conference started successfully`, {
629
+ module: _constants.CC_FILE,
630
+ method: _constants.METHODS.CONSULT_CONFERENCE,
631
+ interactionId: this.data.interactionId
632
+ });
633
+ return response;
634
+ } catch (error) {
635
+ // Send failure event to revert state
636
+ if (this.stateMachineService) {
637
+ this.stateMachineService.send({
638
+ type: _stateMachine.TaskEvent.CONFERENCE_FAILED,
639
+ reason: error.toString()
640
+ });
641
+ }
642
+ const {
643
+ error: detailedError
644
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.CONSULT_CONFERENCE, _constants.CC_FILE);
645
+ const failedParamsData = (0, _Utils.buildConsultConferenceParamData)(consultationData, this.data.interactionId);
646
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_START_FAILED, {
647
+ taskId: this.data.interactionId,
648
+ destination: failedParamsData.data.to,
649
+ destinationType: failedParamsData.data.destinationType,
650
+ agentId: failedParamsData.data.agentId,
651
+ error: error.toString(),
652
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
653
+ }, ['operational', 'behavioral', 'business']);
654
+ _loggerProxy.default.error(`Failed to start consult conference`, {
655
+ module: _constants.CC_FILE,
656
+ method: _constants.METHODS.CONSULT_CONFERENCE,
657
+ interactionId: this.data.interactionId
658
+ });
659
+ throw detailedError;
660
+ }
661
+ }
662
+
663
+ /**
664
+ * Exit from a conference call.
665
+ * Per conference-spec.md:
666
+ * - Primary agent exits to wrapup
667
+ * - Non-primary agent exits to available/connected
668
+ * - Other participants continue the call
669
+ *
670
+ * @returns Promise<TaskResponse>
671
+ * @throws Error if not in conference or exit fails
672
+ * @example
673
+ * ```typescript
674
+ * task.exitConference().then(() => {}).catch(() => {});
675
+ * ```
676
+ */
677
+ async exitConference() {
678
+ // Validate we're in conference state OR conference is in progress per task data
679
+ // This handles cases where:
680
+ // 1. State machine is in CONFERENCING state
681
+ // 2. State machine is in CONNECTED but conference is active (e.g., ownership transferred)
682
+ const state = this.getStateMachineSnapshot();
683
+ const isConferencingState = state?.matches(_stateMachine.TaskState.CONFERENCING);
684
+ const isConferenceInProgressFromData = this.data ? (0, _TaskUtils.getIsConferenceInProgress)(this.data) : false;
685
+ if (!state || !isConferencingState && !isConferenceInProgressFromData) {
686
+ const currentState = state?.value;
687
+ const error = new Error(`Cannot exit conference in ${currentState} state`);
688
+ _loggerProxy.default.error('Exit conference operation not allowed', {
689
+ module: _constants.CC_FILE,
690
+ method: 'exitConference',
691
+ interactionId: this.data.interactionId
692
+ });
693
+ throw error;
694
+ }
695
+
696
+ // Send state machine event
697
+ if (this.stateMachineService) {
698
+ this.stateMachineService.send({
699
+ type: _stateMachine.TaskEvent.EXIT_CONFERENCE,
700
+ agentId: this.data.agentId
701
+ });
702
+ }
703
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
704
+ try {
705
+ _loggerProxy.default.info(`Exiting conference`, {
706
+ module: _constants.CC_FILE,
707
+ method: 'exitConference',
708
+ interactionId: requestInteractionId
709
+ });
710
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_EXIT_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_EXIT_FAILED]);
711
+ const response = await this.contact.exitConference({
712
+ interactionId: requestInteractionId
713
+ });
714
+
715
+ // Send success event to transition state
716
+ if (this.stateMachineService) {
717
+ this.stateMachineService.send({
718
+ type: _stateMachine.TaskEvent.EXIT_CONFERENCE_SUCCESS,
719
+ taskData: response.data
720
+ });
721
+ }
722
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_EXIT_SUCCESS, {
723
+ taskId: this.data.interactionId,
724
+ requestInteractionId,
725
+ agentId: this.data.agentId,
726
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
727
+ }, ['operational', 'behavioral', 'business']);
728
+ _loggerProxy.default.log(`Successfully exited conference`, {
729
+ module: _constants.CC_FILE,
730
+ method: 'exitConference',
731
+ trackingId: response.trackingId,
732
+ interactionId: requestInteractionId
733
+ });
734
+ return response;
735
+ } catch (error) {
736
+ // Send failure event
737
+ if (this.stateMachineService) {
738
+ this.stateMachineService.send({
739
+ type: _stateMachine.TaskEvent.EXIT_CONFERENCE_FAILED,
740
+ reason: error.toString()
741
+ });
742
+ }
743
+ const {
744
+ error: detailedError
745
+ } = (0, _Utils.getErrorDetails)(error, 'exitConference', _constants.CC_FILE);
746
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_EXIT_FAILED, {
747
+ taskId: this.data.interactionId,
748
+ requestInteractionId,
749
+ agentId: this.data.agentId,
750
+ error: error.toString(),
751
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
752
+ }, ['operational', 'behavioral', 'business']);
753
+ _loggerProxy.default.error(`Failed to exit conference`, {
754
+ module: _constants.CC_FILE,
755
+ method: 'exitConference',
756
+ interactionId: requestInteractionId
757
+ });
758
+ throw detailedError;
759
+ }
760
+ }
761
+
762
+ /**
763
+ * Transfer the conference to another participant.
764
+ * Per conference-spec.md: Only primary agent can transfer conference.
765
+ * After transfer, the transferring agent exits to wrapup.
766
+ *
767
+ * @returns Promise<TaskResponse>
768
+ * @throws Error if not in conference or transfer fails
769
+ * @example
770
+ * ```typescript
771
+ * task.transferConference().then(() => {}).catch(() => {});
772
+ * ```
773
+ */
774
+ async transferConference() {
775
+ // Validate we're in conference or consulting state
776
+ // CONSULTING is allowed because agent can transfer conference while consulting
777
+ // (transfers ownership to the consulted agent)
778
+ const state = this.getStateMachineSnapshot();
779
+ const isValidState = state && (state.matches(_stateMachine.TaskState.CONFERENCING) || state.matches(_stateMachine.TaskState.CONSULTING));
780
+ if (!isValidState) {
781
+ const currentState = state?.value;
782
+ const error = new Error(`Cannot transfer conference in ${currentState} state`);
783
+ _loggerProxy.default.error('Transfer conference operation not allowed', {
784
+ module: _constants.CC_FILE,
785
+ method: 'transferConference',
786
+ interactionId: this.data.interactionId
787
+ });
788
+ throw error;
789
+ }
790
+
791
+ // Send state machine event
792
+ if (this.stateMachineService) {
793
+ this.stateMachineService.send({
794
+ type: _stateMachine.TaskEvent.TRANSFER_CONFERENCE,
795
+ agentId: this.data.agentId
796
+ });
797
+ }
798
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
799
+ try {
800
+ _loggerProxy.default.info(`Transferring conference`, {
801
+ module: _constants.CC_FILE,
802
+ method: 'transferConference',
803
+ interactionId: requestInteractionId
804
+ });
805
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_FAILED]);
806
+ const response = await this.contact.conferenceTransfer({
807
+ interactionId: requestInteractionId
808
+ });
809
+
810
+ // Send success event to transition state
811
+ if (this.stateMachineService) {
812
+ this.stateMachineService.send({
813
+ type: _stateMachine.TaskEvent.TRANSFER_CONFERENCE_SUCCESS,
814
+ taskData: response.data
815
+ });
816
+ }
817
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_SUCCESS, {
818
+ taskId: this.data.interactionId,
819
+ requestInteractionId,
820
+ agentId: this.data.agentId,
821
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
822
+ }, ['operational', 'behavioral', 'business']);
823
+ _loggerProxy.default.log(`Successfully transferred conference`, {
824
+ module: _constants.CC_FILE,
825
+ method: 'transferConference',
826
+ trackingId: response.trackingId,
827
+ interactionId: requestInteractionId
828
+ });
829
+ return response;
830
+ } catch (error) {
831
+ // Send failure event
832
+ if (this.stateMachineService) {
833
+ this.stateMachineService.send({
834
+ type: _stateMachine.TaskEvent.TRANSFER_CONFERENCE_FAILED,
835
+ reason: error.toString()
836
+ });
837
+ }
838
+ const {
839
+ error: detailedError
840
+ } = (0, _Utils.getErrorDetails)(error, 'transferConference', _constants.CC_FILE);
841
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_FAILED, {
842
+ taskId: this.data.interactionId,
843
+ requestInteractionId,
844
+ agentId: this.data.agentId,
845
+ error: error.toString(),
846
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
847
+ }, ['operational', 'behavioral', 'business']);
848
+ _loggerProxy.default.error(`Failed to transfer conference`, {
849
+ module: _constants.CC_FILE,
850
+ method: 'transferConference',
851
+ interactionId: requestInteractionId
852
+ });
853
+ throw detailedError;
854
+ }
855
+ }
856
+
857
+ /**
858
+ * Toggle between consult call and main call during consulting.
859
+ * If on consult leg (consultCallHeld = false), switches to main call by holding consult.
860
+ * If on main call (consultCallHeld = true), switches to consult by resuming consult.
861
+ *
862
+ * @returns Promise<TaskResponse>
863
+ * @throws Error if not in CONSULTING state or no consult media resource
864
+ * @example
865
+ * ```typescript
866
+ * await task.switchCall();
867
+ * ```
868
+ */
869
+ async switchCall() {
870
+ // Validate we're in CONSULTING state
871
+ const state = this.getStateMachineSnapshot();
872
+ if (!state?.matches(_stateMachine.TaskState.CONSULTING)) {
873
+ const currentState = state?.value;
874
+ const error = new Error(`Cannot switch call in ${currentState} state`);
875
+ _loggerProxy.default.error('Switch call operation not allowed', {
876
+ module: _constants.CC_FILE,
877
+ method: 'switchCall',
878
+ interactionId: this.data.interactionId
879
+ });
880
+ throw error;
881
+ }
882
+
883
+ // Validate we have a consult media resource
884
+ const consultMediaResourceId = (0, _TaskUtils.getConsultMediaResourceId)(this.data.interaction, this.data.consultMediaResourceId, this.data.agentId);
885
+ if (!consultMediaResourceId) {
886
+ const error = new Error('No consult media resource available');
887
+ _loggerProxy.default.error('Switch call failed - no consult media resource', {
888
+ module: _constants.CC_FILE,
889
+ method: 'switchCall',
890
+ interactionId: this.data.interactionId
891
+ });
892
+ throw error;
893
+ }
894
+ const context = state.context;
895
+ const isOnConsultLeg = !context.consultCallHeld;
896
+
897
+ // Determine direction and send appropriate state machine event
898
+ const targetEvent = isOnConsultLeg ? _stateMachine.TaskEvent.SWITCH_TO_MAIN_CALL : _stateMachine.TaskEvent.SWITCH_TO_CONSULT;
899
+ const revertEvent = isOnConsultLeg ? _stateMachine.TaskEvent.SWITCH_TO_CONSULT : _stateMachine.TaskEvent.SWITCH_TO_MAIN_CALL;
900
+ if (this.stateMachineService) {
901
+ this.stateMachineService.send({
902
+ type: targetEvent
903
+ });
904
+ }
905
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_FAILED]);
906
+ try {
907
+ if (isOnConsultLeg) {
908
+ const response = await this.contact.unHold({
909
+ interactionId: this.data.interactionId,
910
+ data: {
911
+ mediaResourceId: this.data.mediaResourceId
912
+ }
913
+ });
914
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_SUCCESS, {
915
+ taskId: this.data.interactionId,
916
+ direction: 'toMainCall',
917
+ mediaResourceId: consultMediaResourceId,
918
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
919
+ }, ['operational', 'behavioral']);
920
+ _loggerProxy.default.log(`Switched to main call successfully`, {
921
+ module: _constants.CC_FILE,
922
+ method: 'switchCall',
923
+ trackingId: response.trackingId,
924
+ interactionId: this.data.interactionId
925
+ });
926
+ return response;
927
+ }
928
+ const response = await this.contact.hold({
929
+ interactionId: this.data.interactionId,
930
+ data: {
931
+ mediaResourceId: this.data.mediaResourceId
932
+ }
933
+ });
934
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_SUCCESS, {
935
+ taskId: this.data.interactionId,
936
+ direction: 'toConsultCall',
937
+ mediaResourceId: consultMediaResourceId,
938
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
939
+ }, ['operational', 'behavioral']);
940
+ _loggerProxy.default.log(`Switched to consult call successfully`, {
941
+ module: _constants.CC_FILE,
942
+ method: 'switchCall',
943
+ trackingId: response.trackingId,
944
+ interactionId: this.data.interactionId
945
+ });
946
+ return response;
947
+ } catch (error) {
948
+ if (this.stateMachineService) {
949
+ this.stateMachineService.send({
950
+ type: revertEvent
951
+ });
952
+ }
953
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_FAILED, {
954
+ taskId: this.data.interactionId,
955
+ direction: isOnConsultLeg ? 'toMainCall' : 'toConsultCall',
956
+ mediaResourceId: consultMediaResourceId,
957
+ error: error.toString(),
958
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
959
+ }, ['operational', 'behavioral']);
960
+ const {
961
+ error: detailedError
962
+ } = (0, _Utils.getErrorDetails)(error, 'switchCall', _constants.CC_FILE);
963
+ _loggerProxy.default.error(`Failed to switch call`, {
964
+ module: _constants.CC_FILE,
965
+ method: 'switchCall',
966
+ interactionId: this.data.interactionId
967
+ });
968
+ throw detailedError;
969
+ }
970
+ }
971
+ getChannelSpecificActionOverrides() {
972
+ const baseOverrides = super.getChannelSpecificActionOverrides();
973
+ return {
974
+ ...baseOverrides,
975
+ emitTaskHold: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_HOLD, {
976
+ updateTaskData: true
977
+ }),
978
+ emitTaskResume: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RESUME, {
979
+ updateTaskData: true
980
+ }),
981
+ emitTaskRecordingStarted: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_STARTED, {
982
+ updateTaskData: true
983
+ }),
984
+ emitTaskRecordingPaused: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_PAUSED, {
985
+ updateTaskData: true
986
+ }),
987
+ emitTaskRecordingPauseFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_PAUSE_FAILED, {
988
+ updateTaskData: true
989
+ }),
990
+ emitTaskRecordingResumed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_RESUMED, {
991
+ updateTaskData: true
992
+ }),
993
+ emitTaskRecordingResumeFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_RESUME_FAILED, {
994
+ updateTaskData: true
995
+ }),
996
+ // Conference event emitters
997
+ emitTaskParticipantJoined: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_PARTICIPANT_JOINED, {
998
+ updateTaskData: true
999
+ }),
1000
+ emitTaskParticipantLeft: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_PARTICIPANT_LEFT, {
1001
+ updateTaskData: true
1002
+ }),
1003
+ emitTaskConferenceStarted: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONFERENCE_STARTED, {
1004
+ updateTaskData: true
1005
+ }),
1006
+ emitTaskConferenceEnded: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONFERENCE_ENDED, {
1007
+ updateTaskData: true
1008
+ }),
1009
+ emitTaskConferenceFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONFERENCE_FAILED, {
1010
+ updateTaskData: true
1011
+ }),
1012
+ emitTaskExitConference: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_EXIT_CONFERENCE, {
1013
+ updateTaskData: false
1014
+ }),
1015
+ emitTaskTransferConference: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_TRANSFER_CONFERENCE, {
1016
+ updateTaskData: false
1017
+ }),
1018
+ emitTaskSwitchCall: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_SWITCH_CALL, {
1019
+ updateTaskData: false
1020
+ }),
1021
+ emitTaskTransferConferenceFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONFERENCE_TRANSFER_FAILED, {
1022
+ updateTaskData: true
1023
+ }),
1024
+ emitTaskOutdialFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_OUTDIAL_FAILED, {
1025
+ updateTaskData: true
1026
+ })
1027
+ };
1028
+ }
1029
+ }
1030
+ exports.default = Voice;
1031
+ //# sourceMappingURL=Voice.js.map