@xema/omni-protocol 0.1.30 → 0.1.31
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/validation.js +10 -1
- package/guide.md +12 -0
- package/package.json +1 -1
package/dist/validation.js
CHANGED
|
@@ -632,6 +632,7 @@ function validateHandlingHistory(value, path, into) {
|
|
|
632
632
|
into.add("task.handlingHistory.shape", path, "handlingHistory must be an array when present");
|
|
633
633
|
return;
|
|
634
634
|
}
|
|
635
|
+
let previous;
|
|
635
636
|
value.forEach((entry, index) => {
|
|
636
637
|
const at = `${path}[${index}]`;
|
|
637
638
|
if (!isPlainObject(entry)) {
|
|
@@ -639,7 +640,15 @@ function validateHandlingHistory(value, path, into) {
|
|
|
639
640
|
return;
|
|
640
641
|
}
|
|
641
642
|
into.oneOf(entry.step, HANDLING_STEPS, "task.handlingHistory.step", `${at}.step`);
|
|
642
|
-
into.timestamp(entry.at, "task.handlingHistory.at", `${at}.at`)
|
|
643
|
+
if (into.timestamp(entry.at, "task.handlingHistory.at", `${at}.at`)) {
|
|
644
|
+
// The record is one entry per occurrence, oldest first: a second hold is a second entry
|
|
645
|
+
// after the first, never a revision of it or an entry filed out of its turn.
|
|
646
|
+
const instant = Date.parse(entry.at);
|
|
647
|
+
if (previous !== undefined && instant < previous) {
|
|
648
|
+
into.add("task.handlingHistory.order", `${at}.at`, "handling steps are oldest first; this entry is earlier than the one before it");
|
|
649
|
+
}
|
|
650
|
+
previous = instant;
|
|
651
|
+
}
|
|
643
652
|
if (entry.seconds !== undefined) {
|
|
644
653
|
// Omitted while a leg is still running. Nought is a claim that it took no time.
|
|
645
654
|
into.require(isDurationSeconds(entry.seconds) && entry.seconds > 0, "task.handlingHistory.seconds", `${at}.seconds`, "seconds must be a positive whole number; omit it while the step is still running");
|
package/guide.md
CHANGED
|
@@ -2260,6 +2260,8 @@ const immediateProviderCompletion = {
|
|
|
2260
2260
|
handlingHistory: [
|
|
2261
2261
|
{ step: "queued", at: "2026-08-21T00:59:00Z", seconds: 41 },
|
|
2262
2262
|
{ step: "answered", at: "2026-08-21T00:59:41Z", by: "a-17" },
|
|
2263
|
+
{ step: "held", at: "2026-08-21T01:02:10Z", seconds: 35, by: "a-17" },
|
|
2264
|
+
{ step: "held", at: "2026-08-21T01:06:48Z", by: "a-17" },
|
|
2263
2265
|
]
|
|
2264
2266
|
```
|
|
2265
2267
|
|
|
@@ -2273,6 +2275,16 @@ It rides in the snapshot and is replaced whole like everything else there.
|
|
|
2273
2275
|
Steps are `queued`, `offered`, `answered`, `held`, `muted`, `transferred`, `conferenced`,
|
|
2274
2276
|
`unanswered`, and each is defined on `TaskHandlingStep`.
|
|
2275
2277
|
|
|
2278
|
+
**The record is one entry per occurrence, oldest first.** Each hold is its own `held` entry — `at`
|
|
2279
|
+
when it began, `seconds` once it ended and omitted while it runs — and a second hold is a second
|
|
2280
|
+
entry after the first, never a revision of it. The same goes for every step: two mutes are two
|
|
2281
|
+
`muted` entries. Order is enforced: an entry earlier than the one before it is refused
|
|
2282
|
+
(`task.handlingHistory.order`). **Handle time is anchored, not restarted.** It runs from the
|
|
2283
|
+
`answered` step's `at` — from the task's first `in-progress` where the provider reports no
|
|
2284
|
+
history — until the task's media ends, and a hold neither pauses nor resets it: the hold's own
|
|
2285
|
+
duration is the `held` entry's `seconds`, and a desk that restarts its counter on resume is
|
|
2286
|
+
counting the wrong thing.
|
|
2287
|
+
|
|
2276
2288
|
`muted` is there because Omni performs the mute rather than the provider — see **Where a command
|
|
2277
2289
|
executes** — so without a step the one participant that keeps the task's record would have no
|
|
2278
2290
|
account of a period the agent could not be heard.
|