@xema/omni-protocol 0.1.114 → 0.1.116

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/guide/agent.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@xema/omni-protocol`: The agent's work
2
2
 
3
- What an agent does on any channel: the assignment from offer to wrap, the task and its record, the controls a task offers, the commands the desk sends. Part of the contract in `guide.md`, which holds the terms, the shapes and the rules every file here relies on; a reference in bold names the file it points into where that is not this one.
3
+ What an agent does on any channel: the assignment from offer to wrap, the task and its record, the controls a task offers, the commands the agent computer sends. Part of the contract in `guide.md`, which holds the terms, the shapes and the rules every file here relies on; a reference in bold names the file it points into where that is not this one.
4
4
 
5
5
  ## Task assignment lifecycle
6
6
 
@@ -66,7 +66,7 @@ agent's own act — a dialpad call or a connect-back, recognisable by the agent
66
66
  `onCall`; a call a lead took over, carrying `takenOver` — arrives
67
67
  through `task-offered` with `acceptance: "automatic"` whatever `autoAcceptTasks` says, and the
68
68
  validator holds it there under either local policy and under none (`task.acceptance.originated`):
69
- the desk shows no **Accept** for a call the agent placed. The local policy governs work the queue
69
+ the agent computer shows no **Accept** for a call the agent placed. The local policy governs work the queue
70
70
  routes to the agent, and nothing else.
71
71
 
72
72
  ### Pending
@@ -95,7 +95,7 @@ medium the task arrives on, not a separate decision.
95
95
  **Once a task is accepted, the call that comes with it is answered.** Omni has no discretion
96
96
  there and the provider is not consulted twice: one decision about the work, and the medium
97
97
  follows it. Where the audio lands was settled at sign-in — in Omni on a softphone, on the handset
98
- on a desk phone — and is not in question per call. See **How the agent hears the call** in `guide/phone.md`.
98
+ on a hardphone — and is not in question per call. See **How the agent hears the call** in `guide/phone.md`.
99
99
 
100
100
  Automatic acceptance still begins with `task-offered`.
101
101
 
@@ -111,7 +111,7 @@ Omni withdraw **Accept** from a task still pending.
111
111
  **A deadline is seconds left, never an instant.** The agent application and the provider keep
112
112
  different clocks, and a countdown that compares one against the other is a countdown that runs
113
113
  fast or slow by their skew. Seconds from the publication that carries them are the provider's own
114
- arithmetic, counted down on the desk from the moment they arrive, and the transport delay is the
114
+ arithmetic, counted down on the agent computer from the moment they arrive, and the transport delay is the
115
115
  only error. Restated on every publication that carries them, so a snapshot after a reconnect
116
116
  starts the countdown afresh from what is actually left (`task.pending.expiresInSeconds`,
117
117
  `task.preview.previewEndsInSeconds`: a whole number, zero or more).
@@ -166,7 +166,7 @@ time. Runtime conformance checks also require the task channel to match its prov
166
166
  | `reference` | Optional agent-facing reference such as a case, call, conversation, ticket, or message number. It is distinct from the protocol `id`. |
167
167
  | `completionMode` | `agent-command` waits for the channel's `complete` command; `provider-automatic` completes without one, and takes the agent's `complete` as finishing early. A required outcome is the agent's to give, so it needs `agent-command` (`task.outcomes.required.mode`). |
168
168
  | `wrapAllowance` | Fixed time allowed to complete the task after primary interaction ends. For real-time audio, it begins after `task-audio-ended`. Required under `provider-automatic`, where the provider acts on it. Optional under `agent-command`: omitted says the provider imposes no deadline, and Omni counts nothing down; stated, it is the expected wrap, shown and never acted on. `0` under `provider-automatic` is no wrap at all, so such a task publishes no `outcomes` (`task.outcomes.wrapAllowance`). |
169
- | `wrapEndsInSeconds` | In `completing`, wherever `wrapAllowance` is stated: how much of the wrap is left, in whole seconds from this publication, restated on every publication that carries it (`task.completing.wrapEndsInSeconds`, `.required`, `.unexpected`). A reloaded desk and a lead's screen count down the same number. See **Completion timing**. |
169
+ | `wrapEndsInSeconds` | In `completing`, wherever `wrapAllowance` is stated: how much of the wrap is left, in whole seconds from this publication, restated on every publication that carries it (`task.completing.wrapEndsInSeconds`, `.required`, `.unexpected`). A reloaded agent computer and a lead's screen count down the same number. See **Completion timing**. |
170
170
  | `attributes` | Optional ordered, typed `TaskAttribute` entries with keys unique within the task. Each contact or timestamp is a separate array item; new attribute shapes require new union members. |
171
171
  | `history` | The call record: `steps` — the ordered interaction history of this open task, one entry per occurrence, oldest first — and what they add up to before this agent, `interactionSeconds`, `holdSeconds`, `queueSeconds`, `transfers`, each present when the provider knows it. Live task data restated with the task, not a permanent archive. See **Interaction history**. |
172
172
  | `onCall` | Voice only. Who is on the call, or being brought onto it, as the provider states it, replaced whole with the task: `party` is the customer -- carrying a `stage` while being dialled again on the same task, a connect-back with the agent application's `dialId` or a platform's callback without, ringing from the moment the dial is placed and joined on its answered outcome --, `agent` a person by user id, `conferenced` somebody a dial is bringing in, listed from the moment the dial is placed -- with the `destinationId` dialled, the `dialId` where an agent application placed it, the `stage` reached (`ringing` until answered, `joined` after), and `held: true` on anyone joined and parked. `label` names a destination -- a person, a queue -- not a phrase; the agent application supplies the verb. Present when the provider knows the room, absent when it does not. See **Every dial has an outcome** in `guide/voice.md`. |
@@ -224,7 +224,7 @@ and a re-offer. Everything that names a task after the fact -- a dial outcome, a
224
224
  ending, a history report, a command -- would land on whichever assignment is open when it arrives.
225
225
  So the assignment id is unique within the provider and never reused: where the platform's handle
226
226
  never comes back, the adapter passes it through; where it does, the adapter mints the assignment id
227
- and keeps the mapping, and the desk never learns which. A late event finds the assignment it
227
+ and keeps the mapping, and the agent computer never learns which. A late event finds the assignment it
228
228
  belongs to or is refused, and a task-scoped browser session (`PROVIDER_NAME__ASSIGNMENT_ID__TAB_NAME`)
229
229
  lives one assignment, never the next customer's cookies. A dial the agent application placed was
230
230
  already safe, since its outcome is placed by the agent application's own `dialId`; where the
@@ -263,14 +263,14 @@ so a `provider-automatic` task with `wrapAllowance: 0` publishes no `outcomes` a
263
263
 
264
264
  **The allowance means one thing per mode.** Under `provider-automatic` it is what the provider
265
265
  acts on: the task ends when it runs out. Under `agent-command` it is the expected wrap, stated so
266
- the agent can see it: the desk counts it down and, past zero, shows how far over they are, and
266
+ the agent can see it: the agent computer counts it down and, past zero, shows how far over they are, and
267
267
  nothing acts on it -- the task waits for `complete` however long that takes, with its outcomes
268
268
  collected whenever the agent gives them. A provider that would end the task at a time is
269
269
  `provider-automatic`.
270
270
 
271
271
  **What is left travels with the task.** The allowance is the length; `wrapEndsInSeconds` is how
272
272
  much of it remains, stated on the `completing` task and restated on every publication that
273
- carries it, as `previewEndsInSeconds` is on a preview. A desk that reloads mid-wrap finds the
273
+ carries it, as `previewEndsInSeconds` is on a preview. An agent computer that reloads mid-wrap finds the
274
274
  number on the snapshot; a lead's screen finds it on the member; neither starts a clock of its own,
275
275
  and both count down from receipt. Under `provider-automatic` the provider ends the task when it
276
276
  reaches zero; under `agent-command` it is the expected wrap left, `0` once overrun, and nothing
@@ -309,7 +309,7 @@ outcome, and complete the task.
309
309
 
310
310
  `0` means no wrap under `provider-automatic`: the provider completes the task at the end of the
311
311
  interaction, and `complete` has nothing to cut short. Under `agent-command` it is an expected wrap
312
- of nothing -- the desk shows the overrun from the start -- and the task still waits for `complete`.
312
+ of nothing -- the agent computer shows the overrun from the start -- and the task still waits for `complete`.
313
313
 
314
314
  There is no value meaning "unlimited", because a number that is not a duration would be read as
315
315
  one. A provider that imposes no deadline says so by **omitting** `wrapAllowance`, which
@@ -375,16 +375,19 @@ Migration from the earlier spellings:
375
375
  | ForcedBreak.expectedDurationMs | `expectedEndsInSeconds`: seconds left, restated (`break.forced.expectedEndsInSeconds`, `.expectedDurationMs.renamed`); the command keeps `expectedDurationMs` |
376
376
  | MemberShift; the day on the lead's list alone | `Shift`, on `Snapshot.shift` and `shift-updated` for the agent, on `TeamMember.shift` for the lead |
377
377
  | TeamMember.listening as this lead's one entry | `MemberListening[]`, every lead's, each with `leadId` (`team.member.listening.leadId`, `.unique`, `.empty`, `.entry`, `.heard`) |
378
- | a member's history trimmed on the lead's list | the record whole, as the member's desk holds it |
378
+ | a member's history trimmed on the lead's list | the record whole, as the member's computer holds it |
379
379
  | durations counted from the screen's clock | the provider's: `timeCheck` required of a provider publishing a running instant (`manifest.timeCheck.required`), `Snapshot.providerTime` with it (`snapshot.providerTime`, `.unexpected`) |
380
- | a wrap the desk timed from an event's receipt | `Task.wrapEndsInSeconds` in `completing`, restated (`task.completing.wrapEndsInSeconds`, `.required`, `.unexpected`) |
380
+ | a wrap the agent computer timed from an event's receipt | `Task.wrapEndsInSeconds` in `completing`, restated (`task.completing.wrapEndsInSeconds`, `.required`, `.unexpected`) |
381
381
  | MemberTask.capabilities, capabilitySource, browsers | gone: the workspace never travels to a lead (`team.member.task.workspace`); the record and the completion terms do |
382
382
  | a member republished on a hold, a mute, a take-over | on every publication of the member's task to the member |
383
383
  | two clients on one login | the later wins; the first is ended with `recovery: "displaced"` |
384
384
  | the phone unspoken | `PhoneState` -- the device, its mute, its channels -- on `Snapshot.phone`, `phone-updated` and `TeamMember.phone`, from a manifest declaring `phoneStatus` (`snapshot.phone.required`, `.unexpected`, `phone.*`, `phone.channel.*`, `event.phone.capability`) |
385
385
  | the agent's readiness for the next call read into setCapacity | the agent's own queue: `capabilities.nextCall`, `requestNextCall`/`cancelNextCall`/`releaseLinedUp`, `Snapshot.nextCall` and `linedUp`, the `next-call` and `lined-up` events (`snapshot.nextCall.idle`, `nextCall.*`, `linedUp.*`) |
386
386
  | a harness that exercised an adapter, drove a call and evaluated rules | the harness reads as a test: `testAdapter`, `withCall`, `timeoutMs`, `notTested`, `rulesTested`, rules `test.*` (`test.timeout`, `test.offer.expired`, `test.preview.deadline`, ...) |
387
- | an `end-call` while the caller was on hold | refused: a `paused` task is resumed first (`command.endCall.held`), the desk shows End call disabled on hold, the provider answers `failed`, and the test names an adapter that ends from hold (`test.command.held`); `terminate-call` is not gated, it ends the caller's channel too |
387
+ | an `end-call` while the caller was on hold | refused: a `paused` task is resumed first (`command.endCall.held`), the agent computer shows End call disabled on hold, the provider answers `failed`, and the test names an adapter that ends from hold (`test.command.held`); `terminate-call` is not gated, it ends the caller's channel too |
388
+ | the handset spelled by its place on a desk | `hardphone`, on the manifest's `phones` and the login's `phone`; the former spelling is refused |
389
+ | the desk | the agent computer, in the guide's prose |
390
+ | the agent application's Mute on hold | unavailable while the task is `paused`, promised at login by a softphone login's agent application (`host.guarantees.muteUnavailableOnHold`, required there and refused of a hardphone login); a host mute beginning on a paused task is refused (`historyReport.muted.held`) and the test names an adapter that records one (`test.recordStep.held`) |
388
391
 
389
392
  Update producers, consumers, saved task snapshots, and validation-rule assertions together.
390
393
  History and report rule names use `history` and `historyReport`; assignment rules use
@@ -428,7 +431,7 @@ Steps are `queued`, `offered`, `answered`, `held`, `muted`, `transferred`, `conf
428
431
  when it began, `seconds` once it ended and omitted while it runs — and a second hold is a second
