@xema/omni-protocol 0.1.98 → 0.1.100

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/dist/index.d.ts CHANGED
@@ -106,7 +106,7 @@ export type DialOutcome = "answered" | "busy" | "no-answer" | "unreachable" | "r
106
106
  export declare const DIAL_OUTCOMES: readonly ["answered", "busy", "no-answer", "unreachable", "rejected", "cancelled", "unexplained"];
107
107
  /**
108
108
  * How the agent hears the call: on a `softphone`, where the host owns the audio and opens it
109
- * through `openMedia`, or on a `deskPhone`, a handset the platform rings, where the host opens
109
+ * through `openAudio`, or on a `deskPhone`, a handset the platform rings, where the host opens
110
110
  * nothing and only shows the call. A voice manifest lists the phones its platform supports, and
111
111
  * the host picks one for the login at authentication.
112
112
  */
@@ -232,25 +232,6 @@ export interface AuthenticationFailure {
232
232
  /** Names a declared credentials field when the failure belongs to one. */
233
233
  field?: string;
234
234
  }
235
- /** What a lead may do with their team. Declared by presence. */
236
- export interface TeamCapabilities {
237
- /**
238
- * This lead may act on their team's breaks through `executeTeamBreak` -- force-break, end-forced-break, decide-break-request,
239
- * set-break-policy -- as far as the provider supports; a command it lacks answers
240
- * `omni.capability-not-enabled`. Requires `executeTeamBreak`.
241
- */
242
- breakControl?: true;
243
- /** This lead may join a member's call on request. Requires `executeTeamLeadAssist`. */
244
- leadAssistControl?: true;
245
- /**
246
- * This lead may listen to a member's call unasked, in these modes and no others. Coach and
247
- * join-call begin with silent listening, so the list always includes `listen`. Nothing of it reaches the
248
- * member's task. Requires `executeTeamListen`.
249
- */
250
- listeningControl?: ListeningMode[];
251
- /** This lead sets the team's policy per capability -- on, off, or the agent's -- within what the queue allows. Requires `executeTeamPolicy`. */
252
- policyControl?: true;
253
- }
254
235
  /**
255
236
  * How a lead listening to a member's call is heard: `listen` hears both sides in silence,
256
237
  * `coach` is heard by the agent alone, `join-call` by everyone on the call.
@@ -267,8 +248,14 @@ export interface UserCapabilities {
267
248
  breaks?: true;
268
249
  /** The choices the team left to this person, with where each stands. Omitted when there are none. Requires `setPreference`. */
269
250
  preferences?: AgentPreference[];
270
- /** This login leads a team: a `TeamMembers` object is published to it on every snapshot, including `members: []`. */
271
- team?: TeamCapabilities;
251
+ /**
252
+ * This login leads a team. The flag alone turns on the team feature in the agent application:
253
+ * the lead sees their members with their tasks and stats, and acts on them through `executeTeam`
254
+ * with the authority the flag carries. No per-action permission rides beside it. While the lead
255
+ * has the feature on, a `TeamMembers` object is published to them on every snapshot, `members: []`
256
+ * included; to nobody else, ever.
257
+ */
258
+ lead?: true;
272
259
  }
273
260
  /**
274
261
  * Only `authenticated` and `refreshing` know who the agent is and what they may do, and only
@@ -446,7 +433,7 @@ export interface RecordingActions {
446
433
  export interface TaskRecordingPolicy {
447
434
  provider?: RecordingActions;
448
435
  host?: RecordingActions & {
449
- destinationId: string;
436
+ storageId: string;
450
437
  };
451
438
  }
452
439
  /** Current evidence only. Expiry/disconnect means unknown, never a historical stop. */
@@ -491,7 +478,7 @@ export interface HostRecording {
491
478
  announcesToCaller?: true;
492
479
  actions: RecordingAction[];
493
480
  /** Explicitly provisioned destinations. A task chooses one; no upload/storage fallback. */
494
- destinationIds: string[];
481
+ storageIds: string[];
495
482
  execute(request: HostRecordingRequest): Promise<RecordingCommandResult>;
496
483
  }
497
484
  /** Recording applies or fails; it never dials. Rejection without result means unknown. */
@@ -668,6 +655,7 @@ export type TaskCapabilities<C extends Channel = Channel> = C extends "voice" ?
668
655
  hold?: Lockable<true>;
