@webex/contact-center 3.9.0-next.2 → 3.9.0-next.21

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 (106) hide show
  1. package/dist/cc.js +195 -46
  2. package/dist/cc.js.map +1 -1
  3. package/dist/constants.js +1 -0
  4. package/dist/constants.js.map +1 -1
  5. package/dist/index.js +9 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/logger-proxy.js +24 -1
  8. package/dist/logger-proxy.js.map +1 -1
  9. package/dist/metrics/MetricsManager.js +1 -1
  10. package/dist/metrics/MetricsManager.js.map +1 -1
  11. package/dist/metrics/behavioral-events.js +89 -0
  12. package/dist/metrics/behavioral-events.js.map +1 -1
  13. package/dist/metrics/constants.js +32 -2
  14. package/dist/metrics/constants.js.map +1 -1
  15. package/dist/services/AddressBook.js +271 -0
  16. package/dist/services/AddressBook.js.map +1 -0
  17. package/dist/services/EntryPoint.js +227 -0
  18. package/dist/services/EntryPoint.js.map +1 -0
  19. package/dist/services/Queue.js +261 -0
  20. package/dist/services/Queue.js.map +1 -0
  21. package/dist/services/config/constants.js +36 -2
  22. package/dist/services/config/constants.js.map +1 -1
  23. package/dist/services/config/index.js +29 -21
  24. package/dist/services/config/index.js.map +1 -1
  25. package/dist/services/config/types.js +33 -1
  26. package/dist/services/config/types.js.map +1 -1
  27. package/dist/services/core/GlobalTypes.js.map +1 -1
  28. package/dist/services/core/Utils.js +162 -2
  29. package/dist/services/core/Utils.js.map +1 -1
  30. package/dist/services/core/aqm-reqs.js +0 -4
  31. package/dist/services/core/aqm-reqs.js.map +1 -1
  32. package/dist/services/core/websocket/WebSocketManager.js +0 -4
  33. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  34. package/dist/services/task/TaskManager.js +74 -2
  35. package/dist/services/task/TaskManager.js.map +1 -1
  36. package/dist/services/task/constants.js +7 -1
  37. package/dist/services/task/constants.js.map +1 -1
  38. package/dist/services/task/contact.js +86 -0
  39. package/dist/services/task/contact.js.map +1 -1
  40. package/dist/services/task/index.js +384 -72
  41. package/dist/services/task/index.js.map +1 -1
  42. package/dist/services/task/types.js +14 -0
  43. package/dist/services/task/types.js.map +1 -1
  44. package/dist/types/cc.d.ts +115 -35
  45. package/dist/types/constants.d.ts +1 -0
  46. package/dist/types/index.d.ts +3 -2
  47. package/dist/types/metrics/constants.d.ts +25 -1
  48. package/dist/types/services/AddressBook.d.ts +74 -0
  49. package/dist/types/services/EntryPoint.d.ts +67 -0
  50. package/dist/types/services/Queue.d.ts +76 -0
  51. package/dist/types/services/config/constants.d.ts +35 -1
  52. package/dist/types/services/config/index.d.ts +6 -9
  53. package/dist/types/services/config/types.d.ts +79 -58
  54. package/dist/types/services/core/GlobalTypes.d.ts +25 -0
  55. package/dist/types/services/core/Utils.d.ts +40 -1
  56. package/dist/types/services/task/constants.d.ts +6 -0
  57. package/dist/types/services/task/contact.d.ts +10 -0
  58. package/dist/types/services/task/index.d.ts +44 -2
  59. package/dist/types/services/task/types.d.ts +125 -1
  60. package/dist/types/types.d.ts +162 -0
  61. package/dist/types/utils/PageCache.d.ts +173 -0
  62. package/dist/types.js +17 -0
  63. package/dist/types.js.map +1 -1
  64. package/dist/utils/PageCache.js +192 -0
  65. package/dist/utils/PageCache.js.map +1 -0
  66. package/dist/webex.js +1 -1
  67. package/package.json +9 -8
  68. package/src/cc.ts +220 -51
  69. package/src/constants.ts +1 -0
  70. package/src/index.ts +16 -2
  71. package/src/logger-proxy.ts +24 -1
  72. package/src/metrics/MetricsManager.ts +1 -1
  73. package/src/metrics/behavioral-events.ts +94 -0
  74. package/src/metrics/constants.ts +37 -1
  75. package/src/services/AddressBook.ts +291 -0
  76. package/src/services/EntryPoint.ts +241 -0
  77. package/src/services/Queue.ts +277 -0
  78. package/src/services/config/constants.ts +42 -2
  79. package/src/services/config/index.ts +30 -30
  80. package/src/services/config/types.ts +59 -58
  81. package/src/services/core/GlobalTypes.ts +27 -0
  82. package/src/services/core/Utils.ts +199 -1
  83. package/src/services/core/aqm-reqs.ts +0 -5
  84. package/src/services/core/websocket/WebSocketManager.ts +0 -4
  85. package/src/services/task/TaskManager.ts +79 -3
  86. package/src/services/task/constants.ts +6 -0
  87. package/src/services/task/contact.ts +80 -0
  88. package/src/services/task/index.ts +457 -57
  89. package/src/services/task/types.ts +135 -0
  90. package/src/types.ts +180 -0
  91. package/src/utils/PageCache.ts +252 -0
  92. package/test/unit/spec/cc.ts +282 -85
  93. package/test/unit/spec/metrics/MetricsManager.ts +0 -1
  94. package/test/unit/spec/metrics/behavioral-events.ts +42 -0
  95. package/test/unit/spec/services/AddressBook.ts +332 -0
  96. package/test/unit/spec/services/EntryPoint.ts +259 -0
  97. package/test/unit/spec/services/Queue.ts +323 -0
  98. package/test/unit/spec/services/config/index.ts +279 -65
  99. package/test/unit/spec/services/core/Utils.ts +50 -0
  100. package/test/unit/spec/services/core/aqm-reqs.ts +1 -3
  101. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +0 -4
  102. package/test/unit/spec/services/task/TaskManager.ts +145 -1
  103. package/test/unit/spec/services/task/contact.ts +31 -1
  104. package/test/unit/spec/services/task/index.ts +410 -123
  105. package/umd/contact-center.min.js +2 -2
  106. package/umd/contact-center.min.js.map +1 -1