429
432
  entry after the first, never a revision of it. A leg that has ended states its duration, and the
430
433
  task says whether a leg can still be running: a hold runs only while the task is `paused`, a mute
431
- only while its audio is up, so a `held` entry without `seconds` on a task that is not paused, or a
434
+ only while its audio is up and the agent application's own never begins on hold (`historyReport.muted.held`), so a `held` entry without `seconds` on a task that is not paused, or a
432
435
  `muted` one on a call that is over, is a leg nobody closed and reads exactly like a leg running now
433
436
  (`task.history.held.open`, `.muted.open`). Whoever performs the leg closes it — the
434
437
  provider whose platform parks the caller, the agent application whose microphone it is — by restating the entry
@@ -485,7 +488,7 @@ or combine them: report the representation conflict. No ambiguous event is silen
485
488
  **Interaction time is anchored, not restarted.** It runs from the
486
489
  `answered` step's `at` — from the task's first `in-progress` where the provider reports no
487
490
  history — until the task's audio ends, and a hold neither pauses nor resets it: the hold's own
488
- duration is the `held` entry's `seconds`, and a desk that restarts its counter on resume is
491
+ duration is the `held` entry's `seconds`, and an agent computer that restarts its counter on resume is
489
492
  counting the wrong thing.
490
493
 
