@burdenoff/fe-libs 2026.1004.4 → 2026.1004.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/shared/assistant/i18nManifest.d.ts +10 -0
  2. package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
  3. package/dist/shared/assistant/i18nManifest.js +22 -12
  4. package/dist/shared/assistant/index.d.ts +3 -0
  5. package/dist/shared/assistant/index.d.ts.map +1 -1
  6. package/dist/shared/assistant/store.d.ts +10 -0
  7. package/dist/shared/assistant/store.d.ts.map +1 -1
  8. package/dist/shared/assistant/store.js +52 -44
  9. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  10. package/dist/shared/assistant/ui/AssistantChatArea.js +761 -746
  11. package/dist/shared/assistant/ui/AssistantMoreMenu.d.ts.map +1 -1
  12. package/dist/shared/assistant/ui/AssistantMoreMenu.js +58 -56
  13. package/dist/shared/assistant/ui/AssistantSpeechProvider.d.ts.map +1 -1
  14. package/dist/shared/assistant/ui/AssistantSpeechProvider.js +106 -105
  15. package/dist/shared/assistant/ui/composer/AssistantVoiceGraceSelector.d.ts +20 -0
  16. package/dist/shared/assistant/ui/composer/AssistantVoiceGraceSelector.d.ts.map +1 -0
  17. package/dist/shared/assistant/ui/composer/AssistantVoiceGraceSelector.js +39 -0
  18. package/dist/shared/assistant/ui/useVoiceSession.d.ts +35 -2
  19. package/dist/shared/assistant/ui/useVoiceSession.d.ts.map +1 -1
  20. package/dist/shared/assistant/ui/useVoiceSession.js +232 -171
  21. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts +15 -1
  22. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts.map +1 -1
  23. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +121 -101
  24. package/dist/shared/assistant/voice/handsFree.d.ts +160 -0
  25. package/dist/shared/assistant/voice/handsFree.d.ts.map +1 -0
  26. package/dist/shared/assistant/voice/handsFree.js +104 -0
  27. package/dist/shared/assistant/voice/supersededTurns.d.ts +29 -0
  28. package/dist/shared/assistant/voice/supersededTurns.d.ts.map +1 -0
  29. package/dist/shared/assistant/voice/supersededTurns.js +17 -0
  30. package/dist/shared/assistant/voice/useVoiceInput.d.ts +7 -0
  31. package/dist/shared/assistant/voice/useVoiceInput.d.ts.map +1 -1
  32. package/dist/shared/assistant/voice/useVoiceInput.js +13 -10
  33. package/dist/shared/assistant/voice/voiceSession.d.ts +64 -20
  34. package/dist/shared/assistant/voice/voiceSession.d.ts.map +1 -1
  35. package/dist/shared/assistant/voice/voiceSession.js +120 -67
  36. package/dist/shared-assistant.js +206 -203
  37. package/package.json +1 -1
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The turns a person has superseded — the stale-turn guard of hands-free
3
+ * corrections (H2).
4
+ *
5
+ * When someone speaks a correction while the assistant is still PREPARING an
6
+ * answer, the in-flight turn is aborted (`POST /sessions/:id/abort`) and then
7
+ * recorded here. Aborting is best-effort and asynchronous, so the old turn can
8
+ * still deliver something afterwards: its reply landing, its speech starting
9
+ * from the speech feed, its text becoming the "latest reply" the caption and
10
+ * the echo reference are built from. Every one of those paths asks THIS module
11
+ * whether the message belongs to a turn that was superseded, and refuses if so:
12
+ * the late answer never restarts audio, never replaces a caption and never
13
+ * advances the next turn.
14
+ *
15
+ * ★ Module scope on purpose, like `speechFeed`: the publisher (the chat area),
16
+ * the speaker (the speech provider) and the voice session are three components
17
+ * that do not know each other, and the guard has to hold across a remount.
18
+ *
19
+ * ★ Bounded. A session is a handful of turns; the oldest ids are dropped first
20
+ * so a long-lived page cannot grow this without limit, and an id this old can
21
+ * no longer be in flight.
22
+ */
23
+ /** Record that the turn that produced assistant message `messageId` was superseded. */
24
+ export declare function markTurnSuperseded(messageId: string): void;
25
+ /** Was the turn behind `messageId` superseded? Null and undefined never were. */
26
+ export declare function isTurnSuperseded(messageId: string | null | undefined): boolean;
27
+ /** Tests only. */
28
+ export declare function resetSupersededTurnsForTest(): void;
29
+ //# sourceMappingURL=supersededTurns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supersededTurns.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/supersededTurns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAQ1D;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE9E;AAED,kBAAkB;AAClB,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
@@ -0,0 +1,17 @@
1
+ //#region src/shared/assistant/voice/supersededTurns.ts
2
+ var e = 64, t = /* @__PURE__ */ new Set();
3
+ function n(n) {
4
+ for (t.delete(n), t.add(n); t.size > e;) {
5
+ let e = t.values().next();
6
+ if (e.done) break;
7
+ t.delete(e.value);
8
+ }
9
+ }
10
+ function r(e) {
11
+ return typeof e == "string" && t.has(e);
12
+ }
13
+ function i() {
14
+ t.clear();
15
+ }
16
+ //#endregion
17
+ export { r as isTurnSuperseded, n as markTurnSuperseded, i as resetSupersededTurnsForTest };
@@ -31,6 +31,13 @@
31
31
  * - **`stop()` resolves the final transcript** through `onFinalize`, so the
