@webex/contact-center 3.12.0-next.84 → 3.12.0-next.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.sdd/manifest.json +876 -0
  2. package/AGENTS.md +65 -409
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +46 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +25 -18
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +187 -198
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +48 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +341 -0
  17. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  18. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  19. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  20. package/ai-docs/templates/README.md +1 -1
  21. package/ai-docs/templates/new-method/04-validation.md +1 -1
  22. package/ai-docs/templates/new-service/05-validation.md +1 -1
  23. package/dist/webex.js +1 -1
  24. package/package.json +1 -1
  25. package/src/metrics/ai-docs/AGENTS.md +2 -0
  26. package/src/metrics/ai-docs/ARCHITECTURE.md +2 -0
  27. package/src/metrics/ai-docs/metrics-spec.md +854 -0
  28. package/src/services/agent/ai-docs/AGENTS.md +3 -1
  29. package/src/services/agent/ai-docs/ARCHITECTURE.md +2 -0
  30. package/src/services/agent/ai-docs/agent-spec.md +504 -0
  31. package/src/services/ai-docs/AGENTS.md +4 -2
  32. package/src/services/ai-docs/services-spec.md +492 -0
  33. package/src/services/config/ai-docs/AGENTS.md +3 -1
  34. package/src/services/config/ai-docs/ARCHITECTURE.md +2 -0
  35. package/src/services/config/ai-docs/config-spec.md +669 -0
  36. package/src/services/core/ai-docs/AGENTS.md +4 -2
  37. package/src/services/core/ai-docs/ARCHITECTURE.md +2 -0
  38. package/src/services/core/ai-docs/core-spec.md +783 -0
  39. package/src/services/task/ai-docs/AGENTS.md +2 -0
  40. package/src/services/task/ai-docs/ARCHITECTURE.md +11 -2
  41. package/src/services/task/ai-docs/task-spec.md +1319 -0
  42. package/src/services/task/state-machine/ai-docs/AGENTS.md +38 -75
  43. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +6 -4
  44. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2115 -0
  45. package/src/utils/AGENTS.md +3 -1
  46. package/src/utils/ai-docs/utils-spec.md +381 -0
  47. package/umd/contact-center.min.js +2 -2
@@ -1,5 +1,7 @@
1
1
  # Agent Service - AI Agent Guide
2
2
 
3
+ > **Legacy/reference-only.** Canonical SDD: [`agent-spec.md`](agent-spec.md). Use the package [manifest](../../../../.sdd/manifest.json) and [`SPEC_INDEX.md`](../../../../ai-docs/SPEC_INDEX.md) for routing; code and tests remain the behavioral referee.
4
+
3
5
  > **Purpose**: Manage agent lifecycle including login, logout, state changes, and buddy agent queries.
4
6
 
5
7
  ---
