@webex/contact-center 3.11.0 → 3.12.0-llmrefactor.2

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 (267) hide show
  1. package/.sdd/manifest.json +882 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +46 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +48 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +341 -0
  17. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  18. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  19. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  20. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  21. package/ai-docs/patterns/testing-patterns.md +480 -0
  22. package/ai-docs/patterns/typescript-patterns.md +365 -0
  23. package/ai-docs/templates/README.md +102 -0
  24. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  25. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  26. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  27. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  28. package/ai-docs/templates/new-method/00-master.md +80 -0
  29. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  30. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  31. package/ai-docs/templates/new-method/03-tests.md +201 -0
  32. package/ai-docs/templates/new-method/04-validation.md +141 -0
  33. package/ai-docs/templates/new-service/00-master.md +109 -0
  34. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  35. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  36. package/ai-docs/templates/new-service/03-integration.md +178 -0
  37. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  38. package/ai-docs/templates/new-service/05-validation.md +145 -0
  39. package/dist/cc.js +379 -50
  40. package/dist/cc.js.map +1 -1
  41. package/dist/config.js +6 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/constants.js +22 -2
  44. package/dist/constants.js.map +1 -1
  45. package/dist/index.js +27 -5
  46. package/dist/index.js.map +1 -1
  47. package/dist/metrics/behavioral-events.js +114 -0
  48. package/dist/metrics/behavioral-events.js.map +1 -1
  49. package/dist/metrics/constants.js +32 -3
  50. package/dist/metrics/constants.js.map +1 -1
  51. package/dist/services/ApiAiAssistant.js +318 -0
  52. package/dist/services/ApiAiAssistant.js.map +1 -0
  53. package/dist/services/UserPreference.js +427 -0
  54. package/dist/services/UserPreference.js.map +1 -0
  55. package/dist/services/agent/types.js.map +1 -1
  56. package/dist/services/config/Util.js +8 -4
  57. package/dist/services/config/Util.js.map +1 -1
  58. package/dist/services/config/constants.js +35 -2
  59. package/dist/services/config/constants.js.map +1 -1
  60. package/dist/services/config/index.js +41 -2
  61. package/dist/services/config/index.js.map +1 -1
  62. package/dist/services/config/types.js +66 -8
  63. package/dist/services/config/types.js.map +1 -1
  64. package/dist/services/constants.js +27 -1
  65. package/dist/services/constants.js.map +1 -1
  66. package/dist/services/core/Err.js.map +1 -1
  67. package/dist/services/core/Utils.js +122 -25
  68. package/dist/services/core/Utils.js.map +1 -1
  69. package/dist/services/core/aqm-reqs.js +92 -17
  70. package/dist/services/core/aqm-reqs.js.map +1 -1
  71. package/dist/services/core/websocket/WebSocketManager.js +22 -6
  72. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  73. package/dist/services/core/websocket/connection-service.js +3 -1
  74. package/dist/services/core/websocket/connection-service.js.map +1 -1
  75. package/dist/services/core/websocket/types.js.map +1 -1
  76. package/dist/services/index.js +6 -0
  77. package/dist/services/index.js.map +1 -1
  78. package/dist/services/task/Task.js +688 -0
  79. package/dist/services/task/Task.js.map +1 -0
  80. package/dist/services/task/TaskFactory.js +45 -0
  81. package/dist/services/task/TaskFactory.js.map +1 -0
  82. package/dist/services/task/TaskManager.js +751 -457
  83. package/dist/services/task/TaskManager.js.map +1 -1
  84. package/dist/services/task/TaskUtils.js +220 -23
  85. package/dist/services/task/TaskUtils.js.map +1 -1
  86. package/dist/services/task/constants.js +23 -2
  87. package/dist/services/task/constants.js.map +1 -1
  88. package/dist/services/task/dialer.js +129 -0
  89. package/dist/services/task/dialer.js.map +1 -1
  90. package/dist/services/task/digital/Digital.js +77 -0
  91. package/dist/services/task/digital/Digital.js.map +1 -0
  92. package/dist/services/task/state-machine/TaskStateMachine.js +873 -0
  93. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  94. package/dist/services/task/state-machine/actions.js +567 -0
  95. package/dist/services/task/state-machine/actions.js.map +1 -0
  96. package/dist/services/task/state-machine/constants.js +161 -0
  97. package/dist/services/task/state-machine/constants.js.map +1 -0
  98. package/dist/services/task/state-machine/guards.js +382 -0
  99. package/dist/services/task/state-machine/guards.js.map +1 -0
  100. package/dist/services/task/state-machine/index.js +53 -0
  101. package/dist/services/task/state-machine/index.js.map +1 -0
  102. package/dist/services/task/state-machine/types.js +54 -0
  103. package/dist/services/task/state-machine/types.js.map +1 -0
  104. package/dist/services/task/state-machine/uiControlsComputer.js +603 -0
  105. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  106. package/dist/services/task/taskDataNormalizer.js +99 -0
  107. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  108. package/dist/services/task/types.js +227 -4
  109. package/dist/services/task/types.js.map +1 -1
  110. package/dist/services/task/voice/Voice.js +1044 -0
  111. package/dist/services/task/voice/Voice.js.map +1 -0
  112. package/dist/services/task/voice/WebRTC.js +149 -0
  113. package/dist/services/task/voice/WebRTC.js.map +1 -0
  114. package/dist/types/cc.d.ts +894 -0
  115. package/dist/types/config.d.ts +72 -0
  116. package/dist/types/constants.d.ts +66 -0
  117. package/dist/types/index.d.ts +199 -0
  118. package/dist/types/logger-proxy.d.ts +71 -0
  119. package/dist/types/metrics/MetricsManager.d.ts +223 -0
  120. package/dist/types/metrics/behavioral-events.d.ts +29 -0
  121. package/dist/types/metrics/constants.d.ts +181 -0
  122. package/dist/types/services/AddressBook.d.ts +74 -0
  123. package/dist/types/services/ApiAiAssistant.d.ts +49 -0
  124. package/dist/types/services/EntryPoint.d.ts +67 -0
  125. package/dist/types/services/Queue.d.ts +76 -0
  126. package/dist/types/services/UserPreference.d.ts +118 -0
  127. package/dist/types/services/WebCallingService.d.ts +1 -0
  128. package/dist/types/services/agent/index.d.ts +46 -0
  129. package/dist/types/services/agent/types.d.ts +413 -0
  130. package/dist/types/services/config/Util.d.ts +20 -0
  131. package/dist/types/services/config/constants.d.ts +270 -0
  132. package/dist/types/services/config/index.d.ts +177 -0
  133. package/dist/types/services/config/types.d.ts +1368 -0
  134. package/dist/types/services/constants.d.ts +110 -0
  135. package/dist/types/services/core/Err.d.ts +125 -0
  136. package/dist/types/services/core/GlobalTypes.d.ts +58 -0
  137. package/dist/types/services/core/Utils.d.ts +121 -0
  138. package/dist/types/services/core/WebexRequest.d.ts +22 -0
  139. package/dist/types/services/core/aqm-reqs.d.ts +65 -0
  140. package/dist/types/services/core/constants.d.ts +99 -0
  141. package/dist/types/services/core/types.d.ts +47 -0
  142. package/dist/types/services/core/websocket/WebSocketManager.d.ts +36 -0
  143. package/dist/types/services/core/websocket/connection-service.d.ts +27 -0
  144. package/dist/types/services/core/websocket/keepalive.worker.d.ts +2 -0
  145. package/dist/types/services/core/websocket/types.d.ts +37 -0
  146. package/dist/types/services/index.d.ts +54 -0
  147. package/dist/types/services/task/AutoWrapup.d.ts +40 -0
  148. package/dist/types/services/task/Task.d.ts +157 -0
  149. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  150. package/dist/types/services/task/TaskManager.d.ts +1 -0
  151. package/dist/types/services/task/TaskUtils.d.ts +138 -0
  152. package/dist/types/services/task/constants.d.ts +91 -0
  153. package/dist/types/services/task/contact.d.ts +69 -0
  154. package/dist/types/services/task/dialer.d.ts +73 -0
  155. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  156. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1194 -0
  157. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  158. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  159. package/dist/types/services/task/state-machine/guards.d.ts +102 -0
  160. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  161. package/dist/types/services/task/state-machine/types.d.ts +269 -0
  162. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  163. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  164. package/dist/types/services/task/types.d.ts +1856 -0
  165. package/dist/types/services/task/voice/Voice.d.ts +184 -0
  166. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  167. package/dist/types/types.d.ts +778 -0
  168. package/dist/types/utils/PageCache.d.ts +173 -0
  169. package/dist/types/webex-config.d.ts +53 -0
  170. package/dist/types/webex.d.ts +8 -0
  171. package/dist/types.js +130 -1
  172. package/dist/types.js.map +1 -1
  173. package/dist/webex.js +14 -2
  174. package/dist/webex.js.map +1 -1
  175. package/package.json +16 -12
  176. package/src/cc.ts +477 -51
  177. package/src/config.ts +6 -0
  178. package/src/constants.ts +21 -1
  179. package/src/index.ts +24 -5
  180. package/src/metrics/ai-docs/AGENTS.md +350 -0
  181. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  182. package/src/metrics/ai-docs/metrics-spec.md +854 -0
  183. package/src/metrics/behavioral-events.ts +120 -0
  184. package/src/metrics/constants.ts +37 -3
  185. package/src/services/ApiAiAssistant.ts +412 -0
  186. package/src/services/UserPreference.ts +509 -0
  187. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  188. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  189. package/src/services/agent/ai-docs/agent-spec.md +504 -0
  190. package/src/services/agent/types.ts +1 -1
  191. package/src/services/ai-docs/AGENTS.md +386 -0
  192. package/src/services/ai-docs/services-spec.md +492 -0
  193. package/src/services/config/Util.ts +10 -2
  194. package/src/services/config/ai-docs/AGENTS.md +255 -0
  195. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  196. package/src/services/config/ai-docs/config-spec.md +669 -0
  197. package/src/services/config/constants.ts +37 -1
  198. package/src/services/config/index.ts +45 -1
  199. package/src/services/config/types.ts +241 -11
  200. package/src/services/constants.ts +29 -0
  201. package/src/services/core/Err.ts +3 -0
  202. package/src/services/core/Utils.ts +143 -30
  203. package/src/services/core/ai-docs/AGENTS.md +381 -0
  204. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  205. package/src/services/core/ai-docs/core-spec.md +783 -0
  206. package/src/services/core/aqm-reqs.ts +100 -22
  207. package/src/services/core/websocket/WebSocketManager.ts +23 -6
  208. package/src/services/core/websocket/connection-service.ts +5 -1
  209. package/src/services/core/websocket/types.ts +1 -1
  210. package/src/services/index.ts +4 -0
  211. package/src/services/task/Task.ts +837 -0
  212. package/src/services/task/TaskFactory.ts +55 -0
  213. package/src/services/task/TaskManager.ts +793 -521
  214. package/src/services/task/TaskUtils.ts +314 -24
  215. package/src/services/task/ai-docs/AGENTS.md +457 -0
  216. package/src/services/task/ai-docs/ARCHITECTURE.md +594 -0
  217. package/src/services/task/ai-docs/task-spec.md +1319 -0
  218. package/src/services/task/constants.ts +23 -0
  219. package/src/services/task/dialer.ts +136 -1
  220. package/src/services/task/digital/Digital.ts +95 -0
  221. package/src/services/task/state-machine/TaskStateMachine.ts +1166 -0
  222. package/src/services/task/state-machine/actions.ts +738 -0
  223. package/src/services/task/state-machine/ai-docs/AGENTS.md +458 -0
  224. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1137 -0
  225. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2177 -0
  226. package/src/services/task/state-machine/constants.ts +172 -0
  227. package/src/services/task/state-machine/guards.ts +445 -0
  228. package/src/services/task/state-machine/index.ts +28 -0
  229. package/src/services/task/state-machine/types.ts +243 -0
  230. package/src/services/task/state-machine/uiControlsComputer.ts +961 -0
  231. package/src/services/task/taskDataNormalizer.ts +137 -0
  232. package/src/services/task/types.ts +734 -71
  233. package/src/services/task/voice/Voice.ts +1270 -0
  234. package/src/services/task/voice/WebRTC.ts +187 -0
  235. package/src/types.ts +205 -2
  236. package/src/utils/AGENTS.md +278 -0
  237. package/src/utils/ai-docs/utils-spec.md +381 -0
  238. package/src/webex.js +2 -0
  239. package/test/unit/spec/cc.ts +503 -43
  240. package/test/unit/spec/logger-proxy.ts +70 -0
  241. package/test/unit/spec/services/ApiAiAssistant.ts +273 -0
  242. package/test/unit/spec/services/UserPreference.ts +401 -0
  243. package/test/unit/spec/services/WebCallingService.ts +7 -1
  244. package/test/unit/spec/services/config/index.ts +85 -29
  245. package/test/unit/spec/services/core/Utils.ts +481 -2
  246. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +137 -41
  247. package/test/unit/spec/services/core/websocket/connection-service.ts +3 -1
  248. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  249. package/test/unit/spec/services/task/Task.ts +477 -0
  250. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  251. package/test/unit/spec/services/task/TaskManager.ts +1001 -1003
  252. package/test/unit/spec/services/task/TaskUtils.ts +235 -0
  253. package/test/unit/spec/services/task/dialer.ts +372 -96
  254. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  255. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +2651 -0
  256. package/test/unit/spec/services/task/state-machine/guards.ts +637 -0
  257. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  258. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2663 -0
  259. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  260. package/test/unit/spec/services/task/voice/Voice.ts +649 -0
  261. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  262. package/umd/contact-center.min.js +2 -2
  263. package/umd/contact-center.min.js.map +1 -1
  264. package/dist/services/task/index.js +0 -1525
  265. package/dist/services/task/index.js.map +0 -1
  266. package/src/services/task/index.ts +0 -1801
  267. package/test/unit/spec/services/task/index.ts +0 -2184