32
32
  * composer can commit exactly once when the user stops.
33
33
  */
34
+ /**
35
+ * Can this browser recognise speech at all? The same test `useVoiceInput`
36
+ * reports as `isSupported`, for surfaces that must decide whether to OFFER a
37
+ * voice setting without mounting the hook (a settings row for a recogniser
38
+ * that does not exist is a control that cannot do anything).
39
+ */
40
+ export declare function isSpeechRecognitionSupported(): boolean;
34
41
  /**
35
42
  * How long to refuse a restart after `recognition.start()` THREW.
36
43
  *
@@ -1 +1 @@
1
- {"version":3,"file":"useVoiceInput.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/useVoiceInput.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AA+DH;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAW5C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED,MAAM,MAAM,eAAe,GACzB,aAAa,GAAG,WAAW,GAAG,eAAe,GAAG,SAAS,GAAG,wBAAwB,GAAG,SAAS,CAAC;AA+BnG,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IACtC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,uEAAuE;IACvE,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,oBAAoB,GAAG,mBAAmB,CAmO5G"}
1
+ {"version":3,"file":"useVoiceInput.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/useVoiceInput.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AA+DH;;;;;GAKG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CAEtD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAW5C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED,MAAM,MAAM,eAAe,GACzB,aAAa,GAAG,WAAW,GAAG,eAAe,GAAG,SAAS,GAAG,wBAAwB,GAAG,SAAS,CAAC;AA+BnG,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IACtC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,uEAAuE;IACvE,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,oBAAoB,GAAG,mBAAmB,CAmO5G"}
@@ -17,11 +17,14 @@ function o() {
17
17
  let e = window;
18
18
  return e.SpeechRecognition ?? e.webkitSpeechRecognition ?? null;
19
19
  }
20
- var s = 2e3, c = 2;
21
- function l(e, t) {
22
- return t - e < s;
20
+ function s() {
21
+ return o() !== null;
23
22
  }
24
- function u(e) {
23
+ var c = 2e3, l = 2;
24
+ function u(e, t) {
25
+ return t - e < c;
26
+ }
27
+ function d(e) {
25
28
  switch (e) {
26
29
  case "not-allowed":
27
30
  case "service-not-allowed": return "not-allowed";
@@ -32,18 +35,18 @@ function u(e) {
32
35
  default: return "unknown";
33
36
  }
34
37
  }
35
- function d({ onFinalize: s, language: d }) {
38
+ function f({ onFinalize: s, language: c }) {
36
39
  let { locale: f } = e(), [p, m] = i(!1), [h, g] = i(!1), [_, v] = i(""), [y, b] = i(null), x = r(null), S = r(0), C = r(-Infinity), w = r(0), T = r(s);
37
40
  n(() => {
38
41
  T.current = s;
39
42
  }, [s]);
40
- let E = o() !== null, D = d ?? a[f] ?? "en-US";
43
+ let E = o() !== null, D = c ?? a[f] ?? "en-US";
41
44
  n(() => () => {
42
45
  x.current?.abort(), x.current = null;
43
46
  }, []);
44
47
  let O = t((e = "manual") => {
45
48
  let t = o();
46
- if (!t || x.current || e === "auto" && l(C.current, performance.now())) return;
49
+ if (!t || x.current || e === "auto" && u(C.current, performance.now())) return;
47
50
  let n = new t();
48
51
  n.continuous = !0, n.interimResults = !0, n.lang = D;
49
52
  let r = S.current;
@@ -57,7 +60,7 @@ function d({ onFinalize: s, language: d }) {
57
60
  t.trim() && T.current(t.trim()), v(n.trim());
58
61
  }, n.onerror = (e) => {
59
62
  if (r !== S.current) return;
60
- let t = u(e.error);
63
+ let t = d(e.error);
61
64
  t !== "no-speech" && b(t);
62
65
  }, n.onend = () => {
63
66
  r === S.current && (x.current = null, g(!1), m(!1), v(""));
@@ -67,7 +70,7 @@ function d({ onFinalize: s, language: d }) {
67
70
  try {
68
71
  n.start();
69
72
  } catch {
70
- C.current = performance.now(), w.current += 1, w.current >= c && b("unknown"), x.current = null, g(!1), m(!1);
73
+ C.current = performance.now(), w.current += 1, w.current >= l && b("unknown"), x.current = null, g(!1), m(!1);
71
74
  return;
72
75
  }
73
76
  x.current = n, w.current = 0, b(null), v("");
@@ -101,4 +104,4 @@ function d({ onFinalize: s, language: d }) {
101
104
  };
102
105
  }
103
106
  //#endregion
104
- export { s as START_RETRY_COOLDOWN_MS, l as startIsCoolingDown, d as useVoiceInput };
107
+ export { c as START_RETRY_COOLDOWN_MS, s as isSpeechRecognitionSupported, u as startIsCoolingDown, f as useVoiceInput };
@@ -46,6 +46,28 @@ export interface VoiceSessionSnapshot {
46
46
  interim: string;
47
47
  /** Why the session stopped, when it stopped abnormally. */
