@webex/contact-center 3.12.0-next.124 → 3.12.0-next.126

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.
Files changed (60) hide show
  1. package/.sdd/manifest.json +5 -5
  2. package/ai-docs/CONTRACTS.md +2 -0
  3. package/ai-docs/SERVICE_STATE.md +4 -0
  4. package/ai-docs/contact-center-spec.md +26 -3
  5. package/dist/cc.js +163 -2
  6. package/dist/cc.js.map +1 -1
  7. package/dist/constants.js +5 -1
  8. package/dist/constants.js.map +1 -1
  9. package/dist/index.js +25 -10
  10. package/dist/index.js.map +1 -1
  11. package/dist/metrics/constants.js +5 -0
  12. package/dist/metrics/constants.js.map +1 -1
  13. package/dist/services/ApiAiAssistant.js +116 -1
  14. package/dist/services/ApiAiAssistant.js.map +1 -1
  15. package/dist/services/config/Util.js +5 -1
  16. package/dist/services/config/Util.js.map +1 -1
  17. package/dist/services/config/constants.js +10 -1
  18. package/dist/services/config/constants.js.map +1 -1
  19. package/dist/services/config/index.js +51 -0
  20. package/dist/services/config/index.js.map +1 -1
  21. package/dist/services/config/types.js +4 -3
  22. package/dist/services/config/types.js.map +1 -1
  23. package/dist/services/core/Utils.js +5 -1
  24. package/dist/services/core/Utils.js.map +1 -1
  25. package/dist/types/cc.d.ts +21 -1
  26. package/dist/types/constants.d.ts +4 -0
  27. package/dist/types/index.d.ts +11 -1
  28. package/dist/types/metrics/constants.d.ts +5 -0
  29. package/dist/types/services/ApiAiAssistant.d.ts +35 -2
  30. package/dist/types/services/config/constants.d.ts +5 -0
  31. package/dist/types/services/config/types.d.ts +13 -2
  32. package/dist/types/services/core/Utils.d.ts +2 -0
  33. package/dist/types/types.d.ts +56 -1
  34. package/dist/types.js +39 -2
  35. package/dist/types.js.map +1 -1
  36. package/dist/webex.js +9 -1
  37. package/dist/webex.js.map +1 -1
  38. package/package.json +8 -8
  39. package/src/cc.ts +251 -18
  40. package/src/constants.ts +4 -0
  41. package/src/index.ts +11 -0
  42. package/src/metrics/ai-docs/metrics-spec.md +19 -20
  43. package/src/metrics/constants.ts +5 -0
  44. package/src/services/ApiAiAssistant.ts +153 -1
  45. package/src/services/ai-docs/services-spec.md +11 -3
  46. package/src/services/config/Util.ts +6 -0
  47. package/src/services/config/ai-docs/config-spec.md +14 -3
  48. package/src/services/config/constants.ts +12 -0
  49. package/src/services/config/index.ts +65 -0
  50. package/src/services/config/types.ts +11 -2
  51. package/src/services/core/Utils.ts +4 -0
  52. package/src/types.ts +63 -0
  53. package/src/webex.js +8 -0
  54. package/test/unit/spec/cc.ts +268 -0
  55. package/test/unit/spec/services/ApiAiAssistant.ts +134 -2
  56. package/test/unit/spec/services/config/Util.ts +44 -0
  57. package/test/unit/spec/services/config/index.ts +68 -0
  58. package/test/unit/spec/wellnessSampleUtils.ts +288 -0
  59. package/umd/contact-center.min.js +2 -2
  60. package/umd/contact-center.min.js.map +1 -1
@@ -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, and mapped EntryPoint records with optional numbers, exported user-preference request/response types, and preview-campaign methods acceptPreviewContact/skipPreviewContact/removePreviewContact",
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, exported action constants/types, internally sourced action context, system-code, and primary 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,7 @@
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, and tracking-field helpers"
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
100
  ],