@@ -235,4 +237,4 @@ try {
235
237
 
236
238
  - [ARCHITECTURE.md](ARCHITECTURE.md) - Technical deep-dive
237
239
  - [`cc.ts`](../../../cc.ts) - Main plugin implementation
238
- - [`types.ts`](../types.ts) - Type definitions
240
+ - [`types.ts`](../types.ts) - Type definitions
@@ -1,5 +1,7 @@
1
1
  # Agent Service - Architecture
2
2
 
3
+ > **Legacy/reference-only.** Canonical SDD: [`agent-spec.md`](agent-spec.md). Use the package [manifest](../../../../.sdd/manifest.json) and [`SPEC_INDEX.md`](../../../../ai-docs/SPEC_INDEX.md) for routing; code and tests remain the behavioral referee.
4
+
3
5
  > **Purpose**: Technical documentation for agent lifecycle operations.
4
6
 
5
7
  ---
@@ -0,0 +1,504 @@
1
+ # Agent — 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 | `agent` |
10
+ | Source path(s) | `src/services/agent` |
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
+ Agent owns the `routingAgent(AqmReqs)` request factory for station login, station logout, agent-state change, buddy-agent lookup, and agent-session reload. ContactCenter exposes the application-facing methods/events and owns profile/device updates plus recovery policy.
27
+
28
+ The factory initiates authenticated HTTP requests and supplies `CC_EVENTS` success/failure binds to AqmReqs. Public response aliases such as `StationLoginResponse`, `StationLogoutResponse`, `BuddyAgentsResponse`, and `SetStateResponse` are package-level contracts in `src/types.ts`; routing payload/notification types remain in `src/services/agent/types.ts`.
29
+
30
+ ## Purpose / Responsibility
31
+ Own AQM request definitions for station login/logout, state change, buddy-agent queries, and reload. Device/profile update and automated relogin orchestration belong to ContactCenter.
32
+
33
+ ## Stack
34
+ TypeScript 5.4 AQM request factory, REST initiation, WebSocket completion events, Jest 27.
35
+
36
+ ## Folder / Package Structure
37
+ ```text
38
+ src/services/agent/
39
+ ├── index.ts
40
+ ├── types.ts
41
+ ```
42
+
43
+ ```text
44
+ services/agent/
45
+ ├── index.ts # Agent service factory
46
+ ├── types.ts # Agent types and events
47
+ └── ai-docs/
48
+ ├── AGENTS.md # Usage documentation
49
+ └── ARCHITECTURE.md # Preserved legacy migration source (non-canonical)
50
+ ```
51
+
52
+ ## Key Files (source of truth)
53
+ | File | Holds |
54
+ |---|---|
55
+ | `src/services/agent/index.ts` | Authoritative Agent implementation or contract source. |
56
+ | `src/services/agent/types.ts` | Authoritative Agent implementation or contract source. |
57
+ | `src/cc.ts` | Authoritative Agent implementation or contract source. |
58
+
59
+ ## Public Surface
60
+ | Contract | Owner | Real surface | Source |
61
+ |---|---|---|---|
62
+ | `routingAgent` | Agent | exported factory `(routing: AqmReqs) => {reload, logout, stationLogin, stateChange, buddyAgents}` | `src/services/agent/index.ts`, `src/index.ts` |
63
+ | ContactCenter agent methods | Contact Center | `stationLogin`, `stationLogout`, `setAgentState`, `getBuddyAgents` | `src/cc.ts`, `src/types.ts` |
64
+ | Profile/device update | Contact Center | `updateAgentProfile(AgentProfileUpdate)`; not a routingAgent method | `src/cc.ts`, `src/types.ts` |
65
+ | Automated relogin | Contact Center | private `silentRelogin()` invokes `services.agent.reload()` | `src/cc.ts` |
66
+ | Routing notification types | Agent | `Logout`, `StateChange`, `StationLoginSuccess`, `BuddyAgentsSuccess`, `ReloginSuccess`, and related contracts | `src/services/agent/types.ts` |
67
+ | Public response aliases | Package | `StationLoginResponse`, `StationLogoutResponse`, `BuddyAgentsResponse`, `SetStateResponse`, `UpdateDeviceTypeResponse` | `src/types.ts`, `src/index.ts` |
68
+
69
+ Key nested WebSocket binds use the actual outer/data constants, for example `CC_EVENTS.AGENT_STATION_LOGIN` with `data.type = CC_EVENTS.AGENT_STATION_LOGIN_SUCCESS` or `CC_EVENTS.AGENT_STATION_LOGIN_FAILED`. See root `CONTRACTS.md` for the package export index.
70
+
71
+ ## Requires (dependencies)
72
+ - AqmReqs and WCC API gateway
73
+ - Correlated WebSocket success/failure notifications
74
+ - Registered ContactCenter profile and connection state
75
+
76
+ - Requires `cc.register()` to be called first
77
+
78
+ - Agent profile must be fetched before login
79
+
80
+ - WebRTC (BROWSER option) requires mercury connection
81
+
82
+ ## Requirements
83
+ | ID | WHAT | WHY | Source Evidence | Test / Example Evidence | Assumptions / Gaps | Confidence |
84
+ |---|---|---|---|---|---|---|
85
+ | AGENT-R-001 | routingAgent station login/logout must use the documented WCC endpoints and settle on their nested `CC_EVENTS` success/failure notifications. | The backend operation is asynchronous and HTTP acknowledgement is not final agent state. | `src/services/agent/index.ts` | `test/unit/spec/services/agent/index.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
86
+ | AGENT-R-002 | State change must use PUT `/v1/agents/session/state` and preserve typed success/failure binds. | Agent availability drives routing eligibility and must not be inferred from request acknowledgement. | `src/services/agent/index.ts` | `test/unit/spec/services/agent/index.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
87
+ | AGENT-R-003 | Buddy-agent lookup must preserve its typed request and correlated response contract. | Consult/transfer selection depends on backend-filtered availability. | `src/services/agent/index.ts` | `test/unit/spec/services/agent/index.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
88
+ | AGENT-R-004 | The agent factory exposes `reload`, while ContactCenter alone decides when automated relogin is permitted. | Transport recovery lacks the profile/policy context required to mutate an agent session safely. | `src/cc.ts` | `test/unit/spec/cc.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
89
+ | AGENT-R-005 | Device/profile update must be documented as `ContactCenter.updateAgentProfile`, not as an agent-factory method. | Calling a non-existent `routingAgent.deviceUpdate` would fail at runtime. | `src/cc.ts` | `test/unit/spec/cc.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
90
+
91
+ ## Design Overview
92
+ `routingAgent` is a pure AQM factory. It receives an initialized AqmReqs instance and returns five request functions: `reload`, `logout`, `stationLogin`, `stateChange`, and `buddyAgents`. Each request config declares the endpoint/payload plus exact `CC_EVENTS` notification binds.
93
+
94
+ ContactCenter validates and enriches public inputs, starts metrics, delegates to the factory, performs browser-calling work when required, and maps backend notifications to application-facing events. `updateAgentProfile()` and private `silentRelogin()` are ContactCenter methods; the latter calls `services.agent.reload()` only after package-level recovery policy permits it.
95
+
96
+ ## Data Flow
97
+ ```mermaid
98
+ flowchart LR
99
+ App[Application] --> CC[ContactCenter public method]
100
+ CC --> Validate[Validate/enrich profile input]
101
+ Validate --> Factory[routingAgent request function]
102
+ Factory --> AQM[AqmReqs]
103
+ AQM --> HTTP[Authenticated WCC HTTP]
104
+ HTTP --> Ack[Acknowledgement]
105
+ AQM --> WS[Await matching CC_EVENTS notification]
106
+ WS -->|success| Result[Typed result to ContactCenter]
107
+ WS -->|failure/timeout| Error[Structured rejection]
108
+ Result --> AppEvent[Return result / emit application event]
109
+ ```
110
+
111
+ Recovery is separate: ConnectionService emits state → ContactCenter evaluates `allowAutomatedRelogin` → ContactCenter calls private `silentRelogin()` → `services.agent.reload()` uses the agent factory.
112
+
113
+ ### Station-login orchestration detail
114
+
115
+ ```mermaid
116
+ flowchart TD
117
+ A[cc.stationLogin] --> B[Validate dial number for AGENT_DN]
118
+ B --> C[services.agent.stationLogin]
119
+ C --> D[AqmReqs.req]
120
+ D --> E[HTTP REST request to backend]
121
+ E --> F[Backend processes]
122
+ F --> G{Success?}
123
+ G -->|Yes| H[StationLoginSuccess event]
124
+ G -->|No| I[StationLoginFailed event]
125
+ H --> J[Register WebCalling if BROWSER]
126
+ J --> K[Track metrics]
127
+ K --> L[Return response]
128
+ I --> M[getErrorDetails]
129
+ M --> N[Throw error]
130
+ ```
131
+
132
+ ### WebSocket-to-application event mapping
133
+
134
+ ```mermaid
135
+ flowchart LR
136
+ A[WebSocket Message] --> B[WebSocketManager]
137
+ B --> C[cc.handleWebsocketMessage]
138
+ C --> D{Event Type?}
139
+ D -->|AGENT_STATE_CHANGE| E[emit agent:stateChange]
140
+ D -->|data.type check| F{Nested Type?}
141
+ F -->|STATION_LOGIN_SUCCESS| G[Transform channelsMap]
142
+ G --> H[emit agent:stationLoginSuccess]
143
+ F -->|LOGOUT_SUCCESS| I[emit agent:logoutSuccess]
144
+ ```
145
+
146
+ ### Silent-relogin decision flow
147
+
148
+ ```mermaid
149
+ flowchart TD
150
+ A[WebSocket Reconnected] --> B[handleConnectionLost]
151
+ B --> C{allowAutomatedRelogin?}
152
+ C -->|Yes| D[silentRelogin]
153
+ C -->|No| M[Retain reported connection state]
154
+ D --> E[services.agent.reload]
155
+ E --> F{Success?}
156
+ F -->|Yes| G[Update agentConfig and device state]
157
+ G --> H{lastStateChangeReason?}
158
+ H -->|agent-wss-disconnect| I[setAgentState Available]
159
+ H -->|Other| J[Keep backend state]
160
+ F -->|No, AGENT_NOT_FOUND| K[Handle silently]
161
+ F -->|No, Other| L[Throw detailed error]
162
+ ```
163
+
164
+ ## Sequence Diagram(s)
165
+ Sequence coverage:
166
+
167
+ | Operation group | Diagram | Failure / recovery coverage |
168
+ |---|---|---|
169
+ | Station login | Station login | Validation, nested failure notification, HTTP rejection, and timeout throw. |
170
+ | Station logout | Station logout | Nested failure/timeout rejects and calling deregistration occurs only after success. |
171
+ | State change | State change | PUT failure notification/timeout returns a structured rejection. |
172
+ | Buddy agents | Buddy-agent lookup | Correlated retrieval failure/timeout rejects. |
173
+ | Reload | Recovery reload | ContactCenter gates reload; relogin failure or disabled policy preserves failure state. |
174
+
175
+ ### Station login
176
+
177
+ ```mermaid
178
+ sequenceDiagram
179
+ participant App
180
+ participant CC as ContactCenter
181
+ participant Svc as Services.agent
182
+ participant AQM as AqmReqs
183
+ participant WS as WebSocket
184
+ participant BE as Backend
185
+ App->>CC: stationLogin(params)
186
+ CC->>CC: Validate dial number
187
+ CC->>CC: timeEvent(LOGIN_SUCCESS, LOGIN_FAILED)
188
+ CC->>Svc: stationLogin({data})
189
+ Svc->>AQM: req(config)
190
+ AQM->>BE: HTTP POST /v1/agents/login
191
+ alt nested success
192
+ BE-->>WS: AgentStationLoginSuccess
193
+ WS-->>AQM: matching success notification
194
+ AQM-->>Svc: StationLoginSuccess
195
+ Svc-->>CC: login response
196
+ CC->>CC: Register WebCalling if BROWSER and enabled
197
+ CC->>CC: trackEvent(LOGIN_SUCCESS)
198
+ CC-->>App: StationLoginResponse
199
+ else nested failure, HTTP rejection, or timeout
200
+ WS-->>AQM: failure notification or no completion
201
+ AQM-->>CC: structured rejection
202
+ CC->>CC: trackEvent(LOGIN_FAILED)
203
+ CC-->>App: throw detailed error
204
+ end
205
+ ```
206
+
207
+ ### Station logout
208
+
209
+ ```mermaid
210
+ sequenceDiagram
211
+ participant App
212
+ participant CC as ContactCenter
213
+ participant Agent as routingAgent
214
+ participant AQM as AqmReqs
215
+ participant WS as Primary WebSocket
216
+ App->>CC: stationLogout({logoutReason})
217
+ CC->>Agent: logout({data})
218
+ Agent->>AQM: POST /v1/agents/logout + nested binds
219
+ alt AGENT_LOGOUT_SUCCESS
220
+ WS-->>AQM: matching nested success
221
+ AQM-->>CC: LogoutSuccess
222
+ CC->>CC: track success; deregister WebCalling line
223
+ CC-->>App: StationLogoutResponse
224
+ else failure, HTTP rejection, or timeout
225
+ WS-->>AQM: matching failure or no completion
226
+ CC->>CC: track failure
227
+ CC-->>App: throw detailed error
228
+ end
229
+ ```
230
+
231
+ ### State change
232
+
233
+ ```mermaid
234
+ sequenceDiagram
235
+ participant App
236
+ participant CC as ContactCenter
237
+ participant Agent as routingAgent
238
+ participant AQM as AqmReqs
239
+ participant WS as Primary WebSocket
240
+ App->>CC: setAgentState(data)
241
+ CC->>Agent: stateChange({data + agentId})
242
+ Agent->>AQM: PUT /v1/agents/session/state + binds
243
+ alt AGENT_STATE_CHANGE_SUCCESS
244
+ WS-->>AQM: matching nested success
245
+ AQM-->>CC: StateChangeSuccess
246
+ CC-->>App: SetStateResponse
247
+ else failure, HTTP rejection, or timeout
248
+ WS-->>AQM: matching failure or no completion
249
+ AQM-->>CC: structured rejection
250
+ CC-->>App: throw detailed error
251
+ end
252
+ ```
253
+
254
+ ### Buddy-agent lookup
255
+
256
+ ```mermaid
257
+ sequenceDiagram
258
+ participant App
259
+ participant CC as ContactCenter
260
+ participant Agent as routingAgent
261
+ participant AQM as AqmReqs
262
+ participant WS as Primary WebSocket
263
+ App->>CC: getBuddyAgents(query)
264
+ CC->>Agent: buddyAgents({data})
265
+ Agent->>AQM: POST /v1/agents/buddyList + binds
266
+ alt AGENT_BUDDY_AGENTS_SUCCESS
267
+ WS-->>AQM: matching nested success
268
+ AQM-->>App: BuddyAgentsResponse
269
+ else retrieve failure or timeout
270
+ WS-->>AQM: matching failure or no completion
271
+ AQM-->>App: structured rejection
272
+ end
273
+ ```
274
+
275
+ ### Recovery reload
276
+
277
+ ```mermaid
278
+ sequenceDiagram
279
+ participant CS as ConnectionService
280
+ participant CC as ContactCenter
281
+ participant Agent as routingAgent
282
+ CS-->>CC: connectionLost(details)
283
+ alt automated relogin allowed
284
+ CC->>CC: silentRelogin()
285
+ CC->>Agent: reload()
286
+ Agent-->>CC: relogin result/failure
287
+ else not allowed
288
+ CC->>CC: retain reported state
289
+ end
290
+ ```
291
+
292
+ ## Class / Component Relationships
293
+ ```mermaid
294
+ classDiagram
295
+ class ContactCenter
296
+ class routingAgent
297
+ class AqmReqs
298
+ class WebSocketManager
299
+ ContactCenter --> routingAgent : public agent operations / reload
300
+ routingAgent --> AqmReqs : request factories
301
+ AqmReqs --> WebSocketManager : correlated notifications
302
+ ContactCenter --> ContactCenter : updateAgentProfile + silentRelogin ownership
303
+ ```
304
+
305
+ ## Use Cases
306
+ - **UC-1 Station login/logout:** validate public input in ContactCenter, initiate through routingAgent, settle from nested WebSocket notification. Evidence: `src/cc.ts`, `src/services/agent/index.ts`, `test/unit/spec/services/agent/index.ts`.
307
+ - **UC-2 State change:** PUT the state payload and return the correlated typed response. Evidence: `src/services/agent/index.ts`, `test/unit/spec/services/agent/index.ts`.
308
+ - **UC-3 Buddy-agent query:** retrieve backend-filtered candidates for consult/transfer. Evidence: `src/services/agent/index.ts`, `test/unit/spec/services/agent/index.ts`.
309
+ - **UC-4 Recovery reload:** ContactCenter decides whether to invoke private relogin and the factory's `reload`. Evidence: `src/cc.ts`, `test/unit/spec/cc.ts`.
310
+ - **UC-5 Device/profile update:** ContactCenter owns `updateAgentProfile`; the agent factory has no device-update method. Evidence: `src/cc.ts`, `test/unit/spec/cc.ts`.
311
+
312
+ ## Business Rules & Invariants
313
+ - Agent must preserve its typed public/event contracts and must not invent backend states or responses. Enforced in `src/services/agent/index.ts`.
314
+
315
+ Change agent state (Available/Idle).
316
+
317
+ **Parameters**:
318
+
319
+ - `state` ('Available' | 'Idle'): New state
320
+
321
+ - `auxCodeId` (string): Auxiliary code ID
322
+
323
+ - `lastStateChangeReason` (string, optional): Reason for change
324
+
325
+ - `agentId` (string, optional): Agent ID (defaults to current agent)
326
+
327
+ **Returns**: `Promise<SetStateResponse>`
328
+
329
+ **Example**:
330
+
331
+ ```typescript
332
+ // Go Available
333
+ await cc.setAgentState({
334
+ state: 'Available',
335
+ auxCodeId: '0',
336
+ });
337
+
338
+ // Go to Idle with specific code
339
+ await cc.setAgentState({
340
+ state: 'Idle',
341
+ auxCodeId: 'break-code-123',
342
+ lastStateChangeReason: 'Coffee break',
343
+ });
344
+ ```
345
+
346
+ The `AgentState` type (`'Available' | 'Idle' | 'RONA' | string`) is extensible -- the `string` union member allows backend-defined states beyond the known values listed below.
347
+
348
+ | State | SubStatus | Description |
349
+ |---|---|---|
350
+ | LoggedIn | Available | Ready to receive tasks |
351
+ | LoggedIn | Idle | On break or not ready (uses aux code for sub-reason) |
352
+ | RONA | - | Rang but no answer; agent failed to accept offered task |
353
+ | LoggedOut | - | Not logged in |
354
+ | LoggedIn | *(custom)* | Additional org-specific states defined via aux codes |
355
+
356
+ > **Note**: `AgentState` is a union with `string`, so consumers should handle unknown state values gracefully rather than exhaustively matching only the known literals.
357
+
358
+ ## Concurrency & Reactive Flow
359
+ - Async operations must remain non-blocking; listener/queue/actor ordering and cleanup rules in the preserved source content are contractual.
360
+
361
+ ## Protocol / Wire Format
362
+ - Request, response, and event payload ownership is anchored in `src/services/agent/index.ts`. HTTP initiates backend work where applicable; WebSocket messages provide realtime events and, for AQM flows, correlated completion.
363
+
364
+ For example, station login defines the real outer and nested event binds:
365
+
366
+ ```typescript
367
+ {
368
+ url: '/v1/agents/login',
369
+ host: WCC_API_GATEWAY,
370
+ data: p.data,
371
+ err: (e) => new Err.Details('Service.aqm.agent.stationLogin', {/* response fields */}),
372
+ notifSuccess: {
373
+ bind: {
374
+ type: CC_EVENTS.AGENT_STATION_LOGIN,
375
+ data: {type: CC_EVENTS.AGENT_STATION_LOGIN_SUCCESS},
376
+ },
377
+ msg: {} as Agent.StationLoginSuccess,
378
+ },
379
+ notifFail: {
380
+ bind: {
381
+ type: CC_EVENTS.AGENT_STATION_LOGIN,
382
+ data: {type: CC_EVENTS.AGENT_STATION_LOGIN_FAILED},
383
+ },
384
+ errId: 'Service.aqm.agent.stationLoginFailed',
385
+ },
386
+ }
387
+ ```
388
+
389
+ ## Error Handling & Failure Modes
390
+ | Condition | Signal (error/code/result) | Caller recovery |
391
+ |---|---|---|
392
+ | Dependency rejection | Typed/rethrown error or failure event | Inspect structured details, preserve tracking id, and retry only when the operation is safe. |
393
+ | Timeout or missing async completion | Timeout/recovery state | Follow the module-specific recovery path; never synthesize success. |
394
+
395
+ > **Host-application example:** `showStationLoginError` represents consumer-owned UI handling. SDK package implementation must use `LoggerProxy` and must not log raw runtime values.
396
+
397
+ ```typescript
398
+ try {
399
+ await cc.stationLogin(params);
400
+ } catch (error) {
401
+ showStationLoginError({
402
+ message: error.message,
403
+ fieldName: error.data?.fieldName,
404
+ fieldMessage: error.data?.message,
405
+ });
406
+ }
407
+ ```
408
+
409
+ | Reason | Description |
410
+ |---|---|
411
+ | `DUPLICATE_LOCATION` | Extension/DN already in use |
412
+ | `INVALID_DIAL_NUMBER` | Invalid phone number format |
413
+ | `AGENT_NOT_FOUND` | Agent doesn't exist (silent relogin) |
414
+
415
+ For `stationLogin`, special error handling extracts field-specific messages:
416
+
417
+ ```typescript
418
+ // src/services/core/Utils.ts - getStationLoginErrorData
419
+ const errorCodeMessageMap = {
420
+ DUPLICATE_LOCATION: {
421
+ message: 'This extension is already in use',
422
+ fieldName: loginOption,
423
+ },
424
+ INVALID_DIAL_NUMBER: {
425
+ message: 'Enter a valid US dial number...',
426
+ fieldName: loginOption,
427
+ },
428
+ };
429
+ ```
430
+
431
+ **Cause**: Extension/DN already in use by another session
432
+
433
+ **Solution**:
434
+
435
+ 1. Logout from other session
436
+
437
+ 2. Use different extension
438
+
439
+ 3. Contact admin if stuck
440
+
441
+ **Cause**: Agent may be in a call or transitioning state
442
+
443
+ **Solution**:
444
+
445
+ 1. Complete current interaction
446
+
447
+ 2. Wait for state to stabilize
448
+
449
+ 3. Retry state change
450
+
451
+ **Cause**: `allowAutomatedRelogin` config not set
452
+
453
+ **Solution**:
454
+
455
+ ```typescript
456
+ const webex = Webex.init({
457
+ config: {
458
+ cc: {
459
+ allowAutomatedRelogin: true,
460
+ },
461
+ },
462
+ });
463
+ ```
464
+
465
+ ## Pitfalls
466
+ - Station login/logout and state-change binds match both the outer event type and nested `data.type`; flattening either bind can settle the wrong request.
467
+ - `routingAgent` has exactly five request functions and no `deviceUpdate`; profile/device changes belong to ContactCenter.
468
+ - ConnectionService reports transport state, but ContactCenter alone decides whether `silentRelogin()` is allowed and whether `AGENT_NOT_FOUND` is handled silently.
469
+
470
+ ## Module Do's / Don'ts
471
+ - DO keep HTTP endpoint/method and WebSocket success/failure binds in the same routing factory definition.
472
+ - DO keep browser-calling registration/deregistration in ContactCenter around successful station operations.
473
+ - DON'T resolve an agent operation from HTTP acknowledgement.
474
+ - DON'T move automated relogin policy into the agent factory or ConnectionService.
475
+
476
+ ## Key Design Trade-off
477
+ - HTTP initiates each operation while the correlated WebSocket notification is the completion signal, matching backend semantics at the cost of timeout/correlation complexity.
478
+
479
+ ## Test-Case Strategy (module)
480
+ Use `test/unit/spec/services/agent/index.ts` for factory endpoint/bind/payload contracts and `test/unit/spec/cc.ts` for public validation, metrics, calling, updateAgentProfile, and recovery ownership. Cover success, nested failure, HTTP rejection, and timeout without inventing a `deviceUpdate` factory method.
481
+
482
+ | Behavior / Requirement | Existing test evidence | Gap |
483
+ |---|---|---|
484
+ | `AGENT-R-001` | `test/unit/spec/services/agent/index.ts`, `test/unit/spec/cc.ts` | None. |
485
+ | `AGENT-R-002` | `test/unit/spec/services/agent/index.ts`, `test/unit/spec/cc.ts` | None. |
486
+ | `AGENT-R-003` | `test/unit/spec/services/agent/index.ts` | None. |
487
+ | `AGENT-R-004` | `test/unit/spec/cc.ts` | None. |
488
+ | `AGENT-R-005` | `test/unit/spec/cc.ts` | Keep a negative assertion that `routingAgent.deviceUpdate` is absent. |
489
+
490
+ ## Traceability
491
+ - Repo architecture: `../../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../../ai-docs/SPEC_INDEX.md`
492
+ - Coverage state and contracts baseline: `../../../../.sdd/manifest.json`
493
+
494
+ - [`cc.ts`](../../../cc.ts) - Main plugin implementation
495
+
496
+ - [`types.ts`](../types.ts) - Type definitions
497
+
498
+ - [cc.ts](../../../cc.ts) - Main plugin
499
+
500
+ - [agent/index.ts](../index.ts) - Service implementation
501
+
502
+ - [agent/types.ts](../types.ts) - Type definitions
503
+
504
+ - [cc.ts test](../../../../test/unit/spec/cc.ts) - Test file
@@ -1,6 +1,8 @@
1
1
  # Services Layer - AI Agent Guide
2
2
 
3
- > **Scope Authority**: This is the authoritative documentation for the **Services** orchestration layer. It describes how all service modules are composed, instantiated, and how they interact. For task routing, critical rules, and code generation workflows, see the [root orchestrator AGENTS.md](../../../AGENTS.md).
3
+ > **Legacy/reference-only.** Canonical SDD: [`services-spec.md`](services-spec.md). Use the package [manifest](../../../.sdd/manifest.json) and [`SPEC_INDEX.md`](../../../ai-docs/SPEC_INDEX.md) for routing; code and tests remain the behavioral referee.
4
+ >
5
+ > **Legacy scope:** This guide describes how service modules were documented before canonical SDD routing. For repository rules, see the [root orchestrator AGENTS.md](../../../AGENTS.md).
4
6
 
5
7
  ---
6
8
 
@@ -377,7 +379,7 @@ CC Backend
377
379
 
378
380
  ## Related
379
381
 
380
- - [Root orchestrator AGENTS.md](../../../AGENTS.md) — task classification, critical rules, templates
382
+ - [Root orchestrator AGENTS.md](../../../AGENTS.md) — repository rules; use [`SPEC_INDEX.md`](../../../ai-docs/SPEC_INDEX.md) for canonical module routing
381
383
  - [ai-docs/RULES.md](../../../ai-docs/RULES.md) — coding standards
382
384
  - [ai-docs/patterns/](../../../ai-docs/patterns/) — TypeScript, testing, and event patterns
383
385
  - [types.ts](../../types.ts) — public type definitions