491
494
  `muted` is there because the mute is the agent application's and never the provider's — see **The station is
@@ -541,10 +544,10 @@ different claim — it says the task has had none.
541
544
 
542
545
  **What the record adds up to is stated, not summed.** A call that has changed hands arrives
543
546
  carrying what others already used of it, and the agent reads that before they say hello: the
544
- totals are the provider's own — never a desk summing instants that may be rounded or skewed, for
547
+ totals are the provider's own — never an agent computer summing instants that may be rounded or skewed, for
545
548
  the same reason `seconds` is reported and not derived — and each is present when the provider
546
549
  knows it and absent when it does not, never a plausible nought. A fresh call from the queue has
547
- `steps` with no prior `answered` and no totals to state, and a desk shows nothing rather than
550
+ `steps` with no prior `answered` and no totals to state, and an agent computer shows nothing rather than
548
551
  zeros. The record is restated with the task on every `task-updated` and snapshot, so an entry
549
552
  that arrives late corrects the sums. These four are what every platform reports; more will be
550
553
  added here as a need is shown, not invented ahead of one.
@@ -579,7 +582,7 @@ did ask for them forwards upstream, and how often, is its own business. The step
579
582
  `recordStep` is required of every softphone login's connection, since every call on a softphone
580
583
  can be muted by the agent application, and answers `recorded` with the canonical history `at`. A `muted` report says whose the silence was,
581
584
  `mutedBy: "host"` or `"station"`, and no other report has the word (`historyReport.mutedBy`,
582
- `.mutedBy.unexpected`). On a desk phone the microphone is the phone's:
585
+ `.mutedBy.unexpected`). On a hardphone the microphone is the phone's:
583
586
  the agent application mutes nothing and records nothing.
584
587
 
585
588
  **The record is a record.** The microphone is the agent application's, and nothing in the
@@ -816,7 +819,7 @@ until the queue's terms arrive, and that the controls may change when they do --
816
819
  the buttons in front of them now, not about the provider, because that is what changes when the
817
820
  republish lands. It stays for as long as the set is provisional, beside the controls it qualifies;
818
821
  a message that shows and clears has said nothing about the buttons still on the screen. The two
819
- words are close in English and far apart on the desk: `nobody` is silence, `not-yet-read` is a
822
+ words are close in English and far apart on the agent computer: `nobody` is silence, `not-yet-read` is a
820
823
  standing notice.
821
824
 
822
825
  One consequence for whoever builds the agent application: because a conformance run fails on `not-yet-read`, a
@@ -1089,7 +1092,7 @@ react rather than only display the message:
1089
1092
  | `omni.not-authenticated` | The provider session is no longer usable. The adapter has published `expired` at or before this answer — the state is what Omni surfaces reauthentication from; the code says why this action failed, and is never the only signal. |
1090
1093
  | `omni.capability-not-enabled` | The action targets a capability this task, manifest, or login did not declare — including a lead command from a login whose `capabilities` no longer carry it. |
1091
1094
  | `omni.assignment-not-found` | The assignment named is not one the provider holds, typically after the task already ended. |
1092
- | `omni.phone-not-permitted` | The agent application declared a `phone` the platform does not permit for this agent -- a softphone for an agent configured for a desk phone, or the reverse. The login is refused at authentication, and the provider never reconfigures the agent to make the declaration true. See **How the agent hears the call** in `guide/phone.md`. |
1095
+ | `omni.phone-not-permitted` | The agent application declared a `phone` the platform does not permit for this agent -- a softphone for an agent configured for a hardphone, or the reverse. The login is refused at authentication, and the provider never reconfigures the agent to make the declaration true. See **How the agent hears the call** in `guide/phone.md`. |
1093
1096
  | `omni.destination-not-permitted` | The dialled number, or the `destinationId` named, is not one the provider offers this agent. |
1094
1097
  | `omni.rate-limited` | The action was throttled. Pair with `retryAfterMs`. |
1095
1098
  | `omni.unavailable` | The provider is temporarily unable to serve the action, including any command sent while `transport-status` is not `active`. |
package/guide/breaks.md CHANGED
@@ -140,7 +140,7 @@ which forces the break on the member; `by` names the lead who asked it to. A bre
140
140
  imposed on its own -- a schedule, a compliance hold -- says `by: "provider"`, and is the platform's
141
141
  to lift: a lead's `end-forced-break` on it is refused before it is sent
142
142
  (`team.command.endForcedBreak.provider`), and a provider that receives one answers `failed` with
143
- `omni.break-forced-by-provider`. The desk offers End forced break on a member only where
143
+ `omni.break-forced-by-provider`. The agent computer offers End forced break on a member only where
144
144
  `forced.by` names a lead.
145
145
 
146
146
  **A lead lifting the restriction does not resume the agent.** On an applied
@@ -250,7 +250,7 @@ against it (`stream.taskOffered.overCapacity`).
250
250
  idle dialpad arrives through `task-offered` like any other task, and a full agent does not forbid
251
251
  it: the ceiling binds assignment, not the agent's own hand.
252
252
 
253
- **Capacity is not the agent's readiness.** It is the desk's division of one person across
253
+ **Capacity is not the agent's readiness.** It is the agent computer's division of one person across
254
254
  providers, a ceiling on assignments at once, and it says nothing about the moment. An agent who
255
255
  is about to finish a call and wants the next one lined up has a different thing to say, and says
256
256
  it as **The agent's own queue** in `guide/queue.md` sets out; the ceiling stands unchanged while they do,
package/guide/lead.md CHANGED
@@ -7,7 +7,7 @@ The lead's own surface: the team member list, the lead's commands, lead assist,
7
7
  The team feature is the lead's own surface, beside the agent's and never mixed with it. The
8
8
  login's `lead` flag turns it on in the agent application; the lead retrieves their members and
9
9
  sees, for each, their assignments as they stand and the full history of each, and acts on them
10
- with the authority the flag carries. Nothing the lead does here is a task on their desk. A lead
10
+ with the authority the flag carries. Nothing the lead does here is a task on their agent computer. A lead
11
11
  who also takes calls is an agent like any other on the agent side, and a lead who does not want
12
12
  the agent role for now places themself on a break of a working kind and keeps the team feature on.
13
13
 
@@ -29,11 +29,11 @@ computes nothing. See **`team-updated`** in `guide.md` and its companions.
29
29
  | `availability` | Required. What the member is doing now. |
30
30
  | `since` | Optional. When the current `availability` began — not when they signed in, and not when the team member list was read. |
31
31
  | `break` | Present only while the member has an outstanding break request. See **A member waiting for a break**. |
