@webex/contact-center 3.12.0-llmrefactor.12 → 3.12.0-llmrefactor.14
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 +6 -5
- package/ai-docs/CONTRACTS.md +8 -0
- package/ai-docs/SERVICE_STATE.md +4 -0
- package/ai-docs/contact-center-spec.md +26 -3
- package/ai-docs/features/contact-owner-change-refactor.md +78 -0
- package/dist/cc.js +202 -9
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +5 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +25 -10
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +6 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +6 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AnswerCallOnWebexService.js +4 -4
- package/dist/services/AnswerCallOnWebexService.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +116 -1
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/WebexCrossClientService.js +5 -2
- package/dist/services/WebexCrossClientService.js.map +1 -1
- package/dist/services/WxAppTelephonyMercurySync.js +6 -3
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -1
- package/dist/services/config/Util.js +5 -1
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +10 -1
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +51 -0
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +4 -3
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Utils.js +5 -1
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/task/TaskFactory.js +1 -0
- package/dist/services/task/TaskFactory.js.map +1 -1
- package/dist/services/task/TaskManager.js +50 -58
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +63 -44
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/services/task/voice/wxAppOfferObservability.js +145 -0
- package/dist/services/task/voice/wxAppOfferObservability.js.map +1 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js +52 -11
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -1
- package/dist/services/wxAppDiagnosticLogging.js +50 -13
- package/dist/services/wxAppDiagnosticLogging.js.map +1 -1
- package/dist/types/cc.d.ts +21 -1
- package/dist/types/constants.d.ts +4 -0
- package/dist/types/index.d.ts +11 -1
- package/dist/types/metrics/constants.d.ts +6 -0
- package/dist/types/services/ApiAiAssistant.d.ts +35 -2
- package/dist/types/services/config/constants.d.ts +5 -0
- package/dist/types/services/config/types.d.ts +15 -2
- package/dist/types/services/core/Utils.d.ts +2 -0
- package/dist/types/services/task/types.d.ts +2 -0
- package/dist/types/services/task/voice/Voice.d.ts +15 -2
- package/dist/types/services/task/voice/wxAppOfferObservability.d.ts +39 -0
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +19 -6
- package/dist/types/services/wxAppDiagnosticLogging.d.ts +12 -0
- package/dist/types/types.d.ts +56 -1
- package/dist/types.js +39 -2
- package/dist/types.js.map +1 -1
- package/dist/webex.js +9 -1
- package/dist/webex.js.map +1 -1
- package/package.json +9 -9
- package/src/cc.ts +294 -25
- package/src/constants.ts +4 -0
- package/src/index.ts +11 -0
- package/src/metrics/ai-docs/metrics-spec.md +61 -20
- package/src/metrics/behavioral-events.ts +6 -0
- package/src/metrics/constants.ts +6 -0
- package/src/services/AnswerCallOnWebexService.ts +4 -4
- package/src/services/ApiAiAssistant.ts +153 -1
- package/src/services/WebexCrossClientService.ts +7 -2
- package/src/services/WxAppTelephonyMercurySync.ts +3 -3
- package/src/services/ai-docs/services-spec.md +11 -3
- package/src/services/config/Util.ts +6 -0
- package/src/services/config/ai-docs/config-spec.md +14 -3
- package/src/services/config/constants.ts +12 -0
- package/src/services/config/index.ts +65 -0
- package/src/services/config/types.ts +13 -2
- package/src/services/core/Utils.ts +4 -0
- package/src/services/task/TaskFactory.ts +1 -0
- package/src/services/task/TaskManager.ts +85 -87
- package/src/services/task/ai-docs/task-spec.md +7 -3
- package/src/services/task/types.ts +16 -0
- package/src/services/task/voice/Voice.ts +74 -52
- package/src/services/task/voice/wxAppOfferObservability.ts +204 -0
- package/src/services/task/voice/wxAppVoiceMethods.ts +83 -24
- package/src/services/wxAppDiagnosticLogging.ts +135 -23
- package/src/types.ts +65 -0
- package/src/webex.js +8 -0
- package/test/unit/spec/cc.ts +469 -19
- package/test/unit/spec/services/ApiAiAssistant.ts +134 -2
- package/test/unit/spec/services/WebexCrossClientService.ts +45 -3
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +1 -1
- package/test/unit/spec/services/config/Util.ts +44 -0
- package/test/unit/spec/services/config/index.ts +68 -0
- package/test/unit/spec/services/task/TaskManager.ts +214 -3
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +33 -0
- package/test/unit/spec/services/task/voice/Voice.ts +10 -51
- package/test/unit/spec/services/task/voice/wxAppOfferObservability.ts +361 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +121 -5
- package/test/unit/spec/services/wxAppDiagnosticLogging.ts +44 -8
- package/test/unit/spec/wellnessSampleUtils.ts +288 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -690,6 +690,7 @@ class TaskManager extends _events.default {
|
|
|
690
690
|
const interactionId = message.data.interactionId;
|
|
691
691
|
const reservationInteractionId = message.data.reservationInteractionId;
|
|
692
692
|
let task = this.taskCollection[interactionId];
|
|
693
|
+
let ownerChangeResolvedByRelatedInteraction = false;
|
|
693
694
|
|
|
694
695
|
// When a campaign preview contact is accepted, the assigned event may arrive
|
|
695
696
|
// with a new interactionId while the task is stored under the original
|
|
@@ -703,7 +704,35 @@ class TaskManager extends _events.default {
|
|
|
703
704
|
}
|
|
704
705
|
}
|
|
705
706
|
if (!task && eventType === _types2.CC_EVENTS.CONTACT_OWNER_CHANGED) {
|
|
706
|
-
|
|
707
|
+
const incomingShowsCurrentAgentPromotion = Boolean(this.agentId && message.data.interaction?.owner === this.agentId && TaskManager.isParticipantActiveOnMainInteraction(message.data, this.agentId));
|
|
708
|
+
task = this.findUniqueTaskByRelatedInteraction(message.data, candidate => {
|
|
709
|
+
const currentAgentId = this.agentId || candidate.data?.agentId;
|
|
710
|
+
return Boolean(currentAgentId && (TaskManager.isParticipantActiveOnMainInteraction(candidate.data, currentAgentId) || incomingShowsCurrentAgentPromotion));
|
|
711
|
+
}, {
|
|
712
|
+
includeCollectionKeys: true,
|
|
713
|
+
includeMainCallMediaKeys: true
|
|
714
|
+
});
|
|
715
|
+
ownerChangeResolvedByRelatedInteraction = Boolean(task);
|
|
716
|
+
}
|
|
717
|
+
let ownerChangeMainInteractionId;
|
|
718
|
+
if (task && eventType === _types2.CC_EVENTS.CONTACT_OWNER_CHANGED) {
|
|
719
|
+
const taskMainInteractionId = task.data?.interaction?.mainInteractionId;
|
|
720
|
+
const payloadMainInteractionId = message.data.interaction?.mainInteractionId;
|
|
721
|
+
const hasConflictingMainInteractionIds = Boolean(taskMainInteractionId && payloadMainInteractionId && taskMainInteractionId !== payloadMainInteractionId);
|
|
722
|
+
// A promoted child task can retain stale embedded IDs. Prefer the
|
|
723
|
+
// authoritative incoming main-call identity before local snapshot IDs.
|
|
724
|
+
const stableMainInteractionId = payloadMainInteractionId || TaskManager.getMainCallMediaId(message.data.interaction) || TaskManager.getMainCallMediaId(task.data?.interaction) || taskMainInteractionId || message.data.interaction?.interactionId || task.data?.interaction?.interactionId || task.data?.interactionId;
|
|
725
|
+
const taskAtStableKey = stableMainInteractionId ? this.taskCollection[stableMainInteractionId] : undefined;
|
|
726
|
+
if (!stableMainInteractionId || hasConflictingMainInteractionIds || taskAtStableKey && taskAtStableKey !== task) {
|
|
727
|
+
_loggerProxy.default.warn('Unable to safely correlate owner change to the main interaction task', {
|
|
728
|
+
module: _constants.TASK_MANAGER_FILE,
|
|
729
|
+
method: 'prepareEventContext',
|
|
730
|
+
interactionId: payloadMainInteractionId || taskMainInteractionId || message.data.interactionId
|
|
731
|
+
});
|
|
732
|
+
task = undefined;
|
|
733
|
+
} else if (ownerChangeResolvedByRelatedInteraction) {
|
|
734
|
+
ownerChangeMainInteractionId = stableMainInteractionId;
|
|
735
|
+
}
|
|
707
736
|
}
|
|
708
737
|
if (!task && MAIN_INTERACTION_CORRELATED_EVENTS.has(eventType)) {
|
|
709
738
|
task = this.findUniqueTaskByRelatedInteraction(message.data);
|
|
@@ -722,8 +751,11 @@ class TaskManager extends _events.default {
|
|
|
722
751
|
...message.data,
|
|
723
752
|
wrapUpRequired: computeWrapUpRequired()
|
|
724
753
|
} : message.data;
|
|
725
|
-
if (task &&
|
|
726
|
-
adjustedPayload =
|
|
754
|
+
if (task && ownerChangeMainInteractionId) {
|
|
755
|
+
adjustedPayload = {
|
|
756
|
+
...adjustedPayload,
|
|
757
|
+
interactionId: ownerChangeMainInteractionId
|
|
758
|
+
};
|
|
727
759
|
}
|
|
728
760
|
if (task && eventType === _types2.CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE) {
|
|
729
761
|
adjustedPayload = TaskManager.preserveConfirmedOwner(task, adjustedPayload);
|
|
@@ -744,47 +776,12 @@ class TaskManager extends _events.default {
|
|
|
744
776
|
stateMachineEvent
|
|
745
777
|
};
|
|
746
778
|
}
|
|
747
|
-
|
|
748
|
-
/**
|
|
749
|
-
* ContactOwnerChanged can identify the promoted agent's child interaction while
|
|
750
|
-
* the surviving task is stored under the main interaction. Accept one related
|
|
751
|
-
* task when its existing snapshot or the authoritative incoming promotion proves
|
|
752
|
-
* current-agent main-call membership, while excluding non-promoted and ambiguous matches.
|
|
753
|
-
*/
|
|
754
|
-
findTaskForContactOwnerChange(payload) {
|
|
755
|
-
const relatedCandidates = this.findRelatedTasks(payload, {
|
|
756
|
-
includeCollectionKeys: true,
|
|
757
|
-
includeMainCallMediaKeys: true
|
|
758
|
-
});
|
|
759
|
-
const incomingShowsCurrentAgentPromotion = this.isCurrentAgentPromotedOnIncomingMainCall(payload);
|
|
760
|
-
const eligibleCandidates = relatedCandidates.filter(candidate => this.isCurrentAgentActiveOnMainInteraction(candidate.data) || incomingShowsCurrentAgentPromotion);
|
|
761
|
-
if (eligibleCandidates.length === 1) {
|
|
762
|
-
return eligibleCandidates[0];
|
|
763
|
-
}
|
|
764
|
-
if (eligibleCandidates.length > 1) {
|
|
765
|
-
_loggerProxy.default.warn('Unable to correlate task event to a unique main interaction task', {
|
|
766
|
-
module: _constants.TASK_MANAGER_FILE,
|
|
767
|
-
method: 'findTaskForContactOwnerChange',
|
|
768
|
-
interactionId: payload.interaction?.mainInteractionId || payload.interaction?.parentInteractionId || payload.interaction?.callProcessingDetails?.parentInteractionId || payload.interactionId
|
|
769
|
-
});
|
|
770
|
-
return undefined;
|
|
771
|
-
}
|
|
772
|
-
return undefined;
|
|
773
|
-
}
|
|
774
|
-
isCurrentAgentActiveOnMainInteraction(taskData) {
|
|
775
|
-
const currentAgentId = this.agentId || taskData?.agentId;
|
|
776
|
-
if (!currentAgentId) return false;
|
|
777
|
-
return TaskManager.isParticipantActiveOnMainInteraction(taskData, currentAgentId);
|
|
778
|
-
}
|
|
779
779
|
static isParticipantActiveOnMainInteraction(taskData, participantId) {
|
|
780
780
|
const interaction = taskData?.interaction;
|
|
781
781
|
const participant = interaction?.participants?.[participantId];
|
|
782
782
|
if (!participant || participant.hasLeft === true) return false;
|
|
783
783
|
return Object.values(interaction?.media ?? {}).some(media => media?.mType === _constants3.MEDIA_TYPE_MAIN_CALL && media.participants?.includes(participantId));
|
|
784
784
|
}
|
|
785
|
-
isCurrentAgentPromotedOnIncomingMainCall(payload) {
|
|
786
|
-
return Boolean(this.agentId && payload.interaction?.owner === this.agentId && TaskManager.isParticipantActiveOnMainInteraction(payload, this.agentId));
|
|
787
|
-
}
|
|
788
785
|
static getMainCallMediaId(interaction) {
|
|
789
786
|
return Object.entries(interaction?.media ?? {}).find(([, media]) => media?.mType === _constants3.MEDIA_TYPE_MAIN_CALL)?.[0];
|
|
790
787
|
}
|
|
@@ -797,22 +794,6 @@ class TaskManager extends _events.default {
|
|
|
797
794
|
return Boolean(this.agentId && stableInteractionId && interaction?.mediaType === _types.MEDIA_CHANNEL.TELEPHONY && interaction.isTerminated !== true && interaction.owner === this.agentId && TaskManager.isParticipantActiveOnMainInteraction(payload, this.agentId));
|
|
798
795
|
}
|
|
799
796
|
|
|
800
|
-
/** Keep a related owner-change event from re-keying the surviving main task to a child ID. */
|
|
801
|
-
static preserveMainTaskIdentity(task, payload) {
|
|
802
|
-
const currentMainInteractionId = task.data?.interaction?.mainInteractionId;
|
|
803
|
-
const payloadMainInteractionId = payload.interaction?.mainInteractionId;
|
|
804
|
-
const currentMainMediaId = TaskManager.getMainCallMediaId(task.data?.interaction);
|
|
805
|
-
const payloadMainMediaId = TaskManager.getMainCallMediaId(payload.interaction);
|
|
806
|
-
const stableInteractionId = currentMainInteractionId || payloadMainInteractionId || currentMainMediaId || payloadMainMediaId || payload.interaction?.interactionId || task.data?.interaction?.interactionId || task.data?.interactionId;
|
|
807
|
-
if (!stableInteractionId || stableInteractionId === payload.interactionId) {
|
|
808
|
-
return payload;
|
|
809
|
-
}
|
|
810
|
-
return {
|
|
811
|
-
...payload,
|
|
812
|
-
interactionId: stableInteractionId
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
|
|
816
797
|
/**
|
|
817
798
|
* ParticipantLeftConference may arrive after an owner update while still carrying
|
|
818
799
|
* the departed owner. Keep the confirmed owner only when the new roster proves that
|
|
@@ -845,8 +826,8 @@ class TaskManager extends _events.default {
|
|
|
845
826
|
* keys are handled before this fallback. Multiple aliases of the same task are
|
|
846
827
|
* treated as one candidate; genuinely ambiguous matches are intentionally ignored.
|
|
847
828
|
*/
|
|
848
|
-
findUniqueTaskByRelatedInteraction(payload, candidateFilter = () => true) {
|
|
849
|
-
const candidates = this.findRelatedTasks(payload).filter(candidateFilter);
|
|
829
|
+
findUniqueTaskByRelatedInteraction(payload, candidateFilter = () => true, options = {}) {
|
|
830
|
+
const candidates = this.findRelatedTasks(payload, options).filter(candidateFilter);
|
|
850
831
|
if (candidates.length === 1) {
|
|
851
832
|
return candidates[0];
|
|
852
833
|
}
|
|
@@ -864,12 +845,12 @@ class TaskManager extends _events.default {
|
|
|
864
845
|
includeCollectionKeys = false,
|
|
865
846
|
includeMainCallMediaKeys = false
|
|
866
847
|
} = options;
|
|
867
|
-
const payloadInteractionIds = new Set([payload.interactionId, payload.interaction?.interactionId, payload.interaction?.mainInteractionId, payload.interaction?.parentInteractionId, payload.interaction?.callProcessingDetails?.parentInteractionId, ...(includeMainCallMediaKeys ? [TaskManager.getMainCallMediaId(payload.interaction)] : [])].filter(
|
|
848
|
+
const payloadInteractionIds = new Set([payload.interactionId, payload.interaction?.interactionId, payload.interaction?.mainInteractionId, payload.interaction?.parentInteractionId, payload.interaction?.callProcessingDetails?.parentInteractionId, ...(includeMainCallMediaKeys ? [TaskManager.getMainCallMediaId(payload.interaction)] : [])].filter(relatedInteractionId => Boolean(relatedInteractionId)));
|
|
868
849
|
if (payloadInteractionIds.size === 0) return [];
|
|
869
850
|
return [...new Set(Object.entries(this.taskCollection).filter(([taskId, candidate]) => {
|
|
870
851
|
const taskInteraction = candidate?.data?.interaction;
|
|
871
852
|
const candidateInteractionIds = [...(includeCollectionKeys ? [taskId] : []), candidate?.data?.interactionId, taskInteraction?.interactionId, taskInteraction?.mainInteractionId, taskInteraction?.parentInteractionId, taskInteraction?.callProcessingDetails?.parentInteractionId, ...(includeMainCallMediaKeys ? [TaskManager.getMainCallMediaId(taskInteraction)] : [])];
|
|
872
|
-
return candidateInteractionIds.some(
|
|
853
|
+
return candidateInteractionIds.some(relatedInteractionId => Boolean(relatedInteractionId) && payloadInteractionIds.has(relatedInteractionId));
|
|
873
854
|
}).map(([, candidate]) => candidate))];
|
|
874
855
|
}
|
|
875
856
|
|
|
@@ -1180,6 +1161,7 @@ class TaskManager extends _events.default {
|
|
|
1180
1161
|
});
|
|
1181
1162
|
}
|
|
1182
1163
|
removeTaskFromCollection(task) {
|
|
1164
|
+
task.disposeWxAppOfferObservability?.();
|
|
1183
1165
|
if (typeof task.cancelAutoWrapupTimer === 'function') {
|
|
1184
1166
|
task.cancelAutoWrapupTimer();
|
|
1185
1167
|
}
|
|
@@ -1353,6 +1335,16 @@ class TaskManager extends _events.default {
|
|
|
1353
1335
|
TaskManager.syncWxAppMuteFromCallDetailsForTask(task);
|
|
1354
1336
|
});
|
|
1355
1337
|
}
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Re-run OFFERED wxApp offer diagnostics for collected voice tasks.
|
|
1341
|
+
* Used after usersub publish so pre-publish offers can schedule mismatch grace.
|
|
1342
|
+
*/
|
|
1343
|
+
refreshWxAppOfferObservabilityForAllTasks() {
|
|
1344
|
+
Object.values(this.taskCollection).forEach(task => {
|
|
1345
|
+
task.refreshWxAppOfferObservability?.();
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1356
1348
|
static getTaskManager(apiAIAssistant, contact, webCallingService, webSocketManager, rtdWebSocketManager) {
|
|
1357
1349
|
if (!TaskManager.taskManager) {
|
|
1358
1350
|
TaskManager.taskManager = new TaskManager(apiAIAssistant, contact, webCallingService, webSocketManager, rtdWebSocketManager);
|