669
656
  /** The provider ends the caller connection and agent-added channels owned by this interaction, including inherited channels after transfer/takeover. Interaction completion remains separate. */
670
657
  endCall?: Lockable<true>;
658
+ terminateCall?: Lockable<true>;
671
659
  /** Connect back to the party while `completing`, whoever placed the call; the task returns to `in-progress`. */
672
660
  connectBack?: Lockable<true>;
673
661
  coldTransfer?: Lockable<DestinationDirectory>;
@@ -741,9 +729,9 @@ export type TaskPhase =
741
729
  /** What the system does when a preview's deadline passes with no Call pressed. */
742
730
  export type PreviewDeadline =
743
731
  /** Provider initiates dialing when preparation ends; never a host timer command. */
744
- "calls"
732
+ "provider-dials"
745
733
  /** Host initiates the ordinary call command when preparation ends. */
746
- | "host-calls"
734
+ | "host-dials"
747
735
  /** Preparation target has elapsed; remain in preview until the agent presses Call. */
748
736
  | "waits";
749
737
  /** Who ends the task: the agent issuing `complete`, or the provider deciding it is over. */
@@ -875,27 +863,13 @@ export type TaskLeadAssist = {
875
863
  leadId: UserId;
876
864
  });
877
865
  /**
878
- * On the lead's own task for a call they joined: which member asked, with their note. Its
879
- * presence is what makes `lead-assist` `take-over-call` and `leave` issuable.
866
+ * On a task that reached this agent by a lead's take-over: which member the call was taken from,
867
+ * and when. The provider moves the call from one agent to another, and the lead is the new agent,
868
+ * so the task is an ordinary assignment with the call's history -- offered whatever break the lead
869
+ * is on, counted against no capacity, provided their voice channel is free.
880
870
  */