@@ -1,7 +1,13 @@
1
1
  import EventEmitter from 'events';
2
2
  import {CALL_EVENT_KEYS, LocalMicrophoneStream} from '@webex/calling';
3
3
  import {CallId} from '@webex/calling/dist/types/common/types';
4
- import {getErrorDetails} from '../core/Utils';
4
+ import {
5
+ generateTaskErrorObject,
6
+ deriveConsultTransferDestinationType,
7
+ getDestinationAgentId,
8
+ buildConsultConferenceParamData,
9
+ } from '../core/Utils';
10
+ import {Failure} from '../core/GlobalTypes';
5
11
  import {LoginOption} from '../../types';
6
12
  import {TASK_FILE} from '../../constants';
7
13
  import {METHODS} from './constants';
@@ -19,14 +25,12 @@ import {
19
25
  ConsultEndPayload,
20
26
  TransferPayLoad,
21
27
  DESTINATION_TYPE,
22
- CONSULT_TRANSFER_DESTINATION_TYPE,
23
28
  ConsultTransferPayLoad,
24
29
  MEDIA_CHANNEL,
25
30
  } from './types';
26
31
  import WebCallingService from '../WebCallingService';
27
32
  import MetricsManager from '../../metrics/MetricsManager';
28
33
  import {METRIC_EVENT_NAMES} from '../../metrics/constants';
29
- import {Failure} from '../core/GlobalTypes';
30
34
  import AutoWrapup from './AutoWrapup';
31
35
  import {WrapupData} from '../config/types';
32
36
 