32
- | `tasks` | The member's open tasks as `MemberTask`s: the same task the member's desk holds, less the workspace. The assignment, title, task type, phase, party, room, audio and completion terms -- `completionMode`, `wrapAllowance`, `wrapEndsInSeconds` -- are what the lead reads, and the task's record -- `history`, steps and totals -- travels whole, exactly as the member's desk holds it, so the lead's screen and the member's show the same record. The workspace -- `capabilities`, `capabilitySource`, `browsers` and their URLs -- is the member's desk's alone and never travels (`team.member.task.workspace`). The party's number and email are shown to leads or locked as the provider decides for leads, apart from what it decides for the member -- see **What the queue locks is locked on the whole task**. `[]` when the member holds none; omitted only where the provider cannot see them. |
32
+ | `tasks` | The member's open tasks as `MemberTask`s: the same task the member's computer holds, less the workspace. The assignment, title, task type, phase, party, room, audio and completion terms -- `completionMode`, `wrapAllowance`, `wrapEndsInSeconds` -- are what the lead reads, and the task's record -- `history`, steps and totals -- travels whole, exactly as the member's computer holds it, so the lead's screen and the member's show the same record. The workspace -- `capabilities`, `capabilitySource`, `browsers` and their URLs -- is the member's computer's alone and never travels (`team.member.task.workspace`). The party's number and email are shown to leads or locked as the provider decides for leads, apart from what it decides for the member -- see **What the queue locks is locked on the whole task**. `[]` when the member holds none; omitted only where the provider cannot see them. |
33
33
  | `listening` | Every lead on this member's call — listening, coaching or joined — published to every lead alike: each entry names the lead by `leadId`, which of the member's calls by `assignmentId`, the `mode` they are heard in, and since when. The entry naming the signed-in lead is what their own audio opens on. Absent while nobody is on the call, never `[]` (`team.member.listening.*`); a lead is on one member's call at a time (`team.listening.single`), and a lead who is heard is also in the task's `onCall` (`team.member.listening.heard`). |
34
34
  | `request` | Present while the member is asking a lead to join one of their calls: which assignment, the note they wrote, since when. The call named is one their `tasks` carry (`team.member.request.assignment`). Absent when they are not asking. See **Lead assist**. |
35
35
  | `nextCall`, `linedUp` | The member's own queue as their own snapshot carries it: their standing ask for the next call, and the call lined up for them. See **The agent's own queue** in `guide/queue.md`. |
36
- | `phone` | The member's phone as the platform sees it: the same `PhoneState` the member's own snapshot carries, so a lead sees a desk phone that is down, or a call on it that is no task, as the member does. Present where the provider declares `phoneStatus`. See **The phone's own view** in `guide/phone.md`. |
36
+ | `phone` | The member's phone as the platform sees it: the same `PhoneState` the member's own snapshot carries, so a lead sees a hardphone that is down, or a call on it that is no task, as the member does. Present where the provider declares `phoneStatus`. See **The phone's own view** in `guide/phone.md`. |
37
37
  | `shift` | The member's own history for the day, about the person rather than any one call: `signedInAt`, `signedOutAt` once it has happened, today's totals as the provider counts them — `talkSeconds`, `holdSeconds`, `breakSeconds`, `tasksHandled`, each present only when the provider knows it — and the day's sign-in, sign-out and break `events`, oldest first. The same `Shift` the member's own snapshot carries, the same numbers from the same count. Omitted where the provider cannot say. |
38
38
 
39
39
  Each availability value means one thing:
@@ -54,10 +54,10 @@ member at a time on `team-member-updated`, carrying the member whole: their avai
54
54
  tasks, their listening, their shift, their request, as they now stand. Applying the same member
55
55
  twice changes nothing, so a redelivery is harmless, and a member the team never carried is added
56
56
  by it, as a colleague signing in is. `team-member-removed` takes one off. Never a field of a
57
- member, never a task of theirs on its own: a hold on a member's desk is that member republished
57
+ member, never a task of theirs on its own: a hold on a member's computer is that member republished
58
58
  whole on the lead's, and nothing else on the lead's screen moves.
59
59
 
60
- **Whatever the member's desk hears of a task, every lead hears of the member.** The trigger is
60
+ **Whatever the member's computer hears of a task, every lead hears of the member.** The trigger is
61
61
  not a list of changes but the publication itself: each `task-offered`, `task-updated`,
62
62
  `task-audio-started`, `task-audio-ended` and `task-ended` the provider sends to the member is
63
63
  matched by a `team-member-updated` to every lead with the feature on, carrying the member whole
@@ -68,7 +68,7 @@ part for longer than the delay between them.
68
68
 
69
69
  **The agent's day is on the wire.** The lead sees `shift` totals as the provider counts them, and
70
70
  the agent sees the same: `Snapshot.shift` and `shift-updated` carry the agent's own day in the same
71
- shape, from the same count, so "calls today: 12" is one number on both screens. The desk computes
71
+ shape, from the same count, so "calls today: 12" is one number on both screens. The agent computer computes
72
72
  nothing of the day; `tasksHandled` moves when a task ends and `talkSeconds` when a leg closes, and
73
73
  the active call's running time is the screen's own until then, as **Every screen counts from the
74
74
  provider's clock** sets out.