881
- export interface TaskAssisting {
871
+ export interface TaskTakenOver {
882
872
  memberId: UserId;
883
- /** The member's assignment the lead joined: the lead's task has an assignment of its own. */
884
- assignmentId: AssignmentId;
885
- note?: string;
886
- since: IsoTimestamp;
887
- }
888
- /**
889
- * On the lead's own task while they listen to a member's call: whose call, which call, and how the
890
- * lead is heard, restated on every change of mode. Nothing of it reaches the member's task. There
891
- * is no take-over here; a lead who wants the call uses lead assist. It is the lead's only task:
892
- * a lead listens while holding no work of their own, idle or on a break of a kind in
893
- * `LISTENING_BREAK_KINDS`.
894
- */
895
- export interface TaskListening {
896
- memberId: UserId;
897
- assignmentId: AssignmentId;
898
- mode: ListeningMode;
899
873
  since: IsoTimestamp;
900
874
  }
901
875
  /**
@@ -943,12 +917,12 @@ export interface Locked {
943
917
  */
944
918
  export type Lockable<T> = T | Locked;
945
919
  /**
946
- * Who chose a task's capabilities. `undetermined` is a fault the provider states on the task rather
920
+ * Who chose a task's capabilities. `not-yet-read` is a fault the provider states on the task rather
947
921
  * than hides: the platform's terms could not be read, and the set published is what the provider
948
922
  * will honour, not what the platform permits.
949
923
  */
950
- export type CapabilitySource = "queue" | "ungoverned" | "undetermined";
951
- export declare const CAPABILITY_SOURCES: readonly ["queue", "ungoverned", "undetermined"];
924
+ export type CapabilitySource = "queue" | "nobody" | "not-yet-read";
925
+ export declare const CAPABILITY_SOURCES: readonly ["queue", "nobody", "not-yet-read"];
952
926
  export type Task<C extends Channel = Channel> = {
953
927
  /** The assignment this task is the record of, and its one identity. See `AssignmentId`. */
954
928
  assignmentId: AssignmentId;
@@ -959,8 +933,8 @@ export type Task<C extends Channel = Channel> = {
959
933
  capabilities: TaskCapabilities<C>;
960
934
  /**
961
935
  * Where the capabilities came from before the provider put them on the task, so a host can tell
962
- * a fact from a fault: `queue` when somebody chose these terms, `ungoverned` when nothing handed
963
- * the work over, `undetermined` when a queue was named and its terms could not be read -- the
936
+ * a fact from a fault: `queue` when somebody chose these terms, `nobody` when nothing handed
937
+ * the work over, `not-yet-read` when a queue was named and its terms could not be read -- the
964
938
  * provider then publishes what it will honour and says so here, where the controls are drawn.
965
939
  */
966
940
  capabilitySource: CapabilitySource;
@@ -979,7 +953,7 @@ export type Task<C extends Channel = Channel> = {
979
953
  acceptance?: AcceptanceMode;
980
954
  /**
981
955
  * In `preview` only, and together: the preparation target and behavior when it elapses,
982
- * and who acts then -- `calls` makes the provider initiate dialing, `host-calls` makes the
956
+ * and who acts then -- `provider-dials` makes the provider initiate dialing, `host-dials` makes the
983
957
  * host issue Call, and `waits` keeps waiting for the agent without dialing or ending the task.
984
958
  * Absent, the agent has as long as they need, without a preparation countdown.
985
959
  */
@@ -995,16 +969,14 @@ export type Task<C extends Channel = Channel> = {
995
969
  };
996
970
  onCall?: OnCall[];
997
971
  leadAssist?: TaskLeadAssist;
998
- assisting?: TaskAssisting;
999
- listening?: TaskListening;
1000
- media?: TaskMediaState;
972
+ takenOver?: TaskTakenOver;
973
+ audio?: TaskAudioState;
1001
974
  } : {
1002
975
  recording?: never;
1003
976
  onCall?: never;
1004
977
  leadAssist?: never;
1005
- assisting?: never;
1006
- listening?: never;
1007
- media?: never;
978
+ takenOver?: never;
979
+ audio?: never;
1008
980
  });
1009
981
  /**
1010
982
  * What the provider wants of Omni's acceptance policy for one offer. On routed work, present only
@@ -1022,7 +994,7 @@ export type TaskOutcome = {
1022
994
  type: "transferred";
1023
995
  destinationId?: string;
1024
996
  }
1025
- /** A lead took the call over: the agent's task ends and the lead's continues. Named by the lead, since a lead is not a directory item. */
997
+ /** A lead took the call over and the agent has wrapped it: the outcome at the agent's own completion. Named by the lead, since a lead is not a directory item. */
1026
998
  | {
1027
999
  type: "taken-over";
1028
1000
  leadId: UserId;
@@ -1037,16 +1009,12 @@ export type TaskOutcome = {
1037
1009
  | {
1038
1010
  type: "expired";
1039
1011
  phase: "pending" | "confirmed" | "preview";
1040
- }
1041
- /** This agent left a call that continues without them: a lead who joined and dropped. */
1042
- | {
1043
- type: "left";
1044
1012
  } | {
1045
1013
  type: "failed";
1046
1014
  failure: ProtocolFailure;
1047
1015
  };
1048
1016
  export declare const TASK_COMMAND_NAMES: {
1049
- readonly voice: readonly ["answer", "decline", "call", "hold", "resume", "end-call", "connect-back", "transfer", "lead-assist", "conference", "recording", "complete"];
1017
+ readonly voice: readonly ["answer", "decline", "dial", "hold", "resume", "end-call", "terminate-call", "connect-back", "transfer", "lead-assist", "conference", "recording", "complete"];
1050
1018
  readonly chat: readonly ["accept", "decline", "pause", "resume", "complete"];
1051
1019
  readonly email: readonly ["accept", "decline", "complete"];
1052
1020
  };
@@ -1062,17 +1030,21 @@ export type VoiceTaskCommand = {
1062
1030
  }
1063
1031
  /** In `preview`: place the call to the party whose record the agent has read. A dial, gated by the phase alone. */
1064
1032
  | {
1065
- type: "call";
1033
+ type: "dial";
1066
1034
  dialId: DialId;
1067
1035
  } | {
1068
1036
  type: "hold";
1069
1037
  } | {
1070
1038
  type: "resume";
1071
1039
  }
1072
- /** End the caller connection and all agent-added channels owned or inherited by this interaction. Wrap/completion remain separate. Gated by `endCall`. */
1040
+ /** End the agent's channel and every channel the agent added; the caller continues on the provider's path. Gated by `endCall`. */
1073
1041
  | {
1074
1042
  type: "end-call";
1075
1043
  }
1044
+ /** End the caller channel. Gated by `terminateCall`. */
1045
+ | {
1046
+ type: "terminate-call";
1047
+ }
1076
1048
  /** Issuable only in `completing`, under the `connectBack` capability. Dials the party's own number, so it names none. */
1077
1049
  | {
1078
1050
  type: "connect-back";
@@ -1113,16 +1085,6 @@ export type VoiceTaskCommand = {
1113
1085
  type: "lead-assist";
1114
1086
  action: "cancel";
1115
1087
  }
1116
- /** The lead keeps the customer; the agent's task ends `transferred`. Needs `Task.assisting`. */
1117
- | {
1118
- type: "lead-assist";
1119
- action: "take-over-call";
1120
- }
1121
- /** The lead drops; the agent continues. The lead's task ends `left`. Needs `Task.assisting`. */
1122
- | {
1123
- type: "lead-assist";
1124
- action: "leave";
1125
- }
1126
1088
  /** Dial the directory item `destinationId` into the call. Gated by `conference`. */
1127
1089
  | {
1128
1090
  type: "conference";
@@ -1230,12 +1192,6 @@ export declare const BREAK_KINDS: readonly ["short-break", "meal", "rest", "trai
1230
1192
  * problem one level up. `other` matches nothing, including another provider's `other`.
1231
1193
  */
1232
1194
  export type BreakKind = (typeof BREAK_KINDS)[number];
1233
- /**
1234
- * The breaks during which a lead may listen to a member's call: work of another sort, not rest.
1235
- * A listening task is the one task a break in effect may hold, and only on one of these.
1236
- */
1237
- export declare const LISTENING_BREAK_KINDS: readonly ["coaching", "administrative", "training"];
1238
- export declare const breakKindAllowsListening: (kind: BreakKind | undefined) => boolean;
1239
1195
  export interface BreakReason {
1240
1196
  id: string;
1241
1197
  label: string;
@@ -1300,8 +1256,8 @@ export type BreakEndResult = {
1300
1256
  status: "failed";
1301
1257
  failure: ProtocolFailure;
1302
1258
  };
1303
- /** `reserved`: signed in here, and the host holds this agent's capacity for another provider (`count: 0`, host-stopped); not receiving this provider's work. */
1304
- export type TeamMemberAvailability = "ready" | "on-task" | "on-break" | "reserved" | "signed-out";
1259
+ /** `elsewhere`: signed in here, and the host holds this agent's capacity for another provider (`count: 0`, host-stopped); not receiving this provider's work. */
1260
+ export type TeamMemberAvailability = "ready" | "on-task" | "on-break" | "elsewhere" | "signed-out";
1305
1261
  export interface TeamMember {
1306
1262
  id: UserId;
1307
1263
  availability: TeamMemberAvailability;
@@ -1309,24 +1265,65 @@ export interface TeamMember {
1309
1265
  since?: IsoTimestamp;
1310
1266
  /** A request in flight or a grant not yet in effect. `not-requested` is absence, and `on-break` is `availability: "on-break"`. */
1311
1267
  break?: Extract<BreakStatus, "awaiting-approval" | "granted" | "starting-after-task">;
1268
+ /** The member's open tasks, trimmed, kept current by the provider; `[]` when they hold none, omitted only where the provider cannot see them. */
1269
+ tasks?: MemberTask[];
1270
+ /** Present while this lead is on the member's call, listening, coaching or joined; absent otherwise. */
1271
+ listening?: MemberListening;
1312
1272
  }
1313
- /** A member asking this lead to join their call. */
1273
+ /** A member asking this lead to join their call, named by the member and the assignment. */
1314
1274
  export interface LeadRequest {
1315
- id: string;
1316
1275
  memberId: UserId;
1317
1276
  assignmentId: AssignmentId;
1318
1277
  note?: string;
1319
1278
  since: IsoTimestamp;
1320
1279
  }
1321
1280
  /**
1322
- * The login is the permission: published to a login that declares `capabilities.team`, on every
1323
- * snapshot, and to nobody else. What the lead may do with it is on the login too, not here.
1281
+ * A member's task as the lead sees it: the same task the member's desk holds, trimmed by the
1282
+ * provider. The assignment, what the call is and where it stands, the room and the full history
1283
+ * are always here; the workspace -- browsers, controls, completion terms -- is the member's and
1284
+ * travels only if the provider chooses to send it.
1285
+ */
1286
+ export type MemberTask<C extends Channel = Channel> = {
1287
+ assignmentId: AssignmentId;
1288
+ title: string;
1289
+ channel: C;
1290
+ taskType: string;
1291
+ phase: TaskPhase;
1292
+ party?: Contact;
1293
+ reference?: string;
1294
+ attributes?: TaskAttribute[];
1295
+ history?: TaskHistory;
1296
+ capabilities?: TaskCapabilities<C>;
1297
+ capabilitySource?: CapabilitySource;
1298
+ browsers?: TaskBrowser[];
1299
+ completionMode?: CompletionMode;
1300
+ wrapAllowance?: DurationSeconds;
1301
+ } & (C extends "voice" ? {
1302
+ onCall?: OnCall[];
1303
+ leadAssist?: TaskLeadAssist;
1304
+ takenOver?: TaskTakenOver;
1305
+ audio?: TaskAudioState;
1306
+ } : {
1307
+ onCall?: never;
1308
+ leadAssist?: never;
1309
+ takenOver?: never;
1310
+ audio?: never;
1311
+ });
1312
+ /** The lead on this member's call, in the mode they are heard, since when. */
1313
+ export interface MemberListening {
1314
+ mode: ListeningMode;
1315
+ since: IsoTimestamp;
1316
+ }
1317
+ /**
1318
+ * The lead's view of their team: published to a login that declares `capabilities.lead` while the
1319
+ * lead has the team feature on, on every snapshot, and to nobody else. The provider keeps it
1320
+ * current: when a member holds, mutes or is transferred, the list is republished whole.
1324
1321
  */
1325
1322
  export interface TeamMembers {
1326
1323
  members: TeamMember[];
1327
- /** Omitted when the login lacks `team.leadAssistControl`; `[]` when nobody is asking. */
1328
- requests?: LeadRequest[];
1329
- /** The team's policy per capability, as it stands. Present exactly when the login declares `team.policyControl`. */
1324
+ /** Members asking a lead to join their call; `[]` when nobody is asking. */
1325
+ requests: LeadRequest[];
1326
+ /** The team's policy per capability, as it stands. Present where the provider offers policy control; absent where it does not. */
1330
1327
  policies?: TeamPolicies;
1331
1328
  }
1332
1329
  /** A capability a team policy can name: any task control, new call, or a skill by its provider id. */
@@ -1339,42 +1336,57 @@ export interface TeamPolicy extends Resolved {
1339
1336
  }
1340
1337
  export type TeamPolicies = Partial<Record<PolicyKey, TeamPolicy>>;
1341
1338
  export type TeamPolicyCommand = {
1342
- type: "set";
1339
+ type: "set-policy";
1343
1340
  capability: PolicyKey;
1344
1341
  setting: TeamPolicySetting;
1345
1342
  };
1346
- export interface TeamPolicyCommandRequest {
1347
- command: TeamPolicyCommand;
1348
- }
1349
- export type TeamLeadAssistCommand = {
1343
+ /**
1344
+ * The team feature on or off. The lead flag enables it; the lead switches it on the fly, and the
1345
+ * provider needs to know: while it is on, team events scoped to the lead's team arrive and the
1346
+ * lead may act; while it is off, the lead is an ordinary agent and nothing of the team reaches them.
1347
+ */
1348
+ export type TeamFeatureCommand = {
1349
+ type: "lead-features";
1350
+ enabled: boolean;
1351
+ };
1352
+ /**
1353
+ * The lead's acts on a member's call, each naming the member and, where the lead has it, the
1354
+ * member's assignment; the provider resolves the member's current assignment from the member alone.
1355
+ * `join` answers a member's request and `decline` refuses it; `listen` starts unasked, silent,
1356
+ * `coach` is heard by the member alone and `join-call` by everyone; `leave` takes the lead's channel
1357
+ * off the call however it got there; `take-over-call` moves the call to the lead as its new agent,
1358
+ * from a joined call or a listened one alike. One member's call at a time.
1359
+ */
1360
+ export type TeamCallCommand = {
1350
1361
  type: "join";
1351
- requestId: string;
1362
+ memberId: UserId;
1363
+ assignmentId?: AssignmentId;
1352
1364
  } | {
1353
1365
  type: "decline";
1354
- requestId: string;
1366
+ memberId: UserId;
1367
+ assignmentId?: AssignmentId;
1355
1368
  reason?: string;
1356
- };
1357
- export interface TeamLeadAssistCommandRequest {
1358
- command: TeamLeadAssistCommand;
1359
- }
1360
- /**
1361
- * A lead listening to a member's call. `listen` starts one, silent, on a member from the team member list;
1362
- * `coach` and `join-call` change how the standing one is heard; `leave` ends it. One member at a
1363
- * time, and only the modes the login's `listeningControl` lists.
1364
- */
1365
- export type TeamListenCommand = {
1369
+ } | {
1366
1370
  type: "listen";
1367
1371
  memberId: UserId;
1372
+ assignmentId?: AssignmentId;
1368
1373
  } | {
1369
1374
  type: "coach";
1375
+ memberId: UserId;
1376
+ assignmentId?: AssignmentId;
1370
1377
  } | {
1371
1378
  type: "join-call";
1379
+ memberId: UserId;
1380
+ assignmentId?: AssignmentId;
1372
1381
  } | {
1373
1382
  type: "leave";
1383
+ memberId: UserId;
1384
+ assignmentId?: AssignmentId;
1385
+ } | {
1386
+ type: "take-over-call";
1387
+ memberId: UserId;
1388
+ assignmentId?: AssignmentId;
1374
1389
  };
1375
- export interface TeamListenCommandRequest {
1376
- command: TeamListenCommand;
1377
- }
1378
1390
  export type TeamBreakCommand = {
1379
1391
  type: "decide-break-request";
1380
1392
  memberId: UserId;
@@ -1397,34 +1409,36 @@ export type TeamBreakCommand = {
1397
1409
  type: "end-forced-break";
1398
1410
  memberId: UserId;
1399
1411
  };
1412
+ /** Every lead act, as `execute` takes a `TaskCommand`: discriminated by `type`. */
1413
+ export type TeamCommand = TeamFeatureCommand | TeamBreakCommand | TeamCallCommand | TeamPolicyCommand;
1414
+ export interface TeamCommandRequest {
1415
+ command: TeamCommand;
1416
+ }
1400
1417
  export type TeamCommandResult = {
1401
1418
  status: "applied";
1402
1419
  } | {
1403
1420
  status: "failed";
1404
1421
  failure: ProtocolFailure;
1405
1422
  };
1406
- export interface TeamBreakCommandRequest {
1407
- command: TeamBreakCommand;
1408
- }
1409
1423
  /**
1410
1424
  * The task's real-time audio as the provider holds it: `started` while audio should be attached,
1411
1425
  * `ended` once primary interaction's audio ended, and the field omitted while none should be. The
1412
1426
  * provider's word -- a desk attaches and renders audio from it, never from its own senses.
1413
1427
  */
1414
- export type TaskMediaState = "started" | "ended";
1415
- export interface VoiceMediaSession {
1428
+ export type TaskAudioState = "started" | "ended";
1429
+ export interface CallAudio {
1416
1430
  remoteAudio: MediaStream;
1417
1431
  setMuted(muted: boolean): void;
1418
1432
  close(): void;
1419
1433
  }
1420
- export interface OpenMediaRequest {
1434
+ export interface OpenAudioRequest {
1421
1435
  assignmentId: AssignmentId;
1422
1436
  /** The agent's microphone as Omni captured it, `HostReport.audio.input.localAudio`; absent while that input is `unavailable`. */
1423
1437
  localAudio?: MediaStream;
1424
1438
  }
1425
- export type OpenMediaResult = {
1439
+ export type OpenAudioResult = {
1426
1440
  status: "opened";
1427
- session: VoiceMediaSession;
1441
+ audio: CallAudio;
1428
1442
  } | {
1429
1443
  status: "unavailable";
1430
1444
  failure: ProtocolFailure;
@@ -1516,7 +1530,7 @@ export interface Snapshot<C extends Channel = Channel> {
1516
1530
  /** The provider's own count of those tasks, stated rather than inferred: it must equal `tasks.length`, so a blank or unanswered state can never pass as a confirmed empty. */
1517
1531
  taskCount: number;
1518
1532
  contacts?: Contact[];
1519
- scheduledActivities?: ScheduledActivity[];
1533
+ calendar?: ScheduledActivity[];
1520
1534
  team?: TeamMembers;
1521
1535
  }
1522
1536
  /**
@@ -1526,7 +1540,7 @@ export interface Snapshot<C extends Channel = Channel> {
1526
1540
  * tasks against it and needs no new signal when one ends. The agent is one person on several
1527
1541
  * providers, and the host divides their capacity among them: `0` is host-stopped -- the agent's
1528
1542
  * capacity is elsewhere for now, this provider assigns nothing and shows the member as
1529
- * `reserved` -- and is not a break, which is the agent not working at all. The host restates a
1543
+ * `elsewhere` -- and is not a break, which is the agent not working at all. The host restates a
1530
1544
  * count of one or more when this provider has the agent's capacity again.
1531
1545
  */
1532
1546
  export interface AgentCapacity {
@@ -1569,10 +1583,24 @@ export type ProviderEvent<C extends Channel = Channel> = {
1569
1583
  type: "task-updated";
1570
1584
  task: Task<C>;
1571
1585
  } | {
1572
- type: "task-media-started";
1586
+ type: "task-audio-started";
1573
1587
  assignmentId: AssignmentId;
1574
1588
  } | {
1575
- type: "task-media-ended";
1589
+ type: "task-audio-ended";
1590
+ assignmentId: AssignmentId;
1591
+ }
1592
+ /**
1593
+ * The lead's channel is in a member's call -- listening, coaching or joined -- and its audio should
1594
+ * attach: on a softphone the application opens audio on the member's assignment as it does for a
1595
+ * task. Voice, to a login that declares `lead`, never to the member.
1596
+ */
1597
+ | {
1598
+ type: "team-audio-started";
1599
+ memberId: UserId;
1600
+ assignmentId: AssignmentId;
1601
+ } | {
1602
+ type: "team-audio-ended";
1603
+ memberId: UserId;
1576
1604
  assignmentId: AssignmentId;
1577
1605
  } | {
1578
1606
  type: "task-ended";
@@ -1615,7 +1643,7 @@ export type ProviderEvent<C extends Channel = Channel> = {
1615
1643
  contacts: Contact[];
1616
1644
  } | {
1617
1645
  type: "calendar-updated";
1618
- scheduledActivities: ScheduledActivity[];
1646
+ calendar: ScheduledActivity[];
1619
1647
  };
1620
1648
  /**
1621
1649
  * The `Provider` prefix survives here for a mechanical reason rather than a naming one: `Event`
@@ -1687,16 +1715,10 @@ export interface Connection<C extends Channel = Channel> {
1687
1715
  commitBreak?(): Promise<BreakCommitResult>;
1688
1716
  cancelBreak?(): Promise<BreakCancelResult>;
1689
1717
  endBreak?(): Promise<BreakEndResult>;
1690
- /** Required when the login declares `capabilities.team.breakControl`. */
1691
- executeTeamBreak?(request: TeamBreakCommandRequest): Promise<TeamCommandResult>;
1692
- /** Required when the login declares `capabilities.team.leadAssistControl`. */
1693
- executeTeamLeadAssist?(request: TeamLeadAssistCommandRequest): Promise<TeamCommandResult>;
1694
- /** Required when the login declares `capabilities.team.listeningControl`. */
1695
- executeTeamListen?(request: TeamListenCommandRequest): Promise<TeamCommandResult>;
1696
- /** Required when the login declares `capabilities.team.policyControl`. */
1697
- executeTeamPolicy?(request: TeamPolicyCommandRequest): Promise<TeamCommandResult>;
1718
+ /** Required when the login declares `capabilities.lead`: every lead act, on the team surface and nowhere else. */
1719
+ executeTeam?(request: TeamCommandRequest): Promise<TeamCommandResult>;
1698
1720
  /** Required of a voice adapter whose manifest lists `softphone`: on one, the call's audio lands in Omni. */
1699
- openMedia?(request: OpenMediaRequest): Promise<OpenMediaResult>;
1721
+ openAudio?(request: OpenAudioRequest): Promise<OpenAudioResult>;
1700
1722
  /** Required when the login declares `capabilities.preferences`: the person's own choice, kept by the provider and republished as `authenticated`. */
1701
1723
  setPreference?(request: SetPreferenceRequest): Promise<PreferenceResult>;
1702
1724
  /** Records an interaction leg the host performed. Required of a softphone login's connection: the host mutes its microphone on any call, and the record is the provider's. */
@@ -1791,7 +1813,7 @@ export interface BrowserSessionKeyInput {
1791
1813
  * Whether two logins declare the same capabilities, field by field. The comparison an adapter
1792
1814
  * makes before republishing `authenticated`: capabilities are current, not fixed, and the natural
1793
1815
  * guard -- comparing the identity -- never fires on a demotion, because the thing that changed is
1794
- * not the thing being compared. Key order does not matter, and `team: {}` is not `team` absent.
1816
+ * not the thing being compared. Key order does not matter, and a withdrawn `lead` is a change.
1795
1817
  */
1796
1818
  export declare function sameCapabilities(a: UserCapabilities, b: UserCapabilities): boolean;
1797
1819
  /**
package/dist/index.js CHANGED
@@ -71,19 +71,19 @@ export const DEFAULT_LEVELS = [
71
71
  export function effectiveLevels(declared) {
72
72
  return [...(declared ?? DEFAULT_LEVELS)];
73
73
  }
74
- export const CAPABILITY_SOURCES = ["queue", "ungoverned", "undetermined"];
74
+ export const CAPABILITY_SOURCES = ["queue", "nobody", "not-yet-read"];
75
75
  // ---------------------------------------------------------------------------
76
76
  // Task commands.
77
77
  // ---------------------------------------------------------------------------
78
78
  export const TASK_COMMAND_NAMES = {
79
- voice: ["answer", "decline", "call", "hold", "resume", "end-call",
79
+ voice: ["answer", "decline", "dial", "hold", "resume", "end-call", "terminate-call",
80
80
  "connect-back", "transfer", "lead-assist", "conference", "recording", "complete"],
81
81
  chat: ["accept", "decline", "pause", "resume", "complete"],
82
82
  email: ["accept", "decline", "complete"],
83
83
  };
84
84
  /** The dial a command places, by the host's identity for it; `undefined` for a command that dials nothing. */
85
85
  export function commandDialId(command) {
86
- if (command.type === "connect-back" || command.type === "call")
86
+ if (command.type === "connect-back" || command.type === "dial")
87
87
  return command.dialId;
88
88
  if (command.type === "transfer" && (command.action === "cold" || command.action === "warm"))
89
89
  return command.dialId;
@@ -95,12 +95,6 @@ export const BREAK_KINDS = [
95
95
  "short-break", "meal", "rest", "training", "coaching",
96
96
  "meeting", "administrative", "technical", "personal", "other",
97
97
  ];
98
- /**
99
- * The breaks during which a lead may listen to a member's call: work of another sort, not rest.
100
- * A listening task is the one task a break in effect may hold, and only on one of these.
101
- */
102
- export const LISTENING_BREAK_KINDS = ["coaching", "administrative", "training"];
103
- export const breakKindAllowsListening = (kind) => kind !== undefined && LISTENING_BREAK_KINDS.includes(kind);
104
98
  export const OMNI_FAILURE_CODES = [
105
99
  "omni.not-authenticated",
106
100
  "omni.capability-not-enabled",
@@ -177,19 +171,15 @@ export function historyStepExpectsAPerson(step) {
177
171
  * Whether two logins declare the same capabilities, field by field. The comparison an adapter
178
172
  * makes before republishing `authenticated`: capabilities are current, not fixed, and the natural
179
173
  * guard -- comparing the identity -- never fires on a demotion, because the thing that changed is
180
- * not the thing being compared. Key order does not matter, and `team: {}` is not `team` absent.
174
+ * not the thing being compared. Key order does not matter, and a withdrawn `lead` is a change.
181
175
  */
182
176
  export function sameCapabilities(a, b) {
183
- const modes = (team) => team?.listeningControl === undefined ? undefined : [...team.listeningControl].sort().join(",");
184
177
  // Every field, so a capability added later cannot be missed here: `satisfies` pins the field
185
- // lists to the types, and a new key is a compile error until it is compared.
186
- const teamKeys = { breakControl: true, leadAssistControl: true, listeningControl: true, policyControl: true };
187
- void { breaks: true, preferences: true, team: true };
178
+ // list to the type, and a new key is a compile error until it is compared.
179
+ void { breaks: true, preferences: true, lead: true };
188
180
  const preferences = (list) => list === undefined ? undefined : list.map(p => [p.id, p.label, p.enabled, p.setBy, p.lockedBy ?? "", p.reason ?? ""].join("\u0000")).sort().join("\u0001");
189
181
  return a.breaks === b.breaks &&
190
- (a.team === undefined) === (b.team === undefined) &&
191
- Object.keys(teamKeys).every(key => key === "listeningControl" || a.team?.[key] === b.team?.[key]) &&
192
- modes(a.team) === modes(b.team) &&
182
+ a.lead === b.lead &&
193
183
  preferences(a.preferences) === preferences(b.preferences);
194
184
  }
195
185
  /**