@xema/omni-protocol 0.1.101 → 0.1.103

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
@@ -164,7 +164,7 @@ export interface Manifest<C extends Channel = Channel> {
164
164
  /**
165
165
  * The outcomes this platform distinguishes when a dial ends, `answered` and at least one way of
166
166
  * not reaching the destination. Required of a provider that dials at all -- an idle dialpad, or
167
- * a task that may transfer, conference, or call back -- and forbidden off voice, where nothing dials.
167
+ * a task that may conference or call back -- and forbidden off voice, where nothing dials.
168
168
  */
169
169
  dialOutcomes?: C extends "voice" ? DialOutcome[] : never;
170
170
  /**
@@ -179,13 +179,12 @@ export interface Manifest<C extends Channel = Channel> {
179
179
  */
180
180
  runningStepReports?: true;
181
181
  /**
182
- * How long after an applied completion -- `complete`, or a lead's `take-over-call` -- the provider's
183
- * `task-ended` is owed, in milliseconds. A warm transfer's `complete` is not one: the agent's
184
- * wrap runs after it as after any call. `applied` says the provider
185
- * has completed the task; the ending follows within this, or the host resyncs and shows the
186
- * task as unsettled. Stated per provider, since platforms settle at different speeds.
182
+ * How long after `applied` the wire shows what the provider did, in milliseconds: the
183
+ * `task-ended` after a `complete` or a lead's `take-over-call`, the `calendar-updated` after a
184
+ * `schedule`. Past it the host resyncs and shows the thing as unsettled. Stated per provider,
185
+ * since platforms settle at different speeds.
187
186
  */
188
- completionSettleMs: number;
187
+ settleMs: number;
189
188
  }