@@ -174,7 +174,7 @@ executeTeam({ command: { type: "decline", memberId: "A-1", reason: "In a call" }
174
174
  `leadAssist: { stage: "joined", leadId }` and its `onCall` gains the lead as an `agent`, since a
175
175
  lead who is heard is in the room; the member on the team member list carries
176
176
  `listening: [{ leadId, assignmentId, mode: "join-call", since }]`, and the lead's audio opens on
177
- it as **Listening to a call** describes. Nothing is a task on the lead's desk: a join is the lead's act on the team surface, not
177
+ it as **Listening to a call** describes. Nothing is a task on the lead's computer: a join is the lead's act on the team surface, not
178
178
  work assigned to them.
179
179
 
180
180
  **A lead is on one member's call at a time.** A `join` from a lead already on a call -- their own
@@ -193,7 +193,7 @@ else changes; the agent is still on the call.
193
193
  its new agent. There are two paths to it -- the agent asked and the lead joined, or the lead was
194
194
  listening unasked -- and one act at the end of either. What follows is the same on both:
195
195
 
196
- | | The member's task | The lead's desk |
196
+ | | The member's task | The lead's computer |
197
197
  | --- | --- | --- |
198
198
  | Take-over | `task-audio-ended`, then `completing`: the member's interaction is over and their wrap runs, exactly as after `end-call`. The audio ends first, as before every voice ending (`stream.taskEnded.audioOpen`). The member loses this lead's `listening` entry on the team member list no later than the offer, and the lead's listening audio closes. | An ordinary assignment arrives: `task-offered` with `acceptance: "automatic"`, carrying the call's history and `takenOver: { memberId, since }`, within the lead's capacity. |
199
199
  | The member completes | `task-ended` with `{ type: "taken-over", leadId }`, at the member's own completion. The lead is named by user id, since a lead is not a directory item. | The lead works the call as any agent would, and ends it as any call ends. |
@@ -201,7 +201,7 @@ listening unasked -- and one act at the end of either. What follows is the same
201
201
  **The taken-over call is offered whatever break the lead is on, and counted like any other.** A
202
202
  lead working as lead alone is on a break of a working kind, and the provider assigns the call
203
203
  regardless: it is the one task a break in effect may hold (`break.on-break.tasks` allows it, and
204
- nothing else). It is a call landing on the lead's desk, so it counts against their capacity as
204
+ nothing else). It is a call landing on the lead's computer, so it counts against their capacity as
205
205
  every call does, with no exemption: a lead at capacity cannot take over, and the provider answers
206
206
  `failed`. The other conditions are that the lead is not already on another call and their voice
207
207
  channel is free. A lead with the team feature off cannot take over, since they have no member's
@@ -229,7 +229,7 @@ Lead and member alike are `UserId`s of this provider, so an adapter publishing t
229
229
  ### Listening to a call
230
230
 
231
231
  A lead may listen to a member's call without being asked -- to coach, to check quality, to step in
232
- when it goes wrong. It is a team act naming the member, and no task on the lead's desk carries it:
232
+ when it goes wrong. It is a team act naming the member, and no task on the lead's computer carries it:
233
233
  the lead's view of the call is the member's task on the team member list, with its room and its
234
234
  history. The three modes determine who hears the lead:
235
235
 
@@ -296,7 +296,7 @@ listens through it.
296
296
  no trace of the lead: not on `onCall`, not in the record. Whether coaching is announced to the
297
297
  agent is the platform's business and travels on the audio, not on this wire. In `join-call`, and
298
298
  on a `join` answering a request, the lead is heard by everyone and is in the room: the task's
299
- `onCall` carries them as an `agent` by user id, on the member's desk and on every lead's copy of
299
+ `onCall` carries them as an `agent` by user id, on the member's computer and on every lead's copy of
300
300
  the task alike, and `leave` takes the entry off as it takes the channel off
301
301
  (`team.member.listening.heard`).
302
302
 
package/guide/phone.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # `@xema/omni-protocol`: The phone
2
2
 
3
- How the agent hears the call: softphone and desk phone, the station and its headset, opening the audio, the microphone and the record. Part of the contract in `guide.md`, which holds the terms, the shapes and the rules every file here relies on; a reference in bold names the file it points into where that is not this one.
3
+ How the agent hears the call: softphone and hardphone, the station and its headset, opening the audio, the microphone and the record. Part of the contract in `guide.md`, which holds the terms, the shapes and the rules every file here relies on; a reference in bold names the file it points into where that is not this one.
4
4
 
5
5
  ## Real-time audio
6
6
 
7
7
  Every voice provider has audio: `channel: "voice"` says audio exists. Where the agent hears it
8
8
  depends on the `phone` the agent application selected at authentication and connect from the manifest's
9
- `phones`. On a softphone, audio lands in Omni; on a desk phone, it lands on the handset and Omni
9
+ `phones`. On a softphone, audio lands in Omni; on a hardphone, it lands on the handset and Omni
10
10
  opens no audio. See **How the agent hears the call**. Audio transitions are voice-only;
11
11
  chat and email publish none (`event.audio.channel`, `stream.taskAudio.channel`).
12
12
 
@@ -34,7 +34,7 @@ what failed, and reports. It never decides for the adapter what a missing microp
34
34
  **The agent application also guarantees, and a promise the provider cannot see is not one it can rely on.**
35
35
  Two of this contract's obligations fall on the agent application rather than the provider — honouring a task
36
36
  browser's `urlVisibility`, and taking a `consent` offer only on the person's own press — and more
37
- than one desk speaks this contract: a browser and a native application differ in what they can
37
+ than one agent computer speaks this contract: a browser and a native application differ in what they can
38
38
  reach, and a provider never branches on which it is talking to, only on what it has declared —
39
39
  here, and in `host.mute` (see **The station is the agent application's**). So `ConnectContext.host.guarantees` says which promises the
40
40
  connected agent application makes, declared once per connection, presence being the guarantee exactly as it is
@@ -44,6 +44,7 @@ the permission everywhere else:
44
44
  | --- | --- |
45
45
  | `browserUrlVisibility` | Every task browser's `urlVisibility` is honoured in this agent application's chrome, tab by tab. A provider that would send a caller's number in a URL checks this first and tokenises where the promise is absent. |
46
46
  | `personConsent` | A `consent` offer is accepted only by the person's own explicit act, never on their behalf. A provider whose work may only be taken by a human checks this first and does not offer it where the promise is absent. |
47
+ | `muteUnavailableOnHold` | The agent application's Mute is its own control on any call and is never offered while the task is `paused`: a mute standing when a hold begins stands through it, and the agent lifts it after resume. Held to the login's phone at connect: required of a softphone login's agent application, whose microphone it is (`host.guarantee.muteUnavailableOnHold.required`), and refused of a hardphone login's, whose mute is the handset's (`.unexpected`). So an agent application that cannot control its mute fails at login, not on a call. |
47
48
 
48
49
  A guarantee the agent application does not make is an absent key, never `false` — `validateHostGuarantees`
49
50
  refuses a false one, as it refuses a name this contract does not list.
@@ -64,7 +65,7 @@ is the one that knows whether an agent without a microphone, or without a speake
64
65
  The agent application's own obligations here — asking at connect, never publishing `not-asked` when it does,
65
66
  publishing a state and not a flicker — are Omni's tests' to hold. `testAdapter` holds the
66
67
  other side: it validates the shape of whatever agent application a test hands the adapter, requires `audio` on
67
- a softphone login and none elsewhere -- not on a desk phone, not off voice
68
+ a softphone login and none elsewhere -- not on a hardphone, not off voice
68
69
  (`context.host.audio.required` / `.unexpected`), holds `host.mute` to the same line (`host.mute.required`
69
70
  / `.unexpected`, `host.mute` for a third word) -- and refuses a voice adapter that never asked the
70
71
  agent application anything (`connection.host.consulted`), and one that subscribed to nothing will never hear of a
@@ -105,14 +106,14 @@ a return.
105
106
  ### How the agent hears the call
106
107
 
107
108
  A voice platform can put an agent on a **softphone**, where the call's audio lands in the agent application
108
- and Omni owns the microphone and the playback, or on a **desk phone**, a handset on the platform's
109
+ and Omni owns the microphone and the playback, or on a **hardphone**, a handset on the platform's
109
110
  switch that the platform rings, where the agent application owns no audio and only shows the call. Which of
110
111
  these a platform can do is a fact about the platform, and which one a login is on is a choice the
111
112
  agent application makes for that agent -- so the manifest declares and the agent application chooses.
112
113
 
113
114
  ```ts
114
115
  // Manifest: what the platform can do
115
- phones: ["softphone", "deskPhone"]
116
+ phones: ["softphone", "hardphone"]
116
117
  // The agent application, at authentication and again at connect: which one this login is on
117
118
  { phone: "softphone" }
118
119
  ```
@@ -122,37 +123,37 @@ A voice manifest lists its `phones` and any other channel lists none (`manifest.
122
123
  and one the manifest listed (`context.phone.required`, `.unexpected`, `.unsupported`). Everything
123
124
  about audio then follows the phone rather than the channel: on a softphone the agent application reports its
124
125
  audio, the adapter implements `openAudio`, and `task-audio-started` is the word to open it; on a
125
- desk phone the agent application reports no audio, opens nothing, and `task-audio-started` still marks the
126
- moment the call is live so the desk shows it, with the sound on the handset. A platform that lists
127
- `deskPhone` alone never implements `openAudio`; one that lists `softphone` always does.
126
+ hardphone the agent application reports no audio, opens nothing, and `task-audio-started` still marks the
127
+ moment the call is live so the agent computer shows it, with the sound on the handset. A platform that lists
128
+ `hardphone` alone never implements `openAudio`; one that lists `softphone` always does.
128
129
 
129
130
  **The mode comes from the agent application; the status comes from the provider.** The agent application knows which kind
130
131
  of station the agent signed in at, because the person chose it, and nothing else can know that.
131
132
  The provider knows whether that station can carry a call right now -- whether a handset is
132
133
  registered -- which an agent application in a browser cannot see. So the agent application's `phone` selects the branch, and
133
134
  the provider's own knowledge of the device decides readiness within it. A provider never overrides
134
- the agent application's declaration from its device record: treating a desk-phone login as a softphone because
135
+ the agent application's declaration from its device record: treating a hardphone login as a softphone because
135
136
  the handset is momentarily unregistered, and demanding a microphone of it, is the reading this
136
137
  sentence exists to refuse. What the provider does when the handset is not registered is what it
137
138
  does for any station that cannot take a call -- hold the agent not-ready and say why.
138
139
 
139
- **On a desk-phone login the agent application never calls `openAudio`.** There is no stream to hand over and
140
+ **On a hardphone login the agent application never calls `openAudio`.** There is no stream to hand over and
140
141
  no audio to attach; an agent application that calls it anyway is in error, and an adapter that receives the call
141
142
  answers `unavailable` with a non-retryable failure, since waiting changes nothing about a station
142
143
  that is a telephone. The harness requires no `openAudio` of such an adapter and never calls it.
143
144
 
144
- **Which handset a desk-phone login rings is the platform's configuration for that agent**, and
145
+ **Which handset a hardphone login rings is the platform's configuration for that agent**, and
145
146
  this wire never asks the agent for it: an agent application declares `phone` and nothing more. What a platform
146
147
  asks on surfaces of its own is its own decision.
147
148
 
148
149
  **A declared phone the platform does not permit for this agent is a login that cannot be
149
150
  established.** The manifest says what the platform can do; the agent's record, kept by an
150
151
  administrator, says what this agent is configured for, and the two can disagree with the agent application's
151
- declaration -- a softphone declared for an agent whose record says desk phone. Honouring that
152
+ declaration -- a softphone declared for an agent whose record says hardphone. Honouring that
152
153
  declaration on a switch that allows one registration per endpoint would evict the handset: the
153
154
  agent's phone stops ringing and their calls land in a tab, and nobody is told. So the provider
154
155
  refuses the login at authentication, with `omni.phone-not-permitted` and a message the agent application shows
155
- -- "this agent is configured for a desk phone" -- and refusing is correct, not an override of the
156
+ -- "this agent is configured for a hardphone" -- and refusing is correct, not an override of the
156
157
  agent application. It is a refusal, never a negotiation afterwards and never a quiet substitution, and it is
157
158
  never retryable: trying again does not reconfigure the agent, and an agent application validating the answer
158
159
  (`validateAuthenticationResult`) refuses a phone refusal marked otherwise
@@ -218,7 +219,7 @@ changes, and every softphone agent application can do it. A *station* mute silen
218
219
  the operating system: every application on the machine goes quiet, the system shows it, and a
219
220
  headset that follows the system follows it. Only a native agent application can do it. `Host.mute` says which
220
221
  this agent application does -- `stream` or `station` -- stated on a softphone login, where the agent application holds the
221
- microphone, and absent on a desk phone and off voice (`host.mute.required` / `.unexpected`). A
222
+ microphone, and absent on a hardphone and off voice (`host.mute.required` / `.unexpected`). A
222
223
  browser says `stream`. A native agent application says whichever it does. Nothing on the wire says what kind of
223
224
  application the agent application is; a provider reads only what the agent application declared.
224
225
 
@@ -232,7 +233,15 @@ mute through the capture track's muted state, read-only, and cannot lift it; a n
232
233
  the endpoint and can clear an operating-system mute. A hardware slider is nobody's to clear.
233
234
 
234
235
  **The record carries the same word.** A `muted` interaction leg is a period the agent could not be
235
- heard, and the record exists so that period is not a hole. The agent application reports every such period
236
+ heard, and the record exists so that period is not a hole. **The Mute waits for resume.** On a
237
+ softphone the agent application's own Mute is unavailable while the task is `paused`, as it
238
+ promised at login (`muteUnavailableOnHold`): mute then hold is ordinary, and the muted leg runs on
239
+ across the held one; hold then mute is not, and a `muted` leg with `mutedBy: "host"` beginning on a
240
+ paused task is held back by the agent application (`historyReport.muted.held`) and refused by a
241
+ provider that receives one anyway. The test sends one past the validator while the task is held
242
+ and names an adapter that records it (`test.recordStep.held`). A station mute the agent
243
+ application observes on hold -- the headset's slider, the operating system -- is a fact, reported
244
+ with `mutedBy: "station"`, and stands. The agent application reports every such period
236
245
  through `recordStep` -- its own Mute, and a station mute it observed during a call -- with
237
246
  `mutedBy` saying whose the silence was, and the provider writes the word into the entry
238
247
  (`task.history.mutedBy`). The report names no agent because the agent application has exactly one, and
@@ -257,7 +266,7 @@ as by a click. What a call-control headset sends, and what becomes of it:
257
266
  | --- | --- | --- | --- |
258
267
  | Mute button | The headset, on the HID Telephony usage page: a Phone Mute report on the press, a Mute LED the agent application writes back | A press of the agent application's Mute, performed the agent application's way; the LED follows the agent application's state, so button, light and control are one state with one owner | The `muted` leg, `mutedBy: "host"` |
259
268
  | Hook switch | The headset, HID Telephony | A press of the agent application's Answer or End call, only where the task is in a phase that has one; the off-hook and ring lights follow the task | The existing `answer` and `end-call` commands |
260
- | Flash, redial, speed dial | Older headsets and desk-phone style devices | Flash is Hold and Resume where the task offers `hold`; redial and speed dial map to nothing on a desk that never redials, and are ignored | Nothing new |
269
+ | Flash, redial, speed dial | Older headsets and hardphone style devices | Flash is Hold and Resume where the task offers `hold`; redial and speed dial map to nothing on an agent computer that never redials, and are ignored | Nothing new |
261
270
  | Volume up and down | The headset's own amplifier, or the operating system through the consumer-control keys | Nothing: the device and the system handle it | Nothing, except that a speaker at nought is `audio.output.flowing: false` where the agent application can know it |
262
271
  | Microphone gain and level | The operating system, the headset's own boost | A level meter, so the agent can see they are heard | Nothing: a level is a flicker, not a state |
263
272
  | Hardware or operating-system mute | A slider on the headset, the system's input mute | Observes it, publishes `flowing: false, mutedBy: "station"`, records the leg during a call, and tells the agent which it is where it knows -- headset or system -- and what to do; an agent application whose mute is `station` clears a system mute itself, a browser can only say so | The report and the leg |
@@ -279,7 +288,7 @@ There are two views of a call, and the contract carries both. The task side says
279
288
  the agent's work and where each stands: the phase, the audio, the room. The phone side is the
280
289
  device: whether it can take a call at all, its own mute, and the calls on it, which exist whether
281
290
  or not a task is behind them -- an internal call on the extension, a lead's listening leg, a call
282
- the platform put on the phone that the desk never saw as a task. The host's report covers neither:
291
+ the platform put on the phone that the agent computer never saw as a task. The host's report covers neither:
283
292
  it says what the station has, a microphone and a speaker, and cannot say whether the phone is
284
293
  registered. The platform sees the phone, so this is the provider's to publish, as `Snapshot.phone`
285
294
  and `phone-updated`, from a manifest that declares `phoneStatus` (`snapshot.phone.required`,
@@ -287,14 +296,14 @@ and `phone-updated`, from a manifest that declares `phoneStatus` (`snapshot.phon
287
296
 
288
297
  ```ts
289
298
  // a conference in progress on alloc-42 -- one channel, since the bridge mixes -- with alloc-43 parked
290
- const busy: PhoneState = { phone: "deskPhone", status: "ready", muted: true, channels: [
299
+ const busy: PhoneState = { phone: "hardphone", status: "ready", muted: true, channels: [
291
300
  { state: "active", since: "2026-09-12T10:30:04Z", assignmentId: "alloc-42" },
292
301
  { state: "held", since: "2026-09-12T10:35:20Z", assignmentId: "alloc-43" },
293
302
  ] };
294
- // an internal call on the extension the desk never saw as a task
295
- const internal: PhoneState = { phone: "deskPhone", status: "ready", channels: [{ state: "active", since: "2026-09-12T11:02:00Z" }] };
296
- // a desk phone the platform lost
297
- const down: PhoneState = { phone: "deskPhone", status: "unregistered", since: "2026-09-12T10:41:00Z", channels: [] };
303
+ // an internal call on the extension the agent computer never saw as a task
304
+ const internal: PhoneState = { phone: "hardphone", status: "ready", channels: [{ state: "active", since: "2026-09-12T11:02:00Z" }] };
305
+ // a hardphone the platform lost
306
+ const down: PhoneState = { phone: "hardphone", status: "unregistered", since: "2026-09-12T10:41:00Z", channels: [] };
298
307
  ```
299
308
 
300
309
  **The device.** `status` is the phone itself: `ready` is registered and usable, idle or busy, and
@@ -320,12 +329,12 @@ members are on the task's `onCall`, never repeated here. Each channel is `ringin
320
329
  the two views agree** (`phone.channel.task`): `active` with the task at work and its audio
321
330
  started, `held` with the task `paused`, `ringing` with the task `pending` or its party ringing on
322
331
  `onCall`; and a task with its audio started has a channel (`phone.channel.missing`), since the
323
- phone carries every call the desk is on. A channel naming no task is the phone's alone, and the
324
- desk shows it as a call it cannot act on.
332
+ phone carries every call the agent computer is on. A channel naming no task is the phone's alone, and the
333
+ agent computer shows it as a call it cannot act on.
325
334
 
326
335
  **The mute is the phone's, and it silences whatever is active.** It is one flag on the phone, not
327
336
  a property of a channel: whichever channel is active is silent while it is set, and the held
328
- channels are unaffected. Who owns it follows the phone. On a desk phone the mute button is the
337
+ channels are unaffected. Who owns it follows the phone. On a hardphone the mute button is the
329
338
  handset's, and the platform observes it or does not: `muted: true` where it does, absent where it
330
339
  does not, never invented. On a softphone the microphone is the host's, its mute is the host's
331
340
  report as **The station is the agent application's** sets out, and nothing the provider publishes
@@ -334,6 +343,6 @@ moves it: `muted` on a softphone's state is the platform echoing the host, and i
334
343
  never the live flag.
335
344
 
336
345
  **The lead sees the member's phone as the member does.** The member on the team member list
337
- carries the same `PhoneState`, republished with the member on every change, so a desk phone that
346
+ carries the same `PhoneState`, republished with the member on every change, so a hardphone that
338
347
  is down, or a call on it that is no task, shows the same on both screens, and neither derives it
339
348
  from anything else.
package/guide/queue.md CHANGED
@@ -14,7 +14,7 @@ the lined-up call, and the release.
14
14
  // the login declares it, as it declares breaks
15
15
  { status: "authenticated", identity: {...}, capabilities: { breaks: true, nextCall: true } }
16
16
 
17
- // 1. The ask. The agent presses Next call during the call or the wrap; the desk offers the button
17
+ // 1. The ask. The agent presses Next call during the call or the wrap; the agent computer offers the button
18
18
  // when it sees fit -- past the midpoint of the handling time is one way.
19
19
  await connection.requestNextCall()
20
20
  // -> { status: "requested" }: the provider holds the ask; nothing is promised
@@ -41,7 +41,7 @@ await connection.releaseLinedUp()
41
41
  **The ask lives only as long as its purpose.** It needs an assignment at work to be next after,
42
42
  so an idle agent has nothing to press (`snapshot.nextCall.idle`), and the provider clears it on
43
43
  its own when that assignment ends, when a call is lined up to meet it, and when the agent
44
- withdraws it with `cancelNextCall()`. The desk never keeps it past any of those. `requested` says
44
+ withdraws it with `cancelNextCall()`. The agent computer never keeps it past any of those. `requested` says
45
45
  the provider holds the ask, not that a call will come: a queue may be empty.
46
46
 
47
47
  **The queue lives within capacity, and never beside a break.** The ask and the lined-up call are
@@ -50,13 +50,13 @@ promises to assign, and a promise the provider can no longer keep goes:
50
50
  - **Told `count: 0`**, host-stopped, the provider assigns nothing, so it clears the ask and lets the
51
51
  lined-up call go back to the queue for anyone; an entry published after that is refused
52
52
  (`stream.nextCall.stopped`, `stream.linedUp.stopped`). The queue is per provider, as the ask
53
- was made on that provider's call, and the desk's division of capacity is what it was.
53
+ was made on that provider's call, and the agent computer's division of capacity is what it was.
54
54
  - **A break wins.** An agent who has asked for a break, been granted one starting after this
55
55
  task, or been put on one has said the opposite of "line up my next call", and the two never
56
56
  stand together: while a break is in flight or in effect -- any status but `not-requested` --
57
57
  `requestNextCall()` is refused with `omni.unavailable`, and a break arriving after a
58
58
  call was lined up drops the call, the caller going back to the queue for anyone
59
- (`snapshot.nextCall.break`, `snapshot.linedUp.break`). The desk shows Next call or the break
59
+ (`snapshot.nextCall.break`, `snapshot.linedUp.break`). The agent computer shows Next call or the break
60
60
  controls, never both.
61
61
  - **A lined-up call needs an agent at work** as the ask does: a call lined up for an agent with
62
62
  nothing at work is an offer that has not been made, and travels as `task-offered`
@@ -65,7 +65,7 @@ promises to assign, and a promise the provider can no longer keep goes:
65
65
  **The lined-up call is not a task, and rides no task event.** Until the offer there is no
66
66
  assignment and nothing to accept, so it has no phase, no capabilities and no history, and it
67
67
  rings nothing: the caller is still in the platform's queue, the phone has no channel for it, and
68
- the desk shows "next for you" and nothing to act on but the release. It becomes a task by the
68
+ the agent computer shows "next for you" and nothing to act on but the release. It becomes a task by the
69
69
  ordinary `task-offered`, with `acceptance: "automatic"` since the agent asked, and counts against
70
70
  capacity from that moment as any assignment does; the `queued` step in its history carries the
71
71
  caller's whole wait. One at a time: the phone only ever takes the next one, so `linedUp` is an
@@ -79,7 +79,7 @@ the platform's routing: releasing one call, or withdrawing the ask, ends nothing
79
79
  and the provider may line a repeat caller up again.
80
80
 
81
81
  **Letting go is the provider's say.** `release: true` on the lined-up call grants the agent Let
82
- go; absent, the platform means them to take the call and the desk offers nothing
82
+ go; absent, the platform means them to take the call and the agent computer offers nothing
83
83
  (`linedUp.release`). `releaseLinedUp()` against an entry without it is refused with
84
84
  `omni.capability-not-enabled`, as any control the provider did not grant. `cancelNextCall()`
85
85
  withdraws the ask alone: once a call is lined up the ask is met, and what happens to that call is
package/guide/voice.md CHANGED
@@ -37,7 +37,7 @@ is work, not a cancellation. A `preview` task therefore needs a manifest that sa
37
37
 
38
38
  **Preparation and trigger ownership are per task.** Unlimited preparation omits both
39
39
  `previewEndsInSeconds` and `atDeadline`: only an agent pressing Call starts dialing. Fixed
40
- preparation carries the seconds the provider says are left, counted down on the desk from the
40
+ preparation carries the seconds the provider says are left, counted down on the agent computer from the
41
41
  publication that carried them and restated on every later one, and exactly one trigger owner:
42
42
 
43
43
  | Declaration | At preparation end |
@@ -82,7 +82,7 @@ Unsupported source correlation/outcome/audio evidence remains an integration blo
82
82
 
83
83
  **Drop both fields when the phase moves.** A provider that builds the `in-progress` task by
84
84
  spreading the `preview` one carries `previewEndsInSeconds` and `atDeadline` with it, and the agent application refuses
85
- the update (`task.preview.deadline.unexpected`): the desk keeps the task as it last stood, and the
85
+ the update (`task.preview.deadline.unexpected`): the agent computer keeps the task as it last stood, and the
86
86
  provider is told through `refused` exactly which rule, so the state that looked right on its side
87
87
  is named on its side. The task past preview has no deadline to wait for, so it carries neither
88
88
  field.
@@ -224,7 +224,7 @@ capabilities: {
224
224
 
225
225
  | Field | Contract |
226
226
  | --- | --- |
227
- | `destinations` | The items the control offers, at least one, with unique `id` values. Each is a button or a menu item on the desk. |
227
+ | `destinations` | The items the control offers, at least one, with unique `id` values. Each is a button or a menu item on the agent computer. |
228
228
  | `id` | What Omni sends as `destinationId` on a `conference` command, and what the provider executes. |
229
229
  | `label` | What the agent reads. |
230
230
 
@@ -260,7 +260,7 @@ provider decides: another IVR, a queue, a survey, or the end of the call. Gated
260
260
 
261
261
  **Never from hold.** An `end-call` while the task is `paused` would leave the caller in the hold
262
262
  with nobody coming back to them, and the provider's path for a caller who continues never begins.
263
- So the caller is taken off hold first: the desk holds the command back while the task is `paused`
263
+ So the caller is taken off hold first: the agent computer holds the command back while the task is `paused`
264
264
  (`command.endCall.held`) and shows End call disabled on hold, and a provider that receives it
265
265
  anyway answers `failed`. Resume, then end. `terminate-call` needs no such gate: it ends the
266
266
  caller's channel with the rest, held or not, and nobody is left waiting.
@@ -270,7 +270,7 @@ the caller's, any colleague the agent added, and anyone else on the call. Nobody
270
270
  line. Gated by `terminateCall`, a separate permission, since ending a customer's call is a
271
271
  different thing from putting my own side down.
272
272
 
273
- Both are commands to the provider through `execute`, and nothing happens on the desk until the
273
+ Both are commands to the provider through `execute`, and nothing happens on the agent computer until the
274
274
  provider reports it: the agent's audio ends on `task-audio-ended`, the task moves to `completing`,
275
275
  any wrap allowance runs, and the agent completes. Neither is `task-ended`, and `complete` is
276
276
  neither of them. Both capabilities are the queue's to grant and a level's to lock, and both may
@@ -362,7 +362,7 @@ those named here: a statement about the switch, sent instead of the nearest caus
362
362
  `reason` is the switch's own words, optional, and shown to the agent attributed to the switch rather
363
363
  than to Omni. The two are different things and may travel together: a switch can say "could not
364
364
  create dialog" in words and still name no cause a code would carry, so `unexplained` with a
365
- `reason` is a dial the switch described but did not classify, and a desk renders the words without
365
+ `reason` is a dial the switch described but did not classify, and an agent computer renders the words without
366
366
  inventing the class.
367
367
 
368
368
  **`assignmentId` is the task the dial was placed on**, resolved from the dial's own identity and never from
@@ -378,7 +378,7 @@ idle dialpad call, which has no task yet -- or whose entry has already left the
378
378
  outcome for a dial nobody placed and no task mentions is what `stream.dialOutcome.unknown` refuses.
379
379
 
380
380
  **`answered` says what happened to the dial; `onCall` says who is in the room.** They are two
381
- claims, and both are true at once when a leg answers and never joins. A desk shows `answered` as the
381
+ claims, and both are true at once when a leg answers and never joins. An agent computer shows `answered` as the
382
382
  dial's conclusion and says "on the call" only when the person appears on `Task.onCall`; the obvious
383
383
  reading of `answered` -- that they are on the line -- is the one it does not make.
384
384
 
@@ -455,7 +455,7 @@ cannot tell ringing from joined says it contains someone who may never arrive. N
455
455
  held (`task.onCall.held.ringing`). A colleague who never answers is a dial that ended: the
456
456
  provider restates the room without the entry, and the agent is back with the customer.
457
457
 
458
- The desk shows a dial as placed on `dialling`, never as reached; shows the person in the room when
458
+ The agent computer shows a dial as placed on `dialling`, never as reached; shows the person in the room when
459
459
  they appear on `onCall`; and shows the outcome, with the switch's reason, against the call it
460
460
  belonged to -- with no retry, since a wrong number is not worth redialling and the decision is the
461
461
  agent's.