@webex/contact-center 3.12.0-next.73 → 3.12.0-next.74
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/AGENTS.md +438 -0
- package/ai-docs/README.md +131 -0
- package/ai-docs/RULES.md +455 -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 +53 -38
- package/dist/cc.js.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +14 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +26 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +9 -3
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +74 -3
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/config/Util.js +2 -2
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/types.js +25 -9
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Utils.js +74 -27
- 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 +725 -612
- 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 +6 -1
- package/dist/services/task/constants.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 +168 -16
- 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 +19 -18
- package/dist/types/config.d.ts +6 -0
- package/dist/types/constants.d.ts +14 -1
- package/dist/types/index.d.ts +11 -5
- package/dist/types/metrics/constants.d.ts +7 -1
- package/dist/types/services/ApiAiAssistant.d.ts +11 -3
- package/dist/types/services/config/types.d.ts +113 -9
- package/dist/types/services/core/Utils.d.ts +23 -10
- 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 +5 -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 +551 -78
- 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 +92 -0
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +85 -0
- 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 +63 -43
- package/src/config.ts +6 -0
- package/src/constants.ts +14 -1
- package/src/index.ts +14 -5
- package/src/metrics/ai-docs/AGENTS.md +348 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
- package/src/metrics/behavioral-events.ts +28 -0
- package/src/metrics/constants.ts +9 -4
- package/src/services/ApiAiAssistant.ts +104 -3
- package/src/services/agent/ai-docs/AGENTS.md +238 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
- package/src/services/ai-docs/AGENTS.md +384 -0
- package/src/services/config/Util.ts +2 -2
- package/src/services/config/ai-docs/AGENTS.md +253 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
- package/src/services/config/types.ts +116 -10
- package/src/services/core/Utils.ts +85 -34
- package/src/services/core/ai-docs/AGENTS.md +379 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +696 -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 +738 -697
- package/src/services/task/TaskUtils.ts +205 -25
- package/src/services/task/ai-docs/AGENTS.md +455 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +585 -0
- package/src/services/task/constants.ts +5 -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 +495 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -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 +654 -85
- package/src/services/task/voice/Voice.ts +1267 -0
- package/src/services/task/voice/WebRTC.ts +187 -0
- package/src/types.ts +112 -1
- package/src/utils/AGENTS.md +276 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +133 -3
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +122 -17
- package/test/unit/spec/services/WebCallingService.ts +7 -1
- package/test/unit/spec/services/config/index.ts +27 -27
- package/test/unit/spec/services/core/Utils.ts +335 -1
- 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 +821 -1936
- package/test/unit/spec/services/task/TaskUtils.ts +206 -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 -1530
- 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 -1806
- package/test/unit/spec/services/task/index.ts +0 -2205
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# New Service - Test Generation
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Create unit tests for the new service.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Test File Location
|
|
8
|
+
|
|
9
|
+
Create: `test/unit/spec/services/ServiceName.ts`
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Test File Template
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import 'jsdom-global/register';
|
|
17
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
18
|
+
import ServiceName, {
|
|
19
|
+
ServiceListResponse,
|
|
20
|
+
ServiceSearchParams,
|
|
21
|
+
} from '../../../../src/services/ServiceName';
|
|
22
|
+
|
|
23
|
+
jest.mock('../../../../src/logger-proxy', () => ({
|
|
24
|
+
__esModule: true,
|
|
25
|
+
default: {
|
|
26
|
+
log: jest.fn(),
|
|
27
|
+
error: jest.fn(),
|
|
28
|
+
info: jest.fn(),
|
|
29
|
+
warn: jest.fn(),
|
|
30
|
+
trace: jest.fn(),
|
|
31
|
+
initialize: jest.fn(),
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
describe('ServiceName', () => {
|
|
36
|
+
let webex: any;
|
|
37
|
+
let service: ServiceName;
|
|
38
|
+
|
|
39
|
+
// Mock data
|
|
40
|
+
const mockOrgId = 'mock-org-id';
|
|
41
|
+
const mockResponse: ServiceListResponse = {
|
|
42
|
+
data: [
|
|
43
|
+
{ id: 'item-1', name: 'Item 1' },
|
|
44
|
+
{ id: 'item-2', name: 'Item 2' },
|
|
45
|
+
],
|
|
46
|
+
meta: {
|
|
47
|
+
page: 0,
|
|
48
|
+
pageSize: 50,
|
|
49
|
+
totalPages: 1,
|
|
50
|
+
totalRecords: 2,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
webex = MockWebex({
|
|
56
|
+
logger: {
|
|
57
|
+
log: jest.fn(),
|
|
58
|
+
error: jest.fn(),
|
|
59
|
+
info: jest.fn(),
|
|
60
|
+
},
|
|
61
|
+
credentials: {
|
|
62
|
+
getOrgId: jest.fn(() => mockOrgId),
|
|
63
|
+
},
|
|
64
|
+
request: jest.fn(),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
service = new ServiceName(webex);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
afterEach(() => {
|
|
71
|
+
jest.clearAllMocks();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('getItems', () => {
|
|
75
|
+
it('should fetch items successfully', async () => {
|
|
76
|
+
// Arrange
|
|
77
|
+
webex.request.mockResolvedValue({ body: mockResponse });
|
|
78
|
+
|
|
79
|
+
// Act
|
|
80
|
+
const result = await service.getItems();
|
|
81
|
+
|
|
82
|
+
// Assert
|
|
83
|
+
expect(result).toEqual(mockResponse);
|
|
84
|
+
expect(webex.request).toHaveBeenCalledWith({
|
|
85
|
+
method: 'GET',
|
|
86
|
+
uri: expect.stringContaining(mockOrgId),
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should apply pagination parameters', async () => {
|
|
91
|
+
// Arrange
|
|
92
|
+
webex.request.mockResolvedValue({ body: mockResponse });
|
|
93
|
+
const params: ServiceSearchParams = { page: 1, pageSize: 25 };
|
|
94
|
+
|
|
95
|
+
// Act
|
|
96
|
+
await service.getItems(params);
|
|
97
|
+
|
|
98
|
+
// Assert
|
|
99
|
+
expect(webex.request).toHaveBeenCalledWith({
|
|
100
|
+
method: 'GET',
|
|
101
|
+
uri: expect.stringContaining('page=1'),
|
|
102
|
+
});
|
|
103
|
+
expect(webex.request).toHaveBeenCalledWith({
|
|
104
|
+
method: 'GET',
|
|
105
|
+
uri: expect.stringContaining('pageSize=25'),
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should apply search parameter', async () => {
|
|
110
|
+
// Arrange
|
|
111
|
+
webex.request.mockResolvedValue({ body: mockResponse });
|
|
112
|
+
const params: ServiceSearchParams = { search: 'test' };
|
|
113
|
+
|
|
114
|
+
// Act
|
|
115
|
+
await service.getItems(params);
|
|
116
|
+
|
|
117
|
+
// Assert
|
|
118
|
+
expect(webex.request).toHaveBeenCalledWith({
|
|
119
|
+
method: 'GET',
|
|
120
|
+
uri: expect.stringContaining('search=test'),
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should throw error on API failure', async () => {
|
|
125
|
+
// Arrange
|
|
126
|
+
const mockError = new Error('API Error');
|
|
127
|
+
webex.request.mockRejectedValue(mockError);
|
|
128
|
+
|
|
129
|
+
// Act & Assert
|
|
130
|
+
await expect(service.getItems()).rejects.toThrow('API Error');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('getItemById', () => {
|
|
135
|
+
it('should fetch single item successfully', async () => {
|
|
136
|
+
// Arrange
|
|
137
|
+
const mockItem = { id: 'item-1', name: 'Item 1' };
|
|
138
|
+
webex.request.mockResolvedValue({ body: mockItem });
|
|
139
|
+
|
|
140
|
+
// Act
|
|
141
|
+
const result = await service.getItemById('item-1');
|
|
142
|
+
|
|
143
|
+
// Assert
|
|
144
|
+
expect(result).toEqual(mockItem);
|
|
145
|
+
expect(webex.request).toHaveBeenCalledWith({
|
|
146
|
+
method: 'GET',
|
|
147
|
+
uri: expect.stringContaining('item-1'),
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should throw error if item not found', async () => {
|
|
152
|
+
// Arrange
|
|
153
|
+
const mockError = new Error('Not Found');
|
|
154
|
+
webex.request.mockRejectedValue(mockError);
|
|
155
|
+
|
|
156
|
+
// Act & Assert
|
|
157
|
+
await expect(service.getItemById('invalid-id')).rejects.toThrow('Not Found');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Test Integration with cc.ts
|
|
166
|
+
|
|
167
|
+
Add to `test/unit/spec/cc.ts`:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
describe('cc.serviceName', () => {
|
|
171
|
+
it('should initialize service on ready', () => {
|
|
172
|
+
expect(webex.cc.serviceName).toBeDefined();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should fetch items through service', async () => {
|
|
176
|
+
// Mock the service method
|
|
177
|
+
const mockResponse = { data: [], meta: {} };
|
|
178
|
+
jest.spyOn(webex.cc.serviceName, 'getItems').mockResolvedValue(mockResponse);
|
|
179
|
+
|
|
180
|
+
// Act
|
|
181
|
+
const result = await webex.cc.serviceName.getItems();
|
|
182
|
+
|
|
183
|
+
// Assert
|
|
184
|
+
expect(result).toEqual(mockResponse);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Running Tests
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Run specific test file
|
|
195
|
+
yarn workspace @webex/contact-center test -- --testPathPattern=ServiceName
|
|
196
|
+
|
|
197
|
+
# Run with coverage
|
|
198
|
+
yarn workspace @webex/contact-center test -- --coverage --testPathPattern=ServiceName
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Next Step
|
|
204
|
+
|
|
205
|
+
Proceed to: [`05-validation.md`](05-validation.md)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# New Service - Validation Checklist
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Final quality check before completing service creation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Code Quality Checklist
|
|
8
|
+
|
|
9
|
+
### Service Class
|
|
10
|
+
- [ ] File created at correct location (based on placement from pre-questions Q3)
|
|
11
|
+
- [ ] Class has proper JSDoc with `@public` tag
|
|
12
|
+
- [ ] Methods have JSDoc with `@param`, `@returns`, `@example`
|
|
13
|
+
- [ ] Uses `LoggerProxy` for all logging (no `console.log`)
|
|
14
|
+
- [ ] Error handling uses `getErrorDetails` pattern (logs and re-throws)
|
|
15
|
+
- [ ] Module name constant defined (`SERVICE_FILE`)
|
|
16
|
+
- [ ] Method name constants defined (`METHODS`)
|
|
17
|
+
|
|
18
|
+
### Types & Constants
|
|
19
|
+
- [ ] Types placed in the correct location:
|
|
20
|
+
- Folder-based service: service folder's `types.ts`
|
|
21
|
+
- Single-file service: root `src/types.ts`
|
|
22
|
+
- Sub-module: parent service's `types.ts`
|
|
23
|
+
- [ ] Constants: no duplicates — every constant was searched across the hierarchy before adding:
|
|
24
|
+
- `src/constants.ts` (SDK-wide: file names, method names, global settings)
|
|
25
|
+
- `src/services/constants.ts` (shared: API gateways, auth, network)
|
|
26
|
+
- `src/metrics/constants.ts` (all metric event names)
|
|
27
|
+
- `src/services/config/constants.ts` (endpoint maps, pagination, agent states)
|
|
28
|
+
- `src/services/{ServiceName}/constants.ts` (service-specific only)
|
|
29
|
+
- [ ] Constants placed at the correct level (not duplicated at a lower level when shared exists)
|
|
30
|
+
- [ ] New `constants.ts` file created ONLY if service is folder-based AND no existing file AND constants are service-specific
|
|
31
|
+
- [ ] All public types have JSDoc
|
|
32
|
+
- [ ] Response types match actual API response
|
|
33
|
+
- [ ] Parameter types define all optional/required fields
|
|
34
|
+
|
|
35
|
+
### Metrics
|
|
36
|
+
- [ ] `metricsManager.timeEvent` called at method entry with success + failure event names
|
|
37
|
+
- [ ] `metricsManager.trackEvent` called on success path
|
|
38
|
+
- [ ] `metricsManager.trackEvent` called on failure path (in catch block)
|
|
39
|
+
- [ ] Metric event names added to `src/metrics/constants.ts` (`METRIC_EVENT_NAMES`)
|
|
40
|
+
|
|
41
|
+
### Integration
|
|
42
|
+
- [ ] Service initialized at the correct integration point:
|
|
43
|
+
- Folder-based / single-file: in `cc.ts` or `Services` singleton (depends on AQM vs non-AQM)
|
|
44
|
+
- Sub-module: instantiated by parent service
|
|
45
|
+
- [ ] Types re-exported from `src/types.ts` (if public)
|
|
46
|
+
|
|
47
|
+
### Tests
|
|
48
|
+
- [ ] Test file created mirroring source path under `test/unit/spec/`
|
|
49
|
+
- [ ] LoggerProxy mocked
|
|
50
|
+
- [ ] Success cases tested
|
|
51
|
+
- [ ] Error cases tested
|
|
52
|
+
- [ ] Metrics tracking verified (timeEvent and trackEvent calls asserted)
|
|
53
|
+
- [ ] Tests pass: `yarn workspace @webex/contact-center test:unit`
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Pattern Compliance
|
|
58
|
+
|
|
59
|
+
### LoggerProxy Usage
|
|
60
|
+
```typescript
|
|
61
|
+
// ✅ Correct
|
|
62
|
+
LoggerProxy.info('Starting operation', {
|
|
63
|
+
module: SERVICE_FILE,
|
|
64
|
+
method: METHODS.GET_ITEMS,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// ❌ Wrong
|
|
68
|
+
console.log('Starting operation');
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Error Handling
|
|
72
|
+
```typescript
|
|
73
|
+
// ✅ Correct
|
|
74
|
+
catch (error) {
|
|
75
|
+
LoggerProxy.error(`Failed: ${error}`, {
|
|
76
|
+
module: SERVICE_FILE,
|
|
77
|
+
method: METHODS.GET_ITEMS,
|
|
78
|
+
error,
|
|
79
|
+
});
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ❌ Wrong - swallowing error
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error(error);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Type Exports
|
|
90
|
+
```typescript
|
|
91
|
+
// ✅ Correct - in src/types.ts
|
|
92
|
+
export type {
|
|
93
|
+
ServiceItem,
|
|
94
|
+
ServiceSearchParams,
|
|
95
|
+
ServiceListResponse,
|
|
96
|
+
} from './services/ServiceName';
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Build & Test Verification
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Lint
|
|
105
|
+
yarn workspace @webex/contact-center test:styles
|
|
106
|
+
|
|
107
|
+
# Test unit tests
|
|
108
|
+
yarn workspace @webex/contact-center test:unit
|
|
109
|
+
|
|
110
|
+
# Build
|
|
111
|
+
yarn workspace @webex/contact-center build:src
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
All should pass without errors.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Documentation
|
|
119
|
+
|
|
120
|
+
### Update Root AGENTS.md?
|
|
121
|
+
If this is a significant new service, update the root [`AGENTS.md`](../../../AGENTS.md):
|
|
122
|
+
- [ ] Added new service to the [Service Routing Table](../../../AGENTS.md#service-routing-table)
|
|
123
|
+
- [ ] Added to repository structure tree
|
|
124
|
+
- [ ] Added usage example if applicable
|
|
125
|
+
|
|
126
|
+
### Create Service ai-docs?
|
|
127
|
+
For complex services, create service-level documentation (use [`create-agents-md.md`](../documentation/create-agents-md.md) and [`create-architecture-md.md`](../documentation/create-architecture-md.md) templates):
|
|
128
|
+
- [ ] `src/services/ServiceName/ai-docs/AGENTS.md` — usage guide, API reference
|
|
129
|
+
- [ ] `src/services/ServiceName/ai-docs/ARCHITECTURE.md` — technical deep-dive, data flow
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Final Review
|
|
134
|
+
|
|
135
|
+
Ask yourself:
|
|
136
|
+
1. Can another developer understand this service by reading the JSDoc?
|
|
137
|
+
2. Are all error paths properly handled and logged?
|
|
138
|
+
3. Do tests cover the main use cases?
|
|
139
|
+
4. Is the API surface clean and consistent with other services?
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Complete!
|
|
144
|
+
|
|
145
|
+
Service creation is complete when all checkboxes are checked.
|
package/dist/cc.js
CHANGED
|
@@ -318,7 +318,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
318
318
|
this.metricsManager = _MetricsManager.default.getInstance({
|
|
319
319
|
webex: this.$webex
|
|
320
320
|
});
|
|
321
|
-
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager);
|
|
321
|
+
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager, this.services.rtdWebSocketManager);
|
|
322
322
|
this.incomingTaskListener();
|
|
323
323
|
|
|
324
324
|
// Initialize API instances
|
|
@@ -350,6 +350,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
350
350
|
this.trigger(_types4.TASK_EVENTS.TASK_HYDRATE, task);
|
|
351
351
|
};
|
|
352
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Handles multi-login hydrate events for SDK instances without Mobius registration
|
|
355
|
+
* @private
|
|
356
|
+
* @param {ITask} task The task object associated with the multi-login hydrate
|
|
357
|
+
*/
|
|
358
|
+
handleTaskMultiLoginHydrate = task => {
|
|
359
|
+
// @ts-ignore
|
|
360
|
+
this.trigger(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
|
|
361
|
+
};
|
|
362
|
+
|
|
353
363
|
/**
|
|
354
364
|
* Handles task merged events when tasks are combined eg: EPDN merge/transfer
|
|
355
365
|
* @private
|
|
@@ -369,18 +379,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
369
379
|
// @ts-ignore
|
|
370
380
|
this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
|
|
371
381
|
};
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
* Handles multi-login hydrate events emitted when browser login accepts an incoming call.
|
|
375
|
-
* @private
|
|
376
|
-
* @param {ITask} task The task object associated with multi-login hydrate
|
|
377
|
-
*/
|
|
378
|
-
handleTaskMultiLoginHydrate = task => {
|
|
379
|
-
// @ts-ignore
|
|
380
|
-
this.trigger(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
|
|
381
|
-
};
|
|
382
|
-
handleRTDWebsocketMessage = payload => {
|
|
383
|
-
this.taskManager.handleRealtimeWebsocketEvent(payload);
|
|
382
|
+
handleRTDWebsocketMessage = event => {
|
|
383
|
+
this.taskManager.handleRealtimeWebsocketEvent(event);
|
|
384
384
|
};
|
|
385
385
|
|
|
386
386
|
/**
|
|
@@ -391,8 +391,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
391
391
|
incomingTaskListener() {
|
|
392
392
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
393
393
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
394
|
-
this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
|
|
395
394
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
395
|
+
this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
|
|
396
396
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
397
397
|
}
|
|
398
398
|
|
|
@@ -525,6 +525,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
525
525
|
if (!this.services.webSocketManager.isSocketClosed) {
|
|
526
526
|
this.services.webSocketManager.close(false, 'Unregistering the SDK');
|
|
527
527
|
}
|
|
528
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
529
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
|
|
530
|
+
}
|
|
528
531
|
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
529
532
|
this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
|
|
530
533
|
}
|
|
@@ -622,25 +625,6 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
622
625
|
}
|
|
623
626
|
}
|
|
624
627
|
|
|
625
|
-
/**
|
|
626
|
-
* Checks whether WebRTC registration should be skipped by config.
|
|
627
|
-
* @returns {boolean}
|
|
628
|
-
* @private
|
|
629
|
-
*/
|
|
630
|
-
isWebRTCRegistrationDisabled() {
|
|
631
|
-
return this.$config?.disableWebRTCRegistration === true;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Validates contact-center plugin configuration before service initialization
|
|
636
|
-
* @private
|
|
637
|
-
*/
|
|
638
|
-
validatePluginConfig() {
|
|
639
|
-
if (this.$config?.disableWebRTCRegistration === true && this.$config?.allowMultiLogin === false) {
|
|
640
|
-
throw new Error('Invalid Contact Center configuration: disableWebRTCRegistration cannot be true when allowMultiLogin is false. Enable allowMultiLogin or allow WebRTC registration so an SDK instance can receive Mobius/WebRTC task events.');
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
628
|
/**
|
|
645
629
|
* Connects to the websocket and fetches the agent profile
|
|
646
630
|
* @returns {Promise<Profile>} Agent profile information
|
|
@@ -664,18 +648,30 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
664
648
|
module: _constants.CC_FILE,
|
|
665
649
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
666
650
|
});
|
|
667
|
-
|
|
651
|
+
const configFlags = {
|
|
652
|
+
isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
|
|
653
|
+
isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
|
|
654
|
+
webRtcEnabled: this.agentConfig.webRtcEnabled,
|
|
655
|
+
autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
|
|
656
|
+
aiFeature: this.agentConfig.aiFeature
|
|
657
|
+
};
|
|
658
|
+
this.taskManager.setConfigFlags(configFlags);
|
|
668
659
|
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
669
660
|
this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
|
|
670
661
|
this.taskManager.setAgentId(this.agentConfig.agentId);
|
|
671
662
|
this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
|
|
672
663
|
this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
|
|
673
|
-
|
|
674
|
-
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* RTD websocket currently supports realtime transcripts and suggested responses.
|
|
667
|
+
* Extend this condition when additional AI RTD features are introduced.
|
|
668
|
+
*/
|
|
669
|
+
if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable) {
|
|
670
|
+
_loggerProxy.default.info('Connecting to RTD websocket', {
|
|
675
671
|
module: _constants.CC_FILE,
|
|
676
672
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
677
673
|
});
|
|
678
|
-
|
|
674
|
+
this.services.rtdWebSocketManager.initWebSocket({
|
|
679
675
|
body: this.getConnectionConfig(),
|
|
680
676
|
resource: _constants3.RTD_SUBSCRIBE_API
|
|
681
677
|
}).then(() => {
|
|
@@ -685,7 +681,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
685
681
|
});
|
|
686
682
|
this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
|
|
687
683
|
}).catch(error => {
|
|
688
|
-
_loggerProxy.default.error(`Error
|
|
684
|
+
_loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
|
|
689
685
|
module: _constants.CC_FILE,
|
|
690
686
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
691
687
|
});
|
|
@@ -1123,6 +1119,25 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1123
1119
|
}
|
|
1124
1120
|
};
|
|
1125
1121
|
|
|
1122
|
+
/**
|
|
1123
|
+
* Checks whether Mobius/WebRTC registration should be skipped by config
|
|
1124
|
+
* @returns {boolean} True when browser WebRTC registration is disabled
|
|
1125
|
+
* @private
|
|
1126
|
+
*/
|
|
1127
|
+
isWebRTCRegistrationDisabled() {
|
|
1128
|
+
return this.$config?.disableWebRTCRegistration === true;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* Validates contact-center plugin configuration before service initialization
|
|
1133
|
+
* @private
|
|
1134
|
+
*/
|
|
1135
|
+
validatePluginConfig() {
|
|
1136
|
+
if (this.$config?.disableWebRTCRegistration === true && this.$config?.allowMultiLogin === false) {
|
|
1137
|
+
throw new Error('Invalid Contact Center configuration: disableWebRTCRegistration cannot be true when allowMultiLogin is false. Enable allowMultiLogin or allow WebRTC registration so an SDK instance can receive Mobius/WebRTC task events.');
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1126
1141
|
/**
|
|
1127
1142
|
* Initializes event listeners for the Contact Center service
|
|
1128
1143
|
* Sets up handlers for connection state changes and other core events
|