@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
@@ -4,12 +4,17 @@ import {Failure, AugmentedError} from './GlobalTypes';
4
4
  import LoggerProxy from '../../logger-proxy';
5
5
  import WebexRequest from './WebexRequest';
6
6
  import {
7
+ ConsultConferenceData,
8
+ consultConferencePayloadData,
9
+ ConsultTransferDestinationType,
7
10
  TaskData,
8
- ConsultTransferPayLoad,
9
11
  CONSULT_TRANSFER_DESTINATION_TYPE,
12
+ DESTINATION_TYPE,
10
13
  Interaction,
14
+ InteractionParticipant,
11
15
  } from '../task/types';
12
16
  import {PARTICIPANT_TYPES, STATE_CONSULT} from './constants';
17
+ import {DialPlan} from '../config/types';
13
18
 
14
19
  /**
15
20
  * Extracts common error details from a Webex request payload.
@@ -27,32 +32,71 @@ const getCommonErrorDetails = (errObj: WebexRequestPayload) => {
27
32
  };
28
33
 
29
34
  /**
30
- * Checks if the destination type represents an entry point variant (EPDN or ENTRYPOINT).
35
+ * Strips characters defined in the dial plan entry from the input string.
36
+ *
37
+ * @param input - The dial number to sanitize
38
+ * @param strippedChars - String of characters to remove from the input
39
+ * @returns The sanitized input with specified characters removed
31
40
  */
