@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
package/.sdd/manifest.json
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"canonical_spec": "ai-docs/contact-center-spec.md",
|
|
52
52
|
"contracts": {
|
|
53
53
|
"provides": [
|
|
54
|
-
"Published @webex/contact-center package; ContactCenter WebexPlugin; public SDK methods, events, types, Task with ordered action-specific consult/transfer destination controls, AddressBook, ApiAIAssistant, UserPreference, cc.userPreference, existing getQueues/getEntryPoints methods with consult/transfer defaults, full Queue records,
|
|
54
|
+
"Published @webex/contact-center package; ContactCenter WebexPlugin; public SDK methods, events, types, Task with ordered action-specific consult/transfer destination controls, AddressBook, ApiAIAssistant, UserPreference, cc.userPreference, existing getQueues/getEntryPoints methods with consult/transfer defaults, full Queue records, mapped EntryPoint records with optional numbers, exported user-preference request/response types, preview-campaign methods acceptPreviewContact/skipPreviewContact/removePreviewContact, and Agent Wellness Break effective-profile, registered-session Profile projection, exported action constants/types, internally sourced action context, system-code, and primary/RTD notification event APIs",
|
|
55
55
|
"WXCC-6026 wxApp Better Together: enableWxBetterTogether init config, isWxBetterTogetherEnabled read API, unified task telephony (task.accept/decline/toggleMute/transmitDtmf), TASK_WXAPP_MUTE_STATE_UPDATED event, optional main.keypad uiControl, multi-login supported; runtime toggle deferred to Phase 2 (private)",
|
|
56
56
|
"BROWSER stationLogin payload: dialNumber and deviceId are webrtc-{agentId} (contact-center.station-login-browser-dn / AGENT-R-006); public stationLogin({loginOption: 'BROWSER'}) input unchanged"
|
|
57
57
|
],
|
|
@@ -96,7 +96,8 @@
|
|
|
96
96
|
"canonical_spec": "src/metrics/ai-docs/metrics-spec.md",
|
|
97
97
|
"contracts": {
|
|
98
98
|
"provides": [
|
|
99
|
-
"MetricsManager timing, behavioral/operational/business event submission, taxonomy, queues,
|
|
99
|
+
"MetricsManager timing, behavioral/operational/business event submission, taxonomy, queues, tracking-field helpers, and operational Agent Wellness Break action/notification/system-code event names",
|
|
100
|
+
"WXAPP_OFFER_PARTICIPANT_FIELDS_MISSING operational/behavioral telemetry event (contract metrics.wxapp-offer-participant-fields-missing; emit site voice/wxAppOfferObservability.ts)"
|
|
100
101
|
],
|
|
101
102
|
"requires": [
|
|
102
103
|
"Webex internal metrics service; Webex ready lifecycle; LoggerProxy; browser document visibility"
|
|
@@ -139,7 +140,7 @@
|
|
|
139
140
|
"canonical_spec": "src/services/ai-docs/services-spec.md",
|
|
140
141
|
"contracts": {
|
|
141
142
|
"provides": [
|
|
142
|
-
"Services composition root; agent/config/contact/dialer factories; AddressBook, EntryPoint, Queue, UserPreference, ApiAiAssistant, and WebCalling integration; existing Queue/EntryPoint list methods with SDK-owned defaults and compatible existing-parameter overrides; Queue returns full records and EntryPoint maps profile-scoped dial-number rows to typed records with optional numbers; cc.userPreference exposes user-preference CRUD"
|
|
143
|
+
"Services composition root; agent/config/contact/dialer factories; AddressBook, EntryPoint, Queue, UserPreference, ApiAiAssistant, and WebCalling integration; existing Queue/EntryPoint list methods with SDK-owned defaults and compatible existing-parameter overrides; Queue returns full records and EntryPoint maps profile-scoped dial-number rows to typed records with optional numbers; cc.userPreference exposes user-preference CRUD; ApiAiAssistant exposes session-validated direct wellness actions through a read-only context provider supplied at construction"
|
|
143
144
|
],
|
|
144
145
|
"requires": [
|
|
145
146
|
"Core HTTP/WebSocket/AQM infrastructure; WCC APIs; @webex/calling; MetricsManager; PageCache"
|
|
@@ -224,10 +225,10 @@
|
|
|
224
225
|
"canonical_spec": "src/services/config/ai-docs/config-spec.md",
|
|
225
226
|
"contracts": {
|
|
226
227
|
"provides": [
|
|
227
|
-
"Agent profile aggregation; config endpoint methods; CC event/type contracts; outdial ANI access"
|
|
228
|
+
"Agent profile aggregation including fail-closed Agent Wellness Break enablement; config endpoint methods including exact, registration-owned system wellness idle-code lookup; CC event/type contracts; outdial ANI access"
|
|
228
229
|
],
|
|
229
230
|
"requires": [
|
|
230
|
-
"WebexRequest; WCC organization, team, profile, aux-code, dial-plan, site, tenant, and URL-mapping APIs"
|
|
231
|
+
"WebexRequest; WCC organization, team, profile, AI-feature, aux-code, dial-plan, site, tenant, and URL-mapping APIs"
|
|
231
232
|
]
|
|
232
233
|
},
|
|
233
234
|
"section_profile": {
|
package/ai-docs/CONTRACTS.md
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
| `contact-center.state-controls` | Task state machine | `getDefaultUIControls`, `TaskUIControls` with ordered `consultTransferDestinations` arrays | Task controls include per-leg action state plus ordered `consult`/`transfer` destination categories derived from profile and interaction policy | additive semver public field; destination arrays are SDK-owned and first item is the consumer default | `src/services/task/state-machine/ai-docs/task-state-machine-spec.md` | `src/index.ts`, `src/services/task/types.ts`, `src/services/task/state-machine/uiControlsComputer.ts` |
|
|
18
18
|
| `contact-center.conference-participant-drop` | Task | `DropConferenceParticipantPayload`, `ITask.dropConferenceParticipant` | `(payload: {participantId: string}) => Promise<TaskResponse>`; Voice resolves from correlated `ParticipantLeftConference`, while non-voice base Task rejects as unsupported. Existing participant/consult lifecycle events may resolve one unique child-keyed task by `mainInteractionId`; no new public event is introduced. | semver public | `src/services/task/ai-docs/task-spec.md`, `src/services/task/state-machine/ai-docs/task-state-machine-spec.md` | `src/index.ts`, `src/services/task/types.ts`, `src/services/task/voice/Voice.ts`, `src/services/task/contact.ts`, `src/services/task/TaskManager.ts` |
|
|
19
19
|
| `contact-center.wxapp-answer` | Contact Center / Task | `enableWxBetterTogether`, `isWxBetterTogetherEnabled()`, `getWxAppMuted`, `syncWxAppMuteFromCallDetails`, unified task telephony (`ITask.accept`, `decline`, `toggleMute({ muted?, lineOwnerId? })`, `transmitDtmf({ dtmf, lineOwnerId? })`) | init flag ON → usersub `true` + Mercury on supported station login **and silent relogin**; init flag OFF → force usersub `false` on supported station login **and silent relogin** (clears stale suppression after refresh); **Phase 1 init-only** — change flag via re-init; multi-login supported; mute backfill via GET call details + `getWxAppMuted()` on hydrate/refresh; shared-line `lineOwnerId` defaults from participant; SDK `Voice` routes wxApp telephony when flag active | semver public | `src/services/task/ai-docs/task-spec.md`, `ai-docs/contact-center-spec.md`, `src/services/ai-docs/services-spec.md` | `src/cc.ts`, `src/services/task/voice/Voice.ts`, `src/services/task/voice/wxAppVoiceMethods.ts` |
|
|
20
|
+
| `contact-center.agent-wellness-break` | Contact Center / Services / Config | `Profile.isWellnessBreakEnabled`, optional `Profile.agentSessionId` after logged-in registration, `requestWellnessBreak`, `respondToWellnessBreak`, `getWellbeingBreakIdleCode`, `WELLNESS_BREAK_NOTIFICATION_ACTIONS`, `WELLNESS_BREAK_USER_ACTIONS`, `WellnessBreakEvent` | Effective gate = backend-delivered `agentWellbeing.enable` + reminders `ENABLED` + `aiAssistantQuantity > 0`; registration projects the SDK-owned active station session after silent relogin so hosts can validate refresh recovery. Action calls accept no identity or context-mutating fields, read the current organization/agent/session from a read-only provider supplied to ApiAIAssistant at construction, and POST a direct `WellnessBreakAction` custom event; current-session logout, multi-login close, relogin, and deregistration entry update or invalidate the provider's source state; system idle code lookup is exact, registration-generation cached, and rejects stale results; valid wellness notifications from either primary or RTD sockets emit the same public event. | additive semver public; no client-side Split dependency or invented rollout field—the delivered AI feature configuration is the server rollout boundary | `ai-docs/contact-center-spec.md`, `src/services/ai-docs/services-spec.md`, `src/services/config/ai-docs/config-spec.md` | `src/index.ts`, `src/types.ts`, `src/cc.ts`, `src/services/config/types.ts`, `src/services/ApiAiAssistant.ts` |
|
|
20
21
|
|
|
21
22
|
### Events
|
|
22
23
|
|
|
@@ -27,6 +28,13 @@
|
|
|
27
28
|
| `task.wxapp-mute.events` | Task | `task:wxapp-mute-state-updated` | publish to application/task | task spec/types | event-driven | additive | `src/services/task/types.ts`, `src/services/task/voice/Voice.ts` |
|
|
28
29
|
| `cc.events` | Config/Core | backend CC_EVENTS | consume/map | config/core specs | remote WebSocket delivery; AQM correlation where configured | backend contract | `src/services/config/types.ts` |
|
|
29
30
|
| `rtd.events` | Task | realtime transcription/suggestion | consume then publish per task | task spec | websocket best-effort according to remote service | additive payloads | `src/services/task/TaskManager.ts` |
|
|
31
|
+
| `wellness.notification.events` | Contact Center | `CC_AGENT_EVENTS.WELLNESS_BREAK` | consume validated wellness payloads from the primary data-notification socket, then publish normalized application events | Contact Center spec/types | exact current agent/org; notification session is diagnostic and is not compared with the active session; canonical optional `actionText` is normalized to public `actionText`; malformed/stale payloads are ignored | additive | `src/cc.ts`, `src/types.ts`, `src/services/config/types.ts` |
|
|
32
|
+
|
|
33
|
+
### Telemetry / Metrics Events
|
|
34
|
+
|
|
35
|
+
| Contract ID | Owner module | Event constant | Wire name | Payload schema link | Tags | Defined at |
|
|
36
|
+
|---|---|---|---|---|---|---|
|
|
37
|
+
| `metrics.wxapp-offer-participant-fields-missing` | Task / Metrics | `WXAPP_OFFER_PARTICIPANT_FIELDS_MISSING` | `WxApp Offer Participant Fields Missing` | `src/metrics/ai-docs/metrics-spec.md` | operational, behavioral | `src/metrics/constants.ts`, `src/services/task/voice/wxAppOfferObservability.ts` |
|
|
30
38
|
|
|
31
39
|
## Requires — what this repo depends on
|
|
32
40
|
|
package/ai-docs/SERVICE_STATE.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
| `task:*` | publish | Task/TaskManager → application | `src/services/task/types.ts` |
|
|
11
11
|
| `CC_EVENTS` | consume | WCC WebSocket → Core/ContactCenter/Task/AqmReqs | `src/services/config/types.ts` |
|
|
12
12
|
| realtime transcript/suggestion | consume/publish | RTD WebSocket → owning Task | `src/services/task/TaskManager.ts` |
|
|
13
|
+
| `Wellness_Break_Handler` | consume/publish | Primary data-notification WebSocket → ContactCenter → `CC_AGENT_EVENTS.WELLNESS_BREAK` | `src/cc.ts`, `src/types.ts` |
|
|
13
14
|
|
|
14
15
|
## Data Stores
|
|
15
16
|
|
|
@@ -42,6 +43,9 @@
|
|
|
42
43
|
| `allowAutomatedRelogin` | silent relogin after recovery | config-defined | ContactCenter | replacement recovery contract exists |
|
|
43
44
|
| `webRtcEnabled` / login option | browser calling path | remote profile | Config/WCC | remote contract removed |
|
|
44
45
|
| task UI/config flags | task controls and operations | profile/config-defined | Task/Config | owning behavior removed |
|
|
46
|
+
| `Profile.isWellnessBreakEnabled` | wellness event/action APIs and system-code access | false unless backend AI enablement, reminders, and positive license quantity are all present | Config/ContactCenter | wellness contract removed |
|
|
47
|
+
|
|
48
|
+
The backend-delivered `agentWellbeing.enable` value is the supported server rollout decision. The SDK combines it with `wellnessBreakReminders === 'ENABLED'` and `aiAssistantQuantity > 0`; it does not evaluate the Desktop Split flag or define a new rollout response field.
|
|
45
49
|
|
|
46
50
|
## Maintenance
|
|
47
51
|
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
| Doc kind | Module spec |
|
|
12
12
|
| Coverage score | Partial (manifest-authoritative); 15/15 required document fields present |
|
|
13
13
|
| Generated from | `module-spec` @ SDLC template library `0.2.1` |
|
|
14
|
-
| generated_by / approved_by / updated_at | Codex generator / developer-approved
|
|
15
|
-
| Validation status |
|
|
14
|
+
| generated_by / approved_by / updated_at | Codex generator / developer-approved Agent Wellness Break remediation / 2026-09-07 |
|
|
15
|
+
| Validation status | Agent Wellness Break v0.4 remediation independently validated by claude-code on 2026-09-07; coverage remains Partial until the remaining baseline promotion criteria are satisfied |
|
|
16
16
|
|
|
17
17
|
## Evidence Rules
|
|
18
18
|
Every requirement cites stable source and test file paths. Code/tests are the behavioral referee; routed source text supplies explicit intent and rationale. Missing or contradictory evidence blocks promotion.
|
|
@@ -39,6 +39,8 @@ The `@webex/contact-center` package is a Webex SDK plugin that provides a TypeSc
|
|
|
39
39
|
|
|
40
40
|
- **Answer on Webex**: Accept, Decline, Mute, and DTMF for voice offers when the agent uses Webex App desktop calling (`enableWxBetterTogether`).
|
|
41
41
|
|
|
42
|
+
- **Agent Wellness Break**: Effective enablement, agent/org-scoped notifications, active-session action reporting, system idle-code lookup, and legacy state transitions.
|
|
43
|
+
|
|
42
44
|
## Purpose / Responsibility
|
|
43
45
|
Own the published Webex Contact Center SDK plugin surface, registration lifecycle, public method delegation, and application-facing event routing.
|
|
44
46
|
|
|
@@ -79,6 +81,7 @@ src/
|
|
|
79
81
|
| `contact-center.user-preference` | SDK data API | Exported `UserPreference`, `cc.userPreference`, and user-preference request/response types. | Read and mutate user preferences through authenticated REST operations. | Additive public API; removals or signature changes are breaking. | `src/services/UserPreference.ts`, `src/services/config/types.ts` | `CONTRACTS.md` |
|
|
80
82
|
| `contact-center.preview-campaign` | SDK task API | `acceptPreviewContact`, `skipPreviewContact`, `removePreviewContact`. | Resolve campaign preview reservations through typed AQM operations. | Additive public API; removals or signature changes are breaking. | `src/cc.ts`, `src/services/task/dialer.ts`, `src/services/task/types.ts` | `CONTRACTS.md` |
|
|
81
83
|
| `contact-center.conference-participant-drop` | SDK task API | Exported `DropConferenceParticipantPayload` and `ITask.dropConferenceParticipant`. | Remove a conference participant through the media-specific task implementation and correlated AQM completion. | Additive public API; removals or signature changes are breaking. | `src/index.ts`, `src/services/task/types.ts`, `src/services/task/voice/Voice.ts` | `CONTRACTS.md` |
|
|
84
|
+
| `contact-center.agent-wellness-break` | SDK API / events | `Profile.isWellnessBreakEnabled`, `requestWellnessBreak`, `respondToWellnessBreak`, `getWellbeingBreakIdleCode`, and the wellness notification event contract. | Let hosts implement the public wellness-break lifecycle without reproducing backend payloads, routing rules, or session validation. | Additive public API; the effective gate is false unless all supported configuration inputs are affirmative. | `src/cc.ts`, `src/types.ts`, `src/services/config/types.ts` | `CONTRACTS.md` |
|
|
82
85
|
|
|
83
86
|
Compatibility notes:
|
|
84
87
|
- Do not remove or reinterpret exported symbols/events without a documented consumer migration.
|
|
@@ -96,6 +99,9 @@ Compatibility notes:
|
|
|
96
99
|
| CONTACT_CENTER-R-003 | Delegate agent, task, data, user-preference, preview-campaign, AI-assistant, calling, and telemetry behavior to their owning collaborators while preserving typed package methods and events. Existing `getQueues` and `getEntryPoints` delegate to their services with unchanged signatures and full-record responses; the services own consult/transfer telephony filter, profile-view, ordering, and cache defaults while honoring explicit existing-parameter overrides. Before preview delegation, reject disabled skip/remove actions from task campaign flags. | A thin stable façade avoids parallel consumer APIs while service-owned defaults keep ordinary widget calls consistent and preserve an override path for other consumers. | `src/cc.ts`, `src/types.ts`, `src/services/Queue.ts`, `src/services/EntryPoint.ts`, `src/services/UserPreference.ts`, `src/services/task/dialer.ts` | `test/unit/spec/cc.ts`, `test/unit/spec/services/Queue.ts`, `test/unit/spec/services/EntryPoint.ts`, `test/unit/spec/services/UserPreference.ts`, `test/unit/spec/services/task/dialer.ts` | Public preview delegation is covered; the `campaignPreviewSkipDisabled` and `campaignPreviewRemoveDisabled` early-exit guards lack direct unit coverage. Independent review identified this gap on 2026-07-15. | PRESENT |
|
|
97
100
|
| CONTACT_CENTER-R-004 | `deregister()` must remove registered listeners, stop applicable host/calling resources, close primary and RTD WebSockets, clear agent configuration, and surface cleanup failures. | Listener or connection leaks create duplicate events and stale authenticated sessions in long-lived hosts. | `src/cc.ts` | `test/unit/spec/cc.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
98
101
|
| CONTACT_CENTER-R-005 | On `connectionLost`, ContactCenter must own recovery policy and invoke private `silentRelogin()` only when automated relogin is allowed. | ConnectionService reports transport state; only ContactCenter has agent profile and policy context for authentication recovery. | `src/cc.ts` | `test/unit/spec/cc.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
102
|
+
| CONTACT_CENTER-R-006 | Expose Agent Wellness Break methods, action-value objects, and types only through the package façade. Derive the public action unions from those `as const` value objects. Action calls accept no identity or context-mutating API; ApiAIAssistant reads effective enablement and organization/agent/session identity from a read-only provider supplied by ContactCenter at construction and rejects when that context is incomplete. Logout, deregistration entry, a current-session multi-login close, and relogin update the provider's source state. The exact system idle-code cache and its in-flight lookup are owned by one registration generation; a newer registration or deregistration rejects a late result instead of caching it. | Wellness actions and cached configuration are registration-scoped and must not leak across agents, relogins, multi-login closures, organizations, or registrations; one public value/type source prevents wire-value drift. | `src/cc.ts`, `src/types.ts`, `src/services/ApiAiAssistant.ts`, `src/index.ts` | `test/unit/spec/cc.ts`, `test/unit/spec/services/ApiAiAssistant.ts`, `docs/samples/contact-center/` | The backend-delivered `agentWellbeing.enable` value is treated as the server rollout decision because no distinct rollout field exists in the supported SDK response contracts. | PRESENT |
|
|
103
|
+
| CONTACT_CENTER-R-007 | When wellness is effectively enabled, connect the RTD WebSocket even if transcripts and suggested responses are disabled. Route valid `Wellness_Break_Handler` messages from the primary or RTD data-notification socket to `CC_AGENT_EVENTS.WELLNESS_BREAK`. Notification eligibility is scoped to the current agent and organization and deliberately does not compare the notification-provided `agentSessionId` with the active session; outbound wellness APIs remain active-session validated. Ignore malformed or foreign-identity messages without logging the full payload. | A long-lived host needs parity with Desktop notification routing without dropping legitimate nudges whose backend session metadata differs, while actions must still be sent only for the active local session. | `src/cc.ts`, `src/constants.ts`, `src/services/config/types.ts`, `src/services/ApiAiAssistant.ts` | `test/unit/spec/cc.ts`, `test/unit/spec/services/ApiAiAssistant.ts`, `docs/samples/contact-center/` | Notification delivery remains best-effort; the backend owns offer generation and ordering. | PRESENT |
|
|
104
|
+
| CONTACT_CENTER-R-008 | The standalone SDK sample must keep `WellbeingBreak` out of the ordinary idle-code selector, wait for legacy state confirmation and all tasks to become safe, restore `Available` after a completed break with bounded recovery, synchronize authoritative external state changes, use a session-scoped refresh marker without replaying an offer, action, or break, and revoke manual-request eligibility on `WELLNESS_BREAK_NOT_ALLOWED`. A rejected `REJECTED` or `NO_RESPONSE` delivery must retain and re-arm the offer for retry. Logout cleanup must ignore a different agent session, and deregistration cleanup must run when the SDK has completed its local teardown even if a deferred cleanup error is reported. Pure transition helpers own these decisions and are covered behaviorally; browser/source checks are limited to bundle and copy surfaces. | The sample is the executable public-contract reference and must track backend eligibility, avoid duplicated wire literals, and avoid state stranding or cross-session cleanup. | `docs/samples/contact-center/app.js`, `docs/samples/contact-center/wellness-utils.js`, `docs/samples/contact-center/index.html`, `src/webex.js` | `test/unit/spec/wellnessSampleUtils.ts`, sample build | Live QA still supplies authoritative backend/session integration evidence. | PRESENT |
|
|
99
105
|
|
|
100
106
|
## Design Overview
|
|
101
107
|
`ContactCenter` is the package façade and lifecycle owner. Its constructor waits for the host Webex SDK `READY` event, validates plugin configuration, initializes `WebexRequest`, obtains the singleton `Services` graph, and constructs calling, AI-assistant, metrics, task-management, `UserPreference`, and data-service collaborators. `register()` is deliberately narrower: it attaches runtime listeners and establishes the primary Contact Center WebSocket subscription.
|
|
@@ -104,6 +110,16 @@ Direct data/configuration and user-preference operations return authenticated RE
|
|
|
104
110
|
|
|
105
111
|
Durable agent, task, and configuration records remain remote-system owned. The package owns only in-memory profile/task/listener/cache/connection state.
|
|
106
112
|
|
|
113
|
+
### Agent Wellness Break
|
|
114
|
+
|
|
115
|
+
The public enablement signal is `Profile.isWellnessBreakEnabled`. It is true only when the backend-delivered AI feature row has `agentWellbeing.enable === true`, `wellnessBreakReminders === 'ENABLED'`, and the organization reports `aiAssistantQuantity > 0`. The SDK does not create a Desktop Split client or invent a rollout response field: the backend controls rollout by deciding whether the delivered AI feature configuration enables wellness for the organization.
|
|
116
|
+
|
|
117
|
+
After station login or relogin, ContactCenter retains the current agent-session id. When registration silently restores an already logged-in station, the returned `Profile.agentSessionId` projects that active session. It is absent when registration has no active session. This lets hosts recover session-scoped state after refresh without reading SDK internals or trusting a notification's session id. ApiAIAssistant reads the current effective gate and organization/agent/session identity through a read-only provider supplied by ContactCenter at construction; it exposes no context-mutating method or separate factory. Logout, deregistration entry, and a current-session multi-login close invalidate the provider's source state. `requestWellnessBreak()` and `respondToWellnessBreak()` do not accept identity fields; they POST a direct custom event with a fresh numeric timestamp and reject disabled or incomplete context before transport. Public action types are derived from exported `as const` action-value objects so applications and samples can use the same wire values without an enum. `getWellbeingBreakIdleCode()` resolves the exact active system code named `WellbeingBreak` and caches it for the registration lifetime. The lookup captures its registration generation and organization before transport; if either ownership value changes before the response arrives, the stale result is rejected and never repopulates the cache.
|
|
118
|
+
|
|
119
|
+
Wellness payloads are handled by ContactCenter on the primary or RTD data-notification socket before ordinary routing. Only known actions with matching agent and organization are emitted; the notification session is retained as diagnostic metadata and is not treated as action authority. The canonical optional `actionText` field is normalized to public `actionText`. Deregistration clears the wellness session and system-code cache.
|
|
120
|
+
|
|
121
|
+
The standalone SDK browser sample keeps `WellbeingBreak` out of the ordinary status selector. It reads the exported wellness wire constants from the standalone `Webex` constructor, seeds its current session and legacy state from a logged-in registration profile after silent relogin, and shows only the action name in its latest-event display. It creates a session-scoped recovery marker before changing legacy state, clears manual-request eligibility when a break starts so the request control remains disabled after restoration until another `SUGGEST_WELLNESS_BREAK`, confirms the transition, sends `ACCEPTED` only after state success, and waits for every task to leave incoming, active, consult, conference, campaign, and wrap-up work before starting its 60-second demonstration timer. Restoration targets `Available / 0`, retries bounded failures, and retains reconnect recovery ownership after exhaustion. Authoritative external Available changes end the local lifecycle, while refresh recovery restores a matching current session without replaying the offer, response action, or break. Pure helpers own notification, response, logout, and deregistration transition decisions; a failed rejection/no-response delivery retains and re-arms its offer. If SDK deregistration completes its local teardown but reports a deferred error, the sample still detaches listeners and resets its local controls.
|
|
122
|
+
|
|
107
123
|
### wxApp Better Together (WXCC-6026)
|
|
108
124
|
|
|
109
125
|
Contract id: `contact-center.wxapp-answer` ([CONTRACTS.md](./CONTRACTS.md)). Task telephony routing, UI controls, and mute events are specified in [task-spec.md](../src/services/task/ai-docs/task-spec.md). Service collaborators: [services-spec.md](../src/services/ai-docs/services-spec.md).
|
|
@@ -283,6 +299,7 @@ classDiagram
|
|
|
283
299
|
- **UC-3 Delegate SDK operations:** validate/map public inputs, call the owning collaborator, track metrics, and return or emit typed results. Evidence: `src/cc.ts`, `src/index.ts`, `test/unit/spec/cc.ts`.
|
|
284
300
|
- **UC-4 Recover connection:** consume ConnectionService state and conditionally reload the agent session through ContactCenter policy. Evidence: `src/cc.ts`, `test/unit/spec/cc.ts`.
|
|
285
301
|
- **UC-5 Deregister:** remove the same listener identities, shut down applicable host/WebSocket resources, and clear in-memory profile state. Evidence: `src/cc.ts`, `test/unit/spec/cc.ts`.
|
|
302
|
+
- **UC-6 Wellness lifecycle:** consume an agent/org-scoped offer regardless of its notification session metadata, report a user action using the active local session, resolve the system idle code, and demonstrate legacy Idle/Available transitions. Evidence: `src/cc.ts`, `src/services/ApiAiAssistant.ts`, `src/services/config/index.ts`, `test/unit/spec/cc.ts`, `docs/samples/contact-center/`.
|
|
286
303
|
|
|
287
304
|
## State Model
|
|
288
305
|
ContactCenter retains in-memory `agentConfig`, collaborator references, event listeners, task collections through TaskManager, and connection/recovery state. Remote Webex services remain authoritative for agent, task, and organization data. Registration establishes runtime connectivity but does not imply station login; deregistration tears down SDK resources but does not itself perform station logout.
|
|
@@ -294,6 +311,9 @@ ContactCenter retains in-memory `agentConfig`, collaborator references, event li
|
|
|
294
311
|
- ContactCenter owns automated relogin policy; ConnectionService owns transport-state detection/emission. Evidence: `src/cc.ts`, `src/services/core/websocket/connection-service.ts`.
|
|
295
312
|
- Deregistration does not station-logout the agent. Evidence: `src/cc.ts`.
|
|
296
313
|
- Published methods/types/events remain semver-sensitive through `src/index.ts`.
|
|
314
|
+
- Wellness actions take no public identity or context-mutating input and require the effective profile flag plus non-empty SDK-owned organization, registered-agent, and current-session context read from the internal live provider; all checks fail closed after current-session logout, multi-login close, or deregistration.
|
|
315
|
+
- Wellness action unions derive from exported `as const` value objects; backend message-type and enablement sentinels use internal constants rather than duplicated literals.
|
|
316
|
+
- Malformed, unknown-action, stale-agent, and stale-org wellness notifications are ignored and measured without logging the full payload. A different notification `agentSessionId` is retained as diagnostic metadata and does not make an otherwise valid current-agent/current-org wellness event stale.
|
|
297
317
|
|
|
298
318
|
## Concurrency & Reactive Flow
|
|
299
319
|
READY initialization, REST promises, AQM WebSocket correlation, TaskManager events, calling events, and connection timers execute asynchronously. Listener cleanup must use the registered function identity. Message listeners are independent: AqmReqs correlates pending requests, ContactCenter maps package events, TaskManager owns task lifecycle, and ConnectionService tracks liveness/reconnect state.
|
|
@@ -315,7 +335,7 @@ stateDiagram-v2
|
|
|
315
335
|
```
|
|
316
336
|
|
|
317
337
|
## Protocol / Wire Format
|
|
318
|
-
Authenticated REST initiates direct data/config operations and AQM agent/task operations. For AQM, the HTTP response is acknowledgement only; `notifSuccess.bind`/`notifFail.bind` match WebSocket payloads that settle the promise. The primary
|
|
338
|
+
Authenticated REST initiates direct data/config operations and AQM agent/task operations. For AQM, the HTTP response is acknowledgement only; `notifSuccess.bind`/`notifFail.bind` match WebSocket payloads that settle the promise. Wellness actions are the exception: ApiAIAssistant posts a direct `CUSTOM_EVENT` to `/event` and requires HTTP 202. The primary and RTD WebSockets can carry `Wellness_Break_Handler`; ContactCenter routes it before task-specific traffic. Payload and event names are owned by `src/types.ts`, `src/services/config/types.ts`, `src/services/agent/types.ts`, and `src/services/task/types.ts`.
|
|
319
339
|
|
|
320
340
|
## Error Handling & Failure Modes
|
|
321
341
|
| Condition | Signal (error/code/result) | Caller recovery |
|
|
@@ -353,6 +373,9 @@ The module registers as `cc` through the Webex SDK plugin system and depends on
|
|
|
353
373
|
| CONTACT_CENTER-R-003 | `test/unit/spec/cc.ts`, `test/unit/spec/services/UserPreference.ts`, `test/unit/spec/services/task/dialer.ts` | Add direct tests proving disabled skip/remove flags throw before dialer invocation; revalidate typed delegation, user-preference CRUD, preview-campaign AQM operations, and event routing. |
|
|
354
374
|
| CONTACT_CENTER-R-004 | `test/unit/spec/cc.ts` | listener/resource cleanup and error propagation |
|
|
355
375
|
| CONTACT_CENTER-R-005 | `test/unit/spec/cc.ts` | relogin policy ownership |
|
|
376
|
+
| CONTACT_CENTER-R-006 | `test/unit/spec/cc.ts`, `test/unit/spec/services/ApiAiAssistant.ts` | Effective-gate and internal organization/agent/session validation, current-session multi-login invalidation, registration-generation idle-code cache ownership, identity-free public input, exact request body, action validation, and direct-HTTP failure paths. |
|
|
377
|
+
| CONTACT_CENTER-R-007 | `test/unit/spec/cc.ts`, `test/unit/spec/services/ApiAiAssistant.ts` | Wellness normalization on primary and RTD notification sockets, notification-session mismatch acceptance, invalid agent/org filtering, and active-session outbound validation. |
|
|
378
|
+
| CONTACT_CENTER-R-008 | `test/unit/spec/wellnessSampleUtils.ts`, sample build | Safe-work classification, legacy external/RONA decisions, minimal refresh marker, recovery decisions, retryable offer-response transitions, session-scoped logout cleanup, deferred-error deregistration cleanup, and standalone browser constant exposure. |
|
|
356
379
|
|
|
357
380
|
## Traceability
|
|
358
381
|
- Repo architecture: `ARCHITECTURE.md` · Registry: `SPEC_INDEX.md`
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Contact Owner Change Refactor
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
This change refactors only the owner-change propagation introduced by
|
|
6
|
+
webex-js-sdk PR #5187. It preserves the behavior required by Participant Drop:
|
|
7
|
+
when the backend promotes a new primary Agent, existing SDK tasks publish the
|
|
8
|
+
updated owner through the existing `task:hydrate` event so widgets immediately
|
|
9
|
+
recompute the Primary label, icon, and Drop permission.
|
|
10
|
+
|
|
11
|
+
There is no public API, routing-event, state-machine transition, Participant
|
|
12
|
+
Drop request, or widget contract change.
|
|
13
|
+
|
|
14
|
+
## Retained behavior
|
|
15
|
+
|
|
16
|
+
| Behavior | Why it remains | Existing-flow impact |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Map an owner-changing `ContactUpdated` to `CONTACT_OWNER_CHANGED` | Remaining conference Agents receive `ContactUpdated`, not necessarily `ContactOwnerChanged`. The existing state-machine action synchronizes task data and emits `task:hydrate`. | Preserves immediate owner/Primary UI updates without adding a new public event or state transition. Same-owner and owner-less updates remain data-only. |
|
|
19
|
+
| Resolve `ContactOwnerChanged` by exact ID before related IDs | Exact identity remains the safest and existing lookup contract. | Existing exact task routing is unchanged. |
|
|
20
|
+
| Resolve one unique related task using nested interaction IDs, the collection key, or the `mainCall` media-map key | Some supported owner-change payloads identify the surviving call through a child top-level ID and omit `mainInteractionId`. | Preserves cross-channel promotion across the documented payload variants. Task aliases are deduplicated and ambiguous matches remain ignored. |
|
|
21
|
+
| Accept current-Agent main-leg evidence from the existing task or authoritative incoming promotion | A local child task can be briefly stale when the owner-change payload first proves promotion. | Preserves the stale-snapshot fix while continuing to reject ordinary consult-only tasks. |
|
|
22
|
+
| Recover a missing promoted-Agent task from a complete `ContactOwnerChanged` payload | Reloaded or desynchronized clients may receive the authoritative promotion before normal task creation catches up. Agent Desktop supports the same recovery path. | A complete telephony main-leg payload restores the task under the stable main interaction ID, emits one `task:hydrate`, and emits no synthetic `task:incoming`. |
|
|
23
|
+
| Preserve a confirmed owner across a late `ParticipantLeftConference` snapshot that still names the departed owner | Participant Drop can deliver owner change and participant-left notifications in either order. | Prevents the Primary UI from reverting after it has already received the authoritative new owner. |
|
|
24
|
+
|
|
25
|
+
## Refactoring and safety constraints
|
|
26
|
+
|
|
27
|
+
Owner-change correlation and recovery retain the following protections:
|
|
28
|
+
|
|
29
|
+
- generic lifecycle-event correlation is unchanged; collection-key and media-key
|
|
30
|
+
matching are enabled only for `ContactOwnerChanged`;
|
|
31
|
+
- only a task selected by the related-interaction fallback may be re-keyed;
|
|
32
|
+
- conflicting task/payload main IDs are ignored;
|
|
33
|
+
- a stable main key already owned by a different Task causes the event to be
|
|
34
|
+
ignored; and
|
|
35
|
+
- an exact child task is never normalized over a distinct main task;
|
|
36
|
+
- aliases of the same Task object are deduplicated before uniqueness is tested;
|
|
37
|
+
- consult-only and ambiguous matches are rejected; and
|
|
38
|
+
- missing-task recovery is rejected whenever any related task or canonical-key
|
|
39
|
+
occupant already exists.
|
|
40
|
+
|
|
41
|
+
This closes the PR review scenario where an exact child task could previously
|
|
42
|
+
be normalized to a main key and silently replace the actual main Task, orphaning
|
|
43
|
+
its listeners and resources.
|
|
44
|
+
|
|
45
|
+
Recovery is intentionally narrow. It requires a non-terminal telephony payload,
|
|
46
|
+
`interaction.owner` equal to the current Agent, an active participant entry for
|
|
47
|
+
that Agent on an `mType: mainCall` leg, and a stable main interaction ID. It does
|
|
48
|
+
not use `toOwner`, elect an owner locally, or create a task for a missing
|
|
49
|
+
owner-changing `ContactUpdated` event.
|
|
50
|
+
|
|
51
|
+
## Resulting event flow
|
|
52
|
+
|
|
53
|
+
1. The backend chooses the new `interaction.owner`.
|
|
54
|
+
2. The promoted Agent receives `ContactOwnerChanged`; other surviving Agents may
|
|
55
|
+
receive an owner-changing `ContactUpdated`.
|
|
56
|
+
3. TaskManager first uses an exact task match and otherwise accepts one unique,
|
|
57
|
+
eligible related task.
|
|
58
|
+
4. If the promoted Agent has no related task, a complete authoritative payload
|
|
59
|
+
may recover the task under its stable main interaction ID. An internal
|
|
60
|
+
pre-listener `HYDRATE` restores the actor state without publishing an event.
|
|
61
|
+
5. Both notification forms use the existing `CONTACT_OWNER_CHANGED` state-machine
|
|
62
|
+
event.
|
|
63
|
+
6. The state machine updates task/context data, keeps the current task state, and
|
|
64
|
+
emits exactly one public `task:hydrate`.
|
|
65
|
+
7. Widget consumers receive the hydrated Task and render the backend-provided
|
|
66
|
+
owner immediately.
|
|
67
|
+
|
|
68
|
+
`ParticipantLeftConference` continues through its existing event/state-machine
|
|
69
|
+
path. No client elects a successor and no Drop completion fabricates an owner.
|
|
70
|
+
|
|
71
|
+
## Verification coverage
|
|
72
|
+
|
|
73
|
+
The focused TaskManager tests cover owner-changing versus data-only
|
|
74
|
+
`ContactUpdated`, exact and child-keyed correlation, collection-key and
|
|
75
|
+
`mainCall` media-key payloads, stale incoming promotion evidence, consult-only
|
|
76
|
+
and ambiguous rejection, narrow missing-task recovery, listener/alias safety,
|
|
77
|
+
later `AgentContact` and `ContactMerged` reuse, exact-child/main-task collision
|
|
78
|
+
protection, and both owner-change/participant-left orders.
|