@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.
- package/.sdd/manifest.json +882 -0
- package/AGENTS.md +94 -0
- package/ai-docs/ARCHITECTURE.md +168 -0
- package/ai-docs/CONTRACTS.md +46 -0
- package/ai-docs/GETTING_STARTED.md +168 -0
- package/ai-docs/GLOSSARY.md +43 -0
- package/ai-docs/README.md +138 -0
- package/ai-docs/REVIEW_CHECKLIST.md +41 -0
- package/ai-docs/RULES.md +444 -0
- package/ai-docs/SECURITY.md +52 -0
- package/ai-docs/SERVICE_STATE.md +48 -0
- package/ai-docs/SPEC_INDEX.md +65 -0
- package/ai-docs/adr/0001-spec-source-policy.md +55 -0
- package/ai-docs/adr/README.md +8 -0
- package/ai-docs/adr/_adr-template.md +31 -0
- package/ai-docs/contact-center-spec.md +341 -0
- package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
- package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
- package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
- package/ai-docs/patterns/event-driven-patterns.md +485 -0
- package/ai-docs/patterns/testing-patterns.md +480 -0
- package/ai-docs/patterns/typescript-patterns.md +365 -0
- package/ai-docs/templates/README.md +102 -0
- package/ai-docs/templates/documentation/create-agents-md.md +240 -0
- package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
- package/ai-docs/templates/existing-service/bug-fix.md +254 -0
- package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
- package/ai-docs/templates/new-method/00-master.md +80 -0
- package/ai-docs/templates/new-method/01-requirements.md +232 -0
- package/ai-docs/templates/new-method/02-implementation.md +295 -0
- package/ai-docs/templates/new-method/03-tests.md +201 -0
- package/ai-docs/templates/new-method/04-validation.md +141 -0
- package/ai-docs/templates/new-service/00-master.md +109 -0
- package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
- package/ai-docs/templates/new-service/02-code-generation.md +346 -0
- package/ai-docs/templates/new-service/03-integration.md +178 -0
- package/ai-docs/templates/new-service/04-test-generation.md +205 -0
- package/ai-docs/templates/new-service/05-validation.md +145 -0
- package/dist/cc.js +379 -50
- package/dist/cc.js.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +22 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js +27 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +114 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +32 -3
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +318 -0
- package/dist/services/ApiAiAssistant.js.map +1 -0
- package/dist/services/UserPreference.js +427 -0
- package/dist/services/UserPreference.js.map +1 -0
- package/dist/services/agent/types.js.map +1 -1
- package/dist/services/config/Util.js +8 -4
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +35 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +41 -2
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +66 -8
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +27 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +122 -25
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +92 -17
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +22 -6
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/connection-service.js +3 -1
- package/dist/services/core/websocket/connection-service.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +6 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +688 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +45 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +751 -457
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +220 -23
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +23 -2
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/dialer.js +129 -0
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/digital/Digital.js +77 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +873 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +567 -0
- package/dist/services/task/state-machine/actions.js.map +1 -0
- package/dist/services/task/state-machine/constants.js +161 -0
- package/dist/services/task/state-machine/constants.js.map +1 -0
- package/dist/services/task/state-machine/guards.js +382 -0
- package/dist/services/task/state-machine/guards.js.map +1 -0
- package/dist/services/task/state-machine/index.js +53 -0
- package/dist/services/task/state-machine/index.js.map +1 -0
- package/dist/services/task/state-machine/types.js +54 -0
- package/dist/services/task/state-machine/types.js.map +1 -0
- package/dist/services/task/state-machine/uiControlsComputer.js +603 -0
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
- package/dist/services/task/taskDataNormalizer.js +99 -0
- package/dist/services/task/taskDataNormalizer.js.map +1 -0
- package/dist/services/task/types.js +227 -4
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1044 -0
- package/dist/services/task/voice/Voice.js.map +1 -0
- package/dist/services/task/voice/WebRTC.js +149 -0
- package/dist/services/task/voice/WebRTC.js.map +1 -0
- package/dist/types/cc.d.ts +894 -0
- package/dist/types/config.d.ts +72 -0
- package/dist/types/constants.d.ts +66 -0
- package/dist/types/index.d.ts +199 -0
- package/dist/types/logger-proxy.d.ts +71 -0
- package/dist/types/metrics/MetricsManager.d.ts +223 -0
- package/dist/types/metrics/behavioral-events.d.ts +29 -0
- package/dist/types/metrics/constants.d.ts +181 -0
- package/dist/types/services/AddressBook.d.ts +74 -0
- package/dist/types/services/ApiAiAssistant.d.ts +49 -0
- package/dist/types/services/EntryPoint.d.ts +67 -0
- package/dist/types/services/Queue.d.ts +76 -0
- package/dist/types/services/UserPreference.d.ts +118 -0
- package/dist/types/services/WebCallingService.d.ts +1 -0
- package/dist/types/services/agent/index.d.ts +46 -0
- package/dist/types/services/agent/types.d.ts +413 -0
- package/dist/types/services/config/Util.d.ts +20 -0
- package/dist/types/services/config/constants.d.ts +270 -0
- package/dist/types/services/config/index.d.ts +177 -0
- package/dist/types/services/config/types.d.ts +1368 -0
- package/dist/types/services/constants.d.ts +110 -0
- package/dist/types/services/core/Err.d.ts +125 -0
- package/dist/types/services/core/GlobalTypes.d.ts +58 -0
- package/dist/types/services/core/Utils.d.ts +121 -0
- package/dist/types/services/core/WebexRequest.d.ts +22 -0
- package/dist/types/services/core/aqm-reqs.d.ts +65 -0
- package/dist/types/services/core/constants.d.ts +99 -0
- package/dist/types/services/core/types.d.ts +47 -0
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +36 -0
- package/dist/types/services/core/websocket/connection-service.d.ts +27 -0
- package/dist/types/services/core/websocket/keepalive.worker.d.ts +2 -0
- package/dist/types/services/core/websocket/types.d.ts +37 -0
- package/dist/types/services/index.d.ts +54 -0
- package/dist/types/services/task/AutoWrapup.d.ts +40 -0
- package/dist/types/services/task/Task.d.ts +157 -0
- package/dist/types/services/task/TaskFactory.d.ts +12 -0
- package/dist/types/services/task/TaskManager.d.ts +1 -0
- package/dist/types/services/task/TaskUtils.d.ts +138 -0
- package/dist/types/services/task/constants.d.ts +91 -0
- package/dist/types/services/task/contact.d.ts +69 -0
- package/dist/types/services/task/dialer.d.ts +73 -0
- package/dist/types/services/task/digital/Digital.d.ts +22 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1194 -0
- package/dist/types/services/task/state-machine/actions.d.ts +10 -0
- package/dist/types/services/task/state-machine/constants.d.ts +107 -0
- package/dist/types/services/task/state-machine/guards.d.ts +102 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +269 -0
- package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
- package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
- package/dist/types/services/task/types.d.ts +1856 -0
- package/dist/types/services/task/voice/Voice.d.ts +184 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/types.d.ts +778 -0
- package/dist/types/utils/PageCache.d.ts +173 -0
- package/dist/types/webex-config.d.ts +53 -0
- package/dist/types/webex.d.ts +8 -0
- package/dist/types.js +130 -1
- package/dist/types.js.map +1 -1
- package/dist/webex.js +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +16 -12
- package/src/cc.ts +477 -51
- package/src/config.ts +6 -0
- package/src/constants.ts +21 -1
- package/src/index.ts +24 -5
- package/src/metrics/ai-docs/AGENTS.md +350 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
- package/src/metrics/ai-docs/metrics-spec.md +854 -0
- package/src/metrics/behavioral-events.ts +120 -0
- package/src/metrics/constants.ts +37 -3
- package/src/services/ApiAiAssistant.ts +412 -0
- package/src/services/UserPreference.ts +509 -0
- package/src/services/agent/ai-docs/AGENTS.md +240 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
- package/src/services/agent/ai-docs/agent-spec.md +504 -0
- package/src/services/agent/types.ts +1 -1
- package/src/services/ai-docs/AGENTS.md +386 -0
- package/src/services/ai-docs/services-spec.md +492 -0
- package/src/services/config/Util.ts +10 -2
- package/src/services/config/ai-docs/AGENTS.md +255 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
- package/src/services/config/ai-docs/config-spec.md +669 -0
- package/src/services/config/constants.ts +37 -1
- package/src/services/config/index.ts +45 -1
- package/src/services/config/types.ts +241 -11
- package/src/services/constants.ts +29 -0
- package/src/services/core/Err.ts +3 -0
- package/src/services/core/Utils.ts +143 -30
- package/src/services/core/ai-docs/AGENTS.md +381 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
- package/src/services/core/ai-docs/core-spec.md +783 -0
- package/src/services/core/aqm-reqs.ts +100 -22
- package/src/services/core/websocket/WebSocketManager.ts +23 -6
- package/src/services/core/websocket/connection-service.ts +5 -1
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +4 -0
- package/src/services/task/Task.ts +837 -0
- package/src/services/task/TaskFactory.ts +55 -0
- package/src/services/task/TaskManager.ts +793 -521
- package/src/services/task/TaskUtils.ts +314 -24
- package/src/services/task/ai-docs/AGENTS.md +457 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +594 -0
- package/src/services/task/ai-docs/task-spec.md +1319 -0
- package/src/services/task/constants.ts +23 -0
- package/src/services/task/dialer.ts +136 -1
- package/src/services/task/digital/Digital.ts +95 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +1166 -0
- package/src/services/task/state-machine/actions.ts +738 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +458 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1137 -0
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2177 -0
- package/src/services/task/state-machine/constants.ts +172 -0
- package/src/services/task/state-machine/guards.ts +445 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +243 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +961 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +734 -71
- package/src/services/task/voice/Voice.ts +1270 -0
- package/src/services/task/voice/WebRTC.ts +187 -0
- package/src/types.ts +205 -2
- package/src/utils/AGENTS.md +278 -0
- package/src/utils/ai-docs/utils-spec.md +381 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +503 -43
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +273 -0
- package/test/unit/spec/services/UserPreference.ts +401 -0
- package/test/unit/spec/services/WebCallingService.ts +7 -1
- package/test/unit/spec/services/config/index.ts +85 -29
- package/test/unit/spec/services/core/Utils.ts +481 -2
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +137 -41
- package/test/unit/spec/services/core/websocket/connection-service.ts +3 -1
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +477 -0
- package/test/unit/spec/services/task/TaskFactory.ts +62 -0
- package/test/unit/spec/services/task/TaskManager.ts +1001 -1003
- package/test/unit/spec/services/task/TaskUtils.ts +235 -0
- package/test/unit/spec/services/task/dialer.ts +372 -96
- package/test/unit/spec/services/task/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +2651 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +637 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2663 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +649 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/index.js +0 -1525
- package/dist/services/task/index.js.map +0 -1
- package/src/services/task/index.ts +0 -1801
- package/test/unit/spec/services/task/index.ts +0 -2184
|
@@ -1,7 +1,160 @@
|
|
|
1
1
|
/* eslint-disable import/prefer-default-export */
|
|
2
2
|
import {Interaction, ITask, TaskData, MEDIA_CHANNEL} from './types';
|
|
3
|
-
import {OUTDIAL_DIRECTION, OUTDIAL_MEDIA_TYPE, OUTBOUND_TYPE} from '../../constants';
|
|
4
3
|
import {LoginOption} from '../../types';
|
|
4
|
+
import {
|
|
5
|
+
PARTICIPANT_TYPE,
|
|
6
|
+
MEDIA_TYPE_MAIN_CALL,
|
|
7
|
+
CONSULT_STATE,
|
|
8
|
+
INTERACTION_STATE,
|
|
9
|
+
MEDIA_TYPE_CONSULT,
|
|
10
|
+
} from './state-machine/constants';
|
|
11
|
+
import {TaskContext} from './state-machine/types';
|
|
12
|
+
import {CC_EVENTS} from '../config/types';
|
|
13
|
+
import {OUTBOUND_TYPE, OUTDIAL_DIRECTION, OUTDIAL_MEDIA_TYPE} from '../../constants';
|
|
14
|
+
|
|
15
|
+
const CAMPAIGN_PREVIEW_OUTBOUND_TYPES = ['STANDARD_PREVIEW_CAMPAIGN', 'DIRECT_PREVIEW_CAMPAIGN'];
|
|
16
|
+
const CAMPAIGN_PREVIEW_CAMPAIGN_TYPES = ['preview_standard', 'preview_direct'];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Checks if the customer is still in the call (not left)
|
|
20
|
+
*
|
|
21
|
+
* @param interaction - The interaction object
|
|
22
|
+
* @param interactionId - The main interaction ID
|
|
23
|
+
* @returns true if customer is in the call
|
|
24
|
+
*/
|
|
25
|
+
export const getIsCustomerInCall = (interaction: Interaction, interactionId: string): boolean => {
|
|
26
|
+
const mainCallMedia = interaction.media?.[interactionId];
|
|
27
|
+
const participants = interaction.participants;
|
|
28
|
+
if (!mainCallMedia?.participants || !participants) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return mainCallMedia.participants.some((participantId: string) => {
|
|
33
|
+
const participant = participants[participantId];
|
|
34
|
+
|
|
35
|
+
return participant?.pType === PARTICIPANT_TYPE.CUSTOMER && !participant.hasLeft;
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Gets the count of active agent participants in the conference
|
|
41
|
+
* Excludes Customer, Supervisor, and VVA participant types
|
|
42
|
+
*
|
|
43
|
+
* @param interaction - The interaction object
|
|
44
|
+
* @param interactionId - The main interaction ID
|
|
45
|
+
* @returns Number of active agent participants
|
|
46
|
+
*/
|
|
47
|
+
export const getConferenceParticipantsCount = (
|
|
48
|
+
interaction: Interaction,
|
|
49
|
+
interactionId: string
|
|
50
|
+
): number => {
|
|
51
|
+
const mainCallMedia = interaction.media?.[interactionId];
|
|
52
|
+
const participants = interaction.participants;
|
|
53
|
+
if (!mainCallMedia?.participants || !participants) {
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let count = 0;
|
|
58
|
+
for (const participantId of mainCallMedia.participants) {
|
|
59
|
+
const participant = participants[participantId];
|
|
60
|
+
if (
|
|
61
|
+
participant &&
|
|
62
|
+
participant.pType !== PARTICIPANT_TYPE.CUSTOMER &&
|
|
63
|
+
participant.pType !== PARTICIPANT_TYPE.SUPERVISOR &&
|
|
64
|
+
participant.pType !== PARTICIPANT_TYPE.VVA &&
|
|
65
|
+
!participant.hasLeft
|
|
66
|
+
) {
|
|
67
|
+
count += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return count;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Determines if a consult is actively in-progress for conference control gating.
|
|
76
|
+
* This is used to disable conference controls (End/Consult) only when a consult leg
|
|
77
|
+
* still exists outside the main call participants.
|
|
78
|
+
*/
|
|
79
|
+
export const getIsConsultInProgressForConferenceControls = (
|
|
80
|
+
interaction: Interaction | undefined,
|
|
81
|
+
mainCallId: string | undefined,
|
|
82
|
+
selfAgentId: string | undefined
|
|
83
|
+
): boolean => {
|
|
84
|
+
if (!interaction || !mainCallId) return false;
|
|
85
|
+
|
|
86
|
+
const mainParticipants = interaction.media?.[mainCallId]?.participants;
|
|
87
|
+
if (!Array.isArray(mainParticipants) || mainParticipants.length === 0) return false;
|
|
88
|
+
|
|
89
|
+
const mainSet = new Set(mainParticipants);
|
|
90
|
+
const media = interaction.media;
|
|
91
|
+
if (!media) return false;
|
|
92
|
+
|
|
93
|
+
return Object.values(media).some((m: any) => {
|
|
94
|
+
if (!m || m.mType !== 'consult') return false;
|
|
95
|
+
if (!Array.isArray(m.participants) || m.participants.length === 0) return false;
|
|
96
|
+
|
|
97
|
+
return m.participants.some((participantId: string) => {
|
|
98
|
+
const p: any = interaction.participants?.[participantId];
|
|
99
|
+
if (!p || p.hasLeft) return false;
|
|
100
|
+
if (selfAgentId && participantId === selfAgentId) return false;
|
|
101
|
+
if (mainSet.has(participantId)) return false;
|
|
102
|
+
|
|
103
|
+
const participantType = String(p.pType ?? '').toUpperCase();
|
|
104
|
+
const isEpDnParticipant =
|
|
105
|
+
participantType === 'EP-DN' || participantType === 'EP_DN' || participantType === 'DN';
|
|
106
|
+
if (isEpDnParticipant) {
|
|
107
|
+
if (!selfAgentId) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
const selfConsultState = interaction.participants?.[selfAgentId]?.consultState as
|
|
111
|
+
| string
|
|
112
|
+
| undefined;
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
selfConsultState === 'consulting' ||
|
|
116
|
+
selfConsultState === 'conferencing' ||
|
|
117
|
+
selfConsultState === 'consultInitiated'
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const consultState = p.consultState as string | undefined;
|
|
122
|
+
const isRonaPendingConsultee = consultState === 'consultReserved' && p.hasJoined === false;
|
|
123
|
+
const consultLegActive =
|
|
124
|
+
consultState === 'consulting' ||
|
|
125
|
+
p.currentState === 'consulting' ||
|
|
126
|
+
(p.isConsulted === true && consultState !== 'consultCompleted' && !isRonaPendingConsultee);
|
|
127
|
+
|
|
128
|
+
return consultLegActive;
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const getIsConsultedAgentForControls = (
|
|
134
|
+
taskData: TaskData | null,
|
|
135
|
+
context: TaskContext,
|
|
136
|
+
isConsultingState: boolean
|
|
137
|
+
): boolean => {
|
|
138
|
+
return Boolean(taskData?.isConsulted) || (isConsultingState && !context.consultInitiator);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const getServerHoldStateForControls = (
|
|
142
|
+
context: TaskContext,
|
|
143
|
+
mainCallId?: string,
|
|
144
|
+
fallbackTaskData?: TaskData | null
|
|
145
|
+
): boolean | undefined => {
|
|
146
|
+
const media = context.taskData?.interaction?.media ?? fallbackTaskData?.interaction?.media;
|
|
147
|
+
if (!media) return undefined;
|
|
148
|
+
|
|
149
|
+
if (mainCallId && media[mainCallId]) {
|
|
150
|
+
return media[mainCallId].isHold ?? false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const mediaId = context.taskData?.mediaResourceId ?? fallbackTaskData?.mediaResourceId;
|
|
154
|
+
if (!mediaId) return undefined;
|
|
155
|
+
|
|
156
|
+
return media[mediaId]?.isHold;
|
|
157
|
+
};
|
|
5
158
|
|
|
6
159
|
/**
|
|
7
160
|
* Determines if the given agent is the primary agent (owner) of the task
|
|
@@ -31,7 +184,9 @@ export const isParticipantInMainInteraction = (task: ITask, agentId: string): bo
|
|
|
31
184
|
|
|
32
185
|
return Object.values(task.data.interaction.media).some(
|
|
33
186
|
(mediaObj) =>
|
|
34
|
-
mediaObj &&
|
|
187
|
+
mediaObj &&
|
|
188
|
+
mediaObj.mType === MEDIA_TYPE_MAIN_CALL &&
|
|
189
|
+
mediaObj.participants?.includes(agentId)
|
|
35
190
|
);
|
|
36
191
|
};
|
|
37
192
|
|
|
@@ -55,33 +210,110 @@ export const checkParticipantNotInInteraction = (task: ITask, agentId: string):
|
|
|
55
210
|
|
|
56
211
|
/**
|
|
57
212
|
* Determines if a conference is currently in progress based on the number of active agent participants
|
|
58
|
-
* @param
|
|
213
|
+
* @param data - The task data to check for conference status
|
|
59
214
|
* @returns true if there are 2 or more active agent participants in the main call, false otherwise
|
|
215
|
+
*
|
|
216
|
+
* For Agent B (consulted agent), their task's interactionId may be different from the main call.
|
|
217
|
+
* We use mainInteractionId from the interaction if available, otherwise fallback to interactionId.
|
|
60
218
|
*/
|
|
61
219
|
export const getIsConferenceInProgress = (data: TaskData): boolean => {
|
|
62
|
-
|
|
220
|
+
if (!data.interaction) return false;
|
|
221
|
+
|
|
222
|
+
const mainCallId = data.interaction.mainInteractionId || data.interactionId;
|
|
223
|
+
const mediaMainCall = data.interaction.media?.[mainCallId];
|
|
63
224
|
const participantsInMainCall = new Set(mediaMainCall?.participants);
|
|
64
|
-
const participants = data.interaction
|
|
225
|
+
const {participants} = data.interaction;
|
|
65
226
|
|
|
66
227
|
const agentParticipants = new Set();
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
}
|
|
228
|
+
participantsInMainCall.forEach((participantId: string) => {
|
|
229
|
+
const participant = participants[participantId];
|
|
230
|
+
if (
|
|
231
|
+
participant &&
|
|
232
|
+
participant.pType !== PARTICIPANT_TYPE.CUSTOMER &&
|
|
233
|
+
participant.pType !== PARTICIPANT_TYPE.SUPERVISOR &&
|
|
234
|
+
participant.pType !== PARTICIPANT_TYPE.VVA &&
|
|
235
|
+
!participant.hasLeft
|
|
236
|
+
) {
|
|
237
|
+
agentParticipants.add(participantId);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
81
240
|
|
|
82
241
|
return agentParticipants.size >= 2;
|
|
83
242
|
};
|
|
84
243
|
|
|
244
|
+
const EP_DN_MERGE_TERMINAL_CONSULT_EVENTS = new Set<string>([
|
|
245
|
+
CC_EVENTS.AGENT_CONSULT_ENDED,
|
|
246
|
+
CC_EVENTS.AGENT_CONSULT_CONFERENCE_ENDED,
|
|
247
|
+
]);
|
|
248
|
+
|
|
249
|
+
const isEpDnParticipantType = (pType: string | undefined): boolean => {
|
|
250
|
+
const normalized = String(pType ?? '').toUpperCase();
|
|
251
|
+
|
|
252
|
+
return normalized === 'EP-DN' || normalized === 'EP_DN' || normalized === 'DN';
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/** EP-DN consult merged to conference before a second agent joins the main leg (CAI-8329). */
|
|
256
|
+
export const isEpDnConsultPendingConferenceMerge = (
|
|
257
|
+
taskData: TaskData | undefined,
|
|
258
|
+
selfAgentId: string | undefined
|
|
259
|
+
): boolean => {
|
|
260
|
+
if (!taskData?.interaction || !selfAgentId) return false;
|
|
261
|
+
|
|
262
|
+
if (taskData.type && EP_DN_MERGE_TERMINAL_CONSULT_EVENTS.has(taskData.type)) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const interaction = taskData.interaction;
|
|
267
|
+
const mainCallId = interaction.mainInteractionId || taskData.interactionId;
|
|
268
|
+
if (!mainCallId) return false;
|
|
269
|
+
|
|
270
|
+
if (getConferenceParticipantsCount(interaction, mainCallId) > 1) return false;
|
|
271
|
+
|
|
272
|
+
const selfParticipant = interaction.participants?.[selfAgentId] as
|
|
273
|
+
| {consultState?: string}
|
|
274
|
+
| undefined;
|
|
275
|
+
if (taskData.isConsulted === true || selfParticipant?.consultState === 'consultCompleted') {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const mainParticipantIds = new Set(interaction.media?.[mainCallId]?.participants ?? []);
|
|
280
|
+
const hasEpDnOnConsultLegNotMain = Object.values(interaction.media ?? {}).some((media: any) => {
|
|
281
|
+
if (media?.mType !== MEDIA_TYPE_CONSULT) return false;
|
|
282
|
+
|
|
283
|
+
return (media.participants ?? []).some((participantId: string) => {
|
|
284
|
+
if (participantId === selfAgentId || mainParticipantIds.has(participantId)) return false;
|
|
285
|
+
const participant = interaction.participants?.[participantId] as
|
|
286
|
+
| {hasLeft?: boolean; pType?: string}
|
|
287
|
+
| undefined;
|
|
288
|
+
if (!participant || participant.hasLeft) return false;
|
|
289
|
+
|
|
290
|
+
return isEpDnParticipantType(participant.pType);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
if (!hasEpDnOnConsultLegNotMain) return false;
|
|
294
|
+
|
|
295
|
+
const callProcessingDetails = interaction.callProcessingDetails as
|
|
296
|
+
| {hasCustomerLeft?: string}
|
|
297
|
+
| undefined;
|
|
298
|
+
const customerLeft =
|
|
299
|
+
callProcessingDetails?.hasCustomerLeft === 'true' ||
|
|
300
|
+
!getIsCustomerInCall(interaction, mainCallId);
|
|
301
|
+
|
|
302
|
+
const conferenceFromPayload =
|
|
303
|
+
interaction.state === INTERACTION_STATE.CONFERENCE ||
|
|
304
|
+
getIsConferenceInProgress(taskData) ||
|
|
305
|
+
(interaction.state === INTERACTION_STATE.POST_CALL && customerLeft);
|
|
306
|
+
if (!conferenceFromPayload) return false;
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
taskData.consultingAgentId === selfAgentId ||
|
|
310
|
+
interaction.owner === selfAgentId ||
|
|
311
|
+
selfParticipant?.consultState === CONSULT_STATE.CONSULTING ||
|
|
312
|
+
selfParticipant?.consultState === CONSULT_STATE.CONFERENCING ||
|
|
313
|
+
selfParticipant?.consultState === 'consultInitiated'
|
|
314
|
+
);
|
|
315
|
+
};
|
|
316
|
+
|
|
85
317
|
/**
|
|
86
318
|
* Checks if the current agent is a secondary agent in a consultation scenario.
|
|
87
319
|
* Secondary agents are those who were consulted (not the original call owner).
|
|
@@ -103,17 +335,30 @@ export const isSecondaryAgent = (interaction: Interaction): boolean => {
|
|
|
103
335
|
/**
|
|
104
336
|
* Checks if the current agent is a secondary EP-DN (Entry Point Dial Number) agent.
|
|
105
337
|
* This is specifically for telephony consultations to external numbers/entry points.
|
|
106
|
-
* @param
|
|
338
|
+
* @param interaction - The interaction object
|
|
107
339
|
* @returns true if this is a secondary EP-DN agent in telephony consultation, false otherwise
|
|
108
340
|
*/
|
|
109
341
|
export const isSecondaryEpDnAgent = (interaction: Interaction): boolean => {
|
|
110
|
-
if (!interaction) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
342
|
return interaction.mediaType === 'telephony' && isSecondaryAgent(interaction);
|
|
115
343
|
};
|
|
116
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Checks if the task belongs to a campaign preview interaction.
|
|
347
|
+
* Campaign preview ContactEnded events are terminal cleanup events and should not trigger wrapup.
|
|
348
|
+
*/
|
|
349
|
+
export const isCampaignPreviewTask = (taskData?: TaskData | null): boolean => {
|
|
350
|
+
const outboundType = taskData?.interaction?.outboundType ?? '';
|
|
351
|
+
const cpd = taskData?.interaction?.callProcessingDetails as unknown as
|
|
352
|
+
| Record<string, string | undefined>
|
|
353
|
+
| undefined;
|
|
354
|
+
const campaignType = cpd?.campaignType ?? '';
|
|
355
|
+
|
|
356
|
+
return (
|
|
357
|
+
CAMPAIGN_PREVIEW_OUTBOUND_TYPES.includes(outboundType) ||
|
|
358
|
+
CAMPAIGN_PREVIEW_CAMPAIGN_TYPES.includes(campaignType)
|
|
359
|
+
);
|
|
360
|
+
};
|
|
361
|
+
|
|
117
362
|
/**
|
|
118
363
|
* Checks if auto-answer is enabled for the agent participant
|
|
119
364
|
* @param interaction - The interaction object
|
|
@@ -219,3 +464,48 @@ export const shouldAutoAnswerTask = (
|
|
|
219
464
|
|
|
220
465
|
return false;
|
|
221
466
|
};
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Gets the consult media resource ID for switch-call operations.
|
|
470
|
+
* Searches for the consult media leg in the interaction.
|
|
471
|
+
*
|
|
472
|
+
* @param interaction - The interaction object
|
|
473
|
+
* @param consultMediaResourceId - The consult media resource ID from task data
|
|
474
|
+
* @param agentId - Current agent ID
|
|
475
|
+
* @returns The consult media resource ID or undefined
|
|
476
|
+
*/
|
|
477
|
+
export const getConsultMediaResourceId = (
|
|
478
|
+
interaction: Interaction | undefined,
|
|
479
|
+
consultMediaResourceId: string | undefined,
|
|
480
|
+
agentId: string | undefined
|
|
481
|
+
): string | undefined => {
|
|
482
|
+
// First priority: use consultMediaResourceId from task data if available
|
|
483
|
+
if (consultMediaResourceId) {
|
|
484
|
+
return consultMediaResourceId;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Second priority: search for consult media leg in interaction.media
|
|
488
|
+
if (!interaction?.media || !agentId) {
|
|
489
|
+
return undefined;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Find the consult media leg where this agent is a participant
|
|
493
|
+
for (const [mediaId, media] of Object.entries(interaction.media)) {
|
|
494
|
+
if (media.mType === 'consult' && media.participants?.includes(agentId)) {
|
|
495
|
+
return mediaId;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return undefined;
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Checks if a task is a campaign preview reservation that has not yet been accepted.
|
|
504
|
+
* Campaign preview tasks should not trigger incoming call handling until the agent
|
|
505
|
+
* explicitly accepts the preview contact.
|
|
506
|
+
* @param task - The task to check
|
|
507
|
+
* @returns true if the task is a pending campaign preview reservation, false otherwise
|
|
508
|
+
*/
|
|
509
|
+
export const isCampaignPreviewReservation = (task: ITask): boolean => {
|
|
510
|
+
return task?.data?.type === CC_EVENTS.AGENT_OFFER_CAMPAIGN_RESERVATION;
|
|
511
|
+
};
|