48
48
  error: VoiceSessionError | null;
49
+ /**
50
+ * H2: what the turn in flight was sent as, while there is one ('' otherwise).
51
+ * Kept so a result that is only the recogniser finishing, repeating or
52
+ * revising it is not mistaken for a correction, and so a cumulative result
53
+ * ("<sent words> <new words>") contributes only the new words.
54
+ */
55
+ submitted: string;
56
+ /** H2: when `submitted` was sent (the `at` of the `silence` that sent it). */
57
+ submittedAt: number | null;
58
+ /**
59
+ * H2: the words being collected, or the turn in flight, are a CORRECTION of
60
+ * a turn that was superseded. Cleared when the corrected turn is answered,
61
+ * interrupted or the session ends.
62
+ */
63
+ correcting: boolean;
64
+ /**
65
+ * H2: how many times an in-flight turn has been superseded this session.
66
+ * A counter, not a flag, so the hook can act exactly once per supersession
67
+ * (abort the model turn, withdraw outdated proposals) without the reducer
68
+ * doing anything impure. Reset by `start`.
69
+ */
70
+ superseded: number;
49
71
  }
50
72
  /**
51
73
  * Deliberately does NOT include a "playback blocked" variant. Nothing can
@@ -63,10 +85,13 @@ export type VoiceSessionEvent =
63
85
  type: 'speech';
64
86
  transcript: string;
65
87
  final: boolean;
88
+ /** Wall-clock ms when it was heard — what the H2 trailing-result window is measured with. */
89
+ at?: number;
66
90
  }
67
- /** Nothing heard for `SILENCE_SUBMIT_MS`. */
91
+ /** Nothing heard for the person's grace (`resolveVoiceGraceMs`). */
68
92
  | {
69
93
  type: 'silence';
94
+ at?: number;
70
95
  } | {
71
96
  type: 'reply';
72
97
  text: string;
@@ -116,24 +141,19 @@ export type VoiceSessionEvent =
116
141
  type: 'end';
117
142
  };