@@ -135,6 +139,7 @@ export default class Task extends EventEmitter implements ITask {
135
139
  public webCallMap: Record<TaskId, CallId>;
136
140
  private wrapupData: WrapupData;
137
141
  public autoWrapup?: AutoWrapup;
142
+ private agentId: string;
138
143
 
139
144
  /**
140
145
  * Creates a new Task instance which provides the following features:
@@ -147,7 +152,8 @@ export default class Task extends EventEmitter implements ITask {
147
152
  contact: ReturnType<typeof routingContact>,
148
153
  webCallingService: WebCallingService,
149
154
  data: TaskData,
150
- wrapupData: WrapupData
155
+ wrapupData: WrapupData,
156
+ agentId: string
151
157
  ) {
152
158
  super();
153
159
  this.contact = contact;
@@ -158,6 +164,7 @@ export default class Task extends EventEmitter implements ITask {
158
164
  this.metricsManager = MetricsManager.getInstance();
159
165
  this.registerWebCallListeners();
160
166
  this.setupAutoWrapupTimer();
167
+ this.agentId = agentId;
161
168
  }
162
169
 
163
170
  /**
@@ -373,17 +380,25 @@ export default class Task extends EventEmitter implements ITask {
373
380
 
374
381
  return Promise.resolve(); // TODO: reject for extension as part of refactor
375
382
  } catch (error) {
376
- const {error: detailedError} = getErrorDetails(error, METHODS.ACCEPT, TASK_FILE);
383
+ const err = generateTaskErrorObject(error, METHODS.ACCEPT, TASK_FILE);
384
+ const taskErrorProps = {
385
+ trackingId: err.data?.trackingId,
386
+ errorMessage: err.data?.message,
387
+ errorType: err.data?.errorType,
388
+ errorData: err.data?.errorData,
389
+ reasonCode: err.data?.reasonCode,
390
+ };
377
391
  this.metricsManager.trackEvent(
378
392
  METRIC_EVENT_NAMES.TASK_ACCEPT_FAILED,
379
393
  {
380
394
  taskId: this.data.interactionId,
381
395
  error: error.toString(),
396
+ ...taskErrorProps,
382
397
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details as Failure),
383
398
  },
384
399
  ['operational', 'behavioral', 'business']
385
400
  );
386
- throw detailedError;
401
+ throw err;
387
402
  }
388
403
  }
389
404
 
@@ -422,8 +437,8 @@ export default class Task extends EventEmitter implements ITask {
422
437
 
423
438
  return Promise.resolve();
424
439
  } catch (error) {
425
- const {error: detailedError} = getErrorDetails(error, METHODS.TOGGLE_MUTE, TASK_FILE);
426
- throw detailedError;
440
+ const err = generateTaskErrorObject(error, METHODS.TOGGLE_MUTE, TASK_FILE);
441
+ throw err;
427
442
  }
428
443
  }
429
444
 
@@ -470,17 +485,25 @@ export default class Task extends EventEmitter implements ITask {
470
485
 
471
486
  return Promise.resolve();
472
487
  } catch (error) {
473
- const {error: detailedError} = getErrorDetails(error, METHODS.DECLINE, TASK_FILE);
488
+ const err = generateTaskErrorObject(error, METHODS.DECLINE, TASK_FILE);
489
+ const taskErrorProps = {
490
+ trackingId: err.data?.trackingId,
491
+ errorMessage: err.data?.message,
492
+ errorType: err.data?.errorType,
493
+ errorData: err.data?.errorData,
494
+ reasonCode: err.data?.reasonCode,
495
+ };
474
496
  this.metricsManager.trackEvent(
475
497
  METRIC_EVENT_NAMES.TASK_DECLINE_FAILED,
476
498
  {
477
499
  taskId: this.data.interactionId,
478
500
  error: error.toString(),
501
+ ...taskErrorProps,
479
502
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
480
503
  },
481
504
  ['operational', 'behavioral']
482
505
  );
483
- throw detailedError;
506
+ throw err;
484
507
  }
485
508
  }
486
509
 
@@ -547,18 +570,26 @@ export default class Task extends EventEmitter implements ITask {
547
570
 
548
571
  return response;
549
572
  } catch (error) {
550
- const {error: detailedError} = getErrorDetails(error, METHODS.HOLD, TASK_FILE);
573
+ const err = generateTaskErrorObject(error, METHODS.HOLD, TASK_FILE);
574
+ const taskErrorProps = {
575
+ trackingId: err.data?.trackingId,
576
+ errorMessage: err.data?.message,
577
+ errorType: err.data?.errorType,
578
+ errorData: err.data?.errorData,
579
+ reasonCode: err.data?.reasonCode,
580
+ };
551
581
  this.metricsManager.trackEvent(
552
582
  METRIC_EVENT_NAMES.TASK_HOLD_FAILED,
553
583
  {
554
584
  taskId: this.data.interactionId,
555
585
  mediaResourceId: this.data.mediaResourceId,
556
586
  error: error.toString(),
587
+ ...taskErrorProps,
557
588
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
558
589
  },
559
590
  ['operational', 'behavioral']
560
591
  );
561
- throw detailedError;
592
+ throw err;
562
593
  }
563
594
  }
564
595
 
@@ -628,8 +659,15 @@ export default class Task extends EventEmitter implements ITask {
628
659
 
629
660
  return response;
630
661
  } catch (error) {
631
- const {error: detailedError} = getErrorDetails(error, METHODS.RESUME, TASK_FILE);
662
+ const err = generateTaskErrorObject(error, METHODS.RESUME, TASK_FILE);
632
663
  const mainInteractionId = this.data.interaction?.mainInteractionId;
664
+ const taskErrorProps = {
665
+ trackingId: err.data?.trackingId,
666
+ errorMessage: err.data?.message,
667
+ errorType: err.data?.errorType,
668
+ errorData: err.data?.errorData,
669
+ reasonCode: err.data?.reasonCode,
670
+ };
633
671
  this.metricsManager.trackEvent(
634
672
  METRIC_EVENT_NAMES.TASK_RESUME_FAILED,
635
673
  {
@@ -638,11 +676,12 @@ export default class Task extends EventEmitter implements ITask {
638
676
  mediaResourceId: mainInteractionId
639
677
  ? this.data.interaction.media[mainInteractionId].mediaResourceId
640
678
  : '',
679
+ ...taskErrorProps,
641
680
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
642
681
  },
643
682
  ['operational', 'behavioral']
644
683
  );
645
- throw detailedError;
684
+ throw err;
646
685
  }
647
686
  }
648
687
 
@@ -722,16 +761,24 @@ export default class Task extends EventEmitter implements ITask {
722
761
 
723
762
  return response;
724
763
  } catch (error) {
725
- const {error: detailedError} = getErrorDetails(error, METHODS.END, TASK_FILE);
764
+ const err = generateTaskErrorObject(error, METHODS.END, TASK_FILE);
765
+ const taskErrorProps = {
766
+ trackingId: err.data?.trackingId,
767
+ errorMessage: err.data?.message,
768
+ errorType: err.data?.errorType,
769
+ errorData: err.data?.errorData,
770
+ reasonCode: err.data?.reasonCode,
771
+ };
726
772
  this.metricsManager.trackEvent(
727
773
  METRIC_EVENT_NAMES.TASK_END_FAILED,
728
774
  {
729
775
  taskId: this.data.interactionId,
776
+ ...taskErrorProps,
730
777
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
731
778
  },
732
779
  ['operational', 'behavioral', 'business']
733
780
  );
734
- throw detailedError;
781
+ throw err;
735
782
  }
736
783
  }
737
784
 
@@ -826,18 +873,26 @@ export default class Task extends EventEmitter implements ITask {
826
873
 
827
874
  return response;
828
875
  } catch (error) {
829
- const {error: detailedError} = getErrorDetails(error, METHODS.WRAPUP, TASK_FILE);
876
+ const err = generateTaskErrorObject(error, METHODS.WRAPUP, TASK_FILE);
877
+ const taskErrorProps = {
878
+ trackingId: err.data?.trackingId,
879
+ errorMessage: err.data?.message,
880
+ errorType: err.data?.errorType,
881
+ errorData: err.data?.errorData,
882
+ reasonCode: err.data?.reasonCode,
883
+ };
830
884
  this.metricsManager.trackEvent(
831
885
  METRIC_EVENT_NAMES.TASK_WRAPUP_FAILED,
832
886
  {
833
887
  taskId: this.data.interactionId,
834
888
  wrapUpCode: wrapupPayload.auxCodeId,
835
889
  wrapUpReason: wrapupPayload.wrapUpReason,
890
+ ...taskErrorProps,
836
891
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
837
892
  },
838
893
  ['operational', 'behavioral', 'business']
839
894
  );
840
- throw detailedError;
895
+ throw err;
841
896
  }
842
897
  }
843
898
 
@@ -906,17 +961,25 @@ export default class Task extends EventEmitter implements ITask {
906
961
 
907
962
  return result;
908
963
  } catch (error) {
909
- const {error: detailedError} = getErrorDetails(error, METHODS.PAUSE_RECORDING, TASK_FILE);
964
+ const err = generateTaskErrorObject(error, METHODS.PAUSE_RECORDING, TASK_FILE);
965
+ const taskErrorProps = {
966
+ trackingId: err.data?.trackingId,
967
+ errorMessage: err.data?.message,
968
+ errorType: err.data?.errorType,
969
+ errorData: err.data?.errorData,
970
+ reasonCode: err.data?.reasonCode,
971
+ };
910
972
  this.metricsManager.trackEvent(
911
973
  METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_FAILED,
912
974
  {
913
975
  taskId: this.data.interactionId,
914
976
  error: error.toString(),
977
+ ...taskErrorProps,
915
978
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
916
979
  },
917
980
  ['operational', 'behavioral', 'business']
918
981
  );
919
- throw detailedError;
982
+ throw err;
920
983
  }
921
984
  }
922
985
 
@@ -997,17 +1060,25 @@ export default class Task extends EventEmitter implements ITask {
997
1060
 
998
1061
  return result;
999
1062
  } catch (error) {
1000
- const {error: detailedError} = getErrorDetails(error, METHODS.RESUME_RECORDING, TASK_FILE);
1063
+ const err = generateTaskErrorObject(error, METHODS.RESUME_RECORDING, TASK_FILE);
1064
+ const taskErrorProps = {
1065
+ trackingId: err.data?.trackingId,
1066
+ errorMessage: err.data?.message,
1067
+ errorType: err.data?.errorType,
1068
+ errorData: err.data?.errorData,
1069
+ reasonCode: err.data?.reasonCode,
1070
+ };
1001
1071
  this.metricsManager.trackEvent(
1002
1072
  METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_FAILED,
1003
1073
  {
1004
1074
  taskId: this.data.interactionId,
1005
1075
  error: error.toString(),
1076
+ ...taskErrorProps,
1006
1077
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
1007
1078
  },
1008
1079
  ['operational', 'behavioral', 'business']
1009
1080
  );
1010
- throw detailedError;
1081
+ throw err;
1011
1082
  }
1012
1083
  }
1013
1084
 
@@ -1082,7 +1153,14 @@ export default class Task extends EventEmitter implements ITask {
1082
1153
 
1083
1154
  return result;
1084
1155
  } catch (error) {
1085
- const {error: detailedError} = getErrorDetails(error, METHODS.CONSULT, TASK_FILE);
1156
+ const err = generateTaskErrorObject(error, METHODS.CONSULT, TASK_FILE);
1157
+ const taskErrorProps = {
1158
+ trackingId: err.data?.trackingId,
1159
+ errorMessage: err.data?.message,
1160
+ errorType: err.data?.errorType,
1161
+ errorData: err.data?.errorData,
1162
+ reasonCode: err.data?.reasonCode,
1163
+ };
1086
1164
  this.metricsManager.trackEvent(
1087
1165
  METRIC_EVENT_NAMES.TASK_CONSULT_START_FAILED,
1088
1166
  {
@@ -1090,11 +1168,12 @@ export default class Task extends EventEmitter implements ITask {
1090
1168
  destination: consultPayload.to,
1091
1169
  destinationType: consultPayload.destinationType,
1092
1170
  error: error.toString(),
1171
+ ...taskErrorProps,
1093
1172
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
1094
1173
  },
1095
1174
  ['operational', 'behavioral', 'business']
1096
1175
  );
1097
- throw detailedError;
1176
+ throw err;
1098
1177
  }
1099
1178
  }
1100
1179
 
@@ -1167,17 +1246,25 @@ export default class Task extends EventEmitter implements ITask {
1167
1246
 
1168
1247
  return result;
1169
1248
  } catch (error) {
1170
- const {error: detailedError} = getErrorDetails(error, METHODS.END_CONSULT, TASK_FILE);
1249
+ const err = generateTaskErrorObject(error, METHODS.END_CONSULT, TASK_FILE);
1250
+ const taskErrorProps = {
1251
+ trackingId: err.data?.trackingId,
1252
+ errorMessage: err.data?.message,
1253
+ errorType: err.data?.errorType,
1254
+ errorData: err.data?.errorData,
1255
+ reasonCode: err.data?.reasonCode,
1256
+ };
1171
1257
  this.metricsManager.trackEvent(
1172
1258
  METRIC_EVENT_NAMES.TASK_CONSULT_END_FAILED,
1173
1259
  {
1174
1260
  taskId: this.data.interactionId,
1175
1261
  error: error.toString(),
1262
+ ...taskErrorProps,
1176
1263
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
1177
1264
  },
1178
1265
  ['operational', 'behavioral', 'business']
1179
1266
  );
1180
- throw detailedError;
1267
+ throw err;
1181
1268
  }
1182
1269
  }
1183
1270
 
@@ -1258,7 +1345,14 @@ export default class Task extends EventEmitter implements ITask {
1258
1345
 
1259
1346
  return result;
1260
1347
  } catch (error) {
1261
- const {error: detailedError} = getErrorDetails(error, METHODS.TRANSFER, TASK_FILE);
1348
+ const err = generateTaskErrorObject(error, METHODS.TRANSFER, TASK_FILE);
1349
+ const taskErrorProps = {
1350
+ trackingId: err.data?.trackingId,
1351
+ errorMessage: err.data?.message,
1352
+ errorType: err.data?.errorType,
1353
+ errorData: err.data?.errorData,
1354
+ reasonCode: err.data?.reasonCode,
1355
+ };
1262
1356
  this.metricsManager.trackEvent(
1263
1357
  METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
1264
1358
  {
@@ -1267,11 +1361,12 @@ export default class Task extends EventEmitter implements ITask {
1267
1361
  destinationType: transferPayload.destinationType,
1268
1362
  isConsultTransfer: false,
1269
1363
  error: error.toString(),
1364
+ ...taskErrorProps,
1270
1365
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
1271
1366
  },
1272
1367
  ['operational', 'behavioral', 'business']
1273
1368
  );
1274
- throw detailedError;
1369
+ throw err;
1275
1370
  }
1276
1371
  }
1277
1372
 
@@ -1308,68 +1403,373 @@ export default class Task extends EventEmitter implements ITask {
1308
1403
  * ```
1309
1404
  */
1310
1405
  public async consultTransfer(
1311
- consultTransferPayload: ConsultTransferPayLoad
1406
+ consultTransferPayload?: ConsultTransferPayLoad
1312
1407
  ): Promise<TaskResponse> {
1313
1408
  try {
1314
- LoggerProxy.info(`Initiating consult transfer to ${consultTransferPayload.to}`, {
1315
- module: TASK_FILE,
1316
- method: METHODS.CONSULT_TRANSFER,
1317
- interactionId: this.data.interactionId,
1318
- });
1409
+ // Get the destination agent ID using custom logic from participants data
1410
+ const destAgentId = getDestinationAgentId(
1411
+ this.data.interaction?.participants,
1412
+ this.data.agentId
1413
+ );
1414
+
1415
+ // Resolve the target id (queue consult transfers go to the accepted agent)
1416
+ if (!destAgentId) {
1417
+ throw new Error('No agent has accepted this queue consult yet');
1418
+ }
1319
1419
 
1320
- // For queue destinations, use the destAgentId from task data
1321
- if (consultTransferPayload.destinationType === CONSULT_TRANSFER_DESTINATION_TYPE.QUEUE) {
1322
- if (!this.data.destAgentId) {
1323
- throw new Error('No agent has accepted this queue consult yet');
1420
+ LoggerProxy.info(
1421
+ `Initiating consult transfer to ${consultTransferPayload?.to || destAgentId}`,
1422
+ {
1423
+ module: TASK_FILE,
1424
+ method: METHODS.CONSULT_TRANSFER,
1425
+ interactionId: this.data.interactionId,
1324
1426
  }
1427
+ );
1428
+ // Obtain payload based on desktop logic using TaskData
1429
+ const finalDestinationType = deriveConsultTransferDestinationType(this.data);
1325
1430
 
1326
- // Override the destination with the agent who accepted the queue consult
1327
- consultTransferPayload = {
1328
- to: this.data.destAgentId,
1329
- destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
1330
- };
1331
- }
1431
+ // By default we always use the computed destAgentId as the target id
1432
+ const consultTransferRequest: ConsultTransferPayLoad = {
1433
+ to: destAgentId,
1434
+ destinationType: finalDestinationType,
1435
+ };
1332
1436
 
1333
1437
  const result = await this.contact.consultTransfer({
1334
1438
  interactionId: this.data.interactionId,
1335
- data: consultTransferPayload,
1439
+ data: consultTransferRequest,
1336
1440
  });
1337
1441
 
1338
1442
  this.metricsManager.trackEvent(
1339
1443
  METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS,
1340
1444
  {
1341
1445
  taskId: this.data.interactionId,
1342
- destination: consultTransferPayload.to,
1343
- destinationType: consultTransferPayload.destinationType,
1446
+ destination: consultTransferRequest.to,
1447
+ destinationType: consultTransferRequest.destinationType,
1344
1448
  isConsultTransfer: true,
1345
1449
  ...MetricsManager.getCommonTrackingFieldForAQMResponse(result),
1346
1450
  },
1347
1451
  ['operational', 'behavioral', 'business']
1348
1452
  );
1349
1453
 
1350
- LoggerProxy.log(`Consult transfer completed successfully to ${consultTransferPayload.to}`, {
1351
- module: TASK_FILE,
1352
- method: METHODS.CONSULT_TRANSFER,
1353
- trackingId: result.trackingId,
1354
- interactionId: this.data.interactionId,
1355
- });
1454
+ LoggerProxy.log(
1455
+ `Consult transfer completed successfully to ${consultTransferPayload?.to || destAgentId}`,
1456
+ {
1457
+ module: TASK_FILE,
1458
+ method: METHODS.CONSULT_TRANSFER,
1459
+ trackingId: result.trackingId,
1460
+ interactionId: this.data.interactionId,
1461
+ }
1462
+ );
1356
1463
 
1357
1464
  return result;
1358
1465
  } catch (error) {
1359
- const {error: detailedError} = getErrorDetails(error, METHODS.CONSULT_TRANSFER, TASK_FILE);
1466
+ const err = generateTaskErrorObject(error, METHODS.CONSULT_TRANSFER, TASK_FILE);
1467
+ const taskErrorProps = {
1468
+ trackingId: err.data?.trackingId,
1469
+ errorMessage: err.data?.message,
1470
+ errorType: err.data?.errorType,
1471
+ errorData: err.data?.errorData,
1472
+ reasonCode: err.data?.reasonCode,
1473
+ };
1474
+ const failedDestinationType = deriveConsultTransferDestinationType(this.data);
1475
+ const failedDestAgentId = getDestinationAgentId(
1476
+ this.data.interaction?.participants,
1477
+ this.data.agentId
1478
+ );
1360
1479
  this.metricsManager.trackEvent(
1361
1480
  METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
1362
1481
  {
1363
1482
  taskId: this.data.interactionId,
1364
- destination: consultTransferPayload.to,
1365
- destinationType: consultTransferPayload.destinationType,
1483
+ destination: failedDestAgentId || '',
1484
+ destinationType: failedDestinationType,
1366
1485
  isConsultTransfer: true,
1367
1486
  error: error.toString(),
1487
+ ...taskErrorProps,
1488
+ ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
1489
+ },
1490
+ ['operational', 'behavioral', 'business']
1491
+ );
1492
+ throw err;
1493
+ }
1494
+ }
1495
+
1496
+ /**
1497
+ * Starts a consultation conference by merging the consultation call with the main call
1498
+ *
1499
+ * Creates a three-way conference between the agent, customer, and consulted party
1500
+ * Extracts required consultation data from the current task data
1501
+ * On success, emits a `task:conferenceStarted` event
1502
+ *
1503
+ * @returns Promise<TaskResponse> - Response from the consultation conference API
1504
+ * @throws Error if the operation fails or if consultation data is invalid
1505
+ *
1506
+ * @example
1507
+ * ```typescript
1508
+ * try {
1509
+ * await task.consultConference();
1510
+ * console.log('Conference started successfully');
1511
+ * } catch (error) {
1512
+ * console.error('Failed to start conference:', error);
1513
+ * }
1514
+ * ```
1515
+ */
1516
+ public async consultConference(): Promise<TaskResponse> {
1517
+ // Extract consultation conference data from task data (used in both try and catch)
1518
+ const consultationData = {
1519
+ agentId: this.agentId,
1520
+ destAgentId: this.data.destAgentId,
1521
+ destinationType: this.data.destinationType || 'agent',
1522
+ };
1523
+
1524
+ try {
1525
+ LoggerProxy.info(`Initiating consult conference to ${consultationData.destAgentId}`, {
1526
+ module: TASK_FILE,
1527
+ method: METHODS.CONSULT_CONFERENCE,
1528
+ interactionId: this.data.interactionId,
1529
+ });
1530
+
1531
+ const paramsDataForConferenceV2 = buildConsultConferenceParamData(
1532
+ consultationData,
1533
+ this.data.interactionId
1534
+ );
1535
+
1536
+ const response = await this.contact.consultConference({
1537
+ interactionId: paramsDataForConferenceV2.interactionId,
1538
+ data: paramsDataForConferenceV2.data,
1539
+ });
1540
+
1541
+ // Track success metrics (following consultTransfer pattern)
1542
+ this.metricsManager.trackEvent(
1543
+ METRIC_EVENT_NAMES.TASK_CONFERENCE_START_SUCCESS,
1544
+ {
1545
+ taskId: this.data.interactionId,
1546
+ destination: paramsDataForConferenceV2.data.to,
1547
+ destinationType: paramsDataForConferenceV2.data.destinationType,
1548
+ agentId: paramsDataForConferenceV2.data.agentId,
1549
+ ...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
1550
+ },
1551
+ ['operational', 'behavioral', 'business']
1552
+ );
1553
+
1554
+ LoggerProxy.log(`Consult conference started successfully`, {
1555
+ module: TASK_FILE,
1556
+ method: METHODS.CONSULT_CONFERENCE,
1557
+ interactionId: this.data.interactionId,
1558
+ });
1559
+
1560
+ return response;
1561
+ } catch (error) {
1562
+ const err = generateTaskErrorObject(error, METHODS.CONSULT_CONFERENCE, TASK_FILE);
1563
+ const taskErrorProps = {
1564
+ trackingId: err.data?.trackingId,
1565
+ errorMessage: err.data?.message,
1566
+ errorType: err.data?.errorType,
1567
+ errorData: err.data?.errorData,
1568
+ reasonCode: err.data?.reasonCode,
1569
+ };
1570
+
1571
+ // Track failure metrics (following consultTransfer pattern)
1572
+ // Build conference data for error tracking using extracted data
1573
+ const failedParamsData = buildConsultConferenceParamData(
1574
+ consultationData,
1575
+ this.data.interactionId
1576
+ );
1577
+
1578
+ this.metricsManager.trackEvent(
1579
+ METRIC_EVENT_NAMES.TASK_CONFERENCE_START_FAILED,
1580
+ {
1581
+ taskId: this.data.interactionId,
1582
+ destination: failedParamsData.data.to,
1583
+ destinationType: failedParamsData.data.destinationType,
1584
+ agentId: failedParamsData.data.agentId,
1585
+ error: error.toString(),
1586
+ ...taskErrorProps,
1368
1587
  ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
1369
1588
  },
1370
1589
  ['operational', 'behavioral', 'business']
1371
1590
  );
1372
- throw detailedError;
1591
+
1592
+ LoggerProxy.error(`Failed to start consult conference`, {
1593
+ module: TASK_FILE,
1594
+ method: METHODS.CONSULT_CONFERENCE,
1595
+ interactionId: this.data.interactionId,
1596
+ });
1597
+
1598
+ throw err;
1373
1599
  }
1374
1600
  }
1601
+
1602
+ /**
1603
+ * Exits the current conference by removing the agent from the conference call
1604
+ *
1605
+ * Exits the agent from the conference, leaving the customer and consulted party connected
1606
+ * On success, emits a `task:conferenceEnded` event
1607
+ *
1608
+ * @returns Promise<TaskResponse> - Response from the conference exit API
1609
+ * @throws Error if the operation fails or if no active conference exists
1610
+ *
1611
+ * @example
1612
+ * ```typescript
1613
+ * try {
1614
+ * await task.exitConference();
1615
+ * console.log('Successfully exited conference');
1616
+ * } catch (error) {
1617
+ * console.error('Failed to exit conference:', error);
1618
+ * }
1619
+ * ```
1620
+ */
1621
+ public async exitConference(): Promise<TaskResponse> {
1622
+ try {
1623
+ LoggerProxy.info(`Exiting consult conference`, {
1624
+ module: TASK_FILE,
1625
+ method: METHODS.EXIT_CONFERENCE,
1626
+ interactionId: this.data.interactionId,
1627
+ });
1628
+
1629
+ // Validate that interaction ID exists
1630
+ if (!this.data.interactionId) {
1631
+ throw new Error('Invalid interaction ID');
1632
+ }
1633
+
1634
+ const response = await this.contact.exitConference({
1635
+ interactionId: this.data.interactionId,
1636
+ });
1637
+
1638
+ // Track success metrics (following consultTransfer pattern)
1639
+ this.metricsManager.trackEvent(
1640
+ METRIC_EVENT_NAMES.TASK_CONFERENCE_END_SUCCESS,
1641
+ {
1642
+ taskId: this.data.interactionId,
1643
+ ...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
1644
+ },
1645
+ ['operational', 'behavioral', 'business']
1646
+ );
1647
+
1648
+ LoggerProxy.log(`Consult conference exited successfully`, {
1649
+ module: TASK_FILE,
1650
+ method: METHODS.EXIT_CONFERENCE,
1651
+ interactionId: this.data.interactionId,
1652
+ });
1653
+
1654
+ return response;
1655
+ } catch (error) {
1656
+ const err = generateTaskErrorObject(error, METHODS.EXIT_CONFERENCE, TASK_FILE);
1657
+ const taskErrorProps = {
1658
+ trackingId: err.data?.trackingId,
1659
+ errorMessage: err.data?.message,
1660
+ errorType: err.data?.errorType,
1661
+ errorData: err.data?.errorData,
1662
+ reasonCode: err.data?.reasonCode,
1663
+ };
1664
+
1665
+ // Track failure metrics (following consultTransfer pattern)
1666
+ this.metricsManager.trackEvent(
1667
+ METRIC_EVENT_NAMES.TASK_CONFERENCE_END_FAILED,
1668
+ {
1669
+ taskId: this.data.interactionId,
1670
+ error: error.toString(),
1671
+ ...taskErrorProps,
1672
+ ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
1673
+ },
1674
+ ['operational', 'behavioral', 'business']
1675
+ );
1676
+
1677
+ LoggerProxy.error(`Failed to exit consult conference`, {
1678
+ module: TASK_FILE,
1679
+ method: METHODS.EXIT_CONFERENCE,
1680
+ interactionId: this.data.interactionId,
1681
+ });
1682
+
1683
+ throw err;
1684
+ }
1685
+ }
1686
+
1687
+ // TODO: Uncomment this method in future PR for Multi-Party Conference support (>3 participants)
1688
+ // Conference transfer will be supported when implementing enhanced multi-party conference functionality
1689
+ /*
1690
+ /**
1691
+ * Transfers the current conference to another agent
1692
+ *
1693
+ * Moves the entire conference (including all participants) to a new agent,
1694
+ * while the current agent exits and goes to wrapup
1695
+ * On success, the current agent receives `task:conferenceEnded` event
1696
+ *
1697
+ * @returns Promise<TaskResponse> - Response from the conference transfer API
1698
+ * @throws Error if the operation fails or if no active conference exists
1699
+ *
1700
+ * @example
1701
+ * ```typescript
1702
+ * try {
1703
+ * await task.transferConference();
1704
+ * console.log('Conference transferred successfully');
1705
+ * } catch (error) {
1706
+ * console.error('Failed to transfer conference:', error);
1707
+ * }
1708
+ * ```
1709
+ */
1710
+ /* public async transferConference(): Promise<TaskResponse> {
1711
+ try {
1712
+ LoggerProxy.info(`Transferring conference`, {
1713
+ module: TASK_FILE,
1714
+ method: METHODS.TRANSFER_CONFERENCE,
1715
+ interactionId: this.data.interactionId,
1716
+ });
1717
+
1718
+ // Validate that interaction ID exists
1719
+ if (!this.data.interactionId) {
1720
+ throw new Error('Invalid interaction ID');
1721
+ }
1722
+
1723
+ const response = await this.contact.conferenceTransfer({
1724
+ interactionId: this.data.interactionId,
1725
+ });
1726
+
1727
+ // Track success metrics (following consultTransfer pattern)
1728
+ this.metricsManager.trackEvent(
1729
+ METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_SUCCESS,
1730
+ {
1731
+ taskId: this.data.interactionId,
1732
+ ...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
1733
+ },
1734
+ ['operational', 'behavioral', 'business']
1735
+ );
1736
+
1737
+ LoggerProxy.log(`Conference transferred successfully`, {
1738
+ module: TASK_FILE,
1739
+ method: METHODS.TRANSFER_CONFERENCE,
1740
+ interactionId: this.data.interactionId,
1741
+ });
1742
+
1743
+ return response;
1744
+ } catch (error) {
1745
+ const err = generateTaskErrorObject(error, METHODS.TRANSFER_CONFERENCE, TASK_FILE);
1746
+ const taskErrorProps = {
1747
+ trackingId: err.data?.trackingId,
1748
+ errorMessage: err.data?.message,
1749
+ errorType: err.data?.errorType,
1750
+ errorData: err.data?.errorData,
1751
+ reasonCode: err.data?.reasonCode,
1752
+ };
1753
+
1754
+ // Track failure metrics (following consultTransfer pattern)
1755
+ this.metricsManager.trackEvent(
1756
+ METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_FAILED,
1757
+ {
1758
+ taskId: this.data.interactionId,
1759
+ error: error.toString(),
1760
+ ...taskErrorProps,
1761
+ ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
1762
+ },
1763
+ ['operational', 'behavioral', 'business']
1764
+ );
1765
+
1766
+ LoggerProxy.error(`Failed to transfer conference`, {
1767
+ module: TASK_FILE,
1768
+ method: METHODS.TRANSFER_CONFERENCE,
1769
+ interactionId: this.data.interactionId,
1770
+ });
1771
+
1772
+ throw err;
1773
+ }
1774
+ } */
1375
1775
  }