@webex/contact-center 3.12.0-llmrefactor.2 → 3.12.0-llmrefactor.4
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 +6 -2
- 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 +353 -21
- 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 +9 -9
- 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 +522 -16
- 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 +152 -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 +56 -24
- 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 +1294 -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
|
@@ -74,10 +74,11 @@ See root `CONTRACTS.md` for the package-level state-control export.
|
|
|
74
74
|
| TASK_STATE_MACHINE-R-001 | Map typed Task events through the XState graph and preserve guards/actions for offer, assignment, consult, conference, transfer, wrapup, termination, and hydration. | A deterministic event vocabulary isolates lifecycle policy from transport payloads. | `src/services/task/state-machine/TaskStateMachine.ts` | `test/unit/spec/services/task/state-machine/TaskStateMachine.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
75
75
|
| TASK_STATE_MACHINE-R-002 | Keep `handleConferenceFailed`, `handleSwitchToMainCall`, and `handleSwitchToConsult` wired where the graph invokes them; retain `forceConsultInitiator` as defined-but-currently-unwired. | Incorrect absence/wiring claims cause maintainers to duplicate or remove real actions. | `src/services/task/state-machine/actions.ts` | `test/unit/spec/services/task/state-machine/TaskStateMachine.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
76
76
|
| TASK_STATE_MACHINE-R-003 | Treat `syncTaskDataFromEvent` as a Task-supplied machine implementation, not a default action in `actions.ts`. | The reusable graph declares the action name while Task owns integration-specific data synchronization. | `src/services/task/Task.ts` | `test/unit/spec/services/task/Task.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
77
|
-
| TASK_STATE_MACHINE-R-004 | Compute
|
|
77
|
+
| TASK_STATE_MACHINE-R-004 | Compute per-leg action controls and ordered `consultTransferDestinations.consult`/`.transfer` arrays through `uiControlsComputer`, preserving the public `getDefaultUIControls` shape with empty destination arrays. Voice queue rules use Consult profile enablement or Transfer direction plus `callProcessingDetails.outdialTransferToQueueEnabled`; digital supports agent/queue only; profile `NONE` removes the matching category. | Applications depend on one deterministic Task control surface, the default order (`agent`, `queue`, `dialNumber`, `entryPoint`), and correct action/media/profile gating. | `src/services/task/state-machine/uiControlsComputer.ts` | `test/unit/spec/services/task/state-machine/uiControlsComputer.ts` | Consumers may further hide allowed categories but must not infer or enable omitted categories. | PRESENT |
|
|
78
78
|
| TASK_STATE_MACHINE-R-005 | Keep authentication and credentials outside the state-machine layer; it receives typed Task data/events and never invokes authenticated transport. | Pure transition logic remains reusable and cannot leak or mutate host authentication state. | `src/services/task/state-machine/TaskStateMachine.ts`, `src/services/task/state-machine/types.ts` | `test/unit/spec/services/task/state-machine/TaskStateMachine.ts` | None; security/auth applicability is explicitly N/A. | PRESENT |
|
|
79
79
|
| TASK_STATE_MACHINE-R-006 | Treat `UIControlConfig` values as Task-supplied capability configuration, not rollout flags evaluated or owned by the state machine. | Rollout and profile policy must be resolved before actor construction so transitions remain deterministic. | `src/services/task/state-machine/types.ts`, `src/services/task/Task.ts` | `test/unit/spec/services/task/Task.ts` | None; rollout ownership is explicit. | PRESENT |
|
|
80
80
|
| TASK_STATE_MACHINE-R-007 | Keep logging and metrics in Task/TaskManager integration; the state-machine implementation has no LoggerProxy or MetricsManager dependency. | Separating observability side effects from guards/actions preserves deterministic transition tests. | `src/services/task/state-machine/TaskStateMachine.ts`, `src/services/task/Task.ts` | `test/unit/spec/services/task/state-machine/TaskStateMachine.ts`, `test/unit/spec/services/task/Task.ts` | None; observability ownership is explicit. | PRESENT |
|
|
81
|
+
| TASK_STATE_MACHINE-R-008 | `CONTACT_OWNER_CHANGED` must synchronize task/context data and emit `task:hydrate` without transitioning state. A TaskManager-recovered promoted-Agent task first receives an internal IDLE `HYDRATE` before listener installation, then the original owner-change event produces exactly one external hydrate and no incoming event. TaskManager maps an owner-changing `ContactUpdated` for an existing task to that owner-change event, while same-owner or owner-less updates remain `CONTACT_UPDATED`; missing-task `ContactUpdated` does not create a task. It also preserves an already confirmed active owner from a late participant-left snapshot that still names the departed owner. Participant Drop must rely on the existing `ParticipantLeftConference` mapping rather than adding an initiating state event. From every active call-control state, `PARTICIPANT_LEAVE` terminates or wraps the current Agent only when the event names that Agent, marks that Agent `hasLeft`, or removes a previously active Agent from the participant map; an event naming another participant cannot infer self-departure from a partial media roster. `CONSULT_END` evaluates the same explicit evidence before initiator recovery and additionally supports the narrow from-conference nested-consult race where a previously main-leg Agent is absent from the updated `mainCall` but remains active in the participant map and present on the consult leg. Removed accepted Agents emit `task:consultEnd` plus `task:end`, surviving initiators recover to their main call, and an unaccepted OFFERED consultee emits only `task:consultEnd`. Missing, partial, contradictory, or ordinary CONNECTED/HELD media membership is non-terminal, and starting Consult must preserve the prior task snapshot used by the guard. | Owner-sensitive consumers must rerender promptly while owner selection, participant removal, consult removal, and narrowly scoped desynchronization recovery remain backend-authoritative and compatible with existing incoming-task callback behavior. | `src/services/task/state-machine/TaskStateMachine.ts`, `src/services/task/state-machine/actions.ts`, `src/services/task/state-machine/guards.ts`, `src/services/task/TaskManager.ts` | `test/unit/spec/services/task/Task.ts`, `test/unit/spec/services/task/TaskManager.ts`, `test/unit/spec/services/task/state-machine/TaskStateMachine.ts`, `test/unit/spec/services/task/state-machine/guards.ts` | Backend ownership-successor selection and delivery of complete recovery payloads are outside this module. | PRESENT |
|
|
81
82
|
|
|
82
83
|
## Design Overview
|
|
83
84
|
TaskManager maps Contact Center notifications to `TaskEvent` values. Each Task sends those events to its XState actor built by `createTaskStateMachine()`. The configuration applies guards and named actions, updates `TaskContext`, and computes UI controls. Task supplies the integration-specific `syncTaskDataFromEvent` implementation through machine options; it is not a default action in `actions.ts`.
|
|
@@ -215,6 +216,14 @@ sequenceDiagram
|
|
|
215
216
|
|
|
216
217
|
### Hydrate and recovery
|
|
217
218
|
|
|
219
|
+
When TaskManager narrowly recovers a missing promoted-Agent task from a complete
|
|
220
|
+
`ContactOwnerChanged` payload, it sends `HYDRATE` while the new actor is still
|
|
221
|
+
unobserved so the IDLE guards restore CONNECTED, HELD, CONFERENCING, or another
|
|
222
|
+
backend-represented state. TaskManager then installs listeners and forwards the
|
|
223
|
+
original `CONTACT_OWNER_CHANGED`; only that second event emits the single public
|
|
224
|
+
`task:hydrate`. Recovery never emits `task:incoming`, and missing-task
|
|
225
|
+
`ContactUpdated` does not use this path.
|
|
226
|
+
|
|
218
227
|
```mermaid
|
|
219
228
|
sequenceDiagram
|
|
220
229
|
participant TM as TaskManager
|
|
@@ -507,14 +516,18 @@ shouldWrapUpOrIsInitiator(context, event) {
|
|
|
507
516
|
return Boolean(event.taskData?.wrapUpRequired || context.consultInitiator);
|
|
508
517
|
}
|
|
509
518
|
|
|
510
|
-
// Check whether the
|
|
511
|
-
|
|
519
|
+
// Check whether the current agent left the main interaction
|
|
520
|
+
didCurrentAgentLeaveMainInteraction(context, event) {
|
|
512
521
|
const selfAgentId = getSelfAgentId(context, event.taskData);
|
|
513
522
|
if (!selfAgentId) return false;
|
|
514
523
|
|
|
515
524
|
const participantIdFromEvent = 'participantId' in event ? event.participantId : undefined;
|
|
516
525
|
const participantId = participantIdFromEvent ?? event.taskData?.participantId;
|
|
517
|
-
|
|
526
|
+
if (Boolean(participantId) && participantId === selfAgentId) return true;
|
|
527
|
+
// Explicit hasLeft or removal of a previously active self from the participant map is terminal.
|
|
528
|
+
// PARTICIPANT_LEAVE naming another participant does not infer self departure from media.
|
|
529
|
+
// Only a from-conference CONSULT_END may compare mainCall membership, and only when self
|
|
530
|
+
// remains active in the participant map and on the consult leg. Partial ordinary calls are false.
|
|
518
531
|
}
|
|
519
532
|
|
|
520
533
|
// True when this agent initiated the conference transfer (widgets or desktop).
|
|
@@ -859,9 +872,15 @@ It is instantiated by `Task` and receives mapped backend/user events through `se
|
|
|
859
872
|
|
|
860
873
|
- Actions: `updateTaskData`, `setConsultAgentJoined`, `emitTaskConsultAccepted`, `emitTaskConsulting`
|
|
861
874
|
|
|
875
|
+
- `TASK_WRAPUP` -> `WRAPPING_UP`
|
|
876
|
+
|
|
877
|
+
- Guard: `guards.shouldWrapUp`
|
|
878
|
+
|
|
879
|
+
- Actions: `updateTaskData`, `markEnded`, `emitTaskWrapup`
|
|
880
|
+
|
|
862
881
|
- `TASK_WRAPUP` -> `TERMINATED`
|
|
863
882
|
|
|
864
|
-
- Guard:
|
|
883
|
+
- Guard: default (when wrap-up is not required)
|
|
865
884
|
|
|
866
885
|
- Actions: `updateTaskData`, `markEnded`, `emitTaskEnd`
|
|
867
886
|
|
|
@@ -1311,19 +1330,19 @@ It is instantiated by `Task` and receives mapped backend/user events through `se
|
|
|
1311
1330
|
|
|
1312
1331
|
- `PARTICIPANT_LEAVE` -> `WRAPPING_UP`
|
|
1313
1332
|
|
|
1314
|
-
- Guard: `guards.
|
|
1333
|
+
- Guard: `guards.didCurrentAgentLeaveMainInteraction && guards.shouldWrapUp`
|
|
1315
1334
|
|
|
1316
1335
|
- Actions: `updateTaskData`, `handleParticipantLeft`, `markEnded`, `clearConsultState`, `emitTaskParticipantLeft`, `emitTaskWrapup`
|
|
1317
1336
|
|
|
1318
1337
|
- `PARTICIPANT_LEAVE` -> `TERMINATED`
|
|
1319
1338
|
|
|
1320
|
-
- Guard: `guards.
|
|
1339
|
+
- Guard: `guards.didCurrentAgentLeaveMainInteraction`
|
|
1321
1340
|
|
|
1322
1341
|
- Actions: `updateTaskData`, `handleParticipantLeft`, `markEnded`, `clearConsultState`, `emitTaskParticipantLeft`, `emitTaskEnd`
|
|
1323
1342
|
|
|
1324
1343
|
- `PARTICIPANT_LEAVE` -> `CONNECTED`
|
|
1325
1344
|
|
|
1326
|
-
- Guard:
|
|
1345
|
+
- Guard: `guards.shouldDowngradeConferenceToConnected` (after current-agent departure guards)
|
|
1327
1346
|
|
|
1328
1347
|
- Actions: `updateTaskData`, `handleParticipantLeft`, `clearConsultState`, `emitTaskParticipantLeft`, `emitTaskConferenceEnded`
|
|
1329
1348
|
|
|
@@ -1491,13 +1510,13 @@ It is instantiated by `Task` and receives mapped backend/user events through `se
|
|
|
1491
1510
|
|
|
1492
1511
|
- `PARTICIPANT_LEAVE` -> `WRAPPING_UP`
|
|
1493
1512
|
|
|
1494
|
-
- Guard: `guards.
|
|
1513
|
+
- Guard: `guards.didCurrentAgentLeaveMainInteraction && guards.shouldWrapUp`
|
|
1495
1514
|
|
|
1496
1515
|
- Actions: `updateTaskData`, `handleParticipantLeft`, `markEnded`, `clearConsultState`, `emitTaskParticipantLeft`, `emitTaskWrapup`
|
|
1497
1516
|
|
|
1498
1517
|
- `PARTICIPANT_LEAVE` -> `TERMINATED`
|
|
1499
1518
|
|
|
1500
|
-
- Guard: `guards.
|
|
1519
|
+
- Guard: `guards.didCurrentAgentLeaveMainInteraction`
|
|
1501
1520
|
|
|
1502
1521
|
- Actions: `updateTaskData`, `handleParticipantLeft`, `markEnded`, `clearConsultState`, `emitTaskParticipantLeft`, `emitTaskEnd`
|
|
1503
1522
|
|
|
@@ -1513,6 +1532,14 @@ It is instantiated by `Task` and receives mapped backend/user events through `se
|
|
|
1513
1532
|
|
|
1514
1533
|
- Actions: `updateTaskData`, `handleParticipantLeft`, `emitTaskParticipantLeft`
|
|
1515
1534
|
|
|
1535
|
+
Customer hangup and agent-initiated customer Drop share this backend event.
|
|
1536
|
+
When two or more active conference participants survive on the main leg, the
|
|
1537
|
+
customer is removed from the authoritative snapshot while the task remains
|
|
1538
|
+
`CONFERENCING`; no `task:conferenceEnded` event is emitted. When another
|
|
1539
|
+
agent/endpoint leaves, the same rule preserves the remaining conference, and
|
|
1540
|
+
the guarded `CONNECTED` branch is used only after the conference participant
|
|
1541
|
+
count falls below two while the customer remains.
|
|
1542
|
+
|
|
1516
1543
|
- `CONFERENCE_END` -> `WRAPPING_UP`
|
|
1517
1544
|
|
|
1518
1545
|
- Guard: `guards.shouldWrapUp`
|
|
@@ -1561,7 +1588,7 @@ It is instantiated by `Task` and receives mapped backend/user events through `se
|
|
|
1561
1588
|
|
|
1562
1589
|
**Description**: Final wrapped-up terminal state.
|
|
1563
1590
|
|
|
1564
|
-
**Entry Actions
|
|
1591
|
+
**Entry Actions** (order matters — `emitTaskWrappedup` before `cleanupResources` so subscribers receive intact task data):
|
|
1565
1592
|
|
|
1566
1593
|
- `emitTaskWrappedup`
|
|
1567
1594
|
|
|
@@ -1730,8 +1757,8 @@ Complete mapping from backend CC_EVENTS to internal TaskEvent types.
|
|
|
1730
1757
|
| `AGENT_CONTACT_RESERVED` | `TASK_INCOMING` | `IDLE` | `OFFERED` | Incoming task entry |
|
|
1731
1758
|
| `AGENT_OFFER_CONTACT` | `TASK_OFFERED` | `OFFERED` | `OFFERED` | Offer payload refresh |
|
|
1732
1759
|
| `AGENT_CONTACT` | `HYDRATE` | `IDLE` | `WRAPPING_UP` / `CONSULTING` / `HELD` / `CONNECTED` / `CONFERENCING` / `IDLE` | Guard-based restore |
|
|
1733
|
-
| `CONTACT_UPDATED` | `CONTACT_UPDATED`
|
|
1734
|
-
| `CONTACT_OWNER_CHANGED` | `CONTACT_OWNER_CHANGED` | any | same | Context sync
|
|
1760
|
+
| `CONTACT_UPDATED` | `CONTACT_UPDATED` or `CONTACT_OWNER_CHANGED` | any | same | Owner delta uses existing hydrate path; same/missing owner is context sync only |
|
|
1761
|
+
| `CONTACT_OWNER_CHANGED` | `CONTACT_OWNER_CHANGED` | any | same | Context/data sync + `task:hydrate` |
|
|
1735
1762
|
| `AGENT_OFFER_CONSULT` | `OFFER_CONSULT` | `OFFERED` | `OFFERED` | Receiver-side consult offer |
|
|
1736
1763
|
| `AGENT_CONTACT_ASSIGNED` | `ASSIGN` | `OFFERED` / `CONNECTED` / `CONSULTING` | `CONNECTED` | Assign/reassign |
|
|
1737
1764
|
| `AGENT_CONTACT_HELD` | `HOLD_SUCCESS` | `HOLD_INITIATING` | `HELD` | Includes `mediaResourceId` |
|
|
@@ -1746,16 +1773,16 @@ Complete mapping from backend CC_EVENTS to internal TaskEvent types.
|
|
|
1746
1773
|
| `AGENT_BLIND_TRANSFERRED` | `TRANSFER_SUCCESS` | `CONNECTED` / `HELD` / `CONSULTING` | `WRAPPING_UP` / `CONNECTED` | `shouldWrapUpOrIsInitiator` |
|
|
1747
1774
|
| `AGENT_CONSULT_TRANSFERRED` | `TRANSFER_SUCCESS` | `CONNECTED` / `HELD` / `CONSULTING` | `WRAPPING_UP` / `CONNECTED` | Same path |
|
|
1748
1775
|
| `AGENT_VTEAM_TRANSFERRED` | `TRANSFER_SUCCESS` | `CONNECTED` / `HELD` / `CONSULTING` | `WRAPPING_UP` / `CONNECTED` | Same path |
|
|
1749
|
-
| `AGENT_WRAPUP` | `TASK_WRAPUP` | `OFFERED` / `CONNECTED` / `HELD` / `CONSULTING` | `
|
|
1776
|
+
| `AGENT_WRAPUP` | `TASK_WRAPUP` | `OFFERED` / `CONNECTED` / `HELD` / `CONSULTING` | `WRAPPING_UP` / `TERMINATED` | `shouldWrapUp` selects wrap-up; default terminates (wxApp outdial pre-accept agent end may wrap while still `OFFERED`) |
|
|
1750
1777
|
| `AGENT_BLIND_TRANSFER_FAILED` | `TRANSFER_FAILED` | `CONNECTED` / `HELD` / `CONSULTING` | same | Context update |
|
|
1751
1778
|
| `AGENT_VTEAM_TRANSFER_FAILED` | `TRANSFER_FAILED` | `CONNECTED` / `HELD` / `CONSULTING` | same | Context update |
|
|
1752
1779
|
| `AGENT_CONSULT_TRANSFER_FAILED` | `TRANSFER_FAILED` | `CONNECTED` / `HELD` / `CONSULTING` | same | Context update |
|
|
1753
1780
|
| `AGENT_CONFERENCE_TRANSFER_FAILED` | `TRANSFER_FAILED` | `CONNECTED` / `HELD` / `CONSULTING` | same | Context update |
|
|
1754
|
-
| `CONTACT_ENDED` | `CONTACT_ENDED`
|
|
1781
|
+
| `CONTACT_ENDED` | `CONTACT_ENDED` or `OUTBOUND_FAILED` | `OFFERED` / `CONNECTED` / `HELD` / `CONSULTING` / `CONFERENCING` | `WRAPPING_UP` / `TERMINATED` / etc. | wxApp outdial pre-accept decline → `CONTACT_ENDED` → `TERMINATED` (no wrapup) when `wxAppAnswerPending` is false and `agentsPendingWrapUp` is empty (backend may still send `interaction.state: wrapUp`). Post-accept agent end remaps to `OUTBOUND_FAILED` (`AGENT_ENDS`) when `wxAppAnswerPending` or wrapup pending — including while SM is still `OFFERED` before `ASSIGN`. |
|
|
1755
1782
|
| `AGENT_INVITE_FAILED` | `INVITE_FAILED` | `OFFERED` | `TERMINATED` | Reject path |
|
|
1756
1783
|
| `AGENT_CONTACT_ASSIGN_FAILED` | `ASSIGN_FAILED` | `OFFERED` | `TERMINATED` | Reject path |
|
|
1757
1784
|
| `AGENT_CONTACT_OFFER_RONA` | `RONA` | `OFFERED` | `TERMINATED` | Timeout path |
|
|
1758
|
-
| `AGENT_OUTBOUND_FAILED` | `OUTBOUND_FAILED` | `OFFERED`
|
|
1785
|
+
| `AGENT_OUTBOUND_FAILED` | `OUTBOUND_FAILED` | `IDLE` / `OFFERED` / `CONNECTED` / `HOLD_INITIATING` / `HELD` / `RESUME_INITIATING` / `CONSULT_INITIATING` / `CONSULTING` / `CONF_INITIATING` / `CONFERENCING` | `WRAPPING_UP` or `TERMINATED` | Outbound failure; wrapup when `shouldWrapUp`. Non-wxApp agent-terminated `AGENT_ENDS` sets `suppressOutdialFailedPopup` (wrapup without outdial-failed modal). `IDLE` handles race before `TASK_INCOMING`. |
|
|
1759
1786
|
| `CONTACT_RECORDING_STARTED` | `RECORDING_STARTED` | any | same | Recording state update |
|
|
1760
1787
|
| `CONTACT_RECORDING_PAUSED` | `PAUSE_RECORDING` | `CONNECTED` | same | Recording state update |
|
|
1761
1788
|
| `CONTACT_RECORDING_RESUMED` | `RESUME_RECORDING` | `CONNECTED` | same | Recording state update |
|
|
@@ -1775,8 +1802,8 @@ Complete mapping from backend CC_EVENTS to internal TaskEvent types.
|
|
|
1775
1802
|
| `AgentOfferContact` | `TASK_OFFERED` | Stay in OFFERED | Offer confirmation |
|
|
1776
1803
|
| `AgentContact` | `HYDRATE` | Various | State restoration |
|
|
1777
1804
|
| `AgentContactAssigned` | `ASSIGN` | OFFERED → CONNECTED (also CONNECTED/CONSULTING refresh paths) | Task accepted/reassigned |
|
|
1778
|
-
| `ContactUpdated` | `CONTACT_UPDATED`
|
|
1779
|
-
| `ContactOwnerChanged` | `CONTACT_OWNER_CHANGED` | No change | Owner update
|
|
1805
|
+
| `ContactUpdated` | `CONTACT_UPDATED` or `CONTACT_OWNER_CHANGED` | No change | Changed non-empty owner also emits `task:hydrate`; same/missing owner is data-only |
|
|
1806
|
+
| `ContactOwnerChanged` | `CONTACT_OWNER_CHANGED` | No change | Owner update plus `task:hydrate` emission |
|
|
1780
1807
|
| `ContactEnded` | `CONTACT_ENDED` | Guard-based branch | CONFERENCING / WRAPPING_UP / TERMINATED / stay |
|
|
1781
1808
|
| `AgentContactUnassigned` | None | N/A | Handled by other events |
|
|
1782
1809
|
|
|
@@ -1810,9 +1837,10 @@ Complete mapping from backend CC_EVENTS to internal TaskEvent types.
|
|
|
1810
1837
|
| Backend Event / API | TaskEvent | State Transition | Context Update |
|
|
1811
1838
|
|---|---|---|---|
|
|
1812
1839
|
| API `task.consultConference()` | `MERGE_TO_CONFERENCE` | CONSULTING → CONF_INITIATING | Starts merge flow |
|
|
1840
|
+
| API `task.dropConferenceParticipant()` | None | No direct state transition | AQM waits for backend `ParticipantLeftConference`; that event follows the existing `PARTICIPANT_LEAVE` path |
|
|
1813
1841
|
| `AgentConsultConferenced` | `CONFERENCE_START` | CONSULTING/CONF_INITIATING → CONFERENCING | `handleConferenceStarted` path |
|
|
1814
1842
|
| `ParticipantJoinedConference` | `CONFERENCE_START` | CONFERENCING → CONFERENCING | Refresh + emit conference started |
|
|
1815
|
-
| `ParticipantLeftConference` | `PARTICIPANT_LEAVE` |
|
|
1843
|
+
| `ParticipantLeftConference` | `PARTICIPANT_LEAVE` | Any active call-control state → WRAPPING_UP / TERMINATED / CONNECTED / stay | Uses `didCurrentAgentLeaveMainInteraction`, `shouldWrapUp`, `shouldDowngradeConferenceToConnected` |
|
|
1816
1844
|
| `AgentConsultConferenceEnded` | `CONFERENCE_END` | CONFERENCING → WRAPPING_UP / CONNECTED / TERMINATED | Guard-based branch |
|
|
1817
1845
|
| `AgentConsultConferenceFailed` | `CONFERENCE_FAILED` | CONF_INITIATING → CONSULTING | Merge failed fallback |
|
|
1818
1846
|
| `AgentConferenceTransferred` | `TRANSFER_CONFERENCE_SUCCESS` | CONSULTING/CONFERENCING branch logic | Initiator/receiver dependent |
|
|
@@ -1847,6 +1875,7 @@ stateDiagram-v2
|
|
|
1847
1875
|
OFFERED --> TERMINATED: AGENT_CONTACT_ASSIGN_FAILED (CC Event) -> ASSIGN_FAILED (State Machine Event)
|
|
1848
1876
|
OFFERED --> TERMINATED: AGENT_INVITE_FAILED (CC Event) -> INVITE_FAILED (State Machine Event)
|
|
1849
1877
|
OFFERED --> TERMINATED: AGENT_OUTBOUND_FAILED (CC Event) -> OUTBOUND_FAILED (State Machine Event)
|
|
1878
|
+
OFFERED --> WRAPPING_UP: AGENT_WRAPUP (CC Event) -> TASK_WRAPUP (State Machine Event) [shouldWrapUp]
|
|
1850
1879
|
OFFERED --> TERMINATED: AGENT_WRAPUP (CC Event) -> TASK_WRAPUP (State Machine Event)
|
|
1851
1880
|
|
|
1852
1881
|
%% CONNECTED
|
|
@@ -1907,8 +1936,8 @@ stateDiagram-v2
|
|
|
1907
1936
|
|
|
1908
1937
|
%% CONFERENCING
|
|
1909
1938
|
CONFERENCING --> CONSULT_INITIATING: CONSULT (State Machine Event)
|
|
1910
|
-
CONFERENCING --> WRAPPING_UP: PARTICIPANT_LEAVE (CC Event) -> PARTICIPANT_LEAVE (State Machine Event) [
|
|
1911
|
-
CONFERENCING --> TERMINATED: PARTICIPANT_LEAVE (CC Event) -> PARTICIPANT_LEAVE (State Machine Event) [
|
|
1939
|
+
CONFERENCING --> WRAPPING_UP: PARTICIPANT_LEAVE (CC Event) -> PARTICIPANT_LEAVE (State Machine Event) [didCurrentAgentLeaveMainInteraction && shouldWrapUp]
|
|
1940
|
+
CONFERENCING --> TERMINATED: PARTICIPANT_LEAVE (CC Event) -> PARTICIPANT_LEAVE (State Machine Event) [didCurrentAgentLeaveMainInteraction]
|
|
1912
1941
|
CONFERENCING --> CONNECTED: PARTICIPANT_LEAVE (CC Event) -> PARTICIPANT_LEAVE (State Machine Event) [shouldDowngradeConferenceToConnected]
|
|
1913
1942
|
CONFERENCING --> WRAPPING_UP: CONFERENCE_END (CC Event) -> CONFERENCE_END (State Machine Event) [shouldWrapUp]
|
|
1914
1943
|
CONFERENCING --> CONNECTED: CONFERENCE_END (CC Event) -> CONFERENCE_END (State Machine Event) [customerInCall]
|
|
@@ -1930,7 +1959,9 @@ stateDiagram-v2
|
|
|
1930
1959
|
OFFERED --> OFFERED: AGENT_CONTACT_OFFER -> TASK_OFFERED
|
|
1931
1960
|
OFFERED --> OFFERED: AGENT_CONSULT_OFFER -> OFFER_CONSULT
|
|
1932
1961
|
OFFERED --> CONNECTED: AGENT_CONTACT_ASSIGNED -> ASSIGN
|
|
1933
|
-
OFFERED --> TERMINATED: AGENT_CONTACT_OFFER_RONA/AGENT_CONTACT_ASSIGN_FAILED/AGENT_INVITE_FAILED/AGENT_OUTBOUND_FAILED
|
|
1962
|
+
OFFERED --> TERMINATED: AGENT_CONTACT_OFFER_RONA/AGENT_CONTACT_ASSIGN_FAILED/AGENT_INVITE_FAILED/AGENT_OUTBOUND_FAILED -> RONA/ASSIGN_FAILED/INVITE_FAILED/OUTBOUND_FAILED
|
|
1963
|
+
OFFERED --> WRAPPING_UP: AGENT_WRAPUP -> TASK_WRAPUP [shouldWrapUp]
|
|
1964
|
+
OFFERED --> TERMINATED: AGENT_WRAPUP -> TASK_WRAPUP
|
|
1934
1965
|
|
|
1935
1966
|
CONNECTED --> HOLD_INITIATING: task.hold() -> HOLD_INITIATED
|
|
1936
1967
|
CONNECTED --> CONSULT_INITIATING: task.consult() -> CONSULT
|
|
@@ -2012,8 +2043,8 @@ stateDiagram-v2
|
|
|
2012
2043
|
CONFERENCING --> CONFERENCING: AGENT_CONFERENCE_TRANSFERRED -> TRANSFER_CONFERENCE_SUCCESS
|
|
2013
2044
|
CONFERENCING --> CONFERENCING: AGENT_CONFERENCE_TRANSFER_FAILED-> TRANSFER_CONFERENCE_FAILED
|
|
2014
2045
|
|
|
2015
|
-
CONFERENCING --> WRAPPING_UP: PARTICIPANT_LEFT_CONFERENCE -> PARTICIPANT_LEAVE [
|
|
2016
|
-
CONFERENCING --> TERMINATED: PARTICIPANT_LEFT_CONFERENCE -> PARTICIPANT_LEAVE [
|
|
2046
|
+
CONFERENCING --> WRAPPING_UP: PARTICIPANT_LEFT_CONFERENCE -> PARTICIPANT_LEAVE [didCurrentAgentLeaveMainInteraction && shouldWrapUp]
|
|
2047
|
+
CONFERENCING --> TERMINATED: PARTICIPANT_LEFT_CONFERENCE -> PARTICIPANT_LEAVE [didCurrentAgentLeaveMainInteraction]
|
|
2017
2048
|
CONFERENCING --> CONNECTED: PARTICIPANT_LEFT_CONFERENCE -> PARTICIPANT_LEAVE [shouldDowngradeConferenceToConnected]
|
|
2018
2049
|
CONFERENCING --> WRAPPING_UP: AGENT_CONSULT_CONFERENCE_ENDED -> CONFERENCE_END [shouldWrapUp]
|
|
2019
2050
|
CONFERENCING --> CONNECTED: AGENT_CONSULT_CONFERENCE_ENDED -> CONFERENCE_END [customerInCall]
|
|
@@ -2139,6 +2170,7 @@ Use `test/unit/spec/services/task/state-machine/TaskStateMachine.ts`, `guards.ts
|
|
|
2139
2170
|
| `TASK_STATE_MACHINE-R-005` | `test/unit/spec/services/task/state-machine/TaskStateMachine.ts` | Transport/auth absence is also verified from imports. |
|
|
2140
2171
|
| `TASK_STATE_MACHINE-R-006` | `test/unit/spec/services/task/Task.ts` | None. |
|
|
2141
2172
|
| `TASK_STATE_MACHINE-R-007` | `test/unit/spec/services/task/state-machine/TaskStateMachine.ts`, `test/unit/spec/services/task/Task.ts` | Observability absence is also verified from imports. |
|
|
2173
|
+
| `TASK_STATE_MACHINE-R-008` | `test/unit/spec/services/task/Task.ts`, `test/unit/spec/services/task/TaskManager.ts` | None. |
|
|
2142
2174
|
|
|
2143
2175
|
## Traceability
|
|
2144
2176
|
- Repo architecture: `../../../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../../../ai-docs/SPEC_INDEX.md`
|
|
@@ -362,13 +362,14 @@ export const guards = {
|
|
|
362
362
|
},
|
|
363
363
|
|
|
364
364
|
/**
|
|
365
|
-
* True
|
|
365
|
+
* True when an updated lifecycle event shows that this agent left the main interaction.
|
|
366
366
|
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
367
|
+
* Explicit self-participant evidence is authoritative. Main-call membership is used only
|
|
368
|
+
* for the from-conference nested-consult race where CONSULT_END still represents the agent as
|
|
369
|
+
* active on the consult leg after removing them from the main leg. Partial or ordinary call
|
|
370
|
+
* snapshots are not treated as a departure.
|
|
370
371
|
*/
|
|
371
|
-
|
|
372
|
+
didCurrentAgentLeaveMainInteraction: ({context, event}: GuardParams): boolean => {
|
|
372
373
|
const taskData = getTaskDataFromEvent(event);
|
|
373
374
|
const selfAgentId = getSelfAgentId(context, taskData);
|
|
374
375
|
if (!selfAgentId) return false;
|
|
@@ -383,12 +384,64 @@ export const guards = {
|
|
|
383
384
|
return true;
|
|
384
385
|
}
|
|
385
386
|
|
|
386
|
-
//
|
|
387
|
-
//
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
387
|
+
// Routing represents self-departure either by naming the participant or by retaining the
|
|
388
|
+
// participant entry with hasLeft set. Agent Desktop treats both representations as terminal.
|
|
389
|
+
const currentParticipant = taskData?.interaction?.participants?.[selfAgentId];
|
|
390
|
+
if (currentParticipant?.hasLeft === true) {
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// A participant-left event that explicitly identifies somebody else must not use a
|
|
395
|
+
// potentially partial participant or media roster to infer that self also departed.
|
|
396
|
+
if (
|
|
397
|
+
event?.type === TaskEvent.PARTICIPANT_LEAVE &&
|
|
398
|
+
Boolean(participantId) &&
|
|
399
|
+
participantId !== selfAgentId
|
|
400
|
+
) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const previousParticipants = context.taskData?.interaction?.participants;
|
|
405
|
+
const updatedParticipants = taskData?.interaction?.participants;
|
|
406
|
+
const wasPreviouslyActive = Boolean(
|
|
407
|
+
previousParticipants?.[selfAgentId] && previousParticipants[selfAgentId].hasLeft !== true
|
|
408
|
+
);
|
|
409
|
+
// Some EP-DN lifecycle payloads remove the participant entry instead of setting hasLeft.
|
|
410
|
+
// Requiring a previously active entry prevents an incomplete initial snapshot from ending a task.
|
|
411
|
+
if (updatedParticipants && wasPreviouslyActive && !(selfAgentId in updatedParticipants)) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const previousMainMedia = Object.values(context.taskData?.interaction?.media ?? {}).filter(
|
|
416
|
+
(media) => media?.mType === 'mainCall'
|
|
417
|
+
);
|
|
418
|
+
const updatedMainMedia = Object.values(taskData?.interaction?.media ?? {}).filter(
|
|
419
|
+
(media) => media?.mType === 'mainCall'
|
|
420
|
+
);
|
|
421
|
+
const wasPreviouslyInMainCall = previousMainMedia.some((media) =>
|
|
422
|
+
media.participants?.includes(selfAgentId)
|
|
423
|
+
);
|
|
424
|
+
const remainsInMainCall = updatedMainMedia.some((media) =>
|
|
425
|
+
media.participants?.includes(selfAgentId)
|
|
426
|
+
);
|
|
427
|
+
// A hasLeft participant returned above, so presence here means the updated map keeps self active.
|
|
428
|
+
const remainsActiveInParticipantMap = Boolean(currentParticipant);
|
|
429
|
+
const remainsOnConsultLeg = Object.values(taskData?.interaction?.media ?? {}).some(
|
|
430
|
+
(media) => media?.mType === MEDIA_TYPE_CONSULT && media.participants?.includes(selfAgentId)
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
// Agent Desktop uses mainCall membership for AgentConsultEnded cleanup. Restrict that fallback
|
|
434
|
+
// to a consult that originated from conference and require corroborating active-map and
|
|
435
|
+
// consult-leg membership so ordinary partial CONNECTED/HELD payloads cannot terminate a task.
|
|
436
|
+
if (
|
|
437
|
+
event?.type === TaskEvent.CONSULT_END &&
|
|
438
|
+
context.consultFromConference === true &&
|
|
439
|
+
updatedMainMedia.length > 0 &&
|
|
440
|
+
wasPreviouslyInMainCall &&
|
|
441
|
+
!remainsInMainCall &&
|
|
442
|
+
remainsActiveInParticipantMap &&
|
|
443
|
+
remainsOnConsultLeg
|
|
444
|
+
) {
|
|
392
445
|
return true;
|
|
393
446
|
}
|
|
394
447
|
|
|
@@ -6,7 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type {AnyStateNodeConfig, ActionFunctionMap, EventObject, ActionArgs} from 'xstate';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
ConsultTransferDestinationConfig,
|
|
11
|
+
DestinationType,
|
|
12
|
+
TaskChannelType,
|
|
13
|
+
TaskData,
|
|
14
|
+
TaskUIControls,
|
|
15
|
+
VoiceVariant,
|
|
16
|
+
} from '../types';
|
|
10
17
|
import {TaskEvent, TaskState} from './constants';
|
|
11
18
|
|
|
12
19
|
/**
|
|
@@ -43,6 +50,14 @@ export interface UIControlConfig {
|
|
|
43
50
|
isRecordingEnabled: boolean;
|
|
44
51
|
/** Current agent ID for ownership checks (transfer conference) */
|
|
45
52
|
agentId?: string;
|
|
53
|
+
/** Agent-profile policy for ordered consult/transfer destinations */
|
|
54
|
+
consultTransferConfig?: ConsultTransferDestinationConfig;
|
|
55
|
+
/** Whether wxApp thick-client answer is enabled (WXCC-6026) */
|
|
56
|
+
enableWxBetterTogether?: boolean;
|
|
57
|
+
/** True while wxApp telephony answer is in flight (outdial Calling… label) */
|
|
58
|
+
wxAppAnswerPending?: boolean;
|
|
59
|
+
/** True only during the wxApp accept REST call (decline disabled for inbound + outdial) */
|
|
60
|
+
wxAppAcceptInFlight?: boolean;
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
/**
|