118
143
  /**
119
- * How long the user must stop talking before the turn is submitted.
144
+ * How long the user must stop talking before the turn is submitted is a USER
145
+ * PREFERENCE (H1): `DEFAULT_VOICE_GRACE_MS` (2 s), 3 s or 5 s, resolved by
146
+ * `resolveVoiceGraceMs` and applied by `planSubmitTimer` in `./handsFree` —
147
+ * the only place that waits. (`SILENCE_SUBMIT_MS`, which used to live here, is
148
+ * gone: a second constant was a second owner.)
120
149
  *
121
- * Long enough to survive a mid-sentence breath — a farmer describing a problem
122
- * pauses — and short enough that the session does not feel unresponsive. A
123
- * premature send truncates the question, which costs a whole 2-5s round trip to
124
- * recover from.
125
- *
126
- * ★ Raised from 1200ms because 1.2s does not survive an ordinary pause: the
127
- * operator reported being cut off mid-sentence, and the cost is worse than a
128
- * truncated prompt — once the turn is submitted the reducer discards every
129
- * `speech` event outside `listening`, so the rest of the sentence is not
130
- * queued, it is thrown away, and the assistant answers half a question.
131
- *
132
- * The asymmetry is what settles the number: waiting 800ms longer costs a moment
133
- * of silence, while cutting someone off costs the whole round trip AND makes
134
- * them repeat themselves.
150
+ * Why the default is 2 s and not the 1.2 s it started at: 1.2 s does not
151
+ * survive an ordinary pause — once the turn is submitted the reducer discards
152
+ * every `speech` event outside `listening`, so the rest of the sentence is not
153
+ * queued, it is thrown away, and the assistant answers half a question. Waiting
154
+ * 800ms longer costs a moment of silence; cutting someone off costs the whole
155
+ * round trip AND makes them repeat themselves.
135
156
  */
136
- export declare const SILENCE_SUBMIT_MS = 2000;
137
157
  /**
138
158
  * Quiet needed before the pause is SHOWN as a pause.
139
159
  *
@@ -145,7 +165,7 @@ export declare const SILENCE_SUBMIT_MS = 2000;
145
165
  *
146
166
  * Short enough to be seen, long enough that an ordinary breath between words
147
167
  * does not flicker the stage. ★800, not 400: this file already records that
148
- * SILENCE_SUBMIT_MS had to go 1200 -> 2000 because ordinary pauses ran longer
168
+ * the grace had to go 1200 -> 2000 because ordinary pauses ran longer
149
169
  * than expected, so a 400ms threshold sits inside normal inter-clause silence
150
170
  * and would oscillate the stage mid-sentence. Still leaves ~1.2s visible.
151
171
  */
@@ -213,7 +233,14 @@ export declare function isEcho(transcript: string, spokenText: string | null): b
213
233
  * while the phase is `listening`. Leaving it unclaimed meant the NEXT question
214
234
  * found it waiting and spoke the answer to the question the user had cut off.
215
235
  */