32
- const isEntryPointOrEpdn = (destAgentType?: string): boolean => {
33
- return destAgentType === 'EPDN' || destAgentType === 'ENTRYPOINT';
41
+ export const stripDialPlanChars = (input: string, strippedChars: string): string => {
42
+ if (!strippedChars) {
43
+ return input;
44
+ }
45
+
46
+ const charsToStrip = new Set(strippedChars.split(''));
47
+
48
+ return input
49
+ .split('')
50
+ .filter((c) => !charsToStrip.has(c))
51
+ .join('');
34
52
  };
35
53
 
36
54
  /**
37
- * Determines if the task involves dialing a number based on the destination type.
38
- * Returns 'DIAL_NUMBER' for dial-related destinations, empty string otherwise.
55
+ * Validates a dial number against the provided dial plan regex patterns.
56
+ * A number is valid if it matches at least one regex pattern in the dial plans.
57
+ * Skips validation when no dial plan entries are configured, deferring to the server.
58
+ *
59
+ * @param input - The dial number to validate
60
+ * @param dialPlanEntries - Array of dial plan entries containing regex patterns
61
+ * @returns true if the input matches at least one dial plan regex pattern or no entries are configured, false otherwise
39
62
  */
40
- const getAgentActionTypeFromTask = (taskData?: TaskData): 'DIAL_NUMBER' | '' => {
41
- const destAgentType = taskData?.destinationType;
63
+ export const isValidDialNumber = (
64
+ input: string,
65
+ dialPlanEntries: DialPlan['dialPlanEntity']
66
+ ): boolean => {
67
+ if (!input) {
68
+ LoggerProxy.warn('Dial number is empty or undefined.', {
69
+ module: 'Utils',
70
+ method: 'isValidDialNumber',
71
+ });
42
72
 
43
- // Check if destination requires dialing: direct dial number or entry point variants
44
- const isDialNumber = destAgentType === 'DN';
45
- const isEntryPointVariant = isEntryPointOrEpdn(destAgentType);
73
+ return false;
74
+ }
46
75
 
47
- // If the destination type is a dial number or an entry point variant, return 'DIAL_NUMBER'
48
- return isDialNumber || isEntryPointVariant ? 'DIAL_NUMBER' : '';
49
- };
76
+ if (!dialPlanEntries || dialPlanEntries.length === 0) {
77
+ LoggerProxy.log(
78
+ 'No dial plan entries found. Skipping client-side validation, deferring to server.',
79
+ {module: 'Utils', method: 'isValidDialNumber'}
80
+ );
50
81
 
51
- export const isValidDialNumber = (input: string): boolean => {
52
- // This regex checks for a valid dial number format for only few countries such as US, Canada.
53
- const regexForDn = /1[0-9]{3}[2-9][0-9]{6}([,]{1,10}[0-9]+){0,1}/;
82
+ return true;
83
+ }
54
84
 
55
- return regexForDn.test(input);
85
+ return dialPlanEntries.some((entry) => {
86
+ try {
87
+ const sanitizedInput = stripDialPlanChars(input, entry.strippedChars);
88
+ const regex = new RegExp(entry.regex);
89
+
90
+ return regex.test(sanitizedInput);
91
+ } catch (e) {
92
+ LoggerProxy.warn(`Failed to validate dial number against entry "${entry.name}": ${e}`, {
93
+ module: 'Utils',
94
+ method: 'isValidDialNumber',
95
+ });
96
+
97
+ return false;
98
+ }
99
+ });
56
100
  };
57
101
 
58
102
  export const getStationLoginErrorData = (failure: Failure, loginOption: LoginOption) => {
@@ -74,7 +118,7 @@ export const getStationLoginErrorData = (failure: Failure, loginOption: LoginOpt
74
118
  },
75
119
  INVALID_DIAL_NUMBER: {
76
120
  message:
77
- 'Enter a valid US dial number. For help, reach out to your administrator or support team.',
121
+ 'Enter a valid dial number. For help, reach out to your administrator or support team.',
78
122
  fieldName: loginOption,
79
123
  },
80
124
  };
@@ -216,6 +260,7 @@ export const createErrDetailsObject = (errObj: WebexRequestPayload) => {
216
260
  return new Err.Details('Service.reqs.generic.failure', details);
217
261
  };
218
262
 
263
+ /*
219
264
  /**
220
265
  * Gets the consulted agent ID from the media object by finding the agent
221
266
  * in the consult media participants (excluding the current agent).
@@ -294,9 +339,16 @@ export const calculateDestAgentId = (interaction: Interaction, agentId: string):
294
339
  return destAgentIdCBT;
295
340
  }
296
341
 
297
- return interaction.participants[consultingAgent]?.type === PARTICIPANT_TYPES.EP_DN
298
- ? interaction.participants[consultingAgent]?.epId
299
- : interaction.participants[consultingAgent]?.id;
342
+ const participant = interaction.participants[consultingAgent];
343
+ if (!participant) {
344
+ return '';
345
+ }
346
+
347
+ if (participant.type === PARTICIPANT_TYPES.EP_DN) {
348
+ return (participant as InteractionParticipant & {epId?: string}).epId ?? '';
349
+ }
350
+
351
+ return participant.id ?? '';
300
352
  };
301
353
 
302
354
  /**
@@ -331,16 +383,77 @@ export const calculateDestType = (interaction: Interaction, agentId: string): st
331
383
  return CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
332
384
  };
333
385
 
386
+ /**
387
+ * Gets the destination agent ID from participants.
388
+ * Finds a participant who is not the current agent and is an agent type.
389
+ *
390
+ * @param participants - The participants object from interaction
391
+ * @param agentId - The current agent's ID
392
+ * @returns The destination agent ID, or undefined if none found
393
+ */
394
+ export const buildConsultConferenceParamData = (
395
+ dataPassed: consultConferencePayloadData,
396
+ interactionIdPassed: string
397
+ ): {interactionId: string; data: ConsultConferenceData} => {
398
+ const data: ConsultConferenceData = {
399
+ ...('agentId' in dataPassed && {agentId: dataPassed.agentId}),
400
+ to: dataPassed.destAgentId,
401
+ destinationType: '',
402
+ };
403
+
404
+ if ('destinationType' in dataPassed) {
405
+ const destinationType = String(dataPassed.destinationType || '').trim();
406
+ const normalizedDestinationType = destinationType.toUpperCase().replace(/[-_\s]/g, '');
407
+
408
+ if (normalizedDestinationType === 'DN' || normalizedDestinationType === 'DIALNUMBER') {
409
+ data.destinationType = DESTINATION_TYPE.DIALNUMBER;
410
+ } else if (normalizedDestinationType === 'EPDN' || normalizedDestinationType === 'ENTRYPOINT') {
411
+ data.destinationType = DESTINATION_TYPE.ENTRYPOINT;
412
+ } else if (normalizedDestinationType === 'QUEUE') {
413
+ data.destinationType = DESTINATION_TYPE.QUEUE;
414
+ } else if (normalizedDestinationType === 'AGENT') {
415
+ data.destinationType = DESTINATION_TYPE.AGENT;
416
+ } else {
417
+ data.destinationType = destinationType as ConsultConferenceData['destinationType'];
418
+ }
419
+ } else {
420
+ data.destinationType = DESTINATION_TYPE.AGENT;
421
+ }
422
+
423
+ return {
424
+ interactionId: interactionIdPassed,
425
+ data,
426
+ };
427
+ };
428
+
429
+ /**
430
+ * Derives the consult transfer destination type based on task data.
431
+ * This function determines the appropriate destination type for a consult transfer
432
+ * by examining the destination type stored in the task data.
433
+ *
434
+ * @param taskData - The task data containing destination information
435
+ * @returns The derived consult transfer destination type
436
+ * @public
437
+ */
334
438
  export const deriveConsultTransferDestinationType = (
335
- taskData?: TaskData
336
- ): ConsultTransferPayLoad['destinationType'] => {
337
- const agentActionType = getAgentActionTypeFromTask(taskData);
338
-
339
- if (agentActionType === 'DIAL_NUMBER') {
340
- return isEntryPointOrEpdn(taskData?.destinationType)
341
- ? CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT
342
- : CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER;
439
+ taskData: TaskData
440
+ ): ConsultTransferDestinationType => {
441
+ const destType = taskData?.destinationType;
442
+ const normalizedDestType = String(destType || '')
443
+ .toUpperCase()
444
+ .replace(/[-_\s]/g, '');
445
+
446
+ // Map destination types to consult transfer destination types
447
+ if (normalizedDestType === 'DN' || normalizedDestType === 'DIALNUMBER') {
448
+ return CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER;
449
+ }
450
+ if (normalizedDestType === 'EPDN' || normalizedDestType === 'ENTRYPOINT') {
451
+ return CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT;
452
+ }
453
+ if (normalizedDestType === 'QUEUE') {
454
+ return CONSULT_TRANSFER_DESTINATION_TYPE.QUEUE;
343
455
  }
344
456
 
457
+ // Default to agent if no specific type matches
345
458
  return CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
346
459
  };
@@ -0,0 +1,381 @@
1
+ # Core Service - AI Agent Guide
2
+
3
+ > **Legacy/reference-only.** Canonical SDD: [`core-spec.md`](core-spec.md). Use the package [manifest](../../../../.sdd/manifest.json) and [`SPEC_INDEX.md`](../../../../ai-docs/SPEC_INDEX.md) for routing; code and tests remain the behavioral referee.
4
+ >
5
+ > **Legacy scope:** Core infrastructure components include WebSocket management, HTTP requests, error handling, and utilities. For repository rules and cross-service patterns, see the [root orchestrator AGENTS.md](../../../../AGENTS.md).
6
+
7
+ ---
8
+
9
+ ## Key Capabilities
10
+
11
+ The Core service provides the foundational infrastructure layer that all other services depend on:
12
+
13
+ - **WebSocket Communication**: Real-time bidirectional messaging with the contact center backend, including automatic reconnection and keepalive management
14
+ - **HTTP Request Handling**: Authenticated REST API calls to WCC API Gateway with built-in error handling and log upload support
15
+ - **AQM Request/Response Pattern**: A structured pattern used by the routing and contact layers to send HTTP requests to the contact center backend and correlate responses/failures via WebSocket notifications
16
+ - **Error Handling & Logging**: Standardized error extraction, logging via `LoggerProxy`, and log upload utilities that all services use for consistent error reporting
17
+
18
+ | Component | File | Description |
19
+ |-----------|------|-------------|
20
+ | `WebSocketManager` | [`WebSocketManager.ts`](../websocket/WebSocketManager.ts) | Manages the WebSocket connection lifecycle including initialization, message dispatch, and graceful shutdown. Emits `message` events for incoming data and `socketClose` when the connection drops while reconnect is allowed. |
21
+ | `ConnectionService` | [`connection-service.ts`](../websocket/connection-service.ts) | Orchestrates reconnection logic and keepalive heartbeats on top of `WebSocketManager`. Detects connection loss and triggers `silentRelogin()` to restore agent state transparently. |
22
+ | `WebexRequest` | [`WebexRequest.ts`](../WebexRequest.ts) | Singleton HTTP client that wraps authenticated requests to the WCC API Gateway. Handles service routing, response parsing, and provides a `uploadLogs` method for diagnostics. |
23
+ | `AqmReqs` | [`aqm-reqs.ts`](../aqm-reqs.ts) | Factory for creating request methods that send HTTP requests and wait for correlated WebSocket notifications (success or failure). Used by routing and task services to implement their API methods. |
24
+ | `Utils` | [`Utils.ts`](../Utils.ts) | Shared utility functions including `getErrorDetails()` for standardized error handling, `generateTaskErrorObject()` for task-specific errors, and `createErrDetailsObject()` for constructing error detail objects. |
25
+ | `Err` | [`Err.ts`](../Err.ts) | Error class definitions. `Err.Details` carries structured error metadata (status, type, trackingId) for consistent error propagation. |
26
+ | `constants` | [`constants.ts`](../constants.ts) | Timeout values, interval durations, participant types, interaction states, and method name constants used throughout the core layer. Any new constants for core should be defined here. |
27
+
28
+ ---
29
+
30
+ ## File Structure
31
+
32
+ ```
33
+ services/core/
34
+ ├── aqm-reqs.ts # AQM request handler
35
+ ├── constants.ts # Core constants
36
+ ├── Err.ts # Error classes
37
+ ├── GlobalTypes.ts # Failure, Msg<T>, etc.
38
+ ├── types.ts # Request/response types
39
+ ├── Utils.ts # Utility functions
40
+ ├── WebexRequest.ts # HTTP client
41
+ └── websocket/
42
+ ├── WebSocketManager.ts # Main WS handler
43
+ ├── connection-service.ts # Connection lifecycle
44
+ ├── keepalive.worker.js # Keepalive worker
45
+ └── types.ts # WS types
46
+ ```
47
+
48
+ ---
49
+
50
+
51
+ ## WebSocketManager
52
+
53
+ `WebSocketManager` handles the raw WebSocket connection to the contact center backend. It is instantiated by the `Services` layer and used internally — other services interact with it through `ConnectionService`.
54
+
55
+ ### Reference Usage
56
+
57
+ ```typescript
58
+ // Initialize in Services
59
+ this.webSocketManager = new WebSocketManager({webex});
60
+
61
+ // Connect
62
+ const welcomeEvent = await webSocketManager.initWebSocket({
63
+ body: connectionConfig,
64
+ });
65
+
66
+ // Listen for messages
67
+ webSocketManager.on('message', (event) => {
68
+ const data = JSON.parse(event);
69
+ // Handle event
70
+ });
71
+
72
+ // Close
73
+ webSocketManager.close(false, 'Reason');
74
+ ```
75
+
76
+ ### Events
77
+
78
+ | Event | Data | Description |
79
+ |-------|------|-------------|
80
+ | `message` | string (JSON) | WebSocket message received |
81
+ | `socketClose` | - | Socket closed while reconnect is allowed |
82
+
83
+ ### Connection Lifecycle
84
+
85
+ `WebSocketManager` and `ConnectionService` work together to manage the full connection lifecycle. `WebSocketManager` owns the raw socket while `ConnectionService` adds reconnection intelligence and keepalive on top.
86
+
87
+ **Connection Flow:**
88
+
89
+ ```
90
+ 1. initWebSocket() called
91
+ 2. ConnectionService listeners attached (`message`, `socketClose`) during construction
92
+ 3. WebSocket connects to backend
93
+ 4. Keepalive worker started on `onopen`
94
+ 5. Welcome event received
95
+ 6. Runtime messages/keepalive processed via existing listeners
96
+ ```
97
+
98
+ **Reconnection Flow:**
99
+
100
+ ```
101
+ 1. Connection lost detected
102
+ 2. ConnectionService emits 'connectionLost'
103
+ 3. cc.handleConnectionLost() called
104
+ 4. silentRelogin() attempted
105
+ 5. On success: state restored
106
+ 6. On AGENT_NOT_FOUND: handle silently
107
+ ```
108
+
109
+ ### Keepalive
110
+
111
+ A Web Worker ([`keepalive.worker.js`](../websocket/keepalive.worker.js)) runs alongside the WebSocket to detect connection loss and keep the socket alive. It starts on `onopen` and sends `{keepalive: 'true'}` to the backend every **4 seconds** (`KEEPALIVE_WORKER_INTERVAL`). The worker also monitors `navigator.onLine` — if the network goes offline and the socket doesn't close within **16 seconds** (`CLOSE_SOCKET_TIMEOUT`), it force-closes the socket.
112
+
113
+ On the receiving side, `ConnectionService.onPing()` listens for all WebSocket messages and resets two timers on each message:
114
+ - **`reconnectingTimer`** (8s / `WS_DISCONNECT_ALLOWED`) — if no message arrives within 8s, marks connection as lost
115
+ - **`restoreTimer`** (`lostConnectionRecoveryTimeout` from agent config) — if connection isn't restored within this window, marks restore as failed
116
+
117
+ When a keepalive response arrives after a lost-connection state, `ConnectionService` resets its flags and dispatches a recovery event. If the socket fully closes, `ConnectionService` retries `initWebSocket()` every **5 seconds** (`CONNECTIVITY_CHECK_INTERVAL`).
118
+
119
+ ---
120
+
121
+ ## WebexRequest
122
+
123
+ `WebexRequest` is a singleton HTTP client that all services use to make authenticated REST API calls to the contact center backend. It handles service URL resolution, request formatting, and response parsing.
124
+
125
+ ### The `service` Property
126
+
127
+ The `service` field in request options is a **service identifier string** that the Webex SDK's internal service catalog (`this.webex.request()`) resolves to a base URL at runtime. All contact center API calls use:
128
+
129
+ ```typescript
130
+ import {WCC_API_GATEWAY} from '../constants';
131
+ // WCC_API_GATEWAY = 'wcc-api-gateway'
132
+ ```
133
+
134
+ This constant is defined in [`services/constants.ts`](../../constants.ts). The Webex SDK maps `'wcc-api-gateway'` to the appropriate contact center API gateway URL based on the environment. The `resource` is then appended as the path.
135
+
136
+ ### Reference Usage
137
+
138
+ ```typescript
139
+ // Get singleton
140
+ const webexReq = WebexRequest.getInstance({webex});
141
+
142
+ // Make request
143
+ const response = await webexReq.request({
144
+ service: WCC_API_GATEWAY, // resolved to base URL by Webex SDK
145
+ resource: '/v1/endpoint', // appended as path
146
+ method: HTTP_METHODS.POST,
147
+ body: { key: 'value' }, // optional request payload
148
+ });
149
+
150
+ // Upload logs
151
+ await webexReq.uploadLogs({
152
+ correlationId: trackingId,
153
+ });
154
+ ```
155
+
156
+ ### Response Structure
157
+
158
+ ```typescript
159
+ {
160
+ statusCode: 200,
161
+ body: { /* response data */ },
162
+ headers: {
163
+ trackingid: 'uuid',
164
+ },
165
+ }
166
+ ```
167
+
168
+ ---
169
+
170
+ ## AqmReqs
171
+
172
+ The AQM (Agent Queue Manager) layer provides a request/response pattern over HTTP + WebSocket. Services like **routing** and **contact** use `AqmReqs` to define API methods that:
173
+
174
+ 1. Send an HTTP request to the contact center backend via `WebexRequest`
175
+ 2. Wait for a correlated WebSocket notification indicating success or failure
176
+ 3. Return the typed result or throw a structured error
177
+
178
+ This decouples the request initiation (HTTP) from the asynchronous result delivery (WebSocket), which matches the contact center backend's event-driven architecture.
179
+
180
+ ### Reference Usage
181
+
182
+ ```typescript
183
+ // Define request configuration
184
+ const serviceMethod = routing.req((p: {data: ParamType}) => ({
185
+ url: '/v1/endpoint',
186
+ host: WCC_API_GATEWAY,
187
+ data: p.data,
188
+ method: HTTP_METHODS.POST,
189
+ err: errorHandler,
190
+ notifSuccess: {
191
+ bind: {type: CC_EVENTS.SUCCESS, data: {type: CC_EVENTS.SUCCESS}},
192
+ msg: {} as SuccessType,
193
+ },
194
+ notifFail: {
195
+ bind: {type: CC_EVENTS.FAIL, data: {type: CC_EVENTS.FAIL}},
196
+ errId: 'Service.aqm.operation',
197
+ },
198
+ }));
199
+
200
+ // Call method
201
+ const result = await serviceMethod({data: params});
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Error Handling Utilities
207
+
208
+ ### `getErrorDetails()`
209
+
210
+ Standard error handler for SDK operations:
211
+
212
+ ```typescript
213
+ import {getErrorDetails} from './services/core/Utils';
214
+
215
+ try {
216
+ await operation();
217
+ } catch (error) {
218
+ const {error: detailedError, reason} = getErrorDetails(
219
+ error,
220
+ 'methodName', // Method name for logging
221
+ 'ModuleName' // Module name for logging
222
+ );
223
+
224
+ // getErrorDetails automatically:
225
+ // 1. Logs the error
226
+ // 2. Uploads logs (unless AGENT_NOT_FOUND in silentRelogin)
227
+ // 3. Extracts reason from error.details
228
+ // 4. Creates Error with reason as message
229
+
230
+ throw detailedError;
231
+ }
232
+ ```
233
+
234
+ ### `generateTaskErrorObject()`
235
+
236
+ Error handler for task operations:
237
+
238
+ ```typescript
239
+ import {generateTaskErrorObject} from './services/core/Utils';
240
+
241
+ try {
242
+ await taskOperation();
243
+ } catch (error) {
244
+ const taskError = generateTaskErrorObject(
245
+ error,
246
+ 'transfer',
247
+ 'TaskModule'
248
+ );
249
+ throw taskError;
250
+ }
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Type Definitions
256
+
257
+ ### Msg\<T\>
258
+
259
+ Generic message wrapper used throughout the SDK. All WebSocket messages and AQM responses conform to this shape:
260
+
261
+ ```typescript
262
+ export type Msg<T = any> = {
263
+ type: string; // Message/Event type identifier
264
+ orgId: string; // Organization identifier
265
+ trackingId: string; // Unique tracking identifier
266
+ data: T; // Message/Event payload data
267
+ };
268
+
269
+ // Usage — the payload type goes into `data`
270
+ export type LoginSuccess = Msg<{
271
+ agentId: string;
272
+ status: string;
273
+ // ...
274
+ }>;
275
+ // Resulting shape: { type, orgId, trackingId, data: { agentId, status, ... } }
276
+ ```
277
+
278
+ ### Failure
279
+
280
+ A specific `Msg<T>` for failure responses. Access error details via `failure.data`:
281
+
282
+ ```typescript
283
+ export type Failure = Msg<{
284
+ agentId: string;
285
+ trackingId: string;
286
+ reasonCode: number;
287
+ orgId: string;
288
+ reason: string;
289
+ }>;
290
+
291
+ // Usage in catch
292
+ const failure = error.details as Failure;
293
+ LoggerProxy.error(`Operation failed: ${failure.data?.reason}`, {
294
+ module: 'MyService',
295
+ method: 'myMethod',
296
+ trackingId: failure?.trackingId,
297
+ });
298
+ ```
299
+
300
+ ### AugmentedError
301
+
302
+ Error interface with a flexible data field for additional context:
303
+
304
+ ```typescript
305
+ export interface AugmentedError extends Error {
306
+ data?: Record<string, any>;
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Error Classes
313
+
314
+ ### Err.Details
315
+
316
+ ```typescript
317
+ import * as Err from './Err';
318
+
319
+ const error = new Err.Details('Service.aqm.agent.login', {
320
+ status: 401,
321
+ type: 'UNAUTHORIZED',
322
+ trackingId: 'uuid',
323
+ });
324
+ ```
325
+
326
+ ### createErrDetailsObject
327
+
328
+ ```typescript
329
+ import {createErrDetailsObject} from './Utils';
330
+
331
+ const errDetails = createErrDetailsObject(webexRequestPayload);
332
+ // Returns Err.Details with trackingId and body
333
+ ```
334
+
335
+ ---
336
+
337
+ ## Constants
338
+
339
+ All core-level constants (timeouts, intervals, participant types, method names) are defined in [`constants.ts`](../constants.ts). Any new constants for the core layer should be added there.
340
+
341
+ ---
342
+
343
+ ## Best Practices
344
+
345
+ ### Always Use Error Utilities
346
+
347
+ ```typescript
348
+ // Correct
349
+ const {error: detailedError} = getErrorDetails(error, method, module);
350
+ throw detailedError;
351
+
352
+ // Wrong - loses context
353
+ throw error;
354
+ ```
355
+
356
+ ### Check Response Status
357
+
358
+ ```typescript
359
+ const response = await webexReq.request({...});
360
+
361
+ if (response.statusCode !== 200) {
362
+ throw new Error(`API call failed with ${response.statusCode}`);
363
+ }
364
+ ```
365
+
366
+ ### Extract TrackingId
367
+
368
+ ```typescript
369
+ const trackingId = response.headers?.trackingid ||
370
+ response.headers?.TrackingID;
371
+ ```
372
+
373
+ ---
374
+
375
+ ## Related
376
+
377
+ - [Root Orchestrator AGENTS.md](../../../../AGENTS.md) - Task routing, critical rules, cross-service patterns
378
+ - [WebSocketManager.ts](../websocket/WebSocketManager.ts)
379
+ - [WebexRequest.ts](../WebexRequest.ts)
380
+ - [Utils.ts](../Utils.ts)
381
+ - [GlobalTypes.ts](../GlobalTypes.ts)