190
189
  export interface SecretStore {
191
190
  get(key: string): Promise<string | undefined>;
@@ -251,9 +250,10 @@ export interface UserCapabilities {
251
250
  /**
252
251
  * This login leads a team. The flag alone turns on the team feature in the agent application:
253
252
  * 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.
253
+ * with the authority the flag carries. No per-action permission rides beside it. The provider
254
+ * assumes nothing of the switch: the application sends `lead-features` on every connect, and
255
+ * only while it is on does the team reach the lead -- `team-updated` whole after the switch and
256
+ * on any snapshot, then one member at a time as members change; to nobody else, ever.
257
257
  */
258
258
  lead?: true;
259
259
  }
@@ -458,7 +458,6 @@ export type RecordingState = {
458
458
  export type RecordingCommand = {
459
459
  type: "recording";
460
460
  source: RecordingSource;
461
- requestId: string;
462
461
  /** Compare-and-set against current evidence; never act on a replacement recording. */
463
462
  observationId: string;
464
463
  } & ({
@@ -622,7 +621,7 @@ export interface Destination {
622
621
  id: string;
623
622
  label: string;
624
623
  }
625
- /** The items a transfer or conference control offers. Nothing is typed; the agent picks one. */
624
+ /** The items a conference control offers. Nothing is typed; the agent picks one. */
626
625
  export interface DestinationDirectory {
627
626
  destinations: Destination[];
628
627
  }
@@ -653,14 +652,13 @@ export interface SharedTaskCapabilities {
653
652
  export type TaskCapabilities<C extends Channel = Channel> = C extends "voice" ? SharedTaskCapabilities & {
654
653
  decline?: Lockable<true>;
655
654
  hold?: Lockable<true>;
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. */
655
+ /** The provider ends the caller connection and agent-added channels owned by this interaction, including inherited channels after a take-over. Interaction completion remains separate. */
657
656
  endCall?: Lockable<true>;
658
657
  terminateCall?: Lockable<true>;
659
658
  /** Connect back to the party while `completing`, whoever placed the call; the task returns to `in-progress`. */
660
659
  connectBack?: Lockable<true>;
661
- coldTransfer?: Lockable<DestinationDirectory>;
662
- /** Park the customer and call a destination first; then `complete` or `cancel`. */
663
- warmTransfer?: Lockable<DestinationDirectory>;
660
+ /** Put a time on the calendar for this party, from the call: a follow-up the agent promised. */
661
+ schedule?: Lockable<true>;
664
662
  /** Ask a lead to join this call, with a note. The lead's decision arrives on `Task.leadAssist`. */
665
663
  leadAssist?: Lockable<true>;
666
664
  conference?: Lockable<DestinationDirectory>;
@@ -668,8 +666,10 @@ export type TaskCapabilities<C extends Channel = Channel> = C extends "voice" ?
668
666
  } : C extends "chat" ? SharedTaskCapabilities & {
669
667
  decline?: Lockable<true>;
670
668
  hold?: Lockable<true>;
669
+ schedule?: Lockable<true>;
671
670
  } : SharedTaskCapabilities & {
672
671
  decline?: Lockable<true>;
672
+ schedule?: Lockable<true>;
673
673
  };
674
674
  /**
675
675
  * How a reusing browser's session is keyed.
@@ -721,7 +721,7 @@ export type TaskPhase =
721
721
  | "confirmed"
722
722
  /**
723
723
  * Voice only: the customer's record is available for preparation, then dialing before answer. The agent
724
- * presses Call, or `previewEndsAt` arrives and `atDeadline` says what the system does instead.
724
+ * presses Call, or `previewEndsInSeconds` runs out and `atDeadline` says what the system does instead.
725
725
  */
726
726
  | "preview" | "in-progress" | "paused"
727
727
  /** The work is over and the agent is finishing up. */
@@ -807,19 +807,18 @@ export type TaskCompletion = {
807
807
  completionMode: "provider-automatic";
808
808
  wrapAllowance: DurationSeconds;
809
809
  };
810
- export type OnCallRole = "party" | "agent" | "consulted" | "conferenced";
810
+ export type OnCallRole = "party" | "agent" | "conferenced";
811
811
  /** Where a dialled entry stands: `ringing` until its dial is answered, `joined` after. */
812
812
  export type OnCallStage = "ringing" | "joined";
813
- export declare const ON_CALL_ROLES: readonly ["party", "agent", "consulted", "conferenced"];
813
+ export declare const ON_CALL_ROLES: readonly ["party", "agent", "conferenced"];
814
814
  /**
815
815
  * Somebody on the call, or being brought onto it, as the provider states it: who, since when, and
816
- * whether they are held aside. `party` is the customer; `agent` a person, by user id; `consulted`
817
- * and `conferenced` someone a dial is bringing in -- listed from the moment the dial is placed, so
818
- * the agent can call it off while it rings -- carrying the dial when a host placed it, the address
819
- * either way, and the `stage` it has reached: `ringing` until the dial is answered, `joined` after,
820
- * stated so a snapshot says who is present without anyone having seen the outcome. Nobody ringing is
821
- * held. `label` names a destination -- a person, a queue -- not a phrase. At most one `party` and
822
- * one `consulted`: the consult commands name neither because there is exactly one. The `party`
816
+ * whether they are held aside. `party` is the customer; `agent` a person, by user id; `conferenced`
817
+ * someone a dial is bringing in -- listed from the moment the dial is placed, so the agent can call
818
+ * it off while it rings -- carrying the dial when a host placed it, the address either way, and the
819
+ * `stage` it has reached: `ringing` until the dial is answered, `joined` after, stated so a snapshot
820
+ * says who is present without anyone having seen the outcome. Nobody ringing is held. `label` names
821
+ * a destination -- a person, a queue -- not a phrase. At most one `party`. The `party`
823
822
  * carries a `stage` while being dialled -- by any host dial, a dialpad call, a preview Call or a
824
823
  * connect-back, carrying its `dialId`, or by a callback the platform places itself, carrying none --
825
824
  * `ringing` from the moment the dial is placed, `joined` on the publication that follows its
@@ -842,7 +841,7 @@ export type OnCall = {
842
841
  role: "agent";
843
842
  userId: UserId;
844
843
  } | {
845
- role: "consulted" | "conferenced";
844
+ role: "conferenced";
846
845
  destinationId: string;
847
846
  stage: OnCallStage;
848
847
  dialId?: DialId;
@@ -952,12 +951,21 @@ export type Task<C extends Channel = Channel> = {
952
951
  */
953
952
  acceptance?: AcceptanceMode;
954
953
  /**
955
- * In `preview` only, and together: the preparation target and behavior when it elapses,
956
- * and who acts then -- `provider-dials` makes the provider initiate dialing, `host-dials` makes the
957
- * host issue Call, and `waits` keeps waiting for the agent without dialing or ending the task.
958
- * Absent, the agent has as long as they need, without a preparation countdown.
954
+ * In `pending` only: how long the offer has left, in whole seconds from this publication,
955
+ * restated on every publication that carries it so a reconnect snapshot says what is actually
956
+ * left. Absent, the offer stands until the provider says otherwise. Runs out: the provider ends
957
+ * the offer `expired` naming `pending`.
958
+ */
959
+ expiresInSeconds?: DurationSeconds;
960
+ /**
961
+ * In `preview` only, and together: how long the preparation has left, in whole seconds from
962
+ * this publication -- restated on every publication that carries it, so a resync starts the
963
+ * countdown afresh and no clock is compared -- and behavior when it runs out, and who acts then:
964
+ * `provider-dials` makes the provider initiate dialing, `host-dials` makes the host issue Call,
965
+ * and `waits` keeps waiting for the agent without dialing or ending the task. Absent, the agent
966
+ * has as long as they need, without a preparation countdown.
959
967
  */
960
- previewEndsAt?: IsoTimestamp;
968
+ previewEndsInSeconds?: DurationSeconds;
961
969
  atDeadline?: PreviewDeadline;
962
970
  /** The identifier an agent reads back to a customer, where the provider has one. */
963
971
  reference?: string;
@@ -989,11 +997,6 @@ export type TaskOutcome = {
989
997
  type: "completed";
990
998
  by: "agent" | "provider";
991
999
  }
992
- /** A cold transfer to a destination the agent chose: a directory item's id. */
993
- | {
994
- type: "transferred";
995
- destinationId?: string;
996
- }
997
1000
  /** 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. */
998
1001
  | {
999
1002
  type: "taken-over";
@@ -1005,18 +1008,18 @@ export type TaskOutcome = {
1005
1008
  by: "agent" | "provider" | "party";
1006
1009
  reason?: string;
1007
1010
  }
1008
- /** Only the phases in which somebody is still being waited on can expire; an offer that lapses at `assignmentExpiresAt` names `pending`. */
1011
+ /** Only the phases in which somebody is still being waited on can expire: an offer whose `expiresInSeconds` runs out names `pending`, accepted work the platform gave up on names `confirmed`. A preview never lapses: withdrawn, it is `cancelled` by the provider. */
1009
1012
  | {
1010
1013
  type: "expired";
1011
- phase: "pending" | "confirmed" | "preview";
1014
+ phase: "pending" | "confirmed";
1012
1015
  } | {
1013
1016
  type: "failed";
1014
1017
  failure: ProtocolFailure;
1015
1018
  };
1016
1019
  export declare const TASK_COMMAND_NAMES: {
1017
- readonly voice: readonly ["answer", "decline", "dial", "hold", "resume", "end-call", "terminate-call", "connect-back", "transfer", "lead-assist", "conference", "recording", "complete"];
1018
- readonly chat: readonly ["accept", "decline", "pause", "resume", "complete"];
1019
- readonly email: readonly ["accept", "decline", "complete"];
1020
+ readonly voice: readonly ["answer", "decline", "dial", "hold", "resume", "end-call", "terminate-call", "connect-back", "lead-assist", "conference", "recording", "schedule", "complete"];
1021
+ readonly chat: readonly ["accept", "decline", "pause", "resume", "schedule", "complete"];
1022
+ readonly email: readonly ["accept", "decline", "schedule", "complete"];
1020
1023
  };
1021
1024
  export type TaskCommandName<C extends keyof typeof TASK_COMMAND_NAMES> = (typeof TASK_COMMAND_NAMES)[C][number];
1022
1025
  export interface OutcomePayload {
@@ -1049,31 +1052,7 @@ export type VoiceTaskCommand = {
1049
1052
  | {
1050
1053
  type: "connect-back";
1051
1054
  dialId: DialId;
1052
- }
1053
- /** Cold: hand the customer to the directory item `destinationId` with nobody spoken to first. Gated by `coldTransfer`. */
1054
- | {
1055
- type: "transfer";
1056
- action: "cold";
1057
- dialId: DialId;
1058
- destinationId: string;
1059
- }
1060
- /** Warm: park the customer and call the directory item `destinationId` first. Gated by `warmTransfer`. */
1061
- | {
1062
- type: "transfer";
1063
- action: "warm";
1064
- dialId: DialId;
1065
- destinationId: string;
1066
- }
1067
- /** Hand the customer to the consulted destination and leave. Needs a `consulted` entry on `Task.onCall`. */
1068
- | {
1069
- type: "transfer";
1070
- action: "complete";
1071
- }
1072
- /** Drop the consulted destination and return to the customer. Needs a `consulted` entry on `Task.onCall`. */
1073
- | {
1074
- type: "transfer";
1075
- action: "cancel";
1076
- }
1055
+ } | ScheduleCommand
1077
1056
  /** Ask a lead to join, with a note. Gated by `leadAssist`. */
1078
1057
  | {
1079
1058
  type: "lead-assist";
@@ -1113,6 +1092,18 @@ export type VoiceTaskCommand = {
1113
1092
  }) | ({
1114
1093
  type: "complete";
1115
1094
  } & OutcomePayload);
1095
+ /**
1096
+ * Put a time on the calendar for this party: a follow-up promised on the call or in the
1097
+ * conversation, or written up in wrap. Gated by `schedule` on any channel, issuable in
1098
+ * `in-progress`, `paused` or `completing`, under a manifest that declares `calendar` for it to
1099
+ * land on; `applied` says it is on the calendar, and the `calendar-updated` that shows it follows
1100
+ * within the manifest's `settleMs`.
1101
+ */
1102
+ export type ScheduleCommand = {
1103
+ type: "schedule";
1104
+ at: IsoTimestamp;
1105
+ note?: string;
1106
+ };
1116
1107
  export type ChatTaskCommand = {
1117
1108
  type: "accept";
1118
1109
  } | {
@@ -1121,14 +1112,14 @@ export type ChatTaskCommand = {
1121
1112
  type: "pause";
1122
1113
  } | {
1123
1114
  type: "resume";
1124
- } | ({
1115
+ } | ScheduleCommand | ({
1125
1116
  type: "complete";
1126
1117
  } & OutcomePayload);
1127
1118
  export type EmailTaskCommand = {
1128
1119
  type: "accept";
1129
1120
  } | {
1130
1121
  type: "decline";
1131
- } | ({
1122
+ } | ScheduleCommand | ({
1132
1123
  type: "complete";
1133
1124
  } & OutcomePayload);
1134
1125
  export interface CustomTaskCommand {
@@ -1206,9 +1197,15 @@ export interface BreakRequest {
1206
1197
  /** The chosen `BreakReason.id`, where the provider publishes codes. */
1207
1198
  reasonId?: string;
1208
1199
  }
1209
- /** A break forced on the agent; the agent must explicitly resume when ready. */
1200
+ /**
1201
+ * A break forced on the agent; the agent must explicitly resume when ready. A lead's `force-break`
1202
+ * is a command to the provider, which forces the break: `by` names the lead who asked it to, or
1203
+ * `provider` where the platform itself did, on its own rule or a schedule. The agent sees who, a
1204
+ * person is named only when there is one, and a break the platform imposed is the platform's to
1205
+ * lift: a lead's `end-forced-break` on it fails with `omni.break-forced-by-provider`.
1206
+ */
1210
1207
  export type ForcedBreak = {
1211
- by: UserId;
1208
+ by: UserId | "provider";
1212
1209
  /** Optional expected time on break, in milliseconds from actual start. Advisory only. */
1213
1210
  expectedDurationMs?: number;
1214
1211
  };
@@ -1271,10 +1268,11 @@ export interface TeamMember {
1271
1268
  listening?: MemberListening;
1272
1269
  /** The member's own history for the day: sign-in, sign-out, breaks and productivity. Omitted where the provider cannot say. */
1273
1270
  shift?: MemberShift;
1271
+ /** The member's standing ask for a lead on one of their calls; absent when they are not asking. */
1272
+ request?: MemberRequest;
1274
1273
  }
1275
- /** A member asking this lead to join their call, named by the member and the assignment. */
1276
- export interface LeadRequest {
1277
- memberId: UserId;
1274
+ /** This member asking their lead to join a call: which assignment, the note they wrote, since when. */
1275
+ export interface MemberRequest {
1278
1276
  assignmentId: AssignmentId;
1279
1277
  note?: string;
1280
1278
  since: IsoTimestamp;
@@ -1337,19 +1335,20 @@ export interface MemberShift {
1337
1335
  signedOutAt?: IsoTimestamp;
1338
1336
  talkSeconds?: DurationSeconds;
1339
1337
  holdSeconds?: DurationSeconds;
1338
+ /** Every break the member was on today, including time held elsewhere for a break another provider forced: the provider counts it under a break kind of its own. */
1340
1339
  breakSeconds?: DurationSeconds;
1341
1340
  tasksHandled?: number;
1342
1341
  events?: ShiftEvent[];
1343
1342
  }
1344
1343
  /**
1345
1344
  * The lead's view of their team: published to a login that declares `capabilities.lead` while the
1346
- * lead has the team feature on, on every snapshot, and to nobody else. The provider keeps it
1347
- * current: when a member holds, mutes or is transferred, the list is republished whole.
1345
+ * lead has the team feature on, and to nobody else. Whole on `team-updated` -- after the switch,
1346
+ * and on any snapshot -- and from then on one member at a time: `team-member-updated` carries the
1347
+ * member whole, so applying it twice changes nothing, and `team-member-removed` takes one off.
1348
+ * A team of two hundred is never resent because one of them held.
1348
1349
  */
1349
1350
  export interface TeamMembers {
1350
1351
  members: TeamMember[];
1351
- /** Members asking a lead to join their call; `[]` when nobody is asking. */
1352
- requests: LeadRequest[];
1353
1352
  /** The team's policy per capability, as it stands. Present where the provider offers policy control; absent where it does not. */
1354
1353
  policies?: TeamPolicies;
1355
1354
  }
@@ -1605,7 +1604,6 @@ export type ProviderEvent<C extends Channel = Channel> = {
1605
1604
  } | {
1606
1605
  type: "task-offered";
1607
1606
  task: Task<C>;
1608
- assignmentExpiresAt?: IsoTimestamp;
1609
1607
  } | {
1610
1608
  type: "task-updated";
1611
1609
  task: Task<C>;
@@ -1648,9 +1646,22 @@ export type ProviderEvent<C extends Channel = Channel> = {
1648
1646
  expected: string;
1649
1647
  observed: string;
1650
1648
  assignmentId?: AssignmentId;
1651
- } | {
1649
+ }
1650
+ /** The whole team, once: after `lead-features` comes on, and on every snapshot while it is. */
1651
+ | {
1652
1652
  type: "team-updated";
1653
1653
  team: TeamMembers;
1654
+ }
1655
+ /** One member, whole, as they now stand: replaces the member of that id, or adds them. */
1656
+ | {
1657
+ type: "team-member-updated";
1658
+ member: TeamMember;
1659
+ } | {
1660
+ type: "team-member-removed";
1661
+ memberId: UserId;
1662
+ } | {
1663
+ type: "team-policies-updated";
1664
+ policies: TeamPolicies;
1654
1665
  } | {
1655
1666
  type: "contacts-updated";
1656
1667
  contacts: Contact[];
@@ -1670,7 +1681,7 @@ export interface ProviderEventEnvelope<C extends Channel = Channel> {
1670
1681
  occurredAt: IsoTimestamp;
1671
1682
  event: ProviderEvent<C>;
1672
1683
  }
1673
- export declare const OMNI_FAILURE_CODES: readonly ["omni.not-authenticated", "omni.capability-not-enabled", "omni.assignment-not-found", "omni.destination-not-permitted", "omni.phone-not-permitted", "omni.rate-limited", "omni.unavailable", "omni.break-already-committed"];
1684
+ export declare const OMNI_FAILURE_CODES: readonly ["omni.not-authenticated", "omni.capability-not-enabled", "omni.assignment-not-found", "omni.destination-not-permitted", "omni.phone-not-permitted", "omni.rate-limited", "omni.unavailable", "omni.break-already-committed", "omni.recording-unsettled", "omni.break-forced-by-provider"];
1674
1685
  export type OmniFailureCode = (typeof OMNI_FAILURE_CODES)[number];
1675
1686
  /**
1676
1687
  * What the host refused, told to the adapter that published it: a snapshot the host would not
package/dist/index.js CHANGED
@@ -56,7 +56,7 @@ export function isAllowedBrowserUrl(url) {
56
56
  return false;
57
57
  }
58
58
  }
59
- export const ON_CALL_ROLES = ["party", "agent", "consulted", "conferenced"];
59
+ export const ON_CALL_ROLES = ["party", "agent", "conferenced"];
60
60
  /**
61
61
  * The levels a typical organisation has: the ladder in force when a manifest declares no
62
62
  * `orgLevels`. A manifest that declares any states its whole ladder outright.
@@ -77,16 +77,14 @@ export const CAPABILITY_SOURCES = ["queue", "nobody", "not-yet-read"];
77
77
  // ---------------------------------------------------------------------------
78
78
  export const TASK_COMMAND_NAMES = {
79
79
  voice: ["answer", "decline", "dial", "hold", "resume", "end-call", "terminate-call",
80
- "connect-back", "transfer", "lead-assist", "conference", "recording", "complete"],
81
- chat: ["accept", "decline", "pause", "resume", "complete"],
82
- email: ["accept", "decline", "complete"],
80
+ "connect-back", "lead-assist", "conference", "recording", "schedule", "complete"],
81
+ chat: ["accept", "decline", "pause", "resume", "schedule", "complete"],
82
+ email: ["accept", "decline", "schedule", "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
86
  if (command.type === "connect-back" || command.type === "dial")
87
87
  return command.dialId;
88
- if (command.type === "transfer" && (command.action === "cold" || command.action === "warm"))
89
- return command.dialId;
90
88
  if (command.type === "conference" && command.action === "add")
91
89
  return command.dialId;
92
90
  return undefined;
@@ -105,6 +103,10 @@ export const OMNI_FAILURE_CODES = [
105
103
  "omni.rate-limited",
106
104
  "omni.unavailable",
107
105
  "omni.break-already-committed",
106
+ /** A recording command the provider could not settle either way: no start, stop, pause or resume it can vouch for. */
107
+ "omni.recording-unsettled",
108
+ /** A lead asked to lift a break the platform itself imposed; the platform lifts its own. */
109
+ "omni.break-forced-by-provider",
108
110
  ];
109
111
  /**
110
112
  * Preserves the adapter's inferred concrete type while checking it implements `Adapter`.
package/dist/testing.d.ts CHANGED
@@ -7,7 +7,7 @@ export { ProtocolConformanceError, assertNoViolations, type ProtocolViolation }
7
7
  * rules -- each optional part of a task, each optional part of the break state and team member list, each
8
8
  * declared contribution, and each event type.
9
9
  */
10
- declare const STATE_SUBJECTS: readonly ["tasks", "task.browsers", "task.attributes", "task.history", "task.onCall", "task.leadAssist", "task.takenOver", "task.audio", "task.acceptance", "task.outcomes", "task.destinations", "task.custom", "task.locked", "break.reasons", "break.forced", "team.members", "team.requests", "team.tasks", "team.listening", "team.shift", "contacts", "calendar", "team.policies"];
10
+ declare const STATE_SUBJECTS: readonly ["tasks", "task.browsers", "task.attributes", "task.history", "task.onCall", "task.leadAssist", "task.takenOver", "task.audio", "task.acceptance", "task.outcomes", "task.destinations", "task.custom", "task.locked", "break.reasons", "break.forced", "team.members", "team.request", "team.tasks", "team.listening", "team.shift", "contacts", "calendar", "team.policies"];
11
11
  export type ContractSubject = (typeof STATE_SUBJECTS)[number] | `event.${ProviderEvent["type"]}`;
12
12
  export interface AdapterContractResult {
13
13
  events: ProviderEventEnvelope[];
@@ -149,6 +149,8 @@ export declare class TaskStream {
149
149
  private readonly tasks;
150
150
  private readonly assignments;
151
151
  private readonly endedAssignments;
152
+ /** Every assignment a `task-offered` introduced, as against one a snapshot carried: each is owed its ending. */
153
+ private readonly offered;
152
154
  private readonly dials;
153
155
  /** The host placed a dial: its outcome, whenever it arrives, is one the stream expects. */
154
156
  dialled(dialId: string): void;
@@ -160,6 +162,8 @@ export declare class TaskStream {
160
162
  private notOpen;
161
163
  /** How many tasks the stream currently holds open. */
162
164
  openCount(): number;
165
+ /** The assignments an offer introduced that are still open: each was owed a `task-ended` that has not come. */
166
+ unended(): string[];
163
167
  /** Whether an offered task is a dial arriving -- the host's own call, a connect-back -- which counts against no capacity: an entry on its call carrying a dial. */
164
168
  static carriesDial(task: unknown): boolean;
165
169
  /**
@@ -188,6 +192,20 @@ export declare class TaskStream {
188
192
  apply(envelope: unknown, path?: string): ProtocolViolation[];
189
193
  }
190
194
  /** What a stream has said about the agent's break, and the moves it may not make. */
195
+ /**
196
+ * The team as the events left it: whole on `team-updated` and on any snapshot carrying one, then
197
+ * one member at a time. A member event before the whole team, or a removal of a member the team
198
+ * never carried, is a change to a team the lead was never given.
199
+ */
200
+ export declare class TeamStream {
201
+ private members;
202
+ private static ids;
203
+ /** A snapshot carrying a team is the team whole; one carrying none leaves the lead with none. */
204
+ seed(snapshot: unknown): void;
205
+ /** Whether the team currently carries this member, as the events left it. */
206
+ has(id: string): boolean;
207
+ apply(envelope: unknown, path?: string): ProtocolViolation[];
208
+ }
191
209
  export declare class BreakStream {
192
210
  private state;
193
211
  private recovery;
@@ -231,6 +249,13 @@ export interface BreakCandidate {
231
249
  /** Whether the agent can currently receive work from it: connected, with a capacity stated. */
232
250
  holdsCapacity: boolean;
233
251
  }
252
+ /**
253
+ * A break one provider forces stops the agent everywhere: the host states a capacity of zero on
254
+ * every other usable provider holding capacity -- taken, never refused, and nothing the agent can
255
+ * cancel -- and on the forcing provider states nothing, since the break itself holds the agent
256
+ * there. A provider whose login is not usable is left alone, as a break attempt leaves it.
257
+ */
258
+ export declare function assertForcedBreakStopsTheRest(forcedOn: string, candidates: readonly BreakCandidate[], stopped: readonly string[]): void;
234
259
  /**
235
260
  * A break attempt asks every connected provider from which the agent can currently receive work.
236
261
  * A provider whose login is not usable -- `expired` above all -- is not asked, whatever else is