@webex/contact-center 3.12.0-llmrefactor.2 → 3.12.0-llmrefactor.3
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 +5 -4
- package/ai-docs/ARCHITECTURE.md +1 -1
- package/ai-docs/CONTRACTS.md +5 -1
- package/ai-docs/SECURITY.md +1 -1
- package/ai-docs/contact-center-spec.md +22 -4
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/dist/cc.js +440 -10
- package/dist/cc.js.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +10 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +13 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +18 -15
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/AnswerCallOnWebexService.js +174 -0
- package/dist/services/AnswerCallOnWebexService.js.map +1 -0
- package/dist/services/EntryPoint.js +46 -68
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +27 -22
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/WebexCrossClientService.js +171 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +93 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/config/Util.js +3 -0
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +10 -6
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +4 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/WebexRequest.js +6 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +28 -14
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/task/Task.js +73 -7
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskFactory.js +8 -4
- package/dist/services/task/TaskFactory.js.map +1 -1
- package/dist/services/task/TaskManager.js +176 -20
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/WebexCallingUtils.js +70 -0
- package/dist/services/task/WebexCallingUtils.js.map +1 -0
- package/dist/services/task/constants.js +4 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +29 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/digital/Digital.js +3 -2
- package/dist/services/task/digital/Digital.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +135 -37
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +6 -1
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +38 -11
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/types.js.map +1 -1
- package/dist/services/task/state-machine/uiControlsComputer.js +118 -18
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/services/task/types.js +16 -1
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +350 -14
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/services/task/voice/WebRTC.js +4 -1
- package/dist/services/task/voice/WebRTC.js.map +1 -1
- package/dist/services/task/voice/wxAppVoiceMethods.js +201 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppTelephonyUtils.js +19 -0
- package/dist/services/wxAppTelephonyUtils.js.map +1 -0
- package/dist/types/cc.d.ts +77 -4
- package/dist/types/config.d.ts +7 -0
- package/dist/types/constants.d.ts +8 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/services/AddressBook.d.ts +2 -1
- package/dist/types/services/AnswerCallOnWebexService.d.ts +37 -0
- package/dist/types/services/EntryPoint.d.ts +7 -5
- package/dist/types/services/Queue.d.ts +5 -3
- package/dist/types/services/WebexCrossClientService.d.ts +28 -0
- package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
- package/dist/types/services/config/constants.d.ts +8 -5
- package/dist/types/services/config/types.d.ts +17 -4
- package/dist/types/services/core/Err.d.ts +2 -0
- package/dist/types/services/core/WebexRequest.d.ts +1 -0
- package/dist/types/services/core/types.d.ts +2 -0
- package/dist/types/services/task/Task.d.ts +20 -2
- package/dist/types/services/task/TaskFactory.d.ts +2 -1
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +3 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/digital/Digital.d.ts +2 -2
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +260 -56
- package/dist/types/services/task/state-machine/guards.d.ts +6 -5
- package/dist/types/services/task/state-machine/types.d.ts +9 -1
- package/dist/types/services/task/types.d.ts +81 -4
- package/dist/types/services/task/voice/Voice.d.ts +48 -9
- package/dist/types/services/task/voice/WebRTC.d.ts +2 -2
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +52 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +14 -8
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types.js +7 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +19 -5
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/cc.ts +506 -9
- package/src/config.ts +7 -0
- package/src/constants.ts +8 -0
- package/src/index.ts +2 -0
- package/src/metrics/ai-docs/metrics-spec.md +9 -3
- package/src/metrics/behavioral-events.ts +14 -0
- package/src/metrics/constants.ts +2 -0
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +206 -0
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/WebexCrossClientService.ts +212 -0
- package/src/services/WxAppTelephonyMercurySync.ts +115 -0
- package/src/services/ai-docs/AGENTS.md +10 -10
- package/src/services/ai-docs/services-spec.md +6 -1
- package/src/services/config/Util.ts +3 -0
- package/src/services/config/ai-docs/AGENTS.md +1 -1
- package/src/services/config/ai-docs/ARCHITECTURE.md +2 -2
- package/src/services/config/ai-docs/config-spec.md +6 -0
- package/src/services/config/constants.ts +10 -6
- package/src/services/config/types.ts +16 -4
- package/src/services/core/Err.ts +1 -0
- package/src/services/core/WebexRequest.ts +3 -1
- package/src/services/core/ai-docs/core-spec.md +5 -1
- package/src/services/core/aqm-reqs.ts +30 -15
- package/src/services/core/types.ts +2 -0
- package/src/services/task/Task.ts +79 -8
- package/src/services/task/TaskFactory.ts +8 -3
- package/src/services/task/TaskManager.ts +254 -15
- package/src/services/task/WebexCallingUtils.ts +136 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +1 -0
- package/src/services/task/ai-docs/task-spec.md +117 -2
- package/src/services/task/constants.ts +3 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/digital/Digital.ts +4 -2
- package/src/services/task/state-machine/TaskStateMachine.ts +210 -63
- package/src/services/task/state-machine/actions.ts +5 -2
- package/src/services/task/state-machine/ai-docs/AGENTS.md +8 -4
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +17 -8
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +46 -22
- package/src/services/task/state-machine/guards.ts +64 -11
- package/src/services/task/state-machine/types.ts +16 -1
- package/src/services/task/state-machine/uiControlsComputer.ts +206 -32
- package/src/services/task/types.ts +114 -4
- package/src/services/task/voice/Voice.ts +462 -12
- package/src/services/task/voice/WebRTC.ts +5 -1
- package/src/services/task/voice/wxAppVoiceMethods.ts +307 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +33 -9
- package/src/utils/AGENTS.md +21 -10
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +21 -11
- package/test/unit/spec/cc.ts +1274 -0
- package/test/unit/spec/metrics/behavioral-events.ts +18 -0
- package/test/unit/spec/services/AddressBook.ts +37 -6
- package/test/unit/spec/services/AnswerCallOnWebexService.ts +223 -0
- package/test/unit/spec/services/EntryPoint.ts +87 -40
- package/test/unit/spec/services/Queue.ts +123 -12
- package/test/unit/spec/services/WebexCrossClientService.ts +261 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +113 -0
- package/test/unit/spec/services/config/Util.ts +85 -0
- package/test/unit/spec/services/core/WebexRequest.ts +3 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
- package/test/unit/spec/services/task/Task.ts +200 -0
- package/test/unit/spec/services/task/TaskFactory.ts +39 -2
- package/test/unit/spec/services/task/TaskManager.ts +653 -1
- package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
- package/test/unit/spec/services/task/contact.ts +33 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +854 -72
- package/test/unit/spec/services/task/state-machine/guards.ts +210 -8
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +445 -7
- package/test/unit/spec/services/task/voice/Voice.ts +874 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +459 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -33,7 +33,7 @@ Manage task lifecycle including inbound/outbound calls, hold/resume, consult, tr
|
|
|
33
33
|
|
|
34
34
|
- **Event Emission and Public APIs**: Task objects register listeners, update context, emit SDK events (e.g., `task:*`), and expose public methods that delegate to `contact.ts` for call control and to the state machine for transition validation.
|
|
35
35
|
|
|
36
|
-
- **AQM Contact Operations**: `contact.ts` builds the AQM request surface for call control (accept, hold, consult, transfer, wrapup, end) and is the primary bridge from `Task`/`Voice`/`WebRTC`/`Digital` methods to WCC task APIs.
|
|
36
|
+
- **AQM Contact Operations**: `contact.ts` builds the AQM request surface for call control (accept, hold, consult, transfer, participant Drop, wrapup, end) and is the primary bridge from `Task`/`Voice`/`WebRTC`/`Digital` methods to WCC task APIs.
|
|
37
37
|
|
|
38
38
|
- **Outbound and Preview-Campaign Dialing**: `dialer.ts` exposes `startOutdial` plus `acceptPreviewContact`, `skipPreviewContact`, and `removePreviewContact`; ContactCenter publishes these operations through typed `cc` methods.
|
|
39
39
|
|
|
@@ -141,6 +141,8 @@ services/task/
|
|
|
141
141
|
|---|---|---|---|---|---|---|
|
|
142
142
|
| `task.surface` | SDK / event / internal API | Exported Task/types/events plus application-facing task instances and call-control methods. | Stable module consumption boundary. | Additive changes by default; breaking package exports require a major-version transition. | `src/services/task/Task.ts` | `../../../../ai-docs/CONTRACTS.md` |
|
|
143
143
|
| `task.preview-campaign` | SDK/AQM API | `acceptPreviewContact`, `skipPreviewContact`, `removePreviewContact`, and `PreviewContactPayload`. | Accept, skip, or remove a reserved campaign preview contact; each method returns `Promise<TaskResponse>`. | Additive semver-public methods; removals or signature changes are breaking. | `src/cc.ts`, `src/services/task/dialer.ts`, `src/services/task/types.ts` | `../../../../ai-docs/CONTRACTS.md` |
|
|
144
|
+
| `task.consult-transfer-controls` | SDK task controls | `TaskUIControls.consultTransferDestinations` with ordered `consult` and `transfer` arrays. | Surface default destination availability on every Task without an extra policy method. | Additive semver-public field/types; array order is meaningful and the first item is the default. | `src/services/task/types.ts`, `src/services/task/state-machine/uiControlsComputer.ts` | `../../../../ai-docs/CONTRACTS.md` |
|
|
145
|
+
| `task.conference-participant-drop` | SDK/AQM API | `task.dropConferenceParticipant(payload: DropConferenceParticipantPayload): Promise<TaskResponse>`. | Remove a supported target from a voice conference after correlated routing completion. | Additive semver-public method and payload; removals or signature changes are breaking. | `src/services/task/voice/Voice.ts`, `src/services/task/contact.ts`, `src/services/task/types.ts` | `../../../../ai-docs/CONTRACTS.md` |
|
|
144
146
|
|
|
145
147
|
Compatibility notes:
|
|
146
148
|
- Do not remove or reinterpret exported symbols/events without a documented consumer migration.
|
|
@@ -151,6 +153,8 @@ Compatibility notes:
|
|
|
151
153
|
|
|
152
154
|
- `PreviewContactPayload` (`types.ts`) with `interactionId` and campaign-name `campaignId`
|
|
153
155
|
|
|
156
|
+
- `DropConferenceParticipantPayload` (`types.ts`) with a runtime-validated non-empty `participantId`
|
|
157
|
+
|
|
154
158
|
- `ITask`, `IVoice`, `IWebRTC`, `IDigital` (`types.ts`)
|
|
155
159
|
|
|
156
160
|
- `MEDIA_CHANNEL`, `TASK_CHANNEL_TYPE`, `VOICE_VARIANT` (`types.ts`)
|
|
@@ -346,6 +350,20 @@ End consultation without transfer.
|
|
|
346
350
|
|
|
347
351
|
**Returns**: `Promise<TaskResponse>`
|
|
348
352
|
|
|
353
|
+
Remove another participant from a voice conference.
|
|
354
|
+
|
|
355
|
+
**Parameters**:
|
|
356
|
+
|
|
357
|
+
- `participantId` (string, required): backend participant target identifier; blank and non-string values reject before AQM registration or telemetry.
|
|
358
|
+
|
|
359
|
+
**Returns**: `Promise<TaskResponse>` after `ParticipantLeftConference` is received for the latest `interaction.mainInteractionId || task.data.interactionId`.
|
|
360
|
+
|
|
361
|
+
**Failure**: `ParticipantDropConferenceFailed`, HTTP rejection, or the default 20-second AQM timeout rejects the promise. The operation does not add a task state-machine event or optimistically change the roster.
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
await task.dropConferenceParticipant({participantId});
|
|
365
|
+
```
|
|
366
|
+
|
|
349
367
|
### Complete TASK_EVENTS inventory
|
|
350
368
|
|
|
351
369
|
The public `TASK_EVENTS` enum contains 49 members; every member is listed below from `src/services/task/types.ts`.
|
|
@@ -417,6 +435,8 @@ The public `TASK_EVENTS` enum contains 49 members; every member is listed below
|
|
|
417
435
|
| TASK-R-005 | The contact dependency belongs to Task/TaskFactory-created tasks; dialer is an AqmReqs request factory without that constructor. | Misattributing constructor dependencies causes invalid instantiation examples. | `src/services/task/TaskFactory.ts` | `test/unit/spec/services/task/dialer.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
418
436
|
| TASK-R-006 | Keep credentials and authentication outside Task; remote operations delegate through contact/dialer routing, AqmReqs, and Core/WebexRequest. | Task lifecycle objects should never duplicate host token handling or leak authentication state into interaction data. | `src/services/task/Task.ts`, `src/services/task/contact.ts`, `src/services/core/WebexRequest.ts` | `test/unit/spec/services/task/Task.ts`, `test/unit/spec/services/task/contact.ts` | None; authentication ownership is explicit. | PRESENT |
|
|
419
437
|
| TASK-R-007 | Route enabled preview-campaign accept, skip, and remove operations through the dialer AQM factory using `PreviewContactPayload`, returning `Promise<TaskResponse>` from the public ContactCenter methods. Before routing skip/remove, reject the operation when the matching task's disable flag is `'true'`. | Preview reservations require typed payloads and correlated backend completion, while campaign controls must block prohibited skip/remove requests before transport begins. | `src/cc.ts`, `src/services/task/dialer.ts`, `src/services/task/types.ts` | `test/unit/spec/cc.ts`, `test/unit/spec/services/task/dialer.ts` | Public delegation and dialer requests are covered; the `campaignPreviewSkipDisabled` and `campaignPreviewRemoveDisabled` early-exit guards lack direct unit coverage. Independent review identified this gap on 2026-07-15. | PRESENT |
|
|
438
|
+
| TASK-R-008 | Voice `dropConferenceParticipant` must validate the public target, resolve the latest main interaction, POST an empty body to the encoded participant-drop route, and settle only from `ParticipantLeftConference`, `ParticipantDropConferenceFailed`, HTTP failure, or the existing AQM timeout. | Participant removal is backend-authoritative and must preserve event-driven roster/state synchronization without exposing participant identifiers through telemetry or logs. | `src/services/task/voice/Voice.ts`, `src/services/task/contact.ts`, `src/services/task/types.ts` | `test/unit/spec/services/task/voice/Voice.ts`, `test/unit/spec/services/task/contact.ts`, `test/unit/spec/services/core/aqm-reqs.ts` | Backend authorization and media removal are remote-service responsibilities. | PRESENT |
|
|
439
|
+
| TASK-R-009 | ContactCenter must inject Desktop Profile collaboration policy into TaskFactory, and every created voice/digital Task must expose ordered Consult and Transfer destination categories through `TaskUIControls.consultTransferDestinations`. | Task consumers need one already-computed policy surface and must not fetch profile flags or duplicate destination decisions. | `src/cc.ts`, `src/services/task/TaskFactory.ts`, `src/services/task/types.ts` | `test/unit/spec/cc.ts`, `test/unit/spec/services/task/TaskFactory.ts` | Host-specific UI options may only further hide an SDK-allowed category. | PRESENT |
|
|
420
440
|
|
|
421
441
|
## Design Overview
|
|
422
442
|
Task separates its stable consumption boundary from collaborators so ownership and failure behavior stay explicit. A shared Task base preserves a stable API while media-specific subclasses and a separate state engine enforce capability differences.
|
|
@@ -494,6 +514,8 @@ Returns an object of AQM request methods wired to `TASK_API` and `TASK_MESSAGE_T
|
|
|
494
514
|
|
|
495
515
|
- `consultConference`
|
|
496
516
|
|
|
517
|
+
- `dropConferenceParticipant`
|
|
518
|
+
|
|
497
519
|
- `exitConference`
|
|
498
520
|
|
|
499
521
|
- `conferenceTransfer`
|
|
@@ -532,6 +554,8 @@ Uses `contact` for:
|
|
|
532
554
|
|
|
533
555
|
- `consultConference`, `exitConference`, `conferenceTransfer`
|
|
534
556
|
|
|
557
|
+
- `dropConferenceParticipant` (Voice only; base Task rejects as unsupported)
|
|
558
|
+
|
|
535
559
|
Uses `contact.accept` in `accept()`.
|
|
536
560
|
|
|
537
561
|
TaskManager maintains a map of active tasks:
|
|
@@ -588,6 +612,14 @@ this.webSocketManager.on('message', (event) => {
|
|
|
588
612
|
|
|
589
613
|
This keeps transcript and suggestion delivery aligned on the same per-task event surface.
|
|
590
614
|
|
|
615
|
+
**wxApp outdial `ContactEnded` / `AgentOutboundFailed` mapping:** Applies only when the current agent is a **wxApp-managed** outdial (`enableWxBetterTogether` + agent participant `deviceType: wxApp`). Pre-accept decline maps to `CONTACT_ENDED` when `wxAppAnswerPending` is false and `agentsPendingWrapUp` is empty — even if the backend sends misleading `interaction.state: wrapUp`. Post-accept wxApp agent end remaps to `OUTBOUND_FAILED` / `AGENT_ENDS` when `wxAppAnswerPending`, `agentsPendingWrapUp`, or `interaction.state === 'wrapUp'` indicates wrapup. **Non-wxApp** agent-terminated `AgentOutboundFailed` (`AGENT_ENDS` / `terminatingParty: Agent`) stays on `OUTBOUND_FAILED` so the OFFERED-state `shouldWrapUp` path runs; `suppressOutdialFailedPopup` on `taskData` skips the outdial-failed modal only. Non-wxApp `ContactEnded` keeps the legacy path. Other failure reasons (`CUSTOMER_BUSY`, etc.) still use `OUTBOUND_FAILED` with the popup. See `TaskManager.isWxAppManagedOutdialTask`, `isAgentTerminatedOutdialWrapup`, and `task-state-machine-spec.md`.
|
|
616
|
+
|
|
617
|
+
**wxApp consumer contract (WXCC-6026):** Hosts enable `enableWxBetterTogether` at init (Phase 1 init-only; re-init to change), bind UI to `task.uiControls` (including optional `main.keypad`), and call **`task.accept()`**, **`task.decline()`**, **`task.toggleMute({ muted? })`**, **`task.transmitDtmf({ dtmf })`**. SDK routes wxApp telephony internally on `Voice`. Shared-line `lineOwnerId` defaults from the wxApp agent participant when omitted.
|
|
618
|
+
|
|
619
|
+
**wxApp offer UI (`uiControlsComputer`):** `wxAppAcceptInFlight` disables accept/decline during the accept REST call. `wxAppAnswerPending` additionally disables accept and decline for **inbound** offers until ASSIGN; wxApp **outdial** keeps decline enabled during the post-accept "Calling…" phase so `cancelTask` remains available.
|
|
620
|
+
|
|
621
|
+
**wxApp mute backfill guard (`Voice.syncWxAppMuteFromCallDetails`):** Skips telephony `GET /calls/{callId}` when the interaction is terminated or the task is a pre-accept wxApp OFFERED offer (`wxAppAnswerPending` false). Post-accept OFFERED and engaged CONNECTED sync still run. `isWxAppEngagedForControls` and `getWebexCallingCallId` exclude `TERMINATED` and `COMPLETED`. Expected 400 / "Call not found" / `101002` responses are not logged as errors.
|
|
622
|
+
|
|
591
623
|
For BROWSER login, TaskManager integrates with WebCalling:
|
|
592
624
|
|
|
593
625
|
```mermaid
|
|
@@ -689,6 +721,7 @@ isSecondaryEpDnAgent(interaction);
|
|
|
689
721
|
| `TASK_WRAPUP_SUCCESS` | operational | Wrapup completed |
|
|
690
722
|
| `TASK_TRANSFER_SUCCESS` | behavioral, business | Transfer completed |
|
|
691
723
|
| `TASK_OUTDIAL_SUCCESS` | behavioral, business | Outdial completed |
|
|
724
|
+
| `TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS` | operational, behavioral, business | Participant Drop completed |
|
|
692
725
|
|
|
693
726
|
## Data Flow
|
|
694
727
|
1. **WebSocket event arrives** → `TaskManager` maps CC event to `TaskEvent`.
|
|
@@ -727,6 +760,7 @@ Sequence coverage:
|
|
|
727
760
|
| Incoming task creation | Incoming task | Unsupported media or incomplete event context prevents publication of a partial task. |
|
|
728
761
|
| Voice hold/resume | Hold or resume | Invalid state rejects before transport; failure notification/HTTP error/timeout sends the matching failure event and throws. |
|
|
729
762
|
| Consult/transfer/conference | Consult and transfer | Backend failure notifications drive explicit failure actions and preserve stable call context. |
|
|
763
|
+
| Participant Drop | Participant Drop | Validation rejects locally; AQM success/failure/HTTP/timeout paths settle and clean up without optimistic state changes. |
|
|
730
764
|
| Wrapup/end | Wrapup or end | Validation and backend failures throw; backend events retain distinct WRAPPING_UP/COMPLETED/TERMINATED outcomes. |
|
|
731
765
|
| WebRTC and digital accept | Channel-specific accept | WebRTC media/calling failure and Digital AQM failure follow different rejection paths. |
|
|
732
766
|
|
|
@@ -820,6 +854,85 @@ sequenceDiagram
|
|
|
820
854
|
end
|
|
821
855
|
```
|
|
822
856
|
|
|
857
|
+
### Participant Drop
|
|
858
|
+
|
|
859
|
+
```mermaid
|
|
860
|
+
sequenceDiagram
|
|
861
|
+
participant App
|
|
862
|
+
participant Voice
|
|
863
|
+
participant Contact as routingContact
|
|
864
|
+
participant AQM as AqmReqs
|
|
865
|
+
participant Backend
|
|
866
|
+
participant WS as Primary WebSocket
|
|
867
|
+
participant TM as TaskManager/state machine
|
|
868
|
+
App->>Voice: dropConferenceParticipant({participantId})
|
|
869
|
+
alt participantId is invalid
|
|
870
|
+
Voice-->>App: reject before metrics, HTTP, or bind registration
|
|
871
|
+
else valid target
|
|
872
|
+
Voice->>Voice: select latest main interaction ID
|
|
873
|
+
Voice->>Contact: participant Drop request
|
|
874
|
+
Contact->>AQM: POST encoded path with empty body and sensitive-log redaction
|
|
875
|
+
AQM->>Backend: authenticated HTTP initiation
|
|
876
|
+
alt ParticipantLeftConference
|
|
877
|
+
Backend-->>WS: ParticipantLeftConference
|
|
878
|
+
WS-->>AQM: correlated success
|
|
879
|
+
AQM-->>Voice: TaskResponse
|
|
880
|
+
WS-->>TM: existing PARTICIPANT_LEAVE mapping updates roster/conference state
|
|
881
|
+
Voice-->>App: resolve
|
|
882
|
+
else ParticipantDropConferenceFailed, HTTP failure, or timeout
|
|
883
|
+
AQM-->>Voice: structured rejection
|
|
884
|
+
Voice-->>App: reject without participant data in logs/metrics
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
`ParticipantLeftConference` is authoritative for both a customer hangup and an
|
|
890
|
+
agent-initiated customer Drop. The task removes only participants absent from
|
|
891
|
+
the latest interaction snapshot. TaskManager first uses the exact interaction
|
|
892
|
+
key, then the existing reservation fallback, and finally one unique task whose
|
|
893
|
+
`interaction.mainInteractionId`, interaction-level `parentInteractionId`, or
|
|
894
|
+
`callProcessingDetails.parentInteractionId` matches an identifier carried by the
|
|
895
|
+
lifecycle event. Object aliases are deduplicated and all aliases are removed
|
|
896
|
+
during terminal cleanup; ambiguous related-interaction matches are ignored
|
|
897
|
+
without logging participant data. Events carrying none of those correlation
|
|
898
|
+
identifiers are not routed. `ContactMerged` removes the EP-DN child task,
|
|
899
|
+
hydrates the main-interaction task, and publishes the existing `task:merged`
|
|
900
|
+
event so consumers can rebind to the surviving task object.
|
|
901
|
+
|
|
902
|
+
Dropping an Agent while that Agent is consulting continues through the existing
|
|
903
|
+
`PARTICIPANT_LEAVE` transition, which clears consult state and emits the normal
|
|
904
|
+
participant-left and task-end lifecycle. This self-departure check applies in
|
|
905
|
+
every active call-control state and uses an explicit self participant ID,
|
|
906
|
+
`hasLeft`, or removal of a previously active Agent from the participant map. A
|
|
907
|
+
participant-left event naming somebody else never infers self-departure from a
|
|
908
|
+
partial media roster. A consulted Agent receiving
|
|
909
|
+
`AgentConsultEnded` continues through `CONSULT_END`; current-agent departure is
|
|
910
|
+
evaluated before consult-initiator recovery. For the from-conference nested-consult
|
|
911
|
+
ordering race only, the guard also compares `mainCall` membership (located by
|
|
912
|
+
`mType`) when the Agent remains active in the participant map and is still present
|
|
913
|
+
on the consult leg. Missing, contradictory, or ordinary CONNECTED/HELD media snapshots
|
|
914
|
+
are non-terminal. Accepted consultees emit
|
|
915
|
+
`task:consultEnd` and `task:end`, while an unaccepted OFFERED consultee retains
|
|
916
|
+
the existing consult-end-only signal. A surviving consult initiator still
|
|
917
|
+
returns to the main-call state selected by the existing guards. Starting a
|
|
918
|
+
consult preserves the prior task snapshot so this membership comparison remains
|
|
919
|
+
available while the consult is initiating.
|
|
920
|
+
|
|
921
|
+
In the Contact Center sample roster, non-owner and Supervisor targets remain
|
|
922
|
+
visible but non-actionable; the UI does not display a separate read-only label.
|
|
923
|
+
The roster is visible whenever the viewing agent remains active on the main leg
|
|
924
|
+
and at least one supported non-customer participant (Agent, EP-DN, or Supervisor)
|
|
925
|
+
is visible. Consequently, Customer-only calls use the original 1-to-1 UI, while
|
|
926
|
+
a single Agent remains visible after the Customer leaves. Dropping the last
|
|
927
|
+
non-customer participant while the Customer remains restores the 1-to-1 UI.
|
|
928
|
+
Terminated tasks and viewing-agent departure hide the roster immediately.
|
|
929
|
+
|
|
930
|
+
The current consult leg may additionally contribute a pending EP-DN row before
|
|
931
|
+
conference merge. The sample displays its `dn`, then its participant/media key
|
|
932
|
+
as a fallback, and deduplicates the row once it joins the main leg. The owner can
|
|
933
|
+
see a disabled Drop action until merge; other active main-call agents see the
|
|
934
|
+
same row without an action. Consult-only Agent targets remain excluded.
|
|
935
|
+
|
|
823
936
|
### Wrapup or end
|
|
824
937
|
|
|
825
938
|
```mermaid
|
|
@@ -1270,7 +1383,7 @@ await cc.stationLogin({ loginOption: 'BROWSER', ... });
|
|
|
1270
1383
|
- A shared Task base preserves a stable API while media-specific subclasses and a separate state engine enforce capability differences.
|
|
1271
1384
|
|
|
1272
1385
|
## Test-Case Strategy (module)
|
|
1273
|
-
Use `test/unit/spec/services/task/Task.ts`, `TaskFactory.ts`, `TaskManager.ts`, media-specific suites, contact/dialer suites, and state-machine suites. Cover concrete-versus-interface method signatures, every TASK_EVENTS group, unsupported media rejection, primary/RTD event ownership, injected state actions, preview-campaign accept/skip/remove payloads and failure paths, the disabled skip/remove pre-guards, and success/failure/timeout paths.
|
|
1386
|
+
Use `test/unit/spec/services/task/Task.ts`, `TaskFactory.ts`, `TaskManager.ts`, media-specific suites, contact/dialer suites, and state-machine suites. Cover concrete-versus-interface method signatures, every TASK_EVENTS group, unsupported media rejection, primary/RTD event ownership, injected state actions, preview-campaign accept/skip/remove payloads and failure paths, the disabled skip/remove pre-guards, Participant Drop validation/correlation/privacy, and success/failure/timeout paths.
|
|
1274
1387
|
|
|
1275
1388
|
| Behavior / Requirement | Existing test evidence | Gap |
|
|
1276
1389
|
|---|---|---|
|
|
@@ -1281,6 +1394,8 @@ Use `test/unit/spec/services/task/Task.ts`, `TaskFactory.ts`, `TaskManager.ts`,
|
|
|
1281
1394
|
| `TASK-R-005` | `test/unit/spec/services/task/TaskFactory.ts`, `test/unit/spec/services/task/dialer.ts` | None. |
|
|
1282
1395
|
| `TASK-R-006` | `test/unit/spec/services/task/contact.ts`, `test/unit/spec/services/core/WebexRequest.ts` | Authentication ownership is verified across routing/Core boundaries. |
|
|
1283
1396
|
| `TASK-R-007` | `test/unit/spec/cc.ts`, `test/unit/spec/services/task/dialer.ts` | Add direct tests proving disabled skip/remove flags throw before dialer invocation; keep public signatures, metrics/error handling, and AQM request contracts synchronized. |
|
|
1397
|
+
| `TASK-R-008` | `test/unit/spec/services/task/Task.ts`, `test/unit/spec/services/task/voice/Voice.ts`, `test/unit/spec/services/task/contact.ts`, `test/unit/spec/services/core/aqm-reqs.ts`, `test/unit/spec/services/task/TaskManager.ts` | None. |
|
|
1398
|
+
| `TASK-R-009` | `test/unit/spec/cc.ts`, `test/unit/spec/services/task/TaskFactory.ts`, `test/unit/spec/services/task/state-machine/uiControlsComputer.ts` | None. |
|
|
1284
1399
|
|
|
1285
1400
|
## Traceability
|
|
1286
1401
|
- Repo architecture: `../../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../../ai-docs/SPEC_INDEX.md`
|
|
@@ -14,6 +14,8 @@ export const CONSULT = '/consult';
|
|
|
14
14
|
export const CONSULT_ACCEPT = '/consult/accept';
|
|
15
15
|
export const CONSULT_END = '/consult/end';
|
|
16
16
|
export const TRANSFER = '/transfer';
|
|
17
|
+
/** Backend destination value for direct entry-point transfers through the vteam endpoint. */
|
|
18
|
+
export const ENTRY_POINT_TRANSFER_DESTINATION_TYPE = 'entrypointDialNumber';
|
|
17
19
|
export const CONSULT_TRANSFER = '/consult/transfer';
|
|
18
20
|
export const PAUSE = '/record/pause';
|
|
19
21
|
export const RESUME = '/record/resume';
|
|
@@ -73,6 +75,7 @@ export const METHODS = {
|
|
|
73
75
|
TRANSFER: 'transfer',
|
|
74
76
|
CONSULT_TRANSFER: 'consultTransfer',
|
|
75
77
|
CONSULT_CONFERENCE: 'consultConference',
|
|
78
|
+
DROP_CONFERENCE_PARTICIPANT: 'dropConferenceParticipant',
|
|
76
79
|
EXIT_CONFERENCE: 'exitConference',
|
|
77
80
|
TRANSFER_CONFERENCE: 'transferConference',
|
|
78
81
|
UPDATE_TASK_DATA: 'updateTaskData',
|
|
@@ -458,6 +458,36 @@ export default function routingContact(aqm: AqmReqs) {
|
|
|
458
458
|
})
|
|
459
459
|
),
|
|
460
460
|
|
|
461
|
+
/*
|
|
462
|
+
* Drop another participant from an active conference
|
|
463
|
+
*/
|
|
464
|
+
dropConferenceParticipant: aqm.req((p: {interactionId: string; participantId: string}) => ({
|
|
465
|
+
url: `${TASK_API}${p.interactionId}/conference/participants/${encodeURIComponent(
|
|
466
|
+
p.participantId
|
|
467
|
+
)}/drop`,
|
|
468
|
+
data: {},
|
|
469
|
+
host: WCC_API_GATEWAY,
|
|
470
|
+
err,
|
|
471
|
+
redactSensitiveLogs: true,
|
|
472
|
+
notifSuccess: {
|
|
473
|
+
bind: {
|
|
474
|
+
type: TASK_MESSAGE_TYPE,
|
|
475
|
+
data: {
|
|
476
|
+
type: CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE,
|
|
477
|
+
interactionId: p.interactionId,
|
|
478
|
+
},
|
|
479
|
+
},
|
|
480
|
+
msg: {} as Contact.AgentContact,
|
|
481
|
+
},
|
|
482
|
+
notifFail: {
|
|
483
|
+
bind: {
|
|
484
|
+
type: TASK_MESSAGE_TYPE,
|
|
485
|
+
data: {type: CC_EVENTS.PARTICIPANT_DROP_CONFERENCE_FAILED},
|
|
486
|
+
},
|
|
487
|
+
errId: 'Service.aqm.task.dropConferenceParticipant',
|
|
488
|
+
},
|
|
489
|
+
})),
|
|
490
|
+
|
|
461
491
|
/*
|
|
462
492
|
* Exit conference
|
|
463
493
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {CC_FILE, METHODS} from '../../../constants';
|
|
2
2
|
import {getErrorDetails} from '../../core/Utils';
|
|
3
|
-
import {IDigital, TaskResponse, TaskData} from '../types';
|
|
3
|
+
import {ConsultTransferDestinationConfig, IDigital, TaskResponse, TaskData} from '../types';
|
|
4
4
|
import {WrapupData} from '../../config/types';
|
|
5
5
|
import Task from '../Task';
|
|
6
6
|
import routingContact from '../contact';
|
|
@@ -13,7 +13,8 @@ export default class Digital extends Task implements IDigital {
|
|
|
13
13
|
contact: ReturnType<typeof routingContact>,
|
|
14
14
|
data: TaskData,
|
|
15
15
|
wrapupData?: WrapupData,
|
|
16
|
-
agentId?: string
|
|
16
|
+
agentId?: string,
|
|
17
|
+
consultTransferConfig?: ConsultTransferDestinationConfig
|
|
17
18
|
) {
|
|
18
19
|
super(
|
|
19
20
|
contact,
|
|
@@ -22,6 +23,7 @@ export default class Digital extends Task implements IDigital {
|
|
|
22
23
|
isEndTaskEnabled: true,
|
|
23
24
|
isEndConsultEnabled: false,
|
|
24
25
|
isRecordingEnabled: false,
|
|
26
|
+
consultTransferConfig,
|
|
25
27
|
},
|
|
26
28
|
wrapupData,
|
|
27
29
|
agentId
|