package/dist/cc.js CHANGED
@@ -22,9 +22,11 @@ var _WebCallingService = _interopRequireDefault(require("./services/WebCallingSe
22
22
  var _types4 = require("./services/task/types");
23
23
  var _MetricsManager = _interopRequireDefault(require("./metrics/MetricsManager"));
24
24
  var _constants4 = require("./metrics/constants");
25
- var _EntryPoint = _interopRequireDefault(require("./services/EntryPoint"));
26
- var _AddressBook = _interopRequireDefault(require("./services/AddressBook"));
27
- var _Queue = _interopRequireDefault(require("./services/Queue"));
25
+ var _EntryPoint = require("./services/EntryPoint");
26
+ var _AddressBook = require("./services/AddressBook");
27
+ var _Queue = require("./services/Queue");
28
+ var _ApiAiAssistant = require("./services/ApiAiAssistant");
29
+ var _UserPreference = require("./services/UserPreference");
28
30
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
29
31
  /**
30
32
  * @module CCPlugin
@@ -84,6 +86,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
84
86
  * - `task:established` - Task/call has been connected
85
87
  * - `task:ended` - Task/call has ended
86
88
  * - `task:error` - An error occurred during task handling
89
+ * - `task:campaignPreviewReservation` - Campaign preview contact offered to agent
87
90
  *
88
91
  * @public
89
92
  *
@@ -272,6 +275,42 @@ class ContactCenter extends _webexCore.WebexPlugin {
272
275
  * ```
273
276
  */
274
277
 
278
+ /**
279
+ * API instance for managing Webex Contact Center user preferences
280
+ * Provides functionality to get, create, update, and delete user preferences
281
+ * @type {UserPreference}
282
+ * @public
283
+ * @example
284
+ * ```typescript
285
+ * const cc = webex.cc;
286
+ * await cc.register();
287
+ * await cc.stationLogin({ teamId: 'team123', loginOption: 'BROWSER' });
288
+ *
289
+ * // Get user preferences for current user
290
+ * const preferences = await cc.userPreference.getUserPreference();
291
+ *
292
+ * // Create new user preferences
293
+ * const newPrefs = await cc.userPreference.createUserPreference({
294
+ * userId: 'user123',
295
+ * preferences: { e911Reminder: true }
296
+ * });
297
+ *
298
+ * // Update user preferences
299
+ * const updatedPrefs = await cc.userPreference.updateUserPreference('user123', {
300
+ * preferences: { e911Reminder: false }
301
+ * });
302
+ *
303
+ * // Delete user preferences
304
+ * await cc.userPreference.deleteUserPreference('user123');
305
+ * ```
306
+ */
307
+
308
+ /**
309
+ * API instance for AI Assistant operations such as transcript controls.
310
+ * @type {ApiAIAssistant}
311
+ * @public
312
+ */
313
+
275
314
  /**
276
315
  * Logger utility for Contact Center plugin
277
316
  * Provides consistent logging across the plugin
@@ -293,6 +332,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
293
332
  this.$webex.once(_constants.READY, () => {
294
333
  // @ts-ignore
295
334
  this.$config = this.config;
335
+ this.validatePluginConfig();
296
336
 
297
337
  /**
298
338
  * This is used for handling the async requests by sending webex.request and wait for corresponding websocket event.
@@ -304,21 +344,20 @@ class ContactCenter extends _webexCore.WebexPlugin {
304
344
  webex: this.$webex,
305
345
  connectionConfig: this.getConnectionConfig()
306
346
  });
307
- this.services.webSocketManager.on('message', this.handleWebsocketMessage);
308
347
  this.webCallingService = new _WebCallingService.default(this.$webex);
348
+ this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex);
309
349
  this.metricsManager = _MetricsManager.default.getInstance({
310
350
  webex: this.$webex
311
351
  });
312
- this.taskManager = _TaskManager.default.getTaskManager(this.services.contact, this.webCallingService, this.services.webSocketManager);
352
+ this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager, this.services.rtdWebSocketManager);
313
353
  this.incomingTaskListener();
314
354
 
315
355
  // Initialize API instances
316
356
  // will have future function for indivdual fetch etc so better be in an object
317
- this.entryPoint = new _EntryPoint.default(this.$webex);
318
- this.addressBook = new _AddressBook.default(this.$webex, () => this.agentConfig?.addressBookId);
319
- this.queue = new _Queue.default(this.$webex);
320
-
321
- // Initialize logger
357
+ this.entryPoint = new _EntryPoint.EntryPoint(this.$webex);
358
+ this.addressBook = new _AddressBook.AddressBook(this.$webex, () => this.agentConfig?.addressBookId);
359
+ this.queue = new _Queue.Queue(this.$webex);
360
+ this.userPreference = new _UserPreference.UserPreference(this.$webex, () => this.agentConfig?.agentId);
322
361
  _loggerProxy.default.initialize(this.$webex.logger);
323
362
  });
324
363
  }
@@ -343,6 +382,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
343
382
  this.trigger(_types4.TASK_EVENTS.TASK_HYDRATE, task);
344
383
  };
345
384
 
385
+ /**
386
+ * Handles multi-login hydrate events for SDK instances without Mobius registration
387
+ * @private
388
+ * @param {ITask} task The task object associated with the multi-login hydrate
389
+ */
390
+ handleTaskMultiLoginHydrate = task => {
391
+ // @ts-ignore
392
+ this.trigger(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
393
+ };
394
+
346
395
  /**
347
396
  * Handles task merged events when tasks are combined eg: EPDN merge/transfer
348
397
  * @private
@@ -353,6 +402,19 @@ class ContactCenter extends _webexCore.WebexPlugin {
353
402
  this.trigger(_types4.TASK_EVENTS.TASK_MERGED, task);
354
403
  };
355
404
 
405
+ /**
406
+ * Handles campaign preview reservation events when a contact is offered to the agent
407
+ * @private
408
+ * @param {ITask} task The campaign reservation task
409
+ */
410
+ handleCampaignPreviewReservation = task => {
411
+ // @ts-ignore
412
+ this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
413
+ };
414
+ handleRTDWebsocketMessage = event => {
415
+ this.taskManager.handleRealtimeWebsocketEvent(event);
416
+ };
417
+
356
418
  /**
357
419
  * Sets up event listeners for incoming tasks and task hydration
358
420
  * Subscribes to task events from the task manager
@@ -361,7 +423,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
361
423
  incomingTaskListener() {
362
424
  this.taskManager.on(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
363
425
  this.taskManager.on(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
426
+ this.taskManager.on(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
364
427
  this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
428
+ this.taskManager.on(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
365
429
  }
366
430
 
367
431
  /**
@@ -401,13 +465,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
401
465
  * ```
402
466
  */
403
467
  async register() {
404
- _loggerProxy.default.info('Starting CC SDK registration', {
468
+ _loggerProxy.default.log('Starting CC SDK registration', {
405
469
  module: _constants.CC_FILE,
406
470
  method: _constants.METHODS.REGISTER
407
471
  });
408
472
  try {
409
473
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED]);
410
474
  this.setupEventListeners();
475
+ this.services.webSocketManager.on('message', this.handleWebsocketMessage);
411
476
  const resp = await this.connectWebsocket();
412
477
  // Ensure 'dn' is always populated from 'defaultDn'
413
478
  resp.dn = resp.defaultDn;
@@ -470,8 +535,11 @@ class ContactCenter extends _webexCore.WebexPlugin {
470
535
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_FAIL]);
471
536
  this.taskManager.off(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
472
537
  this.taskManager.off(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
538
+ this.taskManager.off(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
539
+ this.taskManager.off(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
473
540
  this.taskManager.unregisterIncomingCallEvent();
474
541
  this.services.webSocketManager.off('message', this.handleWebsocketMessage);
542
+ this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
475
543
  this.services.connectionService.off('connectionLost', this.handleConnectionLost);
476
544
  if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
477
545
  if (this.$webex.internal.mercury.connected) {
@@ -489,6 +557,12 @@ class ContactCenter extends _webexCore.WebexPlugin {
489
557
  if (!this.services.webSocketManager.isSocketClosed) {
490
558
  this.services.webSocketManager.close(false, 'Unregistering the SDK');
491
559
  }
560
+ if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
561
+ this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
562
+ }
563
+ if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
564
+ this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
565
+ }
492
566
 
493
567
  // Clear any cached agent configuration
494
568
  this.agentConfig = null;
@@ -590,13 +664,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
590
664
  * @private
591
665
  */
592
666
  async connectWebsocket() {
593
- _loggerProxy.default.info('Connecting to websocket', {
667
+ _loggerProxy.default.log('Connecting to websocket', {
594
668
  module: _constants.CC_FILE,
595
669
  method: _constants.METHODS.CONNECT_WEBSOCKET
596
670
  });
597
671
  try {
598
672
  const data = await this.services.webSocketManager.initWebSocket({
599
- body: this.getConnectionConfig()
673
+ body: this.getConnectionConfig(),
674
+ resource: _constants3.SUBSCRIBE_API
600
675
  });
601
676
  const agentId = data.agentId;
602
677
  const orgId = this.$webex.credentials.getOrgId();
@@ -605,12 +680,46 @@ class ContactCenter extends _webexCore.WebexPlugin {
605
680
  module: _constants.CC_FILE,
606
681
  method: _constants.METHODS.CONNECT_WEBSOCKET
607
682
  });
608
-
683
+ const configFlags = {
684
+ isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
685
+ isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
686
+ webRtcEnabled: this.agentConfig.webRtcEnabled,
687
+ autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
688
+ aiFeature: this.agentConfig.aiFeature
689
+ };
690
+ this.taskManager.setConfigFlags(configFlags);
609
691
  // TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
610
692
  this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
611
693
  this.taskManager.setAgentId(this.agentConfig.agentId);
612
694
  this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
613
- if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
695
+ this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
696
+
697
+ /**
698
+ * RTD websocket currently supports realtime transcripts and suggested responses.
699
+ * Extend this condition when additional AI RTD features are introduced.
700
+ */
701
+ if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable) {
702
+ _loggerProxy.default.info('Connecting to RTD websocket', {
703
+ module: _constants.CC_FILE,
704
+ method: _constants.METHODS.CONNECT_WEBSOCKET
705
+ });
706
+ this.services.rtdWebSocketManager.initWebSocket({
707
+ body: this.getConnectionConfig(),
708
+ resource: _constants3.RTD_SUBSCRIBE_API
709
+ }).then(() => {
710
+ _loggerProxy.default.log('RTD websocket connected successfully', {
711
+ module: _constants.CC_FILE,
712
+ method: _constants.METHODS.CONNECT_WEBSOCKET
713
+ });
714
+ this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
715
+ }).catch(error => {
716
+ _loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
717
+ module: _constants.CC_FILE,
718
+ method: _constants.METHODS.CONNECT_WEBSOCKET
719
+ });
720
+ });
721
+ }
722
+ if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER) && !this.isWebRTCRegistrationDisabled()) {
614
723
  try {
615
724
  await this.$webex.internal.mercury.connect();
616
725
  _loggerProxy.default.log('Authentication: webex.internal.mercury.connect successful', {
@@ -623,9 +732,19 @@ class ContactCenter extends _webexCore.WebexPlugin {
623
732
  method: _constants.METHODS.CONNECT_WEBSOCKET
624
733
  });
625
734
  }
735
+ } else if (this.isWebRTCRegistrationDisabled()) {
736
+ _loggerProxy.default.info('Skipping Mobius registration because disableWebRTCRegistration is enabled', {
737
+ module: _constants.CC_FILE,
738
+ method: _constants.METHODS.CONNECT_WEBSOCKET
739
+ });
626
740
  }
627
741
  if (this.$config && this.$config.allowAutomatedRelogin) {
628
742
  await this.silentRelogin();
743
+ } else {
744
+ _loggerProxy.default.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
745
+ module: _constants.CC_FILE,
746
+ method: _constants.METHODS.CONNECT_WEBSOCKET
747
+ });
629
748
  }
630
749
  return this.agentConfig;
631
750
  } catch (error) {
@@ -666,21 +785,27 @@ class ContactCenter extends _webexCore.WebexPlugin {
666
785
  * ```
667
786
  */
668
787
  async stationLogin(data) {
669
- _loggerProxy.default.info('Starting agent station login', {
788
+ const loggerContext = {
670
789
  module: _constants.CC_FILE,
671
790
  method: _constants.METHODS.STATION_LOGIN
672
- });
791
+ };
673
792
  try {
793
+ _loggerProxy.default.log(`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`, loggerContext);
674
794
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, _constants4.METRIC_EVENT_NAMES.STATION_LOGIN_FAILED]);
675
- if (data.loginOption === _types.LoginOption.AGENT_DN && !(0, _Utils.isValidDialNumber)(data.dialNumber)) {
676
- const error = new Error('INVALID_DIAL_NUMBER');
677
- // @ts-ignore - adding custom key to the error object
678
- error.details = {
679
- data: {
680
- reason: 'INVALID_DIAL_NUMBER'
681
- }
682
- };
683
- throw error;
795
+ const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
796
+ if (data.loginOption === _types.LoginOption.AGENT_DN) {
797
+ _loggerProxy.default.log(`Validating dial number | dialPlanEnabled: ${!!this.agentConfig?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
798
+ if (!(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
799
+ _loggerProxy.default.log(`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
800
+ const error = new Error('INVALID_DIAL_NUMBER');
801
+ // @ts-ignore - adding custom key to the error object
802
+ error.details = {
803
+ data: {
804
+ reason: 'INVALID_DIAL_NUMBER'
805
+ }
806
+ };
807
+ throw error;
808
+ }
684
809
  }
685
810
  const loginResponse = await this.services.agent.stationLogin({
686
811
  data: {
@@ -696,8 +821,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
696
821
  auxCodeId: _constants.EMPTY_STRING
697
822
  }
698
823
  });
699
- if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER) {
824
+ if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && !this.isWebRTCRegistrationDisabled()) {
700
825
  await this.webCallingService.registerWebCallingLine();
826
+ } else if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && this.isWebRTCRegistrationDisabled()) {
827
+ _loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
828
+ module: _constants.CC_FILE,
829
+ method: _constants.METHODS.STATION_LOGIN
830
+ });
701
831
  }
702
832
  const resp = await loginResponse;
703
833
  const {
@@ -1021,6 +1151,25 @@ class ContactCenter extends _webexCore.WebexPlugin {
1021
1151
  }
1022
1152
  };
1023
1153
 
1154
+ /**
1155
+ * Checks whether Mobius/WebRTC registration should be skipped by config
1156
+ * @returns {boolean} True when browser WebRTC registration is disabled
1157
+ * @private
1158
+ */
1159
+ isWebRTCRegistrationDisabled() {
1160
+ return this.$config?.disableWebRTCRegistration === true;
1161
+ }
1162
+
1163
+ /**
1164
+ * Validates contact-center plugin configuration before service initialization
1165
+ * @private
1166
+ */
1167
+ validatePluginConfig() {
1168
+ if (this.$config?.disableWebRTCRegistration === true && this.$config?.allowMultiLogin === false) {
1169
+ throw new Error('Invalid Contact Center configuration: disableWebRTCRegistration cannot be true when allowMultiLogin is false. Enable allowMultiLogin or allow WebRTC registration so an SDK instance can receive Mobius/WebRTC task events.');
1170
+ }
1171
+ }
1172
+
1024
1173
  /**
1025
1174
  * Initializes event listeners for the Contact Center service
1026
1175
  * Sets up handlers for connection state changes and other core events
@@ -1052,13 +1201,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
1052
1201
  async handleConnectionLost(msg) {
1053
1202
  if (msg.isConnectionLost) {
1054
1203
  // TODO: Emit an event saying connection is lost
1055
- _loggerProxy.default.info('event=handleConnectionLost | Connection lost', {
1204
+ _loggerProxy.default.log('event=handleConnectionLost | Connection lost', {
1056
1205
  module: _constants.CC_FILE,
1057
1206
  method: _constants.METHODS.HANDLE_CONNECTION_LOST
1058
1207
  });
1059
1208
  } else if (msg.isSocketReconnected) {
1060
1209
  // TODO: Emit an event saying connection is re-estabilished
1061
- _loggerProxy.default.info('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
1210
+ _loggerProxy.default.log('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
1062
1211
  module: _constants.CC_FILE,
1063
1212
  method: _constants.METHODS.HANDLE_CONNECTION_LOST
1064
1213
  });
@@ -1073,7 +1222,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1073
1222
  * @private
1074
1223
  */
1075
1224
  async silentRelogin() {
1076
- _loggerProxy.default.info('Starting silent relogin process', {
1225
+ _loggerProxy.default.log('Starting silent relogin process', {
1077
1226
  module: _constants.CC_FILE,
1078
1227
  method: _constants.METHODS.SILENT_RELOGIN
1079
1228
  });
@@ -1095,7 +1244,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1095
1244
  this.agentConfig.currentTeamId = reLoginResponse.data.teamId;
1096
1245
  await this.handleDeviceType(deviceType, dn);
1097
1246
  if (lastStateChangeReason === 'agent-wss-disconnect') {
1098
- _loggerProxy.default.info('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
1247
+ _loggerProxy.default.log('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
1099
1248
  module: _constants.CC_FILE,
1100
1249
  method: _constants.METHODS.SILENT_RELOGIN
1101
1250
  });
@@ -1119,8 +1268,6 @@ class ContactCenter extends _webexCore.WebexPlugin {
1119
1268
  }
1120
1269
  this.agentConfig.lastStateAuxCodeId = auxCodeId;
1121
1270
  this.agentConfig.isAgentLoggedIn = true;
1122
- // TODO: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-626777 Implement the de-register method and close the listener there
1123
- this.services.webSocketManager.on('message', this.handleWebsocketMessage);
1124
1271
  _loggerProxy.default.log(`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`, {
1125
1272
  module: _constants.CC_FILE,
1126
1273
  method: _constants.METHODS.SILENT_RELOGIN,
@@ -1155,6 +1302,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
1155
1302
  this.agentConfig.deviceType = deviceType;
1156
1303
  switch (deviceType) {
1157
1304
  case _types.LoginOption.BROWSER:
1305
+ if (this.isWebRTCRegistrationDisabled()) {
1306
+ _loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
1307
+ module: _constants.CC_FILE,
1308
+ method: _constants.METHODS.HANDLE_DEVICE_TYPE
1309
+ });
1310
+ break;
1311
+ }
1158
1312
  try {
1159
1313
  await this.webCallingService.registerWebCallingLine();
1160
1314
  } catch (error) {
@@ -1336,6 +1490,196 @@ class ContactCenter extends _webexCore.WebexPlugin {
1336
1490
  }
1337
1491
  }
1338
1492
 
1493
+ /**
1494
+ * Accepts a campaign preview contact, initiating the outbound call.
1495
+ *
1496
+ * When a campaign manager reserves a contact for an agent, the agent receives an
1497
+ * `AgentOfferCampaignReservation` event. The agent can then accept the preview contact
1498
+ * to initiate the outbound call.
1499
+ *
1500
+ * @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
1501
+ * @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
1502
+ * @throws {Error} If the operation fails (network error, customer unavailable, etc.)
1503
+ *
1504
+ * @example
1505
+ * ```typescript
1506
+ * webex.cc.on('task:campaignPreviewReservation', async (task) => {
1507
+ * const { interactionId } = task.data;
1508
+ * // campaignId is the campaign name (e.g. "MyCampaign"), not a UUID
1509
+ * const campaignId = task.data.interaction.callProcessingDetails.campaignId;
1510
+ *
1511
+ * const result = await webex.cc.acceptPreviewContact({ interactionId, campaignId });
1512
+ * });
1513
+ * ```
1514
+ */
1515
+ async acceptPreviewContact(payload) {
1516
+ _loggerProxy.default.info('Accepting campaign preview contact', {
1517
+ module: _constants.CC_FILE,
1518
+ method: _constants.METHODS.ACCEPT_PREVIEW_CONTACT
1519
+ });
1520
+ try {
1521
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED]);
1522
+ const result = await this.services.dialer.acceptPreviewContact({
1523
+ data: payload
1524
+ });
1525
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS, {
1526
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
1527
+ interactionId: payload.interactionId,
1528
+ campaignId: payload.campaignId
1529
+ }, ['behavioral', 'business', 'operational']);
1530
+ _loggerProxy.default.log('Campaign preview contact accepted successfully', {
1531
+ module: _constants.CC_FILE,
1532
+ method: _constants.METHODS.ACCEPT_PREVIEW_CONTACT,
1533
+ trackingId: result.trackingId,
1534
+ interactionId: payload.interactionId
1535
+ });
1536
+ return result;
1537
+ } catch (error) {
1538
+ const failure = error.details;
1539
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED, {
1540
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
1541
+ interactionId: payload.interactionId,
1542
+ campaignId: payload.campaignId
1543
+ }, ['behavioral', 'business', 'operational']);
1544
+ const {
1545
+ error: detailedError
1546
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.ACCEPT_PREVIEW_CONTACT, _constants.CC_FILE);
1547
+ throw detailedError;
1548
+ }
1549
+ }
1550
+
1551
+ /**
1552
+ * Skips a campaign preview contact, requesting the next contact from the campaign.
1553
+ *
1554
+ * When a campaign manager reserves a contact for an agent, the agent receives an
1555
+ * `AgentOfferCampaignReservation` event. Instead of accepting, the agent can skip the
1556
+ * preview contact to move to the next contact in the campaign.
1557
+ *
1558
+ * @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
1559
+ * @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
1560
+ * @throws {Error} If the operation fails (network error, etc.)
1561
+ *
1562
+ * @example
1563
+ * ```typescript
1564
+ * webex.cc.on('task:campaignPreviewReservation', async (task) => {
1565
+ * const { interactionId } = task.data;
1566
+ * const campaignId = task.data.interaction.callProcessingDetails.campaignId;
1567
+ *
1568
+ * const result = await webex.cc.skipPreviewContact({ interactionId, campaignId });
1569
+ * });
1570
+ * ```
1571
+ */
1572
+ async skipPreviewContact(payload) {
1573
+ const task = this.taskManager.getTask(payload.interactionId);
1574
+ if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewSkipDisabled === 'true') {
1575
+ _loggerProxy.default.warn('Skip action is disabled for this campaign preview contact', {
1576
+ module: _constants.CC_FILE,
1577
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
1578
+ interactionId: payload.interactionId
1579
+ });
1580
+ throw new Error('Skip action is disabled for this campaign preview contact');
1581
+ }
1582
+ _loggerProxy.default.info('Skipping campaign preview contact', {
1583
+ module: _constants.CC_FILE,
1584
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT
1585
+ });
1586
+ try {
1587
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED]);
1588
+ const result = await this.services.dialer.skipPreviewContact({
1589
+ data: payload
1590
+ });
1591
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, {
1592
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
1593
+ interactionId: payload.interactionId,
1594
+ campaignId: payload.campaignId
1595
+ }, ['behavioral', 'business', 'operational']);
1596
+ _loggerProxy.default.log('Campaign preview contact skipped successfully', {
1597
+ module: _constants.CC_FILE,
1598
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
1599
+ trackingId: result.trackingId,
1600
+ interactionId: payload.interactionId
1601
+ });
1602
+ return result;
1603
+ } catch (error) {
1604
+ const failure = error.details;
1605
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED, {
1606
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
1607
+ interactionId: payload.interactionId,
1608
+ campaignId: payload.campaignId
1609
+ }, ['behavioral', 'business', 'operational']);
1610
+ const {
1611
+ error: detailedError
1612
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.SKIP_PREVIEW_CONTACT, _constants.CC_FILE);
1613
+ throw detailedError;
1614
+ }
1615
+ }
1616
+
1617
+ /**
1618
+ * Removes a campaign preview contact from the campaign list entirely.
1619
+ *
1620
+ * When a campaign manager reserves a contact for an agent, the agent receives an
1621
+ * `AgentOfferCampaignReservation` event. Instead of accepting or skipping, the agent can
1622
+ * remove the preview contact to permanently take it out of the campaign contact list.
1623
+ *
1624
+ * @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
1625
+ * @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
1626
+ * @throws {Error} If the operation fails (network error, etc.)
1627
+ *
1628
+ * @example
1629
+ * ```typescript
1630
+ * webex.cc.on('task:campaignPreviewReservation', async (task) => {
1631
+ * const { interactionId } = task.data;
1632
+ * const campaignId = task.data.interaction.callProcessingDetails.campaignId;
1633
+ *
1634
+ * const result = await webex.cc.removePreviewContact({ interactionId, campaignId });
1635
+ * });
1636
+ * ```
1637
+ */
1638
+ async removePreviewContact(payload) {
1639
+ const task = this.taskManager.getTask(payload.interactionId);
1640
+ if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewRemoveDisabled === 'true') {
1641
+ _loggerProxy.default.warn('Remove action is disabled for this campaign preview contact', {
1642
+ module: _constants.CC_FILE,
1643
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
1644
+ interactionId: payload.interactionId
1645
+ });
1646
+ throw new Error('Remove action is disabled for this campaign preview contact');
1647
+ }
1648
+ _loggerProxy.default.info('Removing campaign preview contact', {
1649
+ module: _constants.CC_FILE,
1650
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT
1651
+ });
1652
+ try {
1653
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED]);
1654
+ const result = await this.services.dialer.removePreviewContact({
1655
+ data: payload
1656
+ });
1657
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, {
1658
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
1659
+ interactionId: payload.interactionId,
1660
+ campaignId: payload.campaignId
1661
+ }, ['behavioral', 'business', 'operational']);
1662
+ _loggerProxy.default.log('Campaign preview contact removed successfully', {
1663
+ module: _constants.CC_FILE,
1664
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
1665
+ trackingId: result.trackingId,
1666
+ interactionId: payload.interactionId
1667
+ });
1668
+ return result;
1669
+ } catch (error) {
1670
+ const failure = error.details;
1671
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED, {
1672
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
1673
+ interactionId: payload.interactionId,
1674
+ campaignId: payload.campaignId
1675
+ }, ['behavioral', 'business', 'operational']);
1676
+ const {
1677
+ error: detailedError
1678
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.REMOVE_PREVIEW_CONTACT, _constants.CC_FILE);
1679
+ throw detailedError;
1680
+ }
1681
+ }
1682
+
1339
1683
  /**
1340
1684
  * Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
1341
1685
  *
@@ -1467,6 +1811,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1467
1811
  /**
1468
1812
  * Updates the agent device type and login configuration.
1469
1813
  * Use this method to change how an agent connects to the contact center system (e.g., switching from browser-based calling to a desk phone extension).
1814
+ * Change to any field of the profile is allowed;
1470
1815
  *
1471
1816
  * @param {AgentDeviceUpdate} data Configuration containing:
1472
1817
  * - loginOption: New device type ('BROWSER', 'EXTENSION', 'AGENT_DN')
@@ -1500,24 +1845,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
1500
1845
  trackingId
1501
1846
  });
1502
1847
  try {
1503
- // Only block if both loginOption AND teamId remain unchanged
1504
- if (this.webCallingService?.loginOption === data.loginOption && data.teamId === this.agentConfig.currentTeamId) {
1505
- const message = 'Will not proceed with device update as new Device type is same as current device type and teamId is same as current teamId';
1506
- const err = new Error(message);
1507
- err.details = {
1508
- type: 'Identical Device Change Failure',
1509
- orgId: this.$webex.credentials.getOrgId(),
1510
- trackingId,
1511
- data: {
1512
- agentId: this.agentConfig.agentId,
1513
- reasonCode: 'R002',
1514
- reason: message
1515
- }
1516
- };
1517
- throw err;
1518
- }
1519
1848
  await this.stationLogout({
1520
- logoutReason: 'User requested agent device change'
1849
+ logoutReason: 'User requested agent profile update'
1521
1850
  });
1522
1851
  const loginPayload = {
1523
1852
  teamId: data.teamId,