@webex/contact-center 3.12.0-llmrefactor.11 → 3.12.0-llmrefactor.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.sdd/manifest.json +5 -5
- package/ai-docs/CONTRACTS.md +2 -0
- package/ai-docs/SERVICE_STATE.md +4 -0
- package/ai-docs/contact-center-spec.md +26 -3
- package/dist/cc.js +163 -2
- 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/constants.js +5 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +116 -1
- package/dist/services/ApiAiAssistant.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/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 +5 -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 +13 -2
- package/dist/types/services/core/Utils.d.ts +2 -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 +251 -18
- package/src/constants.ts +4 -0
- package/src/index.ts +11 -0
- package/src/metrics/ai-docs/metrics-spec.md +19 -20
- package/src/metrics/constants.ts +5 -0
- package/src/services/ApiAiAssistant.ts +153 -1
- 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 +11 -2
- package/src/services/core/Utils.ts +4 -0
- package/src/types.ts +63 -0
- package/src/webex.js +8 -0
- package/test/unit/spec/cc.ts +268 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +134 -2
- package/test/unit/spec/services/config/Util.ts +44 -0
- package/test/unit/spec/services/config/index.ts +68 -0
- 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
|
@@ -12,6 +12,10 @@ import {
|
|
|
12
12
|
HistoricTranscriptsResponse,
|
|
13
13
|
RealTimeAssistanceParams,
|
|
14
14
|
RealTimeAssistanceUserActionParams,
|
|
15
|
+
RespondToWellnessBreakParams,
|
|
16
|
+
WellnessBreakUserAction,
|
|
17
|
+
WELLNESS_BREAK_USER_ACTIONS,
|
|
18
|
+
GenericError,
|
|
15
19
|
} from '../types';
|
|
16
20
|
import {getErrorDetails} from './core/Utils';
|
|
17
21
|
import {
|
|
@@ -22,6 +26,12 @@ import {
|
|
|
22
26
|
} from './constants';
|
|
23
27
|
import {AIFeatureFlags} from './config/types';
|
|
24
28
|
|
|
29
|
+
type WellnessBreakContextProvider = () => {
|
|
30
|
+
isWellnessBreakEnabled: boolean;
|
|
31
|
+
agentId?: string;
|
|
32
|
+
agentSessionId?: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
25
35
|
/**
|
|
26
36
|
* ApiAIAssistant provides AI Assistant APIs for transcript controls.
|
|
27
37
|
* @public
|
|
@@ -30,9 +40,23 @@ export class ApiAIAssistant {
|
|
|
30
40
|
private webex: WebexSDK;
|
|
31
41
|
private metricsManager: MetricsManager;
|
|
32
42
|
private aiFeature: AIFeatureFlags;
|
|
43
|
+
private readonly wellnessContextProvider?: WellnessBreakContextProvider;
|
|
44
|
+
|
|
45
|
+
private createWellnessError(reason: string): GenericError {
|
|
46
|
+
const error = new Error(reason) as GenericError;
|
|
47
|
+
error.details = {
|
|
48
|
+
type: 'SDK_VALIDATION_ERROR',
|
|
49
|
+
orgId: this.webex.credentials.getOrgId(),
|
|
50
|
+
trackingId: '',
|
|
51
|
+
data: {reason},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return error;
|
|
55
|
+
}
|
|
33
56
|
|
|
34
|
-
constructor(webex: WebexSDK) {
|
|
57
|
+
constructor(webex: WebexSDK, wellnessContextProvider?: WellnessBreakContextProvider) {
|
|
35
58
|
this.webex = webex;
|
|
59
|
+
this.wellnessContextProvider = wellnessContextProvider;
|
|
36
60
|
this.metricsManager = MetricsManager.getInstance({webex});
|
|
37
61
|
}
|
|
38
62
|
|
|
@@ -40,6 +64,134 @@ export class ApiAIAssistant {
|
|
|
40
64
|
this.aiFeature = aiFeature;
|
|
41
65
|
}
|
|
42
66
|
|
|
67
|
+
private async sendWellnessBreakAction(
|
|
68
|
+
action: WellnessBreakUserAction,
|
|
69
|
+
method: string
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
this.metricsManager.timeEvent([
|
|
72
|
+
METRIC_EVENT_NAMES.AI_ASSISTANT_WELLNESS_ACTION_ACCEPTED,
|
|
73
|
+
METRIC_EVENT_NAMES.AI_ASSISTANT_WELLNESS_ACTION_FAILED,
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const context = this.wellnessContextProvider?.();
|
|
78
|
+
const agentId = context?.agentId?.trim();
|
|
79
|
+
const agentSessionId = context?.agentSessionId?.trim();
|
|
80
|
+
const orgId = this.webex.credentials.getOrgId()?.trim();
|
|
81
|
+
|
|
82
|
+
if (context?.isWellnessBreakEnabled !== true) {
|
|
83
|
+
throw this.createWellnessError('WELLNESS_BREAK_NOT_ENABLED');
|
|
84
|
+
}
|
|
85
|
+
if (!orgId) {
|
|
86
|
+
throw this.createWellnessError('WELLNESS_BREAK_ORG_ID_REQUIRED');
|
|
87
|
+
}
|
|
88
|
+
if (!agentId) {
|
|
89
|
+
throw this.createWellnessError('WELLNESS_BREAK_AGENT_ID_REQUIRED');
|
|
90
|
+
}
|
|
91
|
+
if (!agentSessionId) {
|
|
92
|
+
throw this.createWellnessError('WELLNESS_BREAK_AGENT_SESSION_REQUIRED');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const baseUrl = this.getBaseUrl();
|
|
96
|
+
const response = (await this.webex.request({
|
|
97
|
+
uri: `${baseUrl}${AI_ASSISTANT_API_URLS.EVENT}`,
|
|
98
|
+
method: HTTP_METHODS.POST,
|
|
99
|
+
addAuthHeader: true,
|
|
100
|
+
body: {
|
|
101
|
+
agentId,
|
|
102
|
+
orgId,
|
|
103
|
+
eventType: AIAssistantEventType.CUSTOM_EVENT,
|
|
104
|
+
eventName: AIAssistantEventName.WELLNESS_BREAK_ACTION,
|
|
105
|
+
eventDetails: {
|
|
106
|
+
data: {
|
|
107
|
+
action,
|
|
108
|
+
agentSessionId,
|
|
109
|
+
actionTimeStamp: Date.now(),
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
})) as IHttpResponse;
|
|
114
|
+
|
|
115
|
+
if (response.statusCode !== 202) {
|
|
116
|
+
throw this.createWellnessError(
|
|
117
|
+
`WELLNESS_BREAK_ACTION_UNEXPECTED_STATUS_${response.statusCode}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.metricsManager.trackEvent(
|
|
122
|
+
METRIC_EVENT_NAMES.AI_ASSISTANT_WELLNESS_ACTION_ACCEPTED,
|
|
123
|
+
{action},
|
|
124
|
+
['operational']
|
|
125
|
+
);
|
|
126
|
+
LoggerProxy.log('Wellness action accepted by AI Assistant', {
|
|
127
|
+
module: CC_FILE,
|
|
128
|
+
method,
|
|
129
|
+
data: {action},
|
|
130
|
+
});
|
|
131
|
+
} catch (error) {
|
|
132
|
+
this.metricsManager.trackEvent(
|
|
133
|
+
METRIC_EVENT_NAMES.AI_ASSISTANT_WELLNESS_ACTION_FAILED,
|
|
134
|
+
{
|
|
135
|
+
action,
|
|
136
|
+
error: error instanceof Error ? error.message : String(error),
|
|
137
|
+
},
|
|
138
|
+
['operational']
|
|
139
|
+
);
|
|
140
|
+
const {error: detailedError} = getErrorDetails(error, method, CC_FILE);
|
|
141
|
+
throw detailedError;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Requests an Agent Wellness Break.
|
|
147
|
+
* The promise resolves when the HTTP request is accepted with status 202; the later
|
|
148
|
+
* approval or denial is delivered independently through a wellness notification.
|
|
149
|
+
* @returns A promise that resolves with no value after HTTP acceptance
|
|
150
|
+
* @throws Structured Contact Center error when disabled, stale, invalid, or delivery fails
|
|
151
|
+
* @example
|
|
152
|
+
* await webex.cc.apiAIAssistant.requestWellnessBreak();
|
|
153
|
+
* @public
|
|
154
|
+
*/
|
|
155
|
+
public async requestWellnessBreak(): Promise<void> {
|
|
156
|
+
return this.sendWellnessBreakAction(
|
|
157
|
+
WELLNESS_BREAK_USER_ACTIONS.REQUESTED,
|
|
158
|
+
METHODS.REQUEST_WELLNESS_BREAK
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Responds to a backend-provided Agent Wellness Break offer.
|
|
164
|
+
* The promise resolves when the HTTP request is accepted with status 202 and does not
|
|
165
|
+
* wait for a WebSocket completion event.
|
|
166
|
+
* @param params - ACCEPTED, REJECTED, or NO_RESPONSE
|
|
167
|
+
* @returns A promise that resolves with no value after HTTP acceptance
|
|
168
|
+
* @throws Structured Contact Center error when disabled, stale, invalid, or delivery fails
|
|
169
|
+
* @example
|
|
170
|
+
* await webex.cc.apiAIAssistant.respondToWellnessBreak({
|
|
171
|
+
* action: WELLNESS_BREAK_USER_ACTIONS.ACCEPTED,
|
|
172
|
+
* });
|
|
173
|
+
* @public
|
|
174
|
+
*/
|
|
175
|
+
public async respondToWellnessBreak(params: RespondToWellnessBreakParams): Promise<void> {
|
|
176
|
+
const {action} = params;
|
|
177
|
+
if (
|
|
178
|
+
![
|
|
179
|
+
WELLNESS_BREAK_USER_ACTIONS.ACCEPTED,
|
|
180
|
+
WELLNESS_BREAK_USER_ACTIONS.REJECTED,
|
|
181
|
+
WELLNESS_BREAK_USER_ACTIONS.NO_RESPONSE,
|
|
182
|
+
].includes(action)
|
|
183
|
+
) {
|
|
184
|
+
const {error} = getErrorDetails(
|
|
185
|
+
this.createWellnessError('WELLNESS_BREAK_ACTION_INVALID'),
|
|
186
|
+
METHODS.RESPOND_TO_WELLNESS_BREAK,
|
|
187
|
+
CC_FILE
|
|
188
|
+
);
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return this.sendWellnessBreakAction(action, METHODS.RESPOND_TO_WELLNESS_BREAK);
|
|
193
|
+
}
|
|
194
|
+
|
|
43
195
|
private getBaseUrl(): string {
|
|
44
196
|
const wccApiGatewayUrl = this.webex.internal.services.get(WCC_API_GATEWAY) || '';
|
|
45
197
|
|
|
@@ -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 /
|
|
15
|
-
| Validation status |
|
|
14
|
+
| generated_by / approved_by / updated_at | Codex generator / Agent Wellness Break v0.4 intake audit / 2026-09-07 |
|
|
15
|
+
| Validation status | Agent Wellness Break v0.4 delta 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.
|
|
@@ -55,6 +55,7 @@ The `src/services/` directory is the service layer of the `@webex/contact-center
|
|
|
55
55
|
| **Utilities** | [`src/utils/PageCache.ts`](../../utils/PageCache.ts) | Shared `PageCache<T>` generic class for pagination caching, plus `BaseSearchParams`, `PaginatedResponse`, and `PaginationMeta` types used by all data services |
|
|
56
56
|
| **WebRTC Calling** | [`WebCallingService.ts`](../WebCallingService.ts) | Browser-based voice calling via `@webex/calling`, line registration, call answer/mute/decline |
|
|
57
57
|
| **WxApp Better Together** | [`WebexCrossClientService.ts`](../WebexCrossClientService.ts), [`AnswerCallOnWebexService.ts`](../AnswerCallOnWebexService.ts), [`WxAppTelephonyMercurySync.ts`](../WxAppTelephonyMercurySync.ts) | usersub cross-client publish (`answer-calls-on-wxcc`), Hydra telephony REST (answer/reject/mute/DTMF/GET call), Mercury mute sync — orchestrated from `cc.ts` when `enableWxBetterTogether` is active |
|
|
58
|
+
| **AI Assistant / Wellness** | [`ApiAiAssistant.ts`](../ApiAiAssistant.ts) | Existing transcript/suggestion requests plus direct, session-validated wellness custom-event reporting. |
|
|
58
59
|
|
|
59
60
|
Each service folder contains its own `ai-docs/` with detailed documentation. **Always load the relevant service docs before making changes.**
|
|
60
61
|
|
|
@@ -230,6 +231,7 @@ Use [`constants.ts`](../constants.ts) as the canonical source for service-level
|
|
|
230
231
|
| `services.surface` | SDK / event / internal API | Internal `Services.getInstance()` composition root plus data-service and calling collaborators consumed by `ContactCenter`. | Stable module consumption boundary. | Additive changes by default; breaking package exports require a major-version transition. | `src/services/index.ts` | `../../../ai-docs/CONTRACTS.md` |
|
|
231
232
|
| `services.destination-lists` | SDK data API | Existing `Queue.getQueues(ContactServiceQueueSearchParams)` and `EntryPoint.getEntryPoints(EntryPointSearchParams)` methods with full-record paginated responses. | Apply consult/transfer telephony eligibility, profile views, and backend name ordering as overridable defaults. | Behavioral default correction on existing methods; no specialized method, projected response, or replacement signature. | `src/services/Queue.ts`, `src/services/EntryPoint.ts`, `src/types.ts` | `../../../ai-docs/CONTRACTS.md` |
|
|
232
233
|
| `services.user-preference` | SDK data API | `UserPreference` and `cc.userPreference`. | Direct REST CRUD for user preferences; separate from PageCache-based pagination services. | Additive semver-public API; removals or signature changes are breaking. | `src/services/UserPreference.ts`, `src/services/config/types.ts` | `../../../ai-docs/CONTRACTS.md` |
|
|
234
|
+
| `services.agent-wellness-break` | SDK data / action API | `ApiAIAssistant.requestWellnessBreak` and `respondToWellnessBreak`, invoked through `ContactCenter`. | Submit validated `WellnessBreakAction` custom events through direct HTTP. | Additive semver-public behavior; exact action/event payload is backend-owned. | `src/services/ApiAiAssistant.ts`, `src/types.ts` | `../../../ai-docs/CONTRACTS.md` |
|
|
233
235
|
|
|
234
236
|
Compatibility notes:
|
|
235
237
|
- Do not remove or reinterpret exported symbols/events without a documented consumer migration.
|
|
@@ -264,6 +266,7 @@ ContactCenter READY callback
|
|
|
264
266
|
| SERVICES-R-005 | Inherit authenticated request identity from the host Webex SDK through Core/WebexRequest; Services must not store, parse, or refresh credentials. | One host-owned authentication boundary avoids duplicate token handling and credential leakage across composed services. | `src/services/index.ts`, `src/services/core/WebexRequest.ts` | `test/unit/spec/services/core/WebexRequest.ts` | None; authentication ownership is explicit. | PRESENT |
|
|
265
267
|
| SERVICES-R-006 | Treat Services composition as unconditionally created by the ContactCenter READY callback; Services owns no rollout or feature-flag decision. | Capability flags belong to the consuming config/task/calling collaborators, so the composition root must not silently gate construction. | `src/services/index.ts`, `src/cc.ts` | `test/unit/spec/cc.ts` | None; rollout applicability is explicitly N/A for Services. | PRESENT |
|
|
266
268
|
| SERVICES-R-007 | Existing Queue and EntryPoint list methods must apply inbound, active, telephony, profile/agent-view, and `name,ASC` defaults while retaining their established parameter and full-record response types. Caller-supplied existing filter, sort, or profile inputs override defaults. Queue must also treat `sortOrder` without `sortBy` as a name sort and bypass the simple-page cache. | Defaults on the established methods let thin consumers request lists without a parallel API, while existing parameters preserve specialized behavior for other consumers and full-record types remain truthful because no field projection is requested. | `src/services/Queue.ts`, `src/services/EntryPoint.ts`, `src/types.ts` | `test/unit/spec/services/Queue.ts`, `test/unit/spec/services/EntryPoint.ts`, `test/unit/spec/cc.ts` | The backend honors the view flags and combined CMS sort value. | PRESENT |
|
|
269
|
+
| SERVICES-R-008 | ApiAIAssistant wellness requests must accept no public identity or context-mutating input, read effective enablement and non-empty SDK-owned organization/agent/session context from a read-only provider supplied at construction, then POST the exact `WellnessBreakAction` custom-event body directly to `/event`; only HTTP 202 resolves successfully. Public action unions derive from exported `as const` action-value objects. | SDK-owned live context prevents callers from supplying stale/different login identities to action calls, one value/type source prevents wire drift, and direct HTTP matches the AI event endpoint rather than AQM completion semantics. | `src/services/ApiAiAssistant.ts`, `src/types.ts`, `src/index.ts`, `src/cc.ts` | `test/unit/spec/services/ApiAiAssistant.ts`, `test/unit/spec/cc.ts` | None. | PRESENT |
|
|
267
270
|
|
|
268
271
|
## Design Overview
|
|
269
272
|
`Services` is a singleton composition root for transport-facing capabilities only. It constructs two `WebSocketManager` instances (primary Contact Center and RTD), creates `AqmReqs` on the primary manager, then creates config, agent, contact, dialer, and ConnectionService collaborators.
|
|
@@ -272,6 +275,8 @@ ContactCenter owns the broader READY-time graph: WebCallingService, ApiAIAssista
|
|
|
272
275
|
|
|
273
276
|
AQM factories return functions whose HTTP request is initiation and whose promise settles on correlated primary-WebSocket notifications. Direct config/data services return authenticated REST responses.
|
|
274
277
|
|
|
278
|
+
ApiAIAssistant wellness reporting is also direct REST, but it reads live context through a read-only provider supplied by ContactCenter at construction rather than a separate factory or context setter. It fails closed unless wellness is effectively enabled and the SDK owns a current organization, agent, and session; public action calls do not accept identity fields.
|
|
279
|
+
|
|
275
280
|
## Data Flow
|
|
276
281
|
```mermaid
|
|
277
282
|
flowchart TD
|
|
@@ -399,6 +404,7 @@ classDiagram
|
|
|
399
404
|
- **UC-2 Direct REST:** configuration, data, and user-preference services return authenticated HTTP results directly. Evidence: `src/services/config/index.ts`, `src/services/UserPreference.ts`, `test/unit/spec/services/config/index.ts`, `test/unit/spec/services/UserPreference.ts`.
|
|
400
405
|
- **UC-3 AQM operation:** initiate HTTP and settle only on matching WebSocket notification or timeout. Evidence: `src/services/core/aqm-reqs.ts`, `test/unit/spec/services/core/aqm-reqs.ts`.
|
|
401
406
|
- **UC-4 Task/AI realtime:** TaskManager consumes primary and RTD streams with ApiAIAssistant/calling collaborators. Evidence: `src/services/task/TaskManager.ts`, `test/unit/spec/services/task/TaskManager.ts`.
|
|
407
|
+
- **UC-5 Wellness action reporting:** validate the current profile/session context and submit a direct AI custom event that completes only on HTTP 202. Evidence: `src/services/ApiAiAssistant.ts`, `test/unit/spec/services/ApiAiAssistant.ts`.
|
|
402
408
|
|
|
403
409
|
## State Model
|
|
404
410
|
`Services` is a process-local singleton. Its first `getInstance({webex, connectionConfig})` call synchronously constructs the two WebSocket managers, AqmReqs-backed factories, config service, and ConnectionService; later calls return that same composed graph. Socket lifecycle and domain records are owned by the corresponding collaborators, not by a Services state machine.
|
|
@@ -409,6 +415,7 @@ classDiagram
|
|
|
409
415
|
- ApiAIAssistant, TaskManager, and UserPreference are READY-time ContactCenter collaborators, not fields constructed by Services.
|
|
410
416
|
- Authentication is inherited from the host SDK through Core/WebexRequest; Services owns no credential lifecycle.
|
|
411
417
|
- Rollout applicability is N/A for the Services composition root: it is created at READY and does not evaluate a feature flag.
|
|
418
|
+
- ApiAIAssistant evaluates the current effective wellness flag and identities through its constructor-supplied read-only provider; the public object exposes no context mutator, and the Services singleton itself remains unconditionally composed.
|
|
412
419
|
|
|
413
420
|
## Concurrency & Reactive Flow
|
|
414
421
|
- `getInstance` composition is synchronous in the JavaScript execution turn. Direct REST promises can proceed independently, while each AQM promise remains pending until its matching primary-WebSocket notification, HTTP failure, or timeout.
|
|
@@ -447,7 +454,7 @@ stateDiagram-v2
|
|
|
447
454
|
```
|
|
448
455
|
|
|
449
456
|
## Protocol / Wire Format
|
|
450
|
-
- Request, response, and event payload ownership is anchored in `src/services/index.ts`. HTTP initiates backend work where applicable; WebSocket messages provide realtime events and, for AQM flows, correlated completion.
|
|
457
|
+
- Request, response, and event payload ownership is anchored in `src/services/index.ts`. HTTP initiates backend work where applicable; WebSocket messages provide realtime events and, for AQM flows, correlated completion. Wellness actions POST `CUSTOM_EVENT` / `WellnessBreakAction` bodies directly to `/event` and accept only status 202; wellness offers arrive as primary `Wellness_Break_Handler` notifications.
|
|
451
458
|
|
|
452
459
|
## Error Handling & Failure Modes
|
|
453
460
|
| Condition | Signal (error/code/result) | Caller recovery |
|
|
@@ -481,6 +488,7 @@ Unit tests mirror module paths under `test/unit/spec/services`. Preserve positiv
|
|
|
481
488
|
| `SERVICES-R-005` | `test/unit/spec/services/core/WebexRequest.ts` | None. |
|
|
482
489
|
| `SERVICES-R-006` | `test/unit/spec/cc.ts` | None. |
|
|
483
490
|
| `SERVICES-R-007` | `test/unit/spec/services/Queue.ts`, `test/unit/spec/services/EntryPoint.ts`, `test/unit/spec/cc.ts` | None. |
|
|
491
|
+
| `SERVICES-R-008` | `test/unit/spec/services/ApiAiAssistant.ts` | None. |
|
|
484
492
|
|
|
485
493
|
## Traceability
|
|
486
494
|
- Repo architecture: `../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../ai-docs/SPEC_INDEX.md`
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {LOST_CONNECTION_RECOVERY_TIMEOUT} from '../core/constants';
|
|
2
|
+
import {WELLNESS_BREAK_REMINDERS_ENABLED} from './constants';
|
|
2
3
|
import {
|
|
3
4
|
AgentResponse,
|
|
4
5
|
AuxCode,
|
|
@@ -186,6 +187,10 @@ function parseAgentConfigs(profileData: {
|
|
|
186
187
|
const defaultWrapUpData = getDefaultWrapUpCode(wrapupCodes);
|
|
187
188
|
const aiFeature: AIFeatureFlags | undefined =
|
|
188
189
|
aiFeatureFlags?.data?.length > 0 ? aiFeatureFlags.data[0] : undefined;
|
|
190
|
+
const isWellnessConfigured =
|
|
191
|
+
aiFeature?.agentWellbeing?.enable === true &&
|
|
192
|
+
aiFeature.agentWellbeing.wellnessBreakReminders === WELLNESS_BREAK_REMINDERS_ENABLED;
|
|
193
|
+
const hasAIAssistantLicense = (orgSettingsData.aiAssistantQuantity ?? 0) > 0;
|
|
189
194
|
|
|
190
195
|
const finalData = {
|
|
191
196
|
teams: teamData,
|
|
@@ -264,6 +269,7 @@ function parseAgentConfigs(profileData: {
|
|
|
264
269
|
lostConnectionRecoveryTimeout:
|
|
265
270
|
tenantData.lostConnectionRecoveryTimeout || LOST_CONNECTION_RECOVERY_TIMEOUT,
|
|
266
271
|
aiFeature,
|
|
272
|
+
isWellnessBreakEnabled: isWellnessConfigured && hasAIAssistantLicense,
|
|
267
273
|
};
|
|
268
274
|
|
|
269
275
|
return finalData;
|
|
@@ -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 delta / 2026-09-02 |
|
|
15
|
+
| Validation status | Agent Wellness Break v0.4 delta 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.
|
|
@@ -100,6 +100,8 @@ services/config/
|
|
|
100
100
|
| Organization masking | `OrgSettings.maskSensitiveData` | `src/services/config/types.ts`, `src/services/config/Util.ts` |
|
|
101
101
|
| Auxiliary-code list URL | includes `desktopProfileFilter=true` | `src/services/config/constants.ts` |
|
|
102
102
|
| Outdial ANI entries | public wrapper through ContactCenter | `src/services/config/index.ts`, `src/cc.ts` |
|
|
103
|
+
| `Profile.isWellnessBreakEnabled` | required effective flag derived from backend AI feature configuration and organization license quantity | `src/services/config/Util.ts`, `src/services/config/types.ts` |
|
|
104
|
+
| `getWellbeingBreakIdleCode(orgId)` | paginated exact lookup for the active system idle code named `WellbeingBreak`, exposed and registration-cached by ContactCenter | `src/services/config/index.ts`, `src/services/config/constants.ts`, `src/cc.ts` |
|
|
103
105
|
|
|
104
106
|
The service has no `TeamList.channelMap` contract. Exact package exports are indexed in root `CONTRACTS.md`.
|
|
105
107
|
|
|
@@ -116,6 +118,8 @@ The service has no `TeamList.channelMap` contract. Exact package exports are ind
|
|
|
116
118
|
| CONFIG-R-003 | Paginate teams and auxiliary codes until completion and include `desktopProfileFilter=true` for auxiliary-code requests. | A partial or unfiltered set yields invalid profile/team/auxiliary choices. | `src/services/config/constants.ts` | `test/unit/spec/services/config/index.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
117
119
|
| CONFIG-R-004 | Expose current response/field names: `MultimediaProfileResponse`, `OrgSettings.maskSensitiveData`, and real TeamList fields only. | Type-name drift causes invalid consumer code and incorrect privacy behavior. | `src/services/config/types.ts` | `test/unit/spec/services/config/index.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
118
120
|
| CONFIG-R-005 | Reject the entire profile aggregation when any required dependent request fails. | Consumers must never receive an internally inconsistent partial Profile. | `src/services/config/index.ts` | `test/unit/spec/services/config/index.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
|
|
121
|
+
| CONFIG-R-006 | Always populate `Profile.isWellnessBreakEnabled`; set it true only when `agentWellbeing.enable` is true, `wellnessBreakReminders` is `ENABLED`, and `OrgSettings.aiAssistantQuantity` is greater than zero. Missing or null inputs fail closed. | Hosts need one license-and-server-rollout-aware signal rather than reconstructing partial configuration. | `src/services/config/Util.ts`, `src/services/config/types.ts` | `test/unit/spec/services/config/Util.ts` | The supported SDK contracts expose no separate rollout response field; backend delivery of enabled `agentWellbeing` configuration is the rollout decision. | PRESENT |
|
|
122
|
+
| CONFIG-R-007 | Retrieve the wellness idle code from `/v2/auxiliary-code` using `workType=IDLE_CODE`, `customFilter=isSystemCode==true`, and `desktopProfileFilter=false`; follow pagination and accept only the exact active system code name `WellbeingBreak`. | The dedicated state must be independent of desktop-profile filtering and must never fall back to a similarly named or non-system code. | `src/services/config/index.ts`, `src/services/config/constants.ts` | `test/unit/spec/services/config/index.ts` | None. | PRESENT |
|
|
119
123
|
|
|
120
124
|
## Design Overview
|
|
121
125
|
Config separates its stable consumption boundary from collaborators so ownership and failure behavior stay explicit. Profile creation is all-or-nothing across dependent API calls so consumers never receive internally inconsistent partial configuration.
|
|
@@ -162,6 +166,7 @@ The AgentProfile is defined as the [`Profile`](../types.ts) type. This is not an
|
|
|
162
166
|
| `accessQueue` | `'ALL' \| 'SPECIFIC' \| 'NONE'` | Collaboration tab queue access scope from Desktop Profile |
|
|
163
167
|
| `accessEntryPoint` | `'ALL' \| 'SPECIFIC' \| 'NONE'` | Collaboration tab entry-point access scope from Desktop Profile |
|
|
164
168
|
| `accessBuddyTeam` | `'ALL' \| 'SPECIFIC' \| 'NONE'` | Collaboration tab buddy-team access scope from Desktop Profile |
|
|
169
|
+
| `isWellnessBreakEnabled` | boolean | Effective wellness gate derived from backend enablement/reminder configuration and positive AI Assistant license quantity |
|
|
165
170
|
|
|
166
171
|
`parseAgentConfigs()` maps the three `access*` fields from `DesktopProfileResponse` onto the public `Profile` returned by `cc.register()`.
|
|
167
172
|
|
|
@@ -264,7 +269,7 @@ The service fetches data from multiple APIs with these response structures:
|
|
|
264
269
|
| `getTenantData` | `TenantData` | `outdialEnabled`, `forceDefaultDn`, `privacyShieldVisible`, `timeoutDesktopInactivityEnabled` | Tenant-level feature flags |
|
|
265
270
|
| `getOrgInfo` | `OrgInfo` | `tenantId`, `timezone` | Organization metadata |
|
|
266
271
|
| `getAllAuxCodes` | `AuxCode[]` | `id`, `name`, `workTypeCode`, `active`, `isSystemCode`, `defaultCode` | Auxiliary codes for idle/wrap-up states |
|
|
267
|
-
| `getOrganizationSetting` | `OrgSettings` | `webRtcEnabled`, `maskSensitiveData`, `campaignManagerEnabled` | Organization-level feature flags |
|
|
272
|
+
| `getOrganizationSetting` | `OrgSettings` | `webRtcEnabled`, `maskSensitiveData`, `campaignManagerEnabled`, `aiAssistantQuantity` | Organization-level feature flags and AI Assistant license quantity |
|
|
268
273
|
| `getDialPlanData` | `DialPlanEntity[]` | `id`, `name`, `regularExpression`, `prefix`, `strippedChars` | Dial plan rules for outbound calling |
|
|
269
274
|
| `getURLMapping` | `URLMapping[]` | `name`, `url` | External service URL mappings |
|
|
270
275
|
| `getSiteInfo` | `SiteInfo` | Site-specific configuration | Site details |
|
|
@@ -449,11 +454,14 @@ classDiagram
|
|
|
449
454
|
- **UC-2 Paginated teams/aux codes:** follow backend page metadata to completion; auxiliary-code requests include `desktopProfileFilter=true`. Evidence: `src/services/config/index.ts`, `test/unit/spec/services/config/index.ts`.
|
|
450
455
|
- **UC-3 Dial plan and URL mapping:** request dial-plan data only when the desktop profile enables it while always including URL mapping in profile aggregation. Evidence: `src/services/config/index.ts`, `test/unit/spec/services/config/index.ts`.
|
|
451
456
|
- **UC-4 Outdial ANI retrieval:** return the organization-scoped ANI list through authenticated WebexRequest and propagate failures without a partial substitute. Evidence: `src/services/config/index.ts`, `test/unit/spec/services/config/index.ts`.
|
|
457
|
+
- **UC-5 Wellness configuration:** produce one fail-closed effective profile flag and retrieve the exact system wellness idle code across pages. Evidence: `src/services/config/Util.ts`, `src/services/config/index.ts`, `test/unit/spec/services/config/Util.ts`, `test/unit/spec/services/config/index.ts`.
|
|
452
458
|
|
|
453
459
|
## Business Rules & Invariants
|
|
454
460
|
- `getAgentConfig` rejects when any required dependent request rejects; it never returns a partial Profile.
|
|
455
461
|
- `Profile.aiFeature` is derived from the AI-feature response, and sensitive-data masking uses the real `maskSensitiveData` field.
|
|
456
462
|
- Team data has no `channelMap` contract; multimedia profile responses use `MultimediaProfileResponse`.
|
|
463
|
+
- `isWellnessBreakEnabled` is always boolean and defaults false when any gate is absent, disabled, or unlicensed.
|
|
464
|
+
- The system wellness code lookup is separate from profile auxiliary-code aggregation and uses `desktopProfileFilter=false`.
|
|
457
465
|
|
|
458
466
|
## Concurrency & Reactive Flow
|
|
459
467
|
- The initial user lookup supplies identifiers for a ten-promise `Promise.all`; pagination loops await pages in order and stop from returned metadata.
|
|
@@ -465,6 +473,7 @@ All Config operations are authenticated REST calls through WebexRequest. Importa
|
|
|
465
473
|
|---|---|
|
|
466
474
|
| AI feature flags | `organization/{orgId}/v2/ai-feature?page=0&pageSize=100` |
|
|
467
475
|
| Auxiliary codes | pagination/filter/attributes plus `desktopProfileFilter=true` |
|
|
476
|
+
| Wellness system idle code | `organization/{orgId}/v2/auxiliary-code?page={page}&pageSize={pageSize}&workType=IDLE_CODE&customFilter=isSystemCode==true&desktopProfileFilter=false` |
|
|
468
477
|
| Multimedia profile | organization-scoped multimedia-profile resource |
|
|
469
478
|
| Dial plan | organization-scoped dial-plan resource when desktop profile enables it |
|
|
470
479
|
|
|
@@ -653,6 +662,8 @@ public async getUserUsingCI(orgId: string, agentId: string): Promise<AgentRespon
|
|
|
653
662
|
| `CONFIG-R-003` | `test/unit/spec/services/config/index.ts` | None. |
|
|
654
663
|
| `CONFIG-R-004` | `test/unit/spec/services/config/index.ts` | None. |
|
|
655
664
|
| `CONFIG-R-005` | `test/unit/spec/services/config/index.ts` | Keep an explicit rejection assertion for each required dependency category. |
|
|
665
|
+
| `CONFIG-R-006` | `test/unit/spec/services/config/Util.ts` | None. |
|
|
666
|
+
| `CONFIG-R-007` | `test/unit/spec/services/config/index.ts` | None. |
|
|
656
667
|
|
|
657
668
|
## Traceability
|
|
658
669
|
- Repo architecture: `../../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../../ai-docs/SPEC_INDEX.md`
|
|
@@ -34,6 +34,12 @@ export const AGENT_STATE_AVAILABLE_ID = '0';
|
|
|
34
34
|
*/
|
|
35
35
|
export const AGENT_STATE_AVAILABLE = 'Available';
|
|
36
36
|
|
|
37
|
+
/** System idle-code name reserved for Agent Wellness Break. */
|
|
38
|
+
export const WELLBEING_BREAK_IDLE_CODE = 'WellbeingBreak';
|
|
39
|
+
|
|
40
|
+
/** Backend sentinel indicating wellness-break reminders are enabled. @internal */
|
|
41
|
+
export const WELLNESS_BREAK_REMINDERS_ENABLED = 'ENABLED';
|
|
42
|
+
|
|
37
43
|
/**
|
|
38
44
|
* Description for the 'Available' agent state.
|
|
39
45
|
* @type {string}
|
|
@@ -75,6 +81,7 @@ export const METHODS = {
|
|
|
75
81
|
GET_URL_MAPPING: 'getURLMapping',
|
|
76
82
|
GET_DIAL_PLAN_DATA: 'getDialPlanData',
|
|
77
83
|
GET_AI_FEATURE_FLAGS: 'getAIFeatureFlags',
|
|
84
|
+
GET_WELLBEING_BREAK_IDLE_CODE: 'getWellbeingBreakIdleCode',
|
|
78
85
|
GET_QUEUES: 'getQueues',
|
|
79
86
|
|
|
80
87
|
// Util methods
|
|
@@ -175,6 +182,11 @@ export const endPointMap = {
|
|
|
175
182
|
filter && filter.length > 0 ? `&filter=id=in=(${filter})` : ''
|
|
176
183
|
}&attributes=${attributes}&desktopProfileFilter=true`,
|
|
177
184
|
|
|
185
|
+
/** Lists system idle codes without applying the agent Desktop Profile filter. */
|
|
186
|
+
systemIdleCodes: (orgId: string, page: number, pageSize: number) =>
|
|
187
|
+
`organization/${orgId}/v2/auxiliary-code?page=${page}&pageSize=${pageSize}` +
|
|
188
|
+
'&workType=IDLE_CODE&customFilter=isSystemCode==true&desktopProfileFilter=false',
|
|
189
|
+
|
|
178
190
|
/**
|
|
179
191
|
* Gets the endpoint for organization info.
|
|
180
192
|
* @param orgId - Organization ID.
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
OutdialAniEntriesResponse,
|
|
24
24
|
OutdialAniParams,
|
|
25
25
|
AIFeatureFlagsResponse,
|
|
26
|
+
Entity,
|
|
26
27
|
} from './types';
|
|
27
28
|
import WebexRequest from '../core/WebexRequest';
|
|
28
29
|
import {WCC_API_GATEWAY} from '../constants';
|
|
@@ -34,6 +35,7 @@ import {
|
|
|
34
35
|
DEFAULT_PAGE_SIZE,
|
|
35
36
|
endPointMap,
|
|
36
37
|
METHODS,
|
|
38
|
+
WELLBEING_BREAK_IDLE_CODE,
|
|
37
39
|
} from './constants';
|
|
38
40
|
|
|
39
41
|
/**
|
|
@@ -470,6 +472,69 @@ export default class AgentConfigService {
|
|
|
470
472
|
}
|
|
471
473
|
}
|
|
472
474
|
|
|
475
|
+
/**
|
|
476
|
+
* Retrieves the exact system-managed WellbeingBreak idle code.
|
|
477
|
+
* This query intentionally bypasses Desktop Profile filtering so the system code does not
|
|
478
|
+
* need to appear in the normal agent-selectable idle-code list.
|
|
479
|
+
* @param orgId - Organization identifier
|
|
480
|
+
* @returns The normalized WellbeingBreak entity
|
|
481
|
+
* @throws When the request fails or the exact system code is unavailable
|
|
482
|
+
* @internal
|
|
483
|
+
*/
|
|
484
|
+
public async getWellbeingBreakIdleCode(orgId: string): Promise<Entity> {
|
|
485
|
+
LoggerProxy.info('Fetching WellbeingBreak system idle code', {
|
|
486
|
+
module: CONFIG_FILE_NAME,
|
|
487
|
+
method: METHODS.GET_WELLBEING_BREAK_IDLE_CODE,
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
try {
|
|
491
|
+
let page = DEFAULT_PAGE;
|
|
492
|
+
let totalPages = 1;
|
|
493
|
+
|
|
494
|
+
do {
|
|
495
|
+
// Pagination is intentionally sequential so the lookup can stop as soon as the code is found.
|
|
496
|
+
// eslint-disable-next-line no-await-in-loop
|
|
497
|
+
const response = await this.webexReq.request({
|
|
498
|
+
service: WCC_API_GATEWAY,
|
|
499
|
+
resource: endPointMap.systemIdleCodes(orgId, page, DEFAULT_PAGE_SIZE),
|
|
500
|
+
method: HTTP_METHODS.GET,
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
if (response.statusCode !== 200) {
|
|
504
|
+
throw new Error(`API call failed with ${response.statusCode}`);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const result = response.body as ListAuxCodesResponse;
|
|
508
|
+
const wellbeingCode = result.data?.find(
|
|
509
|
+
(code) =>
|
|
510
|
+
code.active === true &&
|
|
511
|
+
code.isSystemCode === true &&
|
|
512
|
+
code.name === WELLBEING_BREAK_IDLE_CODE
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
if (wellbeingCode) {
|
|
516
|
+
return {
|
|
517
|
+
id: wellbeingCode.id,
|
|
518
|
+
name: wellbeingCode.name,
|
|
519
|
+
isSystem: true,
|
|
520
|
+
isDefault: wellbeingCode.defaultCode,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
totalPages = result.meta?.totalPages ?? 1;
|
|
525
|
+
page += 1;
|
|
526
|
+
} while (page < totalPages);
|
|
527
|
+
|
|
528
|
+
throw new Error('WELLBEING_BREAK_IDLE_CODE_NOT_FOUND');
|
|
529
|
+
} catch (error) {
|
|
530
|
+
LoggerProxy.error(`getWellbeingBreakIdleCode API call failed with ${error}`, {
|
|
531
|
+
module: CONFIG_FILE_NAME,
|
|
532
|
+
method: METHODS.GET_WELLBEING_BREAK_IDLE_CODE,
|
|
533
|
+
});
|
|
534
|
+
throw error;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
473
538
|
/**
|
|
474
539
|
* Fetches the site data for the given orgId and siteId.
|
|
475
540
|
* @ignore
|
|
@@ -150,8 +150,7 @@ export const CC_TASK_EVENTS = {
|
|
|
150
150
|
/**
|
|
151
151
|
* Events emitted on Contact Center agent operations
|
|
152
152
|
* @enum {string}
|
|
153
|
-
* @
|
|
154
|
-
* @ignore
|
|
153
|
+
* @public
|
|
155
154
|
*/
|
|
156
155
|
export const CC_AGENT_EVENTS = {
|
|
157
156
|
/** Welcome event when agent connects to websocket/backend */
|
|
@@ -190,6 +189,8 @@ export const CC_AGENT_EVENTS = {
|
|
|
190
189
|
AGENT_BUDDY_AGENTS_RETRIEVE_FAILED: 'BuddyAgentsRetrieveFailed',
|
|
191
190
|
/** Event emitted when contact is reserved for agent */
|
|
192
191
|
AGENT_CONTACT_RESERVED: 'AgentContactReserved',
|
|
192
|
+
/** Agent-level Agent Wellness Break notification */
|
|
193
|
+
WELLNESS_BREAK: 'WellnessBreak',
|
|
193
194
|
} as const;
|
|
194
195
|
|
|
195
196
|
/**
|
|
@@ -729,6 +730,8 @@ export type OrgSettings = {
|
|
|
729
730
|
maskSensitiveData: boolean;
|
|
730
731
|
/** Whether campaign manager features are enabled */
|
|
731
732
|
campaignManagerEnabled: boolean;
|
|
733
|
+
/** Number of AI Assistant licenses assigned to the organization */
|
|
734
|
+
aiAssistantQuantity?: number | null;
|
|
732
735
|
};
|
|
733
736
|
|
|
734
737
|
/**
|
|
@@ -1245,6 +1248,12 @@ export type Profile = {
|
|
|
1245
1248
|
lastIdleCodeChangeTimestamp?: number;
|
|
1246
1249
|
/** AI feature flags resolved from organization config */
|
|
1247
1250
|
aiFeature?: AIFeatureFlags;
|
|
1251
|
+
/**
|
|
1252
|
+
* Whether Agent Wellness Break is effectively enabled for this profile.
|
|
1253
|
+
* This combines the organization wellbeing configuration with AI Assistant licensing;
|
|
1254
|
+
* Server-side rollout remains enforced by the backend configuration and notification delivery.
|
|
1255
|
+
*/
|
|
1256
|
+
isWellnessBreakEnabled?: boolean;
|
|
1248
1257
|
};
|
|
1249
1258
|
|
|
1250
1259
|
/**
|
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
import {PARTICIPANT_TYPES, STATE_CONSULT} from './constants';
|
|
17
17
|
import {DialPlan} from '../config/types';
|
|
18
18
|
|
|
19
|
+
/** Returns whether a value is a non-null object with string keys. */
|
|
20
|
+
export const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
21
|
+
typeof value === 'object' && value !== null;
|
|
22
|
+
|
|
19
23
|
/**
|
|
20
24
|
* Extracts common error details from a Webex request payload.
|
|
21
25
|
*
|
package/src/types.ts
CHANGED
|
@@ -8,6 +8,7 @@ import * as Agent from './services/agent/types';
|
|
|
8
8
|
import * as Contact from './services/task/types';
|
|
9
9
|
import {
|
|
10
10
|
AIFeatureFlags,
|
|
11
|
+
Entity,
|
|
11
12
|
Profile,
|
|
12
13
|
CreateUserPreferenceRequest,
|
|
13
14
|
UpdateUserPreferenceRequest,
|
|
@@ -419,6 +420,9 @@ export interface IContactCenter {
|
|
|
419
420
|
* cc.register().then(profile => { ... });
|
|
420
421
|
*/
|
|
421
422
|
register(): Promise<Profile>;
|
|
423
|
+
|
|
424
|
+
/** Returns the system-managed WellbeingBreak idle code for the registered session. */
|
|
425
|
+
getWellbeingBreakIdleCode(): Promise<Entity>;
|
|
422
426
|
}
|
|
423
427
|
|
|
424
428
|
/**
|
|
@@ -945,6 +949,63 @@ export type RealTimeAssistanceUserActionParams = {
|
|
|
945
949
|
languageCode?: string;
|
|
946
950
|
};
|
|
947
951
|
|
|
952
|
+
/**
|
|
953
|
+
* Wellness notification actions delivered by the Contact Center notification service.
|
|
954
|
+
* @public
|
|
955
|
+
*/
|
|
956
|
+
export const WELLNESS_BREAK_NOTIFICATION_ACTIONS = {
|
|
957
|
+
PROVIDE_WELLNESS_BREAK: 'PROVIDE_WELLNESS_BREAK',
|
|
958
|
+
SUGGEST_WELLNESS_BREAK: 'SUGGEST_WELLNESS_BREAK',
|
|
959
|
+
WELLNESS_BREAK_NOT_ALLOWED: 'WELLNESS_BREAK_NOT_ALLOWED',
|
|
960
|
+
} as const;
|
|
961
|
+
|
|
962
|
+
/** Union of supported wellness notification actions. @public */
|
|
963
|
+
export type WellnessBreakNotificationAction = Enum<typeof WELLNESS_BREAK_NOTIFICATION_ACTIONS>;
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Agent actions accepted by the wellness action API.
|
|
967
|
+
* @public
|
|
968
|
+
*/
|
|
969
|
+
export const WELLNESS_BREAK_USER_ACTIONS = {
|
|
970
|
+
REQUESTED: 'REQUESTED',
|
|
971
|
+
ACCEPTED: 'ACCEPTED',
|
|
972
|
+
REJECTED: 'REJECTED',
|
|
973
|
+
NO_RESPONSE: 'NO_RESPONSE',
|
|
974
|
+
} as const;
|
|
975
|
+
|
|
976
|
+
/** Union of supported wellness action API values. @public */
|
|
977
|
+
export type WellnessBreakUserAction = Enum<typeof WELLNESS_BREAK_USER_ACTIONS>;
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Validated, agent-scoped wellness notification emitted by Contact Center.
|
|
981
|
+
* @public
|
|
982
|
+
*/
|
|
983
|
+
export interface WellnessBreakEvent {
|
|
984
|
+
/** Agent identifier */
|
|
985
|
+
agentId: string;
|
|
986
|
+
/** Organization identifier */
|
|
987
|
+
orgId: string;
|
|
988
|
+
/** Session identifier supplied by the notification; it may differ from the consumer's active session */
|
|
989
|
+
agentSessionId: string;
|
|
990
|
+
/** Backend wellness action */
|
|
991
|
+
actionEvent: WellnessBreakNotificationAction;
|
|
992
|
+
/** Optional untrusted plain-text message supplied by the backend */
|
|
993
|
+
actionText?: string;
|
|
994
|
+
/** Optional normalized interaction diagnostic */
|
|
995
|
+
interactionId?: string;
|
|
996
|
+
/** Notification diagnostic only; never an action-request correlation identifier */
|
|
997
|
+
trackingId?: string;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* Parameters for responding to a backend-provided wellness offer.
|
|
1002
|
+
* @public
|
|
1003
|
+
*/
|
|
1004
|
+
export interface RespondToWellnessBreakParams {
|
|
1005
|
+
/** Agent response; REQUESTED is available only through requestWellnessBreak */
|
|
1006
|
+
action: Exclude<WellnessBreakUserAction, typeof WELLNESS_BREAK_USER_ACTIONS.REQUESTED>;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
948
1009
|
/**
|
|
949
1010
|
* Supported AI Assistant event categories.
|
|
950
1011
|
* @public
|
|
@@ -994,6 +1055,8 @@ export const AIAssistantEventName = {
|
|
|
994
1055
|
SUGGESTED_RESPONSES_DIGITAL: 'SUGGESTED_RESPONSES_DIGITAL',
|
|
995
1056
|
/** User action on a suggested response adaptive card */
|
|
996
1057
|
SUGGESTED_RESPONSES_USER_ACTION: 'SUGGESTED_RESPONSES_USER_ACTION',
|
|
1058
|
+
/** Agent Wellness Break request/response action */
|
|
1059
|
+
WELLNESS_BREAK_ACTION: 'WellnessBreakAction',
|
|
997
1060
|
} as const;
|
|
998
1061
|
|
|
999
1062
|
/**
|
package/src/webex.js
CHANGED
|
@@ -9,6 +9,8 @@ import '@webex/internal-plugin-support';
|
|
|
9
9
|
import './index';
|
|
10
10
|
|
|
11
11
|
import config from './webex-config';
|
|
12
|
+
import {CC_AGENT_EVENTS} from './services/config/types';
|
|
13
|
+
import {WELLNESS_BREAK_NOTIFICATION_ACTIONS, WELLNESS_BREAK_USER_ACTIONS} from './types';
|
|
12
14
|
|
|
13
15
|
export * from './index';
|
|
14
16
|
|
|
@@ -30,6 +32,12 @@ const Webex = WebexCore.extend({
|
|
|
30
32
|
version: PACKAGE_VERSION,
|
|
31
33
|
});
|
|
32
34
|
|
|
35
|
+
// The standalone UMD bundle exports the Webex constructor as its default value. Attach the
|
|
36
|
+
// public agent-event contract so browser samples can use the same constants as module consumers.
|
|
37
|
+
Webex.CC_AGENT_EVENTS = CC_AGENT_EVENTS;
|
|
38
|
+
Webex.WELLNESS_BREAK_NOTIFICATION_ACTIONS = WELLNESS_BREAK_NOTIFICATION_ACTIONS;
|
|
39
|
+
Webex.WELLNESS_BREAK_USER_ACTIONS = WELLNESS_BREAK_USER_ACTIONS;
|
|
40
|
+
|
|
33
41
|
/**
|
|
34
42
|
* Initializes a new Webex instance with merged configuration.
|
|
35
43
|
*
|