101
101
  "requires": [
102
102
  "Webex internal metrics service; Webex ready lifecycle; LoggerProxy; browser document visibility"
@@ -139,7 +139,7 @@
139
139
  "canonical_spec": "src/services/ai-docs/services-spec.md",
140
140
  "contracts": {
141
141
  "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"
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; ApiAiAssistant exposes session-validated direct wellness actions through a read-only context provider supplied at construction"
143
143
  ],
144
144
  "requires": [
145
145
  "Core HTTP/WebSocket/AQM infrastructure; WCC APIs; @webex/calling; MetricsManager; PageCache"
@@ -224,10 +224,10 @@
224
224
  "canonical_spec": "src/services/config/ai-docs/config-spec.md",
225
225
  "contracts": {
226
226
  "provides": [
227
- "Agent profile aggregation; config endpoint methods; CC event/type contracts; outdial ANI access"
227
+ "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
228
  ],
229
229
  "requires": [
230
- "WebexRequest; WCC organization, team, profile, aux-code, dial-plan, site, tenant, and URL-mapping APIs"
230
+ "WebexRequest; WCC organization, team, profile, AI-feature, aux-code, dial-plan, site, tenant, and URL-mapping APIs"
231
231
  ]
232
232
  },
233
233
  "section_profile": {
@@ -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`, `requestWellnessBreak`, `respondToWellnessBreak`, `getWellbeingBreakIdleCode`, `WELLNESS_BREAK_NOTIFICATION_ACTIONS`, `WELLNESS_BREAK_USER_ACTIONS`, `WellnessBreakEvent` | Effective gate = backend-delivered `agentWellbeing.enable` + reminders `ENABLED` + `aiAssistantQuantity > 0`; public action unions derive from exported `as const` values. 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. | 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/ApiAiAssistant.ts` |
20
21
 
21
22
  ### Events
22
23
 
@@ -27,6 +28,7 @@
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` |
30
32
 
31
33
  ## Requires — what this repo depends on
32
34
 
@@ -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 follow-up review remediation / 2026-08-21 |
15
- | Validation status | Follow-up validation passed (independent Claude fallback, 2026-07-21); 1 existing test-coverage gap; coverage remains Partial |
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, route valid `Wellness_Break_Handler` messages from the primary 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 the legacy pre-break state 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. 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 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, creates a session-scoped recovery marker before changing legacy state, 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 WebSocket carries Contact Center notifications; the RTD WebSocket carries transcript/suggestion 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`.
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 WebSocket carries Contact Center and legacy data-notification traffic, including `Wellness_Break_Handler`. 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 the primary notification socket, 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`
package/dist/cc.js CHANGED
@@ -240,6 +240,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
240
240
  * @private
241
241
  */
242
242
 
243
+ /** Current login/relogin session used for agent-scoped wellness validation. */
244
+
245
+ /** Registered-session cache for the system WellbeingBreak idle code. */
246
+
247
+ /** Registration generation that owns the wellness idle-code cache and in-flight lookups. */
248
+ wellnessRegistrationGeneration = 0;
249
+ updateWellnessSession(agentSessionId) {
250
+ this.currentAgentSessionId = agentSessionId;
251
+ }
252
+
243
253
  /**
244
254
  * API instance for managing Webex Contact Center entry points
245
255
  * Provides functionality to fetch entry points with caching support
@@ -375,7 +385,11 @@ class ContactCenter extends _webexCore.WebexPlugin {
375
385
  this.answerCallOnWebexService = new _AnswerCallOnWebexService.default(this.$webex);
376
386
  this.webexCrossClientService = new _WebexCrossClientService.default(this.$webex);
377
387
  this.wxAppTelephonyMercurySync = new _WxAppTelephonyMercurySync.default(this.$webex);
378
- this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex);
388
+ this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex, () => ({
389
+ isWellnessBreakEnabled: this.agentConfig?.isWellnessBreakEnabled === true,
390
+ agentId: this.agentConfig?.agentId,
391
+ agentSessionId: this.currentAgentSessionId
392
+ }));
379
393
  this.metricsManager = _MetricsManager.default.getInstance({
380
394
  webex: this.$webex
381
395
  });
@@ -442,6 +456,72 @@ class ContactCenter extends _webexCore.WebexPlugin {
442
456
  // @ts-ignore
443
457
  this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
444
458
  };
459
+ trackInvalidWellnessEvent(reason) {
460
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.AI_ASSISTANT_WELLNESS_EVENT_INVALID, {
461
+ reason
462
+ }, ['operational']);
463
+ }
464
+ normalizeWellnessBreakEvent(payload) {
465
+ if (this.agentConfig?.isWellnessBreakEnabled !== true) {
466
+ this.trackInvalidWellnessEvent('wellness_disabled');
467
+ return null;
468
+ }
469
+ const notificationData = (0, _Utils.isRecord)(payload.data) ? payload.data : null;
470
+ const notificationDetails = notificationData && (0, _Utils.isRecord)(notificationData.notifDetails) ? notificationData.notifDetails : null;
471
+ const sessionData = notificationData && (0, _Utils.isRecord)(notificationData.data) ? notificationData.data : null;
472
+ const actionEvent = notificationDetails?.actionEvent;
473
+ if (payload.type !== _constants.WELLNESS_BREAK_HANDLER || notificationData?.notifType !== _constants.WELLNESS_BREAK_HANDLER || typeof actionEvent !== 'string') {
474
+ this.trackInvalidWellnessEvent('malformed_wellness_event');
475
+ return null;
476
+ }
477
+ if (!Object.values(_types.WELLNESS_BREAK_NOTIFICATION_ACTIONS).includes(actionEvent)) {
478
+ this.trackInvalidWellnessEvent('unknown_wellness_action');
479
+ return null;
480
+ }
481
+ const agentId = notificationData.agentId;
482
+ const eventOrgId = notificationData.orgId;
483
+ const sessionOrgId = sessionData?.orgId;
484
+ const envelopeOrgId = payload.orgId;
485
+ const agentSessionId = sessionData?.agentSessionId;
486
+ const currentOrgId = this.$webex.credentials.getOrgId();
487
+ if (typeof agentId !== 'string' || typeof eventOrgId !== 'string' || typeof sessionOrgId !== 'string' || typeof envelopeOrgId !== 'string' || typeof agentSessionId !== 'string' || !agentId || !eventOrgId || !sessionOrgId || !envelopeOrgId || !agentSessionId) {
488
+ this.trackInvalidWellnessEvent('missing_wellness_identity');
489
+ return null;
490
+ }
491
+ if (agentId !== this.agentConfig?.agentId || eventOrgId !== currentOrgId || sessionOrgId !== currentOrgId || envelopeOrgId !== currentOrgId) {
492
+ this.trackInvalidWellnessEvent('mismatched_wellness_identity');
493
+ return null;
494
+ }
495
+ const interactionValue = sessionData.interactionId ?? sessionData.InteractionId;
496
+ const actionText = notificationDetails.actionText;
497
+ const trackingId = payload.trackingId;
498
+ return {
499
+ agentId,
500
+ orgId: currentOrgId,
501
+ agentSessionId,
502
+ actionEvent: actionEvent,
503
+ ...(typeof actionText === 'string' ? {
504
+ actionText
505
+ } : {}),
506
+ ...(typeof interactionValue === 'string' ? {
507
+ interactionId: interactionValue
508
+ } : {}),
509
+ ...(typeof trackingId === 'string' ? {
510
+ trackingId
511
+ } : {})
512
+ };
513
+ }
514
+ handleWellnessBreakWebsocketPayload(payload) {
515
+ if (payload.type !== _constants.WELLNESS_BREAK_HANDLER) {
516
+ return false;
517
+ }
518
+ const wellnessEvent = this.normalizeWellnessBreakEvent(payload);
519
+ if (wellnessEvent) {
520
+ // @ts-ignore - WebexPlugin emit is available at runtime but absent from its declaration.
521
+ this.emit(_types3.CC_EVENTS.WELLNESS_BREAK, wellnessEvent);
522
+ }
523
+ return true;
524
+ }
445
525
  handleRTDWebsocketMessage = event => {
446
526
  this.taskManager.handleRealtimeWebsocketEvent(event);
447
527
  };
@@ -496,6 +576,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
496
576
  * ```
497
577
  */
498
578
  async register() {
579
+ this.wellnessRegistrationGeneration += 1;
580
+ this.wellbeingBreakIdleCode = undefined;
499
581
  _loggerProxy.default.log('Starting CC SDK registration', {
500
582
  module: _constants.CC_FILE,
501
583
  method: _constants.METHODS.REGISTER
@@ -562,6 +644,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
562
644
  *
563
645
  */
564
646
  async deregister() {
647
+ this.wellnessRegistrationGeneration += 1;
648
+ this.wellbeingBreakIdleCode = undefined;
649
+ this.updateWellnessSession();
565
650
  try {
566
651
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_FAIL]);
567
652
  this.taskManager.off(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
@@ -601,7 +686,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
601
686
  }
602
687
 
603
688
  // Clear any cached agent configuration
689
+ this.wellbeingBreakIdleCode = undefined;
604
690
  this.agentConfig = null;
691
+ this.updateWellnessSession();
605
692
  if (wxAppPublishError) {
606
693
  throw wxAppPublishError;
607
694
  }
@@ -748,6 +835,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
748
835
  this.taskManager.setAgentId(this.agentConfig.agentId);
749
836
  this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
750
837
  this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
838
+ this.wellbeingBreakIdleCode = undefined;
839
+ this.updateWellnessSession();
751
840
 
752
841
  /**
753
842
  * RTD websocket currently supports realtime transcripts and suggested responses.
@@ -803,6 +892,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
803
892
  }
804
893
  return this.agentConfig;
805
894
  } catch (error) {
895
+ this.updateWellnessSession();
806
896
  _loggerProxy.default.error(`Error during register: ${error}`, {
807
897
  module: _constants.CC_FILE,
808
898
  method: _constants.METHODS.CONNECT_WEBSOCKET
@@ -891,6 +981,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
891
981
  channelsMap,
892
982
  ...loginData
893
983
  } = resp.data;
984
+ this.updateWellnessSession(resp.data.agentSessionId);
894
985
  this.agentConfig.currentTeamId = resp.data.teamId;
895
986
  const response = {
896
987
  ...loginData,
@@ -978,6 +1069,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
978
1069
  this.webCallingService.deregisterWebCallingLine();
979
1070
  }
980
1071
  await this.teardownWxAppLocalState();
1072
+ this.updateWellnessSession();
981
1073
  _loggerProxy.default.log(`Agent station logout completed successfully`, {
982
1074
  module: _constants.CC_FILE,
983
1075
  method: _constants.METHODS.STATION_LOGOUT,
@@ -1098,6 +1190,63 @@ class ContactCenter extends _webexCore.WebexPlugin {
1098
1190
  }
1099
1191
  }
1100
1192
 
1193
+ /**
1194
+ * Returns the system-managed `WellbeingBreak` idle code for the current registration.
1195
+ * The value is fetched outside Desktop Profile filtering and cached until deregistration.
1196
+ * @returns The normalized system idle-code entity
1197
+ * @throws Structured Contact Center error when wellness is disabled or the code is unavailable
1198
+ * @example
1199
+ * const idleCode = await webex.cc.getWellbeingBreakIdleCode();
1200
+ * @public
1201
+ */
1202
+ async getWellbeingBreakIdleCode() {
1203
+ const method = _constants.METHODS.GET_WELLBEING_BREAK_IDLE_CODE;
1204
+ try {
1205
+ if (!this.agentConfig?.isWellnessBreakEnabled) {
1206
+ const validationError = new Error('WELLNESS_BREAK_NOT_ENABLED');
1207
+ validationError.details = {
1208
+ type: 'SDK_VALIDATION_ERROR',
1209
+ orgId: this.$webex.credentials.getOrgId(),
1210
+ trackingId: _constants.EMPTY_STRING,
1211
+ data: {
1212
+ reason: 'WELLNESS_BREAK_NOT_ENABLED'
1213
+ }
1214
+ };
1215
+ throw validationError;
1216
+ }
1217
+ if (this.wellbeingBreakIdleCode) {
1218
+ return this.wellbeingBreakIdleCode;
1219
+ }
1220
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_SUCCESS, _constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_FAILED]);
1221
+ const registrationGeneration = this.wellnessRegistrationGeneration;
1222
+ const orgId = this.$webex.credentials.getOrgId();
1223
+ const idleCode = await this.services.config.getWellbeingBreakIdleCode(orgId);
1224
+ if (registrationGeneration !== this.wellnessRegistrationGeneration || orgId !== this.$webex.credentials.getOrgId() || !this.agentConfig?.isWellnessBreakEnabled) {
1225
+ const staleRegistrationError = new Error('WELLNESS_BREAK_REGISTRATION_CHANGED');
1226
+ staleRegistrationError.details = {
1227
+ type: 'SDK_VALIDATION_ERROR',
1228
+ orgId,
1229
+ trackingId: _constants.EMPTY_STRING,
1230
+ data: {
1231
+ reason: 'WELLNESS_BREAK_REGISTRATION_CHANGED'
1232
+ }
1233
+ };
1234
+ throw staleRegistrationError;
1235
+ }
1236
+ this.wellbeingBreakIdleCode = idleCode;
1237
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_SUCCESS, {}, ['operational']);
1238
+ return idleCode;
1239
+ } catch (error) {
1240
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_FAILED, {
1241
+ reason: error instanceof Error ? error.message : _constants.UNKNOWN_ERROR
1242
+ }, ['operational']);
1243
+ const {
1244
+ error: detailedError
1245
+ } = (0, _Utils.getErrorDetails)(error, method, _constants.CC_FILE);
1246
+ throw detailedError;
1247
+ }
1248
+ }
1249
+
1101
1250
  /**
1102
1251
  * Processes incoming websocket messages and emits corresponding events
1103
1252
  * Handles various event types including agent state changes, login events,
@@ -1131,8 +1280,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
1131
1280
  };
1132
1281
  this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WEBSOCKET_EVENT_RECEIVED, metricsPayload, ['operational']);
1133
1282
  }
1283
+ if (this.handleWellnessBreakWebsocketPayload(eventData)) {
1284
+ return;
1285
+ }
1134
1286
  switch (eventData.type) {
1135
1287
  case _types3.CC_EVENTS.AGENT_MULTI_LOGIN:
1288
+ if (eventData.data?.type === 'AgentMultiLoginCloseSession' && (!eventData.data.agentSessionId || eventData.data.agentSessionId === this.currentAgentSessionId)) {
1289
+ this.updateWellnessSession();
1290
+ }
1136
1291
  // @ts-ignore
1137
1292
  this.emit(_types2.AGENT_EVENTS.AGENT_MULTI_LOGIN, eventData.data);
1138
1293
  break;
@@ -1153,6 +1308,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1153
1308
  channelsMap,
1154
1309
  ...loginData
1155
1310
  } = eventData.data;
1311
+ this.updateWellnessSession(loginData.agentSessionId);
1156
1312
  const stationLoginData = {
1157
1313
  ...loginData,
1158
1314
  mmProfile: {
@@ -1174,6 +1330,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1174
1330
  channelsMap,
1175
1331
  ...loginData
1176
1332
  } = eventData.data;
1333
+ this.updateWellnessSession(loginData.agentSessionId);
1177
1334
  const stationReLoginData = {
1178
1335
  ...loginData,
1179
1336
  mmProfile: {
@@ -1186,8 +1343,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
1186
1343
  };
1187
1344
  // @ts-ignore
1188
1345
  this.emit(_types2.AGENT_EVENTS.AGENT_RELOGIN_SUCCESS, stationReLoginData);
1346
+ break;
1189
1347
  }
1190
- break;
1191
1348
  case _types3.CC_EVENTS.AGENT_STATE_CHANGE_SUCCESS:
1192
1349
  // @ts-ignore
1193
1350
  this.emit(_types2.AGENT_EVENTS.AGENT_STATE_CHANGE_SUCCESS, eventData.data);
@@ -1201,6 +1358,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
1201
1358
  this.emit(_types2.AGENT_EVENTS.AGENT_STATION_LOGIN_FAILED, eventData.data);
1202
1359
  break;
1203
1360
  case _types3.CC_EVENTS.AGENT_LOGOUT_SUCCESS:
1361
+ if (!eventData.data.agentSessionId || eventData.data.agentSessionId === this.currentAgentSessionId) {
1362
+ this.updateWellnessSession();
1363
+ }
1204
1364
  // @ts-ignore
1205
1365
  this.emit(_types2.AGENT_EVENTS.AGENT_LOGOUT_SUCCESS, eventData.data);
1206
1366
  break;
@@ -1759,6 +1919,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1759
1919
  });
1760
1920
  try {
1761
1921
  const reLoginResponse = await this.services.agent.reload();
1922
+ this.updateWellnessSession(reLoginResponse.data.agentSessionId);
1762
1923
  const {
1763
1924
  agentId,
1764
1925
  lastStateChangeReason,