216
- export declare function planReplyConsumption(replyId: string | null | undefined, phase: VoiceSessionPhase, consumedReplyId: string | null): {
236
+ export declare function planReplyConsumption(replyId: string | null | undefined, phase: VoiceSessionPhase, consumedReplyId: string | null,
237
+ /**
238
+ * H2: the reply belongs to a turn the person superseded (`isTurnSuperseded`).
239
+ * It is claimed and never advances the session, whatever the phase — a late
240
+ * answer to a question the person has since corrected must not move the
241
+ * turn that REPLACED it out of `thinking`.
242
+ */
243
+ supersededReply?: boolean): {
217
244
  claim: boolean;
218
245
  advance: boolean;
219
246
  };
@@ -265,13 +292,30 @@ export declare function planListeningHold(input: {
265
292
  held: boolean;
266
293
  };
267
294
  /**
268
- * Is the microphone capturing right now?
295
+ * Is the microphone capturing right now — in the sense the AUDIO guards mean?
269
296
  *
270
297
  * False while the assistant speaks, which is the whole point: an open
271
298
  * microphone during playback is what created the feedback loop. False whenever
272
299
  * muted, whatever the phase.
300
+ *
301
+ * ★ Deliberately still `listening` only, though the recogniser now also runs in
302
+ * `thinking` (see `shouldRecognise`). This is what the speech provider is told
303
+ * ("the microphone is open: refuse to auto-speak a reply into it"), and the
304
+ * not-capturing notice is judged by. A correction heard in `thinking` supersedes
305
+ * the turn and returns the phase to `listening`, so a late reply is then refused
306
+ * by exactly this guard — it is not weakened by listening for corrections.
273
307
  */
274
308
  export declare function isCapturing(snapshot: VoiceSessionSnapshot): boolean;
309
+ /**
310
+ * Should the recogniser be RUNNING right now (H2)?
311
+ *
312
+ * While `listening`, and also while the assistant is `thinking`: nothing plays
313
+ * then, so there is no echo to fear, and keeping the microphone open is what
314
+ * lets a person correct themselves without tapping. Closed for the whole of
315
+ * `speaking`, and whenever muted. Barge-in while SPEAKING is a separate step
316
+ * (H3) and is NOT enabled here.
317
+ */
318
+ export declare function shouldRecognise(snapshot: VoiceSessionSnapshot): boolean;
275
319
  /** The orb's visual mode. Kept here so the UI has no state logic of its own. */
276
320
  export declare function orbMode(snapshot: VoiceSessionSnapshot): 'idle' | 'listening' | 'thinking' | 'speaking';
277
321
  //# sourceMappingURL=voiceSession.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"voiceSession.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/voiceSession.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"voiceSession.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/voiceSession.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,21 @@
1
+ import { mergeFinalPhrase as e, planThinkingSpeech as t, stripSubmittedPrefix as n } from "./handsFree.js";
1
2
  //#region src/shared/assistant/voice/voiceSession.ts
2
- var e = 2e3, t = 800, n = 1500, r = 500;
3
- function i(e) {
3
+ var r = 800, i = 1500, a = 500;
4
+ function o(e) {
4
5
  return e.trim().length > 0;
5
6
  }
6
- function a(e) {
7
+ function s(e) {
7
8
  return `${e.pending} ${e.interim}`.replace(/\s+/g, " ").trim();
8
9
  }
9
- var o = {
10
+ var c = {
10
11
  text: "",
11
12
  at: null
12
- }, s = (e) => e ? e.split(" ").length : 0;
13
- function c(e, t, n) {
14
- let r = a(t);
15
- if (!r) return o;
13
+ }, l = (e) => e ? e.split(" ").length : 0;
14
+ function u(e, t, n) {
15
+ let r = s(t);
16
+ if (!r) return c;
16
17
  let i = r.toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, " ").trim();
17
- return i === e.text || e.text.startsWith(i) ? e : t.interim.trim() === "" && s(i) <= s(e.text) ? {
18
+ return i === e.text || e.text.startsWith(i) ? e : t.interim.trim() === "" && l(i) <= l(e.text) ? {
18
19
  text: i,
19
20
  at: e.at
20
21
  } : {
@@ -22,120 +23,169 @@ function c(e, t, n) {
22
23
  at: n
23
24
  };
24
25
  }
25
- function l(e) {
26
+ function d(e) {
26
27
  return e.toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
27
28
  }
28
- var u = 3;
29
- function d(e, t) {
29
+ var f = 3;
30
+ function p(e, t) {
30
31
  if (!t) return !1;
31
- let n = l(e);
32
- return n.length === 0 ? !0 : n.split(" ").length < u ? !1 : ` ${l(t)} `.includes(` ${n} `);
32
+ let n = d(e);
33
+ return n.length === 0 ? !0 : n.split(" ").length < f ? !1 : ` ${d(t)} `.includes(` ${n} `);
33
34
  }
34
- function f(e, t, n) {
35
+ function m(e, t, n, r = !1) {
35
36
  return !e || e === n ? {
36
37
  claim: !1,
37
38
  advance: !1
39
+ } : r ? {
40
+ claim: !0,
41
+ advance: !1
38
42
  } : {
39
43
  claim: !0,
40
44
  advance: t === "thinking"
41
45
  };
42
46
  }
43
- var p = Object.freeze({
47
+ var h = Object.freeze({
44
48
  phase: "idle",
45
49
  muted: !1,
46
50
  pending: "",
47
51
  interim: "",
48
- error: null
49
- });
50
- function m(e, t, n = null) {
51
- if (t.type === "start") return {
52
- ...p,
52
+ error: null,
53
+ submitted: "",
54
+ submittedAt: null,
55
+ correcting: !1,
56
+ superseded: 0
57
+ }), g = {
58
+ submitted: "",
59
+ submittedAt: null,
60
+ correcting: !1
61
+ };
62
+ function _(e, n, r) {
63
+ if (p(n.transcript, r)) return e;
64
+ let i = t({
65
+ transcript: n.transcript,
66
+ submitted: e.submitted,
67
+ sinceSubmitMs: n.at !== void 0 && e.submittedAt !== null ? n.at - e.submittedAt : null
68
+ });
69
+ if (i.kind === "ignore") return e;
70
+ let a = i.text.replace(/\s+/g, " ").trim();
71
+ return {
72
+ ...e,
73
+ phase: "listening",
74
+ correcting: !0,
75
+ superseded: e.superseded + 1,
76
+ pending: n.final ? a : "",
77
+ interim: n.final ? "" : a
78
+ };
79
+ }
80
+ function v(t, r, i = null) {
81
+ if (r.type === "start") return {
82
+ ...h,
53
83
  phase: "listening"
54
84
  };
55
- if (t.type === "end") return {
56
- ...e,
85
+ if (r.type === "end") return {
86
+ ...t,
87
+ ...g,
57
88
  phase: "ended",
58
89
  pending: "",
59
90
  interim: "",
60
91
  error: null
61
92
  };
62
- if (e.phase === "ended") return e;
63
- if (t.type === "fail") return {
64
- ...e,
93
+ if (t.phase === "ended") return t;
94
+ if (r.type === "fail") return {
95
+ ...t,
96
+ ...g,
65
97
  phase: "ended",
66
98
  pending: "",
67
99
  interim: "",
68
- error: t.error
100
+ error: r.error
69
101
  };
70
- switch (t.type) {
102
+ switch (r.type) {
71
103
  case "mute": return {
72
- ...e,
73
- muted: t.muted,
74
- ...t.muted ? {
104
+ ...t,
105
+ muted: r.muted,
106
+ ...r.muted ? {
75
107
  pending: "",
76
108
  interim: ""
77
109
  } : {}
78
110
  };
79
- case "interrupt": return e.phase === "speaking" || e.phase === "thinking" ? {
80
- ...e,
111
+ case "interrupt": return t.phase === "speaking" || t.phase === "thinking" ? {
112
+ ...t,
113
+ ...g,
81
114
  phase: "listening",
82
115
  pending: "",
83
116
  interim: ""
84
- } : e;
85
- case "speech": return e.muted || e.phase !== "listening" || d(t.transcript, n) ? e : t.final ? {
86
- ...e,
87
- pending: `${e.pending} ${t.transcript}`.replace(/\s+/g, " ").trim(),
88
- interim: ""
89
- } : {
90
- ...e,
91
- interim: t.transcript
117
+ } : t;
118
+ case "speech": {
119
+ if (t.muted) return t;
120
+ if (t.phase === "thinking") return _(t, r, i);
121
+ if (t.phase !== "listening" || p(r.transcript, i)) return t;
122
+ let a = t.correcting ? n(r.transcript, t.submitted) : r.transcript;
123
+ if (t.correcting && a === "") return t;
124
+ if (r.final) {
125
+ let n = e(t.pending, a);
126
+ return n === t.pending && t.interim === "" ? t : {
127
+ ...t,
128
+ pending: n,
129
+ interim: ""
130
+ };
131
+ }
132
+ return a === t.interim ? t : {
133
+ ...t,
134
+ interim: a
135
+ };
136
+ }
137
+ case "silence": return t.phase !== "listening" || t.muted || !o(s(t)) ? t : {
138
+ ...t,
139
+ phase: "thinking",
140
+ submitted: s(t),
141
+ submittedAt: r.at ?? null
92
142
  };
93
- case "silence": return e.phase !== "listening" || e.muted || !i(a(e)) ? e : {
94
- ...e,
95
- phase: "thinking"
96
- };
97
- case "reply": return e.phase === "thinking" ? {
98
- ...e,
143
+ case "reply": return t.phase === "thinking" ? {
144
+ ...t,
145
+ ...g,
99
146
  phase: "speaking",
100
147
  pending: "",
101
148
  interim: ""
102
- } : e;
103
- case "reply-audio-started": return e.phase === "thinking" ? {
104
- ...e,
149
+ } : t;
150
+ case "reply-audio-started": return t.phase === "thinking" ? {
151
+ ...t,
152
+ ...g,
105
153
  phase: "speaking",
106
154
  pending: "",
107
155
  interim: ""
108
- } : e;
109
- case "speech-ended": return e.phase === "speaking" ? {
110
- ...e,
156
+ } : t;
157
+ case "speech-ended": return t.phase === "speaking" ? {
158
+ ...t,
159
+ ...g,
111
160
  phase: "listening",
112
161
  pending: "",
113
162
  interim: ""
114
- } : e;
115
- case "answered-locally": return e.phase === "thinking" ? {
116
- ...e,
163
+ } : t;
164
+ case "answered-locally": return t.phase === "thinking" ? {
165
+ ...t,
166
+ ...g,
117
167
  phase: "speaking",
118
168
  pending: "",
119
169
  interim: ""
120
- } : e;
121
- case "announce": return e.phase === "listening" && a(e) === "" ? {
122
- ...e,
170
+ } : t;
171
+ case "announce": return t.phase === "listening" && s(t) === "" ? {
172
+ ...t,
123
173
  phase: "speaking",
124
174
  pending: "",
125
175
  interim: ""
126
- } : e;
127
- default: return e;
176
+ } : t;
177
+ default: return t;
128
178
  }
129
179
  }
130
- function h(e) {
180
+ function y(e) {
131
181
  switch (e.phase) {
132
- case "listening": return a(e) === "" ? "start" : "drop";
182
+ case "listening": return s(e) === "" ? "start" : "drop";
133
183
  case "thinking":
134
184
  case "speaking": return "queue";
135
185
  default: return "drop";
136
186
  }
137
187
  }
138
- function g(e) {
188
+ function b(e) {
139
189
  let { requested: t, held: n, muted: r } = e;
140
190
  return t ? n ? {
141
191
  mute: null,
@@ -154,10 +204,13 @@ function g(e) {
154
204
  held: !1
155
205
  };
156
206
  }
157
- function _(e) {
207
+ function x(e) {
158
208
  return e.muted ? !1 : e.phase === "listening";
159
209
  }
160
- function v(e) {
210
+ function S(e) {
211
+ return e.muted ? !1 : e.phase === "listening" || e.phase === "thinking";
212
+ }
213
+ function C(e) {
161
214
  switch (e.phase) {
162
215
  case "thinking": return "thinking";
163
216
  case "speaking": return "speaking";
@@ -166,4 +219,4 @@ function v(e) {
166
219
  }
167
220
  }
168
221
  //#endregion
169
- export { t as ENDPOINT_GRACE_MS, p as INITIAL_SESSION, n as INTERRUPT_MAX_MS, r as INTERRUPT_MIN_MS, o as NOTHING_HEARD, e as SILENCE_SUBMIT_MS, c as advanceHeardClock, _ as isCapturing, d as isEcho, i as isSubmittable, v as orbMode, g as planListeningHold, f as planReplyConsumption, h as planVoiceAnnouncement, a as spokenSoFar, m as voiceSessionReducer };
222
+ export { r as ENDPOINT_GRACE_MS, h as INITIAL_SESSION, i as INTERRUPT_MAX_MS, a as INTERRUPT_MIN_MS, c as NOTHING_HEARD, u as advanceHeardClock, x as isCapturing, p as isEcho, o as isSubmittable, C as orbMode, b as planListeningHold, m as planReplyConsumption, y as planVoiceAnnouncement, S as shouldRecognise, s as spokenSoFar, v as voiceSessionReducer };