@webex/contact-center 3.12.0-next.9 → 3.12.0-next.91
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 +876 -0
- package/AGENTS.md +94 -0
- package/ai-docs/ARCHITECTURE.md +168 -0
- package/ai-docs/CONTRACTS.md +46 -0
- package/ai-docs/GETTING_STARTED.md +168 -0
- package/ai-docs/GLOSSARY.md +43 -0
- package/ai-docs/README.md +138 -0
- package/ai-docs/REVIEW_CHECKLIST.md +41 -0
- package/ai-docs/RULES.md +444 -0
- package/ai-docs/SECURITY.md +52 -0
- package/ai-docs/SERVICE_STATE.md +48 -0
- package/ai-docs/SPEC_INDEX.md +65 -0
- package/ai-docs/adr/0001-spec-source-policy.md +55 -0
- package/ai-docs/adr/README.md +8 -0
- package/ai-docs/adr/_adr-template.md +31 -0
- package/ai-docs/contact-center-spec.md +341 -0
- package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
- package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
- package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
- package/ai-docs/patterns/event-driven-patterns.md +485 -0
- package/ai-docs/patterns/testing-patterns.md +480 -0
- package/ai-docs/patterns/typescript-patterns.md +365 -0
- package/ai-docs/templates/README.md +102 -0
- package/ai-docs/templates/documentation/create-agents-md.md +240 -0
- package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
- package/ai-docs/templates/existing-service/bug-fix.md +254 -0
- package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
- package/ai-docs/templates/new-method/00-master.md +80 -0
- package/ai-docs/templates/new-method/01-requirements.md +232 -0
- package/ai-docs/templates/new-method/02-implementation.md +295 -0
- package/ai-docs/templates/new-method/03-tests.md +201 -0
- package/ai-docs/templates/new-method/04-validation.md +141 -0
- package/ai-docs/templates/new-service/00-master.md +109 -0
- package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
- package/ai-docs/templates/new-service/02-code-generation.md +346 -0
- package/ai-docs/templates/new-service/03-integration.md +178 -0
- package/ai-docs/templates/new-service/04-test-generation.md +205 -0
- package/ai-docs/templates/new-service/05-validation.md +145 -0
- package/dist/cc.js +265 -29
- package/dist/cc.js.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +17 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +101 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +25 -4
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +153 -8
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/UserPreference.js +427 -0
- package/dist/services/UserPreference.js.map +1 -0
- package/dist/services/config/Util.js +3 -3
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +23 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +49 -9
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +107 -32
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +2 -1
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +688 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +45 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +728 -527
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +162 -26
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +9 -2
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/dialer.js +78 -0
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/digital/Digital.js +77 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +837 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +543 -0
- package/dist/services/task/state-machine/actions.js.map +1 -0
- package/dist/services/task/state-machine/constants.js +161 -0
- package/dist/services/task/state-machine/constants.js.map +1 -0
- package/dist/services/task/state-machine/guards.js +340 -0
- package/dist/services/task/state-machine/guards.js.map +1 -0
- package/dist/services/task/state-machine/index.js +53 -0
- package/dist/services/task/state-machine/index.js.map +1 -0
- package/dist/services/task/state-machine/types.js +54 -0
- package/dist/services/task/state-machine/types.js.map +1 -0
- package/dist/services/task/state-machine/uiControlsComputer.js +553 -0
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
- package/dist/services/task/taskDataNormalizer.js +99 -0
- package/dist/services/task/taskDataNormalizer.js.map +1 -0
- package/dist/services/task/types.js +212 -4
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1042 -0
- package/dist/services/task/voice/Voice.js.map +1 -0
- package/dist/services/task/voice/WebRTC.js +149 -0
- package/dist/services/task/voice/WebRTC.js.map +1 -0
- package/dist/types/cc.d.ts +94 -1
- package/dist/types/config.d.ts +6 -0
- package/dist/types/constants.d.ts +17 -1
- package/dist/types/index.d.ts +21 -6
- package/dist/types/metrics/constants.d.ts +21 -1
- package/dist/types/services/ApiAiAssistant.d.ts +22 -4
- package/dist/types/services/UserPreference.d.ts +118 -0
- package/dist/types/services/config/constants.d.ts +21 -0
- package/dist/types/services/config/types.d.ts +171 -10
- package/dist/types/services/core/Err.d.ts +4 -0
- package/dist/types/services/core/Utils.d.ts +33 -13
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
- package/dist/types/services/core/websocket/types.d.ts +1 -1
- package/dist/types/services/index.d.ts +1 -1
- package/dist/types/services/task/Task.d.ts +157 -0
- package/dist/types/services/task/TaskFactory.d.ts +12 -0
- package/dist/types/services/task/TaskUtils.d.ts +46 -2
- package/dist/types/services/task/constants.d.ts +7 -0
- package/dist/types/services/task/dialer.d.ts +30 -0
- package/dist/types/services/task/digital/Digital.d.ts +22 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1144 -0
- package/dist/types/services/task/state-machine/actions.d.ts +10 -0
- package/dist/types/services/task/state-machine/constants.d.ts +107 -0
- package/dist/types/services/task/state-machine/guards.d.ts +90 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +267 -0
- package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
- package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
- package/dist/types/services/task/types.d.ts +603 -66
- package/dist/types/services/task/voice/Voice.d.ts +184 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/types.d.ts +135 -0
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +118 -2
- package/dist/types.js.map +1 -1
- package/dist/webex.js +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +15 -12
- package/src/cc.ts +329 -30
- package/src/config.ts +6 -0
- package/src/constants.ts +17 -1
- package/src/index.ts +23 -5
- package/src/metrics/ai-docs/AGENTS.md +350 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
- package/src/metrics/ai-docs/metrics-spec.md +854 -0
- package/src/metrics/behavioral-events.ts +106 -0
- package/src/metrics/constants.ts +27 -4
- package/src/services/ApiAiAssistant.ts +203 -8
- package/src/services/UserPreference.ts +509 -0
- package/src/services/agent/ai-docs/AGENTS.md +240 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
- package/src/services/agent/ai-docs/agent-spec.md +504 -0
- package/src/services/ai-docs/AGENTS.md +386 -0
- package/src/services/ai-docs/services-spec.md +492 -0
- package/src/services/config/Util.ts +3 -3
- package/src/services/config/ai-docs/AGENTS.md +255 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
- package/src/services/config/ai-docs/config-spec.md +669 -0
- package/src/services/config/constants.ts +25 -1
- package/src/services/config/types.ts +174 -11
- package/src/services/core/Err.ts +2 -0
- package/src/services/core/Utils.ts +123 -37
- package/src/services/core/ai-docs/AGENTS.md +381 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
- package/src/services/core/ai-docs/core-spec.md +783 -0
- package/src/services/core/websocket/WebSocketManager.ts +2 -0
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +1 -1
- package/src/services/task/Task.ts +837 -0
- package/src/services/task/TaskFactory.ts +55 -0
- package/src/services/task/TaskManager.ts +739 -614
- package/src/services/task/TaskUtils.ts +205 -25
- package/src/services/task/ai-docs/AGENTS.md +457 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +594 -0
- package/src/services/task/ai-docs/task-spec.md +1319 -0
- package/src/services/task/constants.ts +7 -0
- package/src/services/task/dialer.ts +80 -0
- package/src/services/task/digital/Digital.ts +95 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +1077 -0
- package/src/services/task/state-machine/actions.ts +685 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +458 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1137 -0
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2115 -0
- package/src/services/task/state-machine/constants.ts +172 -0
- package/src/services/task/state-machine/guards.ts +406 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +241 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +867 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +710 -71
- package/src/services/task/voice/Voice.ts +1267 -0
- package/src/services/task/voice/WebRTC.ts +187 -0
- package/src/types.ts +166 -2
- package/src/utils/AGENTS.md +278 -0
- package/src/utils/ai-docs/utils-spec.md +381 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +343 -23
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +178 -20
- package/test/unit/spec/services/UserPreference.ts +401 -0
- package/test/unit/spec/services/WebCallingService.ts +7 -1
- package/test/unit/spec/services/config/index.ts +30 -30
- package/test/unit/spec/services/core/Utils.ts +425 -8
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +477 -0
- package/test/unit/spec/services/task/TaskFactory.ts +62 -0
- package/test/unit/spec/services/task/TaskManager.ts +834 -1704
- package/test/unit/spec/services/task/TaskUtils.ts +206 -0
- package/test/unit/spec/services/task/dialer.ts +190 -0
- package/test/unit/spec/services/task/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +1825 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +479 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2020 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +631 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/index.js +0 -1525
- package/dist/services/task/index.js.map +0 -1
- package/dist/types/services/task/index.d.ts +0 -650
- package/src/services/task/index.ts +0 -1801
- package/test/unit/spec/services/task/index.ts +0 -2184
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
# Config — SPEC
|
|
2
|
+
|
|
3
|
+
> Start here → root [`AGENTS.md`](../../../../AGENTS.md) · router [`SPEC_INDEX.md`](../../../../ai-docs/SPEC_INDEX.md) · system [`ARCHITECTURE.md`](../../../../ai-docs/ARCHITECTURE.md). This is the module's canonical specification.
|
|
4
|
+
|
|
5
|
+
## Metadata
|
|
6
|
+
|
|
7
|
+
| Field | Value |
|
|
8
|
+
|---|---|
|
|
9
|
+
| Module id | `config` |
|
|
10
|
+
| Source path(s) | `src/services/config` |
|
|
11
|
+
| Doc kind | Module spec |
|
|
12
|
+
| Coverage score | Partial (manifest-authoritative); 15/15 required document fields present |
|
|
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-07-21 |
|
|
15
|
+
| Validation status | Follow-up validation passed (independent Claude fallback, 2026-07-21); coverage remains Partial |
|
|
16
|
+
|
|
17
|
+
## Evidence Rules
|
|
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.
|
|
19
|
+
|
|
20
|
+
## Source Material Register
|
|
21
|
+
| Source material | Scope | Decision | Detail location or disposition |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| Reviewed prior module guides and architecture material | overview / architecture / API / tests | used and code-checked | Content is placed by meaning throughout this specification; exact routing remains in the manifest. |
|
|
24
|
+
|
|
25
|
+
## Overview
|
|
26
|
+
Config is one of nine confirmed Contact Center SDK modules. Own retrieval and aggregation of remote organization, agent, team, profile, auxiliary-code, dial-plan, and feature configuration. Existing reviewed documentation is migrated by meaning and code/tests remain the behavioral referee.
|
|
27
|
+
|
|
28
|
+
The Config Service is an **internal service** that builds the comprehensive AgentProfile (`Profile` type) by:
|
|
29
|
+
|
|
30
|
+
1. Fetching user data
|
|
31
|
+
|
|
32
|
+
2. Fetching desktop profile
|
|
33
|
+
|
|
34
|
+
3. Fetching teams
|
|
35
|
+
|
|
36
|
+
4. Fetching aux codes (idle/wrapup codes)
|
|
37
|
+
|
|
38
|
+
5. Fetching organization settings
|
|
39
|
+
|
|
40
|
+
6. Aggregating all data into a single AgentProfile
|
|
41
|
+
|
|
42
|
+
The AgentProfile is the central configuration object required for an agent to operate within the contact center. It is built during the registration flow (`cc.register()`) and contains all the data an agent needs: identity, team assignments, dial plans, aux codes, login options, and feature flags. Once constructed, the AgentProfile is stored on the `ContactCenter` plugin instance as `this.agentConfig` and is used by other services (Agent, Task) throughout the session.
|
|
43
|
+
|
|
44
|
+
- **AgentProfile Aggregation**: Combines data from 8+ API endpoints
|
|
45
|
+
|
|
46
|
+
- **Aux Codes Fetching**: Gets all idle and wrapup codes with pagination
|
|
47
|
+
|
|
48
|
+
- **Team Data**: Retrieves agent's team assignments
|
|
49
|
+
|
|
50
|
+
- **Dial Plan**: Fetches number transformation rules
|
|
51
|
+
|
|
52
|
+
- **Outdial ANI**: Retrieves outbound caller ID options (standalone, publicly exposed via `cc.ts`)
|
|
53
|
+
|
|
54
|
+
- **Multimedia Profile**: Fetches channel capacity and blending config (standalone, not yet publicly exposed)
|
|
55
|
+
|
|
56
|
+
- **Paginated Data Access**: `getListOfTeams` and `getListOfAuxCodes` support custom pagination independent of profile building
|
|
57
|
+
|
|
58
|
+
## Purpose / Responsibility
|
|
59
|
+
Own retrieval and aggregation of remote organization, agent, team, profile, auxiliary-code, dial-plan, and feature configuration.
|
|
60
|
+
|
|
61
|
+
## Stack
|
|
62
|
+
TypeScript 5.4 REST client, Promise-based parallel aggregation, Jest 27.
|
|
63
|
+
|
|
64
|
+
## Folder / Package Structure
|
|
65
|
+
```text
|
|
66
|
+
src/services/config/
|
|
67
|
+
├── Util.ts
|
|
68
|
+
├── constants.ts
|
|
69
|
+
├── index.ts
|
|
70
|
+
├── types.ts
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
services/config/
|
|
75
|
+
├── index.ts # AgentConfigService class
|
|
76
|
+
├── types.ts # Profile, CC_EVENTS, types
|
|
77
|
+
├── constants.ts # API endpoints, defaults
|
|
78
|
+
├── Util.ts # parseAgentConfigs helper
|
|
79
|
+
└── ai-docs/
|
|
80
|
+
├── AGENTS.md # Usage documentation
|
|
81
|
+
└── ARCHITECTURE.md # Preserved legacy migration source (non-canonical)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Key Files (source of truth)
|
|
85
|
+
| File | Holds |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `src/services/config/index.ts` | Authoritative Config implementation or contract source. |
|
|
88
|
+
| `src/services/config/Util.ts` | Authoritative Config implementation or contract source. |
|
|
89
|
+
| `src/services/config/types.ts` | Authoritative Config implementation or contract source. |
|
|
90
|
+
| `src/services/config/constants.ts` | Authoritative Config implementation or contract source. |
|
|
91
|
+
|
|
92
|
+
## Public Surface
|
|
93
|
+
| Surface | Contract | Source |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `getAgentConfig(orgId, agentId)` | staged, all-or-nothing `Promise<Profile>` aggregation | `src/services/config/index.ts` |
|
|
96
|
+
| User/profile/site/team/aux-code fetches | typed REST methods including pagination helpers | `src/services/config/index.ts`, `src/services/config/types.ts` |
|
|
97
|
+
| `getAIFeatureFlags(orgId)` | `AIFeatureFlagsResponse` from `organization/{orgId}/v2/ai-feature?page=0&pageSize=100` | `src/services/config/index.ts`, `src/services/config/constants.ts` |
|
|
98
|
+
| `Profile.aiFeature` | optional first AI-feature row mapped by `parseAgentConfigs` | `src/services/config/Util.ts`, `src/services/config/types.ts` |
|
|
99
|
+
| Multimedia profile | `MultimediaProfileResponse` | `src/services/config/types.ts` |
|
|
100
|
+
| Organization masking | `OrgSettings.maskSensitiveData` | `src/services/config/types.ts`, `src/services/config/Util.ts` |
|
|
101
|
+
| Auxiliary-code list URL | includes `desktopProfileFilter=true` | `src/services/config/constants.ts` |
|
|
102
|
+
| Outdial ANI entries | public wrapper through ContactCenter | `src/services/config/index.ts`, `src/cc.ts` |
|
|
103
|
+
|
|
104
|
+
The service has no `TeamList.channelMap` contract. Exact package exports are indexed in root `CONTRACTS.md`.
|
|
105
|
+
|
|
106
|
+
## Requires (dependencies)
|
|
107
|
+
- WebexRequest
|
|
108
|
+
- WCC organization/profile/team/site/tenant APIs
|
|
109
|
+
- ContactCenter registration flow
|
|
110
|
+
|
|
111
|
+
## Requirements
|
|
112
|
+
| ID | WHAT | WHY | Source Evidence | Test / Example Evidence | Assumptions / Gaps | Confidence |
|
|
113
|
+
|---|---|---|---|---|---|---|
|
|
114
|
+
| CONFIG-R-001 | Fetch user config first, then aggregate ten dependent promises including AI feature flags, auxiliary codes, profile/site/team/dial-plan, organization, tenant, and URL data. | Dependent IDs and all-or-nothing consistency require staged orchestration. | `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 |
|
|
115
|
+
| CONFIG-R-002 | Include `getAIFeatureFlags` response in `parseAgentConfigs` so `Profile.aiFeature` reflects `/v2/ai-feature`. | ApiAIAssistant behavior is gated by the remote organization feature contract. | `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 |
|
|
116
|
+
| 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
|
+
| 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
|
+
| 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 |
|
|
119
|
+
|
|
120
|
+
## Design Overview
|
|
121
|
+
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.
|
|
122
|
+
|
|
123
|
+
> **Purpose**: Fetch and aggregate agent configuration data from multiple API endpoints to build the AgentProfile.
|
|
124
|
+
>
|
|
125
|
+
> **Scope Authority**: This is the authoritative documentation for the **Config** service scope. See [Root AGENTS.md](../../../../AGENTS.md) for the orchestrator and cross-scope rules.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// Config service is used internally during the registration flow.
|
|
129
|
+
// Inside cc.ts → connectWebsocket(), after WebSocket connection is established:
|
|
130
|
+
const agentId = data.agentId;
|
|
131
|
+
const orgId = this.$webex.credentials.getOrgId();
|
|
132
|
+
this.agentConfig = await this.services.config.getAgentConfig(orgId, agentId);
|
|
133
|
+
|
|
134
|
+
// The returned AgentProfile contains all agent configuration:
|
|
135
|
+
LoggerProxy.info(`Agent ID: ${this.agentConfig.agentId}`, {
|
|
136
|
+
module: 'cc',
|
|
137
|
+
method: 'connectWebsocket',
|
|
138
|
+
});
|
|
139
|
+
LoggerProxy.info(`Teams: ${this.agentConfig.teams}`, {
|
|
140
|
+
module: 'cc',
|
|
141
|
+
method: 'connectWebsocket',
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The AgentProfile is defined as the [`Profile`](../types.ts) type. This is not an exhaustive list — see [`types.ts`](../types.ts) for the full 50+ field definition. Key fields:
|
|
146
|
+
|
|
147
|
+
| Field | Type | Description |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| `agentId` | string | Unique agent identifier |
|
|
150
|
+
| `agentName` | string | Display name |
|
|
151
|
+
| `agentMailId` | string | Email address |
|
|
152
|
+
| `teams` | [`TeamList[]`](../types.ts) | Assigned teams (runtime data from `getAllTeams()` — `Profile` type declares `Team[]` but actual objects are `TeamList` with `id`, `name`, `teamType`, `siteId`, etc.) |
|
|
153
|
+
| `defaultDn` | string | Default dial number |
|
|
154
|
+
| `idleCodes` | [`Entity[]`](../types.ts) | Available idle codes |
|
|
155
|
+
| `wrapupCodes` | [`Entity[]`](../types.ts) | Available wrapup codes |
|
|
156
|
+
| `webRtcEnabled` | boolean | WebRTC calling enabled |
|
|
157
|
+
| `loginVoiceOptions` | [`LoginOption[]`](../types.ts) | Available login types |
|
|
158
|
+
| `dialPlan` | [`DialPlan`](../types.ts) | Number transformation rules |
|
|
159
|
+
| `isOutboundEnabledForAgent` | boolean | Outbound calling allowed |
|
|
160
|
+
| `outDialEp` | string | Outbound entry point ID |
|
|
161
|
+
|
|
162
|
+
The following diagram shows how `getAgentConfig` orchestrates multiple API calls and combines their results into the AgentProfile via `parseAgentConfigs()`:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
getUserUsingCI ────────────┐
|
|
166
|
+
│
|
|
167
|
+
getOrgInfo ────────────────┤
|
|
168
|
+
│
|
|
169
|
+
getOrganizationSetting ────┤
|
|
170
|
+
│
|
|
171
|
+
getTenantData ─────────────┤
|
|
172
|
+
│
|
|
173
|
+
getURLMapping ─────────────┼──► parseAgentConfigs() ──► AgentProfile
|
|
174
|
+
│
|
|
175
|
+
getAIFeatureFlags ─────────┤ (maps the first row to Profile.aiFeature)
|
|
176
|
+
│
|
|
177
|
+
getAllAuxCodes ─────────────┤
|
|
178
|
+
│
|
|
179
|
+
getDesktopProfileById ─────┤
|
|
180
|
+
│
|
|
181
|
+
getSiteInfo ───────────────┤ (computes multimediaProfileId)
|
|
182
|
+
│
|
|
183
|
+
getAllTeams ────────────────┤
|
|
184
|
+
│
|
|
185
|
+
getDialPlanData ───────────┘
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Types used by the config service, all defined in [`types.ts`](../types.ts):
|
|
189
|
+
|
|
190
|
+
| Type | Description |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `Profile` | Final aggregated agent config returned by `getAgentConfig()` |
|
|
193
|
+
| `AgentResponse` | Raw response from `getUserUsingCI()` — agent metadata, teamIds, siteId, agentProfileId |
|
|
194
|
+
| `DesktopProfileResponse` | Desktop profile settings — layout, dial plan, login options |
|
|
195
|
+
| `TeamList` | Team record from API — `id`, `name`, `teamType`, `siteId`, `multiMediaProfileId` |
|
|
196
|
+
| `ListTeamsResponse` | Paginated wrapper around `TeamList[]` with `meta` for pagination |
|
|
197
|
+
| `OrgInfo` | Organization info — `tenantId`, timezone |
|
|
198
|
+
| `OrgSettings` | Org feature flags — `webRtcEnabled`, `maskSensitiveData` |
|
|
199
|
+
| `TenantData` | Tenant-level config — inactivity timeout, `forceDefaultDn`, `outdialEnabled` |
|
|
200
|
+
| `SiteInfo` | Site config — `id`, `name`, `multimediaProfileId` |
|
|
201
|
+
| `URLMapping` | External URL mapping — `id`, `name`, `url` |
|
|
202
|
+
| `MultimediaProfileResponse` | Multimedia profile — channel capacities and settings |
|
|
203
|
+
| `AuxCode` | Auxiliary code record — `id`, `name`, `description`, `workTypeCode` |
|
|
204
|
+
| `ListAuxCodesResponse` | Paginated wrapper around `AuxCode[]` with `meta` |
|
|
205
|
+
| `DialPlanEntity` | Dial plan rule — regex pattern, prefix, strip digits |
|
|
206
|
+
| `Entity` | Basic entity info — `isSystem`, `name`, `id`, `description` |
|
|
207
|
+
| `WrapupData` | Wrap-up config — auto-wrapup settings, available wrapup codes |
|
|
208
|
+
| `OutdialAniParams` | Parameters for `getOutdialAniEntries()` — ANI ID, pagination, filtering |
|
|
209
|
+
| `Team` | Simplified team shape in `Profile` — `teamId`, `teamName`, `desktopLayoutId` |
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// In register() -> connectWebsocket()
|
|
213
|
+
const agentId = data.agentId;
|
|
214
|
+
const orgId = this.$webex.credentials.getOrgId();
|
|
215
|
+
this.agentConfig = await this.services.config.getAgentConfig(orgId, agentId);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
> **Purpose**: Technical documentation for agent configuration aggregation.
|
|
219
|
+
|
|
220
|
+
For endpoints with pagination (teams, aux codes):
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import {DEFAULT_PAGE} from './constants'; // DEFAULT_PAGE = 0
|
|
224
|
+
|
|
225
|
+
public async getAllTeams(orgId, pageSize, filter): Promise<TeamList[]> {
|
|
226
|
+
let allTeams: TeamList[] = [];
|
|
227
|
+
let page = DEFAULT_PAGE;
|
|
228
|
+
|
|
229
|
+
// First request to get totalPages
|
|
230
|
+
const firstResponse = await this.getListOfTeams(orgId, page, pageSize, filter);
|
|
231
|
+
allTeams = allTeams.concat(firstResponse.data);
|
|
232
|
+
const totalPages = firstResponse.meta.totalPages;
|
|
233
|
+
|
|
234
|
+
// Parallel requests for remaining pages
|
|
235
|
+
const requests = [];
|
|
236
|
+
for (page = DEFAULT_PAGE + 1; page < totalPages; page += 1) {
|
|
237
|
+
requests.push(this.getListOfTeams(orgId, page, pageSize, filter));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const responses = await Promise.all(requests);
|
|
241
|
+
for (const response of responses) {
|
|
242
|
+
allTeams = allTeams.concat(response.data);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return allTeams;
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`parseAgentConfigs` in Util.ts combines all data into a unified `Profile` object. See [types.ts](../types.ts) for full type definitions.
|
|
250
|
+
|
|
251
|
+
The service fetches data from multiple APIs with these response structures:
|
|
252
|
+
|
|
253
|
+
| API Method | Response Type | Key Fields | Usage |
|
|
254
|
+
|---|---|---|---|
|
|
255
|
+
| `getUserUsingCI` | `AgentResponse` | `ciUserId`, `id`, `firstName`, `lastName`, `email`, `teamIds`, `agentProfileId`, `siteId` | Primary agent identity and profile references |
|
|
256
|
+
| `getDesktopProfileById` | `DesktopProfileResponse` | `dialPlanEnabled`, `autoAnswer`, `accessWrapUpCode`, `wrapUpCodes`, `accessIdleCode`, `idleCodes`, `loginVoiceOptions` | Agent desktop settings and feature enablement |
|
|
257
|
+
| `getAllTeams` | `TeamList[]` | real `TeamList` fields from `src/services/config/types.ts` | Team identity, name, type, and site assignment; channel capacities belong to `MultimediaProfileResponse` |
|
|
258
|
+
| `getTenantData` | `TenantData` | `outdialEnabled`, `forceDefaultDn`, `privacyShieldVisible`, `timeoutDesktopInactivityEnabled` | Tenant-level feature flags |
|
|
259
|
+
| `getOrgInfo` | `OrgInfo` | `tenantId`, `timezone` | Organization metadata |
|
|
260
|
+
| `getAllAuxCodes` | `AuxCode[]` | `id`, `name`, `workTypeCode`, `active`, `isSystemCode`, `defaultCode` | Auxiliary codes for idle/wrap-up states |
|
|
261
|
+
| `getOrganizationSetting` | `OrgSettings` | `webRtcEnabled`, `maskSensitiveData`, `campaignManagerEnabled` | Organization-level feature flags |
|
|
262
|
+
| `getDialPlanData` | `DialPlanEntity[]` | `id`, `name`, `regularExpression`, `prefix`, `strippedChars` | Dial plan rules for outbound calling |
|
|
263
|
+
| `getURLMapping` | `URLMapping[]` | `name`, `url` | External service URL mappings |
|
|
264
|
+
| `getSiteInfo` | `SiteInfo` | Site-specific configuration | Site details |
|
|
265
|
+
|
|
266
|
+
These responses are parsed and aggregated into a single `Profile` object by the `parseAgentConfigs` function.
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// See full implementation in Util.ts
|
|
270
|
+
function parseAgentConfigs(profileData: {
|
|
271
|
+
userData: AgentResponse; // See types.ts:AgentResponse
|
|
272
|
+
teamData: Team[]; // NOTE: Declared as Team[] (teamId, teamName) but receives TeamList[] (id, name, + 12 more fields) at runtime
|
|
273
|
+
tenantData: TenantData; // See types.ts:TenantData
|
|
274
|
+
orgInfoData: OrgInfo; // See types.ts:OrgInfo
|
|
275
|
+
auxCodes: AuxCode[]; // See types.ts:AuxCode
|
|
276
|
+
orgSettingsData: OrgSettings; // See types.ts:OrgSettings
|
|
277
|
+
agentProfileData: DesktopProfileResponse; // See types.ts:DesktopProfileResponse
|
|
278
|
+
dialPlanData: DialPlanEntity[]; // See types.ts:DialPlanEntity
|
|
279
|
+
urlMapping: URLMapping[]; // See types.ts:URLMapping
|
|
280
|
+
multimediaProfileId: string;
|
|
281
|
+
aiFeatureFlags: AIFeatureFlagsResponse;
|
|
282
|
+
}): Profile { // See types.ts:Profile
|
|
283
|
+
const { userData, teamData, tenantData, orgInfoData, auxCodes,
|
|
284
|
+
orgSettingsData, agentProfileData, dialPlanData, urlMapping,
|
|
285
|
+
aiFeatureFlags } = profileData;
|
|
286
|
+
|
|
287
|
+
const aiFeature = aiFeatureFlags?.data?.length > 0
|
|
288
|
+
? aiFeatureFlags.data[0]
|
|
289
|
+
: undefined;
|
|
290
|
+
|
|
291
|
+
// Aux code filtering via getFilterAuxCodes():
|
|
292
|
+
// - checks auxCode.active
|
|
293
|
+
// - checks specificCodes access level (ALL → no filter, SPECIFIC → include list)
|
|
294
|
+
// - maps to Entity {id, name, isSystem, isDefault}
|
|
295
|
+
const wrapupCodes = getFilterAuxCodes(auxCodes, WRAP_UP_CODE,
|
|
296
|
+
agentProfileData.accessWrapUpCode === 'ALL' ? [] : agentProfileData.wrapUpCodes);
|
|
297
|
+
const idleCodes = getFilterAuxCodes(auxCodes, IDLE_CODE,
|
|
298
|
+
agentProfileData.accessIdleCode === 'ALL' ? [] : agentProfileData.idleCodes);
|
|
299
|
+
|
|
300
|
+
// Hardcoded "Available" state always appended to idle codes
|
|
301
|
+
idleCodes.push({ id: '0', name: 'Available', isSystem: false, isDefault: false });
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
agentId: userData.ciUserId, // NOTE: uses ciUserId for agent identification
|
|
305
|
+
analyserUserId: userData.id, // NOTE: userData.id is used for analytics/reporting
|
|
306
|
+
agentName: `${userData.firstName} ${userData.lastName}`,
|
|
307
|
+
teams: teamData, // NOTE: Raw TeamList[] passed directly without mapping
|
|
308
|
+
idleCodes, // NOTE: Filtered via getFilterAuxCodes() + hardcoded "Available" state
|
|
309
|
+
wrapupCodes, // NOTE: Filtered via getFilterAuxCodes()
|
|
310
|
+
webRtcEnabled: orgSettingsData.webRtcEnabled,
|
|
311
|
+
loginVoiceOptions: agentProfileData.loginVoiceOptions ?? [],
|
|
312
|
+
enterpriseId: orgInfoData.tenantId,
|
|
313
|
+
tenantTimezone: orgInfoData.timezone,
|
|
314
|
+
multimediaProfileId: profileData.multimediaProfileId,
|
|
315
|
+
aiFeature,
|
|
316
|
+
// ... 30+ more fields — see Util.ts for full implementation
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Data Flow
|
|
322
|
+
```mermaid
|
|
323
|
+
flowchart TD
|
|
324
|
+
Start[getAgentConfig orgId + agentId] --> User[getUserUsingCI awaited first]
|
|
325
|
+
Start --> Org[getOrgInfo]
|
|
326
|
+
Start --> OrgSettings[getOrganizationSetting]
|
|
327
|
+
Start --> Tenant[getTenantData]
|
|
328
|
+
Start --> URL[getURLMapping]
|
|
329
|
+
Start --> AI[getAIFeatureFlags]
|
|
330
|
+
Start --> Aux[getAllAuxCodes]
|
|
331
|
+
User --> Profile[getDesktopProfileById]
|
|
332
|
+
User --> Site[getSiteInfo]
|
|
333
|
+
User --> Teams[getAllTeams or empty]
|
|
334
|
+
Profile --> Dial{dialPlanEnabled?}
|
|
335
|
+
Dial -->|yes| DialPlan[getDialPlanData]
|
|
336
|
+
Dial -->|no| Empty[empty dial plan]
|
|
337
|
+
Profile --> All[Promise.all of ten result promises]
|
|
338
|
+
Site --> All
|
|
339
|
+
Teams --> All
|
|
340
|
+
DialPlan --> All
|
|
341
|
+
Empty --> All
|
|
342
|
+
Org --> All
|
|
343
|
+
OrgSettings --> All
|
|
344
|
+
Tenant --> All
|
|
345
|
+
URL --> All
|
|
346
|
+
AI --> All
|
|
347
|
+
Aux --> All
|
|
348
|
+
All --> Parse[parseAgentConfigs including aiFeatureFlags]
|
|
349
|
+
Parse --> Result[Profile with aiFeature + maskSensitiveData]
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Sequence Diagram(s)
|
|
353
|
+
Sequence coverage:
|
|
354
|
+
|
|
355
|
+
| Operation group | Diagram | Failure / recovery coverage |
|
|
356
|
+
|---|---|---|
|
|
357
|
+
| Profile aggregation and AI feature flags | Profile aggregation | Any required request rejection rejects `getAgentConfig`; no partial Profile is returned. |
|
|
358
|
+
| Team/aux-code pagination | Pagination | Continue until page metadata is exhausted; any page rejection rejects the operation. |
|
|
359
|
+
|
|
360
|
+
AI-feature retrieval shares the same actors, ordering, Promise aggregation, and all-or-nothing failure outcome as the other profile dependencies, so it is represented in the Profile aggregation diagram rather than duplicated.
|
|
361
|
+
|
|
362
|
+
### Profile aggregation
|
|
363
|
+
|
|
364
|
+
```mermaid
|
|
365
|
+
sequenceDiagram
|
|
366
|
+
participant CC as ContactCenter
|
|
367
|
+
participant Cfg as AgentConfigService
|
|
368
|
+
participant API as WCC APIs
|
|
369
|
+
participant Util as parseAgentConfigs
|
|
370
|
+
CC->>Cfg: getAgentConfig(orgId, agentId)
|
|
371
|
+
par requests started before user data resolves
|
|
372
|
+
Cfg->>API: getUserUsingCI
|
|
373
|
+
Cfg->>API: org info + org settings + tenant + URL mapping
|
|
374
|
+
Cfg->>API: ai-feature flags + all aux codes
|
|
375
|
+
end
|
|
376
|
+
API-->>Cfg: user IDs/profile/site/team IDs
|
|
377
|
+
par user-dependent requests
|
|
378
|
+
Cfg->>API: desktop profile + site + teams
|
|
379
|
+
Cfg->>API: conditional dial plan chained from desktop profile
|
|
380
|
+
end
|
|
381
|
+
Note over Cfg,API: Promise.all awaits 10 result promises in total
|
|
382
|
+
alt all succeed
|
|
383
|
+
API-->>Cfg: ten results
|
|
384
|
+
Cfg->>Util: parseAgentConfigs(..., aiFeatureFlags)
|
|
385
|
+
Util-->>CC: Profile including aiFeature
|
|
386
|
+
else any fails
|
|
387
|
+
Cfg-->>CC: throw; no partial Profile
|
|
388
|
+
end
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Pagination
|
|
392
|
+
|
|
393
|
+
```mermaid
|
|
394
|
+
sequenceDiagram
|
|
395
|
+
participant Caller
|
|
396
|
+
participant Cfg as AgentConfigService
|
|
397
|
+
participant WR as WebexRequest
|
|
398
|
+
participant API as WCC API
|
|
399
|
+
Caller->>Cfg: getAllTeams/getAllAuxCodes(orgId, pageSize, filters)
|
|
400
|
+
Cfg->>WR: request page 0
|
|
401
|
+
WR->>API: authenticated GET
|
|
402
|
+
alt first page succeeds
|
|
403
|
+
API-->>Cfg: page 0 data + meta.totalPages
|
|
404
|
+
par remaining pages 1..totalPages-1
|
|
405
|
+
Cfg->>WR: Promise.all(page requests)
|
|
406
|
+
WR->>API: authenticated GETs
|
|
407
|
+
API-->>Cfg: remaining page responses
|
|
408
|
+
end
|
|
409
|
+
alt every remaining page succeeds
|
|
410
|
+
Cfg->>Cfg: concatenate responses in request order
|
|
411
|
+
Cfg-->>Caller: complete accumulated list
|
|
412
|
+
else any remaining page rejects
|
|
413
|
+
Cfg-->>Caller: reject; do not return a partial list
|
|
414
|
+
end
|
|
415
|
+
else first page rejects
|
|
416
|
+
Cfg-->>Caller: reject
|
|
417
|
+
end
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Class / Component Relationships
|
|
421
|
+
```mermaid
|
|
422
|
+
classDiagram
|
|
423
|
+
class ContactCenter
|
|
424
|
+
class AgentConfigService
|
|
425
|
+
class WebexRequest
|
|
426
|
+
class parseAgentConfigs
|
|
427
|
+
class Profile
|
|
428
|
+
ContactCenter --> AgentConfigService : getAgentConfig
|
|
429
|
+
AgentConfigService --> WebexRequest : ten dependent requests
|
|
430
|
+
AgentConfigService --> parseAgentConfigs : aggregate results
|
|
431
|
+
parseAgentConfigs --> Profile : aiFeature + maskSensitiveData
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
| Component | File | Responsibility |
|
|
435
|
+
|---|---|---|
|
|
436
|
+
| `AgentConfigService` | `config/index.ts` | Main config service class |
|
|
437
|
+
| `parseAgentConfigs` | `config/Util.ts` | Profile parsing/aggregation |
|
|
438
|
+
| `endPointMap` | `config/constants.ts` | API endpoint definitions |
|
|
439
|
+
| `types` | `config/types.ts` | Types, events, interfaces |
|
|
440
|
+
|
|
441
|
+
## Use Cases
|
|
442
|
+
- **UC-1 Two-wave profile aggregation:** retrieve the user first, run ten dependent promises including AI feature flags, then parse one complete Profile or reject the whole operation. Evidence: `src/services/config/index.ts`, `src/services/config/Util.ts`, `test/unit/spec/services/config/index.ts`.
|
|
443
|
+
- **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`.
|
|
444
|
+
- **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`.
|
|
445
|
+
- **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`.
|
|
446
|
+
|
|
447
|
+
## Business Rules & Invariants
|
|
448
|
+
- `getAgentConfig` rejects when any required dependent request rejects; it never returns a partial Profile.
|
|
449
|
+
- `Profile.aiFeature` is derived from the AI-feature response, and sensitive-data masking uses the real `maskSensitiveData` field.
|
|
450
|
+
- Team data has no `channelMap` contract; multimedia profile responses use `MultimediaProfileResponse`.
|
|
451
|
+
|
|
452
|
+
## Concurrency & Reactive Flow
|
|
453
|
+
- The initial user lookup supplies identifiers for a ten-promise `Promise.all`; pagination loops await pages in order and stop from returned metadata.
|
|
454
|
+
|
|
455
|
+
## Protocol / Wire Format
|
|
456
|
+
All Config operations are authenticated REST calls through WebexRequest. Important current routes include:
|
|
457
|
+
|
|
458
|
+
| Operation | Resource shape |
|
|
459
|
+
|---|---|
|
|
460
|
+
| AI feature flags | `organization/{orgId}/v2/ai-feature?page=0&pageSize=100` |
|
|
461
|
+
| Auxiliary codes | pagination/filter/attributes plus `desktopProfileFilter=true` |
|
|
462
|
+
| Multimedia profile | organization-scoped multimedia-profile resource |
|
|
463
|
+
| Dial plan | organization-scoped dial-plan resource when desktop profile enables it |
|
|
464
|
+
|
|
465
|
+
Exact resources live in `src/services/config/constants.ts`; response/profile fields live in `src/services/config/types.ts`.
|
|
466
|
+
|
|
467
|
+
## Error Handling & Failure Modes
|
|
468
|
+
| Condition | Signal (error/code/result) | Caller recovery |
|
|
469
|
+
|---|---|---|
|
|
470
|
+
| Dependency rejection | Typed/rethrown error or failure event | Inspect structured details, preserve tracking id, and retry only when the operation is safe. |
|
|
471
|
+
| Timeout or missing async completion | Timeout/recovery state | Follow the module-specific recovery path; never synthesize success. |
|
|
472
|
+
|
|
473
|
+
All API methods within the config service throw errors on failure. After `getUserUsingCI`, `getAgentConfig` awaits ten dependent requests via `Promise.all`: desktop profile, site, teams, conditional dial plan, organization info, organization settings, tenant data, URL mapping, AI feature flags, and all auxiliary codes. A failure in any required request, including `getAIFeatureFlags`, causes the entire AgentProfile fetch to fail. There is no partial profile — either all data is successfully fetched and aggregated, or the operation throws.
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
try {
|
|
477
|
+
const profile = await this.services.config.getAgentConfig(orgId, agentId);
|
|
478
|
+
} catch (error) {
|
|
479
|
+
LoggerProxy.error(`Config fetch failed: ${error}`, {
|
|
480
|
+
module: 'ConfigService',
|
|
481
|
+
method: 'getAgentConfig',
|
|
482
|
+
});
|
|
483
|
+
throw error;
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Each method follows consistent error handling:
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
public async getUserUsingCI(orgId: string, agentId: string): Promise<AgentResponse> {
|
|
491
|
+
LoggerProxy.info('Fetching user data using CI', {
|
|
492
|
+
module: CONFIG_FILE_NAME,
|
|
493
|
+
method: METHODS.GET_USER_USING_CI,
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
try {
|
|
497
|
+
const resource = endPointMap.userByCI(orgId, agentId);
|
|
498
|
+
const response = await this.webexReq.request({
|
|
499
|
+
service: WCC_API_GATEWAY,
|
|
500
|
+
resource,
|
|
501
|
+
method: HTTP_METHODS.GET,
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
if (response.statusCode !== 200) {
|
|
505
|
+
throw new Error(`API call failed with ${response.statusCode}`);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
LoggerProxy.log('getUserUsingCI api success.', {
|
|
509
|
+
module: CONFIG_FILE_NAME,
|
|
510
|
+
method: METHODS.GET_USER_USING_CI,
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
return Promise.resolve(response.body);
|
|
514
|
+
} catch (error) {
|
|
515
|
+
LoggerProxy.error(`getUserUsingCI API call failed with ${error}`, {
|
|
516
|
+
module: CONFIG_FILE_NAME,
|
|
517
|
+
method: METHODS.GET_USER_USING_CI,
|
|
518
|
+
});
|
|
519
|
+
throw error;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
**Cause**: One of the parallel API calls failed (network error, 401/403/404/500 response)
|
|
525
|
+
|
|
526
|
+
**Log patterns to search for:**
|
|
527
|
+
|
|
528
|
+
```typescript
|
|
529
|
+
// General config failure
|
|
530
|
+
"getAgentConfig call failed"
|
|
531
|
+
"module": "config/index.ts", "method": "getAgentConfig"
|
|
532
|
+
|
|
533
|
+
// Specific API method failures
|
|
534
|
+
"getUserUsingCI API call failed"
|
|
535
|
+
"getDesktopProfileById API call failed"
|
|
536
|
+
"getAllTeams API call failed"
|
|
537
|
+
"getAllAuxCodes API call failed"
|
|
538
|
+
|
|
539
|
+
// Look for HTTP error codes
|
|
540
|
+
"API call failed with 401" // Authentication
|
|
541
|
+
"API call failed with 403" // Authorization
|
|
542
|
+
"API call failed with 404" // Not found
|
|
543
|
+
"API call failed with 500" // Server error
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
**Solution**:
|
|
547
|
+
|
|
548
|
+
1. Check logs for specific API that failed
|
|
549
|
+
|
|
550
|
+
2. Verify orgId and agentId are correct
|
|
551
|
+
|
|
552
|
+
3. Ensure authentication tokens are valid
|
|
553
|
+
|
|
554
|
+
4. Check network connectivity to WCC API Gateway
|
|
555
|
+
|
|
556
|
+
**Cause**: Pagination not completing or filter parameters incorrect
|
|
557
|
+
|
|
558
|
+
**Log patterns:**
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
"getAllTeams API call failed"
|
|
562
|
+
"getAllAuxCodes API call failed"
|
|
563
|
+
"method": "getListOfTeams"
|
|
564
|
+
"method": "getListOfAuxCodes"
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Solution**:
|
|
568
|
+
|
|
569
|
+
1. Check `totalPages` in first response
|
|
570
|
+
|
|
571
|
+
2. Verify filter array contains valid team/aux code IDs
|
|
572
|
+
|
|
573
|
+
3. Check if pageSize is appropriate (default: 100)
|
|
574
|
+
|
|
575
|
+
4. Ensure all pages are fetched in Promise.all()
|
|
576
|
+
|
|
577
|
+
**Cause**: Organization or tenant settings have feature disabled
|
|
578
|
+
|
|
579
|
+
**Log patterns:**
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
"getOrganizationSetting api success"
|
|
583
|
+
"getTenantData api success"
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
**Solution**:
|
|
587
|
+
|
|
588
|
+
1. Check `orgSettingsData.webRtcEnabled` in response
|
|
589
|
+
|
|
590
|
+
2. Check `tenantData.outdialEnabled` for outbound features
|
|
591
|
+
|
|
592
|
+
3. Verify feature is enabled in admin portal settings
|
|
593
|
+
|
|
594
|
+
4. Confirm agentProfileData has correct feature flags
|
|
595
|
+
|
|
596
|
+
**Cause**: `dialPlanEnabled` is false in desktop profile
|
|
597
|
+
|
|
598
|
+
**Solution**:
|
|
599
|
+
|
|
600
|
+
1. Check `agentProfileData.dialPlanEnabled` value
|
|
601
|
+
|
|
602
|
+
2. Verify dial plans are assigned in agent profile configuration
|
|
603
|
+
|
|
604
|
+
3. Note: dial plan fetch only happens if `dialPlanEnabled === true`
|
|
605
|
+
|
|
606
|
+
**Cause**: Access level set to 'SPECIFIC' but missing code IDs
|
|
607
|
+
|
|
608
|
+
**Log patterns:**
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
"method": "getFilterAuxCodes"
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
**Solution**:
|
|
615
|
+
|
|
616
|
+
1. Check `agentProfileData.accessWrapUpCode` (should be 'ALL' or 'SPECIFIC')
|
|
617
|
+
|
|
618
|
+
2. Check `agentProfileData.accessIdleCode`
|
|
619
|
+
|
|
620
|
+
3. If 'SPECIFIC', verify `wrapUpCodes` and `idleCodes` arrays contain valid IDs
|
|
621
|
+
|
|
622
|
+
4. Ensure aux codes have `active: true` status
|
|
623
|
+
|
|
624
|
+
5. Note: "Available" state is always appended to idle codes
|
|
625
|
+
|
|
626
|
+
## Pitfalls
|
|
627
|
+
- `getUserUsingCI` must complete before profile/site/team-dependent requests are constructed, while the ten dependent promises remain all-or-nothing.
|
|
628
|
+
- AI feature flags are part of the ten-result aggregation and must be passed into `parseAgentConfigs`; omitting them silently removes `Profile.aiFeature`.
|
|
629
|
+
- Team responses do not own channel configuration, and auxiliary-code requests require `desktopProfileFilter=true` during profile construction.
|
|
630
|
+
|
|
631
|
+
## Module Do's / Don'ts
|
|
632
|
+
- DO preserve the user-first dependency boundary and the exact ten-promise result order.
|
|
633
|
+
- DO paginate team and auxiliary-code endpoints until their metadata indicates completion.
|
|
634
|
+
- DON'T return a partially assembled Profile after any required dependency fails.
|
|
635
|
+
- DON'T invent TeamList fields such as `channelMap` or omit `maskSensitiveData`/`aiFeature` mappings.
|
|
636
|
+
|
|
637
|
+
## Key Design Trade-off
|
|
638
|
+
- Profile creation is all-or-nothing across dependent API calls so consumers never receive internally inconsistent partial configuration.
|
|
639
|
+
|
|
640
|
+
## Test-Case Strategy (module)
|
|
641
|
+
`test/unit/spec/services/config/index.ts` must cover staged user-first orchestration, ten-promise aggregation, AI-feature mapping, conditional dial plan, pagination, auxiliary-code URL filtering, real response field names, and whole-profile rejection on any required failure.
|
|
642
|
+
|
|
643
|
+
| Behavior / Requirement | Existing test evidence | Gap |
|
|
644
|
+
|---|---|---|
|
|
645
|
+
| `CONFIG-R-001` | `test/unit/spec/services/config/index.ts` | None. |
|
|
646
|
+
| `CONFIG-R-002` | `test/unit/spec/services/config/index.ts` | None. |
|
|
647
|
+
| `CONFIG-R-003` | `test/unit/spec/services/config/index.ts` | None. |
|
|
648
|
+
| `CONFIG-R-004` | `test/unit/spec/services/config/index.ts` | None. |
|
|
649
|
+
| `CONFIG-R-005` | `test/unit/spec/services/config/index.ts` | Keep an explicit rejection assertion for each required dependency category. |
|
|
650
|
+
|
|
651
|
+
## Traceability
|
|
652
|
+
- Repo architecture: `../../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../../ai-docs/SPEC_INDEX.md`
|
|
653
|
+
- Coverage state and contracts baseline: `../../../../.sdd/manifest.json`
|
|
654
|
+
|
|
655
|
+
- [Root AGENTS.md](../../../../AGENTS.md) - Orchestrator and cross-scope rules
|
|
656
|
+
|
|
657
|
+
- [types.ts](../types.ts) - Type definitions
|
|
658
|
+
|
|
659
|
+
- [Util.ts](../Util.ts) - AgentProfile parsing utilities
|
|
660
|
+
|
|
661
|
+
- [constants.ts](../constants.ts) - API endpoints
|
|
662
|
+
|
|
663
|
+
- [index.ts](../index.ts) - Service implementation with all API methods
|
|
664
|
+
|
|
665
|
+
- [types.ts](../types.ts) - Complete type definitions and event constants
|
|
666
|
+
|
|
667
|
+
- [Util.ts](../Util.ts) - Profile parsing utilities (parseAgentConfigs, getFilterAuxCodes, etc.)
|
|
668
|
+
|
|
669
|
+
- [constants.ts](../constants.ts) - API endpoints, default values, and method names
|