@burdenoff/fe-libs 2026.1005.1 → 2026.1005.2

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 (73) hide show
  1. package/dist/shared/assistant/i18nManifest.d.ts +4 -0
  2. package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
  3. package/dist/shared/assistant/i18nManifest.js +4 -0
  4. package/dist/shared/assistant/index.d.ts +16 -0
  5. package/dist/shared/assistant/index.d.ts.map +1 -1
  6. package/dist/shared/assistant/speech/browserSpeechEngine.d.ts.map +1 -1
  7. package/dist/shared/assistant/speech/browserSpeechEngine.js +46 -45
  8. package/dist/shared/assistant/speech/hostedTtsSpeechEngine.d.ts.map +1 -1
  9. package/dist/shared/assistant/speech/hostedTtsSpeechEngine.js +80 -79
  10. package/dist/shared/assistant/store.d.ts +3 -0
  11. package/dist/shared/assistant/store.d.ts.map +1 -1
  12. package/dist/shared/assistant/store.js +43 -35
  13. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  14. package/dist/shared/assistant/ui/AssistantChatArea.js +1076 -1074
  15. package/dist/shared/assistant/ui/AssistantMoreMenu.d.ts.map +1 -1
  16. package/dist/shared/assistant/ui/AssistantMoreMenu.js +59 -57
  17. package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.d.ts +17 -0
  18. package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.d.ts.map +1 -0
  19. package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.js +34 -0
  20. package/dist/shared/assistant/ui/useVoiceSession.d.ts +29 -2
  21. package/dist/shared/assistant/ui/useVoiceSession.d.ts.map +1 -1
  22. package/dist/shared/assistant/ui/useVoiceSession.js +247 -213
  23. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +2 -0
  24. package/dist/shared/assistant/voice/handsfree/audioTrackTransport.d.ts +33 -0
  25. package/dist/shared/assistant/voice/handsfree/audioTrackTransport.d.ts.map +1 -0
  26. package/dist/shared/assistant/voice/handsfree/audioTrackTransport.js +98 -0
  27. package/dist/shared/assistant/voice/handsfree/backendStreamTransport.d.ts +34 -0
  28. package/dist/shared/assistant/voice/handsfree/backendStreamTransport.d.ts.map +1 -0
  29. package/dist/shared/assistant/voice/handsfree/backendStreamTransport.js +130 -0
  30. package/dist/shared/assistant/voice/handsfree/bargeIn.d.ts +43 -0
  31. package/dist/shared/assistant/voice/handsfree/bargeIn.d.ts.map +1 -0
  32. package/dist/shared/assistant/voice/handsfree/bargeIn.js +32 -0
  33. package/dist/shared/assistant/voice/handsfree/captureWorklet.d.ts +47 -0
  34. package/dist/shared/assistant/voice/handsfree/captureWorklet.d.ts.map +1 -0
  35. package/dist/shared/assistant/voice/handsfree/captureWorklet.js +85 -0
  36. package/dist/shared/assistant/voice/handsfree/echoGate.d.ts +140 -0
  37. package/dist/shared/assistant/voice/handsfree/echoGate.d.ts.map +1 -0
  38. package/dist/shared/assistant/voice/handsfree/echoGate.js +198 -0
  39. package/dist/shared/assistant/voice/handsfree/handsFreeController.d.ts +77 -0
  40. package/dist/shared/assistant/voice/handsfree/handsFreeController.d.ts.map +1 -0
  41. package/dist/shared/assistant/voice/handsfree/handsFreeController.js +126 -0
  42. package/dist/shared/assistant/voice/handsfree/handsFreeRuntime.d.ts +15 -0
  43. package/dist/shared/assistant/voice/handsfree/handsFreeRuntime.d.ts.map +1 -0
  44. package/dist/shared/assistant/voice/handsfree/handsFreeRuntime.js +78 -0
  45. package/dist/shared/assistant/voice/handsfree/handsFreeSetting.d.ts +26 -0
  46. package/dist/shared/assistant/voice/handsfree/handsFreeSetting.d.ts.map +1 -0
  47. package/dist/shared/assistant/voice/handsfree/handsFreeSetting.js +25 -0
  48. package/dist/shared/assistant/voice/handsfree/micCapture.d.ts +21 -0
  49. package/dist/shared/assistant/voice/handsfree/micCapture.d.ts.map +1 -0
  50. package/dist/shared/assistant/voice/handsfree/micCapture.js +72 -0
  51. package/dist/shared/assistant/voice/handsfree/playbackReference.d.ts +38 -0
  52. package/dist/shared/assistant/voice/handsfree/playbackReference.d.ts.map +1 -0
  53. package/dist/shared/assistant/voice/handsfree/playbackReference.js +55 -0
  54. package/dist/shared/assistant/voice/handsfree/preRollRing.d.ts +32 -0
  55. package/dist/shared/assistant/voice/handsfree/preRollRing.d.ts.map +1 -0
  56. package/dist/shared/assistant/voice/handsfree/preRollRing.js +34 -0
  57. package/dist/shared/assistant/voice/handsfree/sttTransport.d.ts +94 -0
  58. package/dist/shared/assistant/voice/handsfree/sttTransport.d.ts.map +1 -0
  59. package/dist/shared/assistant/voice/handsfree/sttTransport.js +27 -0
  60. package/dist/shared/assistant/voice/handsfree/useHandsFreeInterrupt.d.ts +33 -0
  61. package/dist/shared/assistant/voice/handsfree/useHandsFreeInterrupt.d.ts.map +1 -0
  62. package/dist/shared/assistant/voice/handsfree/useHandsFreeInterrupt.js +70 -0
  63. package/dist/shared/assistant/voice/handsfree/vad.d.ts +55 -0
  64. package/dist/shared/assistant/voice/handsfree/vad.d.ts.map +1 -0
  65. package/dist/shared/assistant/voice/handsfree/vad.js +41 -0
  66. package/dist/shared/assistant/voice/handsfree/webSpeechTransport.d.ts +3 -0
  67. package/dist/shared/assistant/voice/handsfree/webSpeechTransport.d.ts.map +1 -0
  68. package/dist/shared/assistant/voice/handsfree/webSpeechTransport.js +16 -0
  69. package/dist/shared/assistant/voice/voiceSession.d.ts +9 -0
  70. package/dist/shared/assistant/voice/voiceSession.d.ts.map +1 -1
  71. package/dist/shared/assistant/voice/voiceSession.js +2 -2
  72. package/dist/shared-assistant.js +218 -202
  73. package/package.json +2 -1
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The playback reference (BOFF-8613, H3): the assistant's own output, made
3
+ * available to the capture worklet's second input so the echo gate can meter it
4
+ * on the microphone's clock.
5
+ *
6
+ * Process-wide registry, because the two sides are far apart: the hosted TTS
7
+ * engine creates one `Audio` element per chunk and the capture graph lives in
8
+ * the voice session. With nothing attached (hands-free off, or capture not yet
9
+ * started) `tapPlaybackElement` is a no-op and playback is untouched.
10
+ *
11
+ * When attached, each element is routed
12
+ * element -> MediaElementSource -> gain -> { reference bus, speakers }
13
+ * so the speakers still get the sound and the reference bus gets the same
14
+ * samples. Routing through Web Audio is also what lets `silence()` cut an
15
+ * element's output the same instant (gain 0) rather than at the next media tick.
16
+ *
17
+ * The device `speechSynthesis` voice does not pass through the browser's output
18
+ * graph and cannot be tapped. It reports itself through `setDeviceVoice` so the
19
+ * gate can switch to its no-reference mode; the browser engine calls it.
20
+ */
21
+ export type PlaybackSource = "hosted" | "device" | null;
22
+ export declare function attachPlaybackReference(context: AudioContext, referenceBus: AudioNode): void;
23
+ /**
24
+ * Stop referencing. `closeContext` is run now, or - if a tapped element is
25
+ * still playing through the context - when the last one ends, so muting the
26
+ * microphone never cuts a reply off mid-word.
27
+ */
28
+ export declare function detachPlaybackReference(closeContext: () => void): void;
29
+ /** Route a freshly created playback element through the reference bus. */
30
+ export declare function tapPlaybackElement(element: HTMLMediaElement): void;
31
+ /** Cut every tapped element's output at once (a barge-in). */
32
+ export declare function silencePlaybackReference(): void;
33
+ export declare function setDeviceVoice(speaking: boolean): void;
34
+ /** What is making sound right now, if anything. */
35
+ export declare function activePlaybackSource(): PlaybackSource;
36
+ /** Test seam: forget everything. */
37
+ export declare function resetPlaybackReferenceForTest(): void;
38
+ //# sourceMappingURL=playbackReference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playbackReference.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/playbackReference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;AAkBxD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,YAAY,EACrB,YAAY,EAAE,SAAS,GACtB,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,IAAI,GAAG,IAAI,CAQtE;AAWD,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAmBlE;AAED,8DAA8D;AAC9D,wBAAgB,wBAAwB,IAAI,IAAI,CAQ/C;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAEtD;AAED,mDAAmD;AACnD,wBAAgB,oBAAoB,IAAI,cAAc,CAIrD;AAED,oCAAoC;AACpC,wBAAgB,6BAA6B,IAAI,IAAI,CAKpD"}
@@ -0,0 +1,55 @@
1
+ //#region src/shared/assistant/voice/handsfree/playbackReference.ts
2
+ var e = null, t = null, n = [], r = !1;
3
+ function i(t, n) {
4
+ e = {
5
+ context: t,
6
+ referenceBus: n
7
+ };
8
+ }
9
+ function a(r) {
10
+ if (e = null, n.some((e) => e.active)) {
11
+ t = r;
12
+ return;
13
+ }
14
+ n = [], r();
15
+ }
16
+ function o(e, r) {
17
+ if (e.active = r, r || !t || n.some((e) => e.active)) return;
18
+ let i = t;
19
+ t = null, n = [], i();
20
+ }
21
+ function s(t) {
22
+ let r = e;
23
+ if (r) try {
24
+ let e = r.context.createMediaElementSource(t), i = r.context.createGain();
25
+ e.connect(i), i.connect(r.context.destination), i.connect(r.referenceBus);
26
+ let a = {
27
+ element: t,
28
+ gain: i,
29
+ active: !1
30
+ };
31
+ n.push(a), t.addEventListener("playing", () => o(a, !0));
32
+ for (let e of [
33
+ "pause",
34
+ "ended",
35
+ "error",
36
+ "emptied"
37
+ ]) t.addEventListener(e, () => o(a, !1));
38
+ } catch {}
39
+ }
40
+ function c() {
41
+ for (let e of n) try {
42
+ e.gain.gain.value = 0;
43
+ } catch {}
44
+ }
45
+ function l(e) {
46
+ r = e;
47
+ }
48
+ function u() {
49
+ return n.some((e) => e.active) ? "hosted" : r ? "device" : null;
50
+ }
51
+ function d() {
52
+ e = null, t = null, n = [], r = !1;
53
+ }
54
+ //#endregion
55
+ export { u as activePlaybackSource, i as attachPlaybackReference, a as detachPlaybackReference, d as resetPlaybackReferenceForTest, l as setDeviceVoice, c as silencePlaybackReference, s as tapPlaybackElement };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The pre-roll ring: the last N milliseconds of microphone audio, always
3
+ * filled, never sent (BOFF-8613, H3).
4
+ *
5
+ * Why it exists: confirming that someone has started talking takes about
6
+ * 100 ms by construction (four 20 ms frames plus delivery), and the first
7
+ * word is spoken inside that window. Without the ring the opening of a
8
+ * correction is exactly what is lost. At a confirmed onset the ring is flushed
9
+ * FIRST, then live frames follow.
10
+ *
11
+ * Memory only. `clear()` zeroes every retained frame before dropping it, and
12
+ * is called when the session ends, when the mic is muted and on `pagehide`.
13
+ */
14
+ export declare const DEFAULT_PREROLL_MS = 700;
15
+ export declare const MIN_PREROLL_MS = 500;
16
+ export declare const MAX_PREROLL_MS = 800;
17
+ /** Keep the requested depth inside the range the design allows. */
18
+ export declare function clampPreRollMs(ms: number): number;
19
+ export declare class PreRollRing {
20
+ private readonly frames;
21
+ private head;
22
+ private count;
23
+ readonly capacity: number;
24
+ constructor(depthMs: number, frameMs: number);
25
+ push(frame: Int16Array): void;
26
+ /** The retained frames, oldest first. The frames are not copied. */
27
+ snapshot(): Int16Array[];
28
+ get size(): number;
29
+ /** Zero and drop everything. */
30
+ clear(): void;
31
+ }
32
+ //# sourceMappingURL=preRollRing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preRollRing.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/preRollRing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAK;IAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAO5C,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAM7B,oEAAoE;IACpE,QAAQ,IAAI,UAAU,EAAE;IAUxB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,gCAAgC;IAChC,KAAK,IAAI,IAAI;CAMd"}
@@ -0,0 +1,34 @@
1
+ //#region src/shared/assistant/voice/handsfree/preRollRing.ts
2
+ var e = 700, t = 500, n = 800;
3
+ function r(e) {
4
+ return Number.isFinite(e) ? Math.min(800, Math.max(500, Math.round(e))) : 700;
5
+ }
6
+ var i = class {
7
+ frames;
8
+ head = 0;
9
+ count = 0;
10
+ capacity;
11
+ constructor(e, t) {
12
+ this.capacity = Math.max(1, Math.ceil(r(e) / t)), this.frames = Array(this.capacity).fill(void 0);
13
+ }
14
+ push(e) {
15
+ this.frames[this.head] = e, this.head = (this.head + 1) % this.capacity, this.count < this.capacity && (this.count += 1);
16
+ }
17
+ snapshot() {
18
+ let e = [], t = (this.head - this.count + this.capacity) % this.capacity;
19
+ for (let n = 0; n < this.count; n += 1) {
20
+ let r = this.frames[(t + n) % this.capacity];
21
+ r && e.push(r);
22
+ }
23
+ return e;
24
+ }
25
+ get size() {
26
+ return this.count;
27
+ }
28
+ clear() {
29
+ for (let e of this.frames) e?.fill(0);
30
+ this.frames.fill(void 0), this.head = 0, this.count = 0;
31
+ }
32
+ };
33
+ //#endregion
34
+ export { e as DEFAULT_PREROLL_MS, n as MAX_PREROLL_MS, t as MIN_PREROLL_MS, i as PreRollRing, r as clampPreRollMs };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The STT transport seam (BOFF-8613, H3).
3
+ *
4
+ * Three implementations behind one interface, chosen per session by
5
+ * `selectSttTransport` and never mixed within a session (Chrome Android's OS
6
+ * recogniser and a getUserMedia stream contend for the microphone):
7
+ *
8
+ * - `audio-track` desktop Chrome >= 135: `SpeechRecognition.start(track)`
9
+ * fed OUR echo-cancelled track (`audioTrackTransport`);
10
+ * - `backend-stream` our gateway WebSocket (`backendStreamTransport`),
11
+ * flagged: the provider API is not enabled today;
12
+ * - `web-speech` the current `webkitSpeechRecognition` path, owned by
13
+ * `useVoiceInput` (`webSpeechTransport`). This is the
14
+ * fallback and what ships today.
15
+ *
16
+ * Every transcript carries `{utteranceId, epoch}`; the controller drops any whose
17
+ * epoch is not current (see `bargeIn.ts`).
18
+ */
19
+ export type SttTransportKind = "audio-track" | "backend-stream" | "web-speech";
20
+ export interface TransportTranscript {
21
+ text: string;
22
+ final: boolean;
23
+ utteranceId: string;
24
+ epoch: number;
25
+ language?: string;
26
+ }
27
+ export type SttErrorCode = "unavailable" | "auth" | "quota" | "upstream" | "closed" | "not-allowed";
28
+ export interface SttTransportError {
29
+ code: SttErrorCode;
30
+ /** The caller may retry once with the audio it still holds. */
31
+ retryable: boolean;
32
+ }
33
+ export interface SttTransportHandlers {
34
+ onTranscript(transcript: TransportTranscript): void;
35
+ onError(error: SttTransportError): void;
36
+ }
37
+ export interface SttAudioGraph {
38
+ context: AudioContext;
39
+ /** The microphone, already routed through our echo-cancelled `getUserMedia` track. */
40
+ micSource: MediaStreamAudioSourceNode;
41
+ track: MediaStreamTrack;
42
+ }
43
+ export interface OpenUtterance {
44
+ utteranceId: string;
45
+ epoch: number;
46
+ /** The pre-roll, oldest first: s16le mono 16 kHz, 20 ms frames. */
47
+ preRoll: readonly Int16Array[];
48
+ }
49
+ export interface SttTransport {
50
+ readonly kind: SttTransportKind;
51
+ /**
52
+ * Who runs the recogniser. `session-hook`: the existing `useVoiceInput` does
53
+ * (this transport only reports capability); `transport`: this object does and
54
+ * the session hook must not start its own.
55
+ */
56
+ readonly recognitionOwner: "transport" | "session-hook";
57
+ /** Whether the words spoken BEFORE the onset was confirmed reach the recogniser. */
58
+ readonly keepsOpeningWords: boolean;
59
+ start(graph: SttAudioGraph | null, language: string, handlers: SttTransportHandlers): Promise<void>;
60
+ openUtterance(utterance: OpenUtterance): void;
61
+ /** A live 16 kHz frame while an utterance is open. */
62
+ pushFrame(frame: Int16Array): void;
63
+ /** The user stopped (VAD hangover): finalise. */
64
+ closeUtterance(utteranceId: string): void;
65
+ /** The utterance was superseded: stop it and stop being billed for it. */
66
+ cancelUtterance(utteranceId: string): void;
67
+ stop(): void;
68
+ }
69
+ export interface TransportEnvironment {
70
+ /** `navigator.userAgent`. */
71
+ userAgent: string;
72
+ hasSpeechRecognition: boolean;
73
+ hasAudioWorklet: boolean;
74
+ /** Flag `voice.fullDuplex` / the test override says the backend stream may be used. */
75
+ backendStreamEnabled: boolean;
76
+ /** A ticket endpoint is configured (the gateway route exists). */
77
+ backendStreamConfigured: boolean;
78
+ }
79
+ /** Chrome (not Edge/Opera/Android) major version, or null. */
80
+ export declare function desktopChromeMajor(userAgent: string): number | null;
81
+ /** `SpeechRecognition.start(audioTrack)` shipped in Chrome 135, desktop only. */
82
+ export declare const AUDIO_TRACK_MIN_CHROME = 135;
83
+ export interface TransportChoice {
84
+ kind: SttTransportKind;
85
+ /** Why, in one phrase, for telemetry and tests. */
86
+ because: string;
87
+ }
88
+ /**
89
+ * Pure choice. Order: the backend stream (when flagged AND configured) is the
90
+ * only route that works on Chrome Android; else the audio-track route on
91
+ * desktop Chrome >= 135; else the current Web Speech path.
92
+ */
93
+ export declare function selectSttTransport(env: TransportEnvironment): TransportChoice;
94
+ //# sourceMappingURL=sttTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sttTransport.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/sttTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAE/E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GACpB,aAAa,GACb,MAAM,GACN,OAAO,GACP,UAAU,GACV,QAAQ,GACR,aAAa,CAAC;AAElB,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,YAAY,CAAC;IACnB,+DAA+D;IAC/D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACpD,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,YAAY,CAAC;IACtB,sFAAsF;IACtF,SAAS,EAAE,0BAA0B,CAAC;IACtC,KAAK,EAAE,gBAAgB,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,WAAW,GAAG,cAAc,CAAC;IACxD,oFAAoF;IACpF,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,KAAK,CACH,KAAK,EAAE,aAAa,GAAG,IAAI,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,aAAa,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9C,sDAAsD;IACtD,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACnC,iDAAiD;IACjD,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,0EAA0E;IAC1E,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,IAAI,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,uFAAuF;IACvF,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kEAAkE;IAClE,uBAAuB,EAAE,OAAO,CAAC;CAClC;AAED,8DAA8D;AAC9D,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAInE;AAED,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,gBAAgB,CAAC;IACvB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,oBAAoB,GAAG,eAAe,CAe7E"}
@@ -0,0 +1,27 @@
1
+ //#region src/shared/assistant/voice/handsfree/sttTransport.ts
2
+ function e(e) {
3
+ if (/Android|Mobile|Edg\/|OPR\/|Firefox|CriOS/.test(e)) return null;
4
+ let t = /Chrome\/(\d+)/.exec(e);
5
+ return t ? Number(t[1]) : null;
6
+ }
7
+ var t = 135;
8
+ function n(t) {
9
+ if (!t.hasAudioWorklet) return {
10
+ kind: "web-speech",
11
+ because: "no-audio-worklet"
12
+ };
13
+ if (t.backendStreamEnabled && t.backendStreamConfigured) return {
14
+ kind: "backend-stream",
15
+ because: "flagged-and-configured"
16
+ };
17
+ let n = e(t.userAgent);
18
+ return t.hasSpeechRecognition && n !== null && n >= 135 ? {
19
+ kind: "audio-track",
20
+ because: "chrome-135-desktop"
21
+ } : {
22
+ kind: "web-speech",
23
+ because: "fallback"
24
+ };
25
+ }
26
+ //#endregion
27
+ export { t as AUDIO_TRACK_MIN_CHROME, e as desktopChromeMajor, n as selectSttTransport };
@@ -0,0 +1,33 @@
1
+ import { VoiceSessionPhase } from '../voiceSession';
2
+ import { FallbackReason } from './handsFreeController';
3
+ import { SttTransportKind } from './sttTransport';
4
+ /** Hidden this long and the microphone is released (and re-opened when visible). */
5
+ export declare const HIDDEN_RELEASE_MS = 30000;
6
+ export type HandsFreeMode =
7
+ /** Setting off, or no live unmuted session: nothing is open. */
8
+ "off"
9
+ /** Hands-free cannot run on this device (no capture, or a phone with no stream transport). */
10
+ | "unavailable" | "starting" | "active"
11
+ /** Gave up; the tap-first Web Speech path is in charge, and says why. */
12
+ | "fallback";
13
+ export interface UseHandsFreeInterruptOptions {
14
+ /** The viewer's setting (or the test override), already resolved. */
15
+ enabled: boolean;
16
+ phase: VoiceSessionPhase;
17
+ muted: boolean;
18
+ language: string;
19
+ /** The user's voice started while the assistant was audible. */
20
+ onBargeIn: () => void;
21
+ onTranscript: (text: string, final: boolean, language: string | undefined) => void;
22
+ }
23
+ export interface HandsFreeState {
24
+ mode: HandsFreeMode;
25
+ transportKind: SttTransportKind | null;
26
+ /** The session hook must NOT start its own recogniser: a transport owns recognition. */
27
+ suppressWebSpeech: boolean;
28
+ fallbackReason: FallbackReason | null;
29
+ /** A barge-in produced no words: show "Say that again, or tap to replay". */
30
+ nothingHeard: boolean;
31
+ }
32
+ export declare function useHandsFreeInterrupt(options: UseHandsFreeInterruptOptions): HandsFreeState;
33
+ //# sourceMappingURL=useHandsFreeInterrupt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHandsFreeInterrupt.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/useHandsFreeInterrupt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAS/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAExC,MAAM,MAAM,aAAa;AACvB,gEAAgE;AAC9D,KAAK;AACP,8FAA8F;GAC5F,aAAa,GACb,UAAU,GACV,QAAQ;AACV,yEAAyE;GACvE,UAAU,CAAC;AAEf,MAAM,WAAW,4BAA4B;IAC3C,qEAAqE;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,iBAAiB,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,EAAE,CACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,KACzB,IAAI,CAAC;CACX;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,aAAa,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACvC,wFAAwF;IACxF,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,6EAA6E;IAC7E,YAAY,EAAE,OAAO,CAAC;CACvB;AAKD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,4BAA4B,GACpC,cAAc,CAsHhB"}
@@ -0,0 +1,70 @@
1
+ import { activePlaybackSource as e } from "./playbackReference.js";
2
+ import { looksLikeHeadset as t, startMicCapture as n } from "./micCapture.js";
3
+ import { createHandsFreeController as r } from "./handsFreeController.js";
4
+ import { chooseTransport as i, createRuntimeTransport as a, isMobileUserAgent as o, readTransportEnvironment as s } from "./handsFreeRuntime.js";
5
+ import { useEffect as c, useMemo as l, useRef as u, useState as d } from "react";
6
+ //#region src/shared/assistant/voice/handsfree/useHandsFreeInterrupt.ts
7
+ var f = 3e4, p = (e) => e === "listening" || e === "thinking" || e === "speaking";
8
+ function m(m) {
9
+ let { enabled: h, phase: g, muted: _ } = m, v = u(m);
10
+ v.current = m;
11
+ let [y, b] = d(null), [x, S] = d(!1), [C, w] = d(!1), [T, E] = d(!1), D = u(!1), O = l(() => {
12
+ let e = s(), t = i(e), n = t.kind === "web-speech" && o(e.userAgent);
13
+ return {
14
+ choice: t,
15
+ supported: e.hasAudioWorklet && !n
16
+ };
17
+ }, []);
18
+ c(() => {
19
+ (g === "idle" || g === "ended") && (b(null), S(!1));
20
+ }, [g]), c(() => {
21
+ if (!h || typeof document > "u") return;
22
+ let e = null, t = () => {
23
+ e !== null && clearTimeout(e), e = null, document.visibilityState === "hidden" ? e = setTimeout(() => w(!0), f) : w(!1);
24
+ };
25
+ return document.addEventListener("visibilitychange", t), () => {
26
+ document.removeEventListener("visibilitychange", t), e !== null && clearTimeout(e);
27
+ };
28
+ }, [h]);
29
+ let k = h && O.supported && p(g) && !_ && y === null && !C;
30
+ c(() => {
31
+ if (!k) return;
32
+ let i = r({
33
+ startCapture: n,
34
+ transport: a(O.choice.kind),
35
+ getSession: () => ({
36
+ phase: v.current.phase,
37
+ muted: v.current.muted
38
+ }),
39
+ getPlaybackSource: e,
40
+ getHeadsetHint: () => D.current,
41
+ language: () => v.current.language,
42
+ onBargeIn: () => {
43
+ S(!1), v.current.onBargeIn();
44
+ },
45
+ onTranscript: (e, t, n) => {
46
+ S(!1), v.current.onTranscript(e, t, n);
47
+ },
48
+ onFallback: b,
49
+ onNothingHeard: () => S(!0),
50
+ isEnabled: () => v.current.enabled
51
+ }), o = !1;
52
+ return i.start().then(() => {
53
+ o || E(!0);
54
+ }), navigator.mediaDevices?.enumerateDevices().then((e) => {
55
+ D.current = t(e.filter((e) => e.kind === "audiooutput").map((e) => e.label));
56
+ }).catch(() => void 0), () => {
57
+ o = !0, i.stop(), E(!1);
58
+ };
59
+ }, [k, O]);
60
+ let A = "off";
61
+ return h && !O.supported ? A = "unavailable" : y === null ? k && (A = T ? "active" : "starting") : A = "fallback", {
62
+ mode: A,
63
+ transportKind: O.supported ? O.choice.kind : null,
64
+ suppressWebSpeech: h && O.supported && O.choice.kind !== "web-speech" && y === null && p(g),
65
+ fallbackReason: y,
66
+ nothingHeard: x
67
+ };
68
+ }
69
+ //#endregion
70
+ export { f as HIDDEN_RELEASE_MS, m as useHandsFreeInterrupt };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Stage A voice-activity detector: energy plus zero-crossing rate, with an
3
+ * adaptive noise floor (BOFF-8613, H3).
4
+ *
5
+ * Always on, in every hands-free session. It is the whole VAD when the optional
6
+ * Silero stage is absent (it is OFF in this change), and it is what the echo
7
+ * gate sits on. Pure: frames in, decisions out, no clock, no DOM.
8
+ *
9
+ * A frame is VOICED when its level is above the noise floor by
10
+ * `voicedAboveFloorDb` (and above an absolute floor), and its zero-crossing
11
+ * rate is in the band speech occupies (a hum is below it, hiss is above).
12
+ * Onset is `onsetFrames` consecutive voiced frames that ALSO pass the echo gate,
13
+ * so the assistant's own voice, which is voiced, can never open an utterance.
14
+ * The segment ends after `hangoverMs` of unvoiced frames.
15
+ */
16
+ export interface VadParams {
17
+ /** Consecutive voiced+gated frames that confirm an onset (4 x 20 ms = 80 ms). */
18
+ onsetFrames: number;
19
+ hangoverMs: number;
20
+ voicedAboveFloorDb: number;
21
+ absFloorDb: number;
22
+ zcrMin: number;
23
+ zcrMax: number;
24
+ /** Frames the noise-floor percentile is taken over (100 x 20 ms = 2 s). */
25
+ floorWindowFrames: number;
26
+ floorPercentile: number;
27
+ frameMs: number;
28
+ }
29
+ export declare const DEFAULT_VAD_PARAMS: Readonly<VadParams>;
30
+ /**
31
+ * The stricter onset used when the playback reference is unavailable (the
32
+ * device `speechSynthesis` voice) or the CPU probe failed: a false barge-in is
33
+ * the most visible failure, so with less evidence ask for more frames.
34
+ */
35
+ export declare const STRICT_ONSET_FRAMES = 6;
36
+ export interface VadFrame {
37
+ rmsDb: number;
38
+ zcr: number;
39
+ }
40
+ export type VadEvent = "onset" | "end" | null;
41
+ export interface VadStep {
42
+ voiced: boolean;
43
+ event: VadEvent;
44
+ inSegment: boolean;
45
+ floorDb: number;
46
+ }
47
+ export interface Vad {
48
+ /** `gatePass`: the echo gate accepts this frame as someone other than the assistant. */
49
+ push(frame: VadFrame, gatePass: boolean): VadStep;
50
+ reset(): void;
51
+ /** Change the number of frames that confirm an onset (strict mode). */
52
+ setOnsetFrames(frames: number): void;
53
+ }
54
+ export declare function createVad(overrides?: Partial<VadParams>): Vad;
55
+ //# sourceMappingURL=vad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vad.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/vad.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,SAAS;IACxB,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,SAAS,CAUjD,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;AAE9C,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,QAAQ,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,GAAG;IAClB,wFAAwF;IACxF,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC;IAClD,KAAK,IAAI,IAAI,CAAC;IACd,uEAAuE;IACvE,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AASD,wBAAgB,SAAS,CAAC,SAAS,GAAE,OAAO,CAAC,SAAS,CAAM,GAAG,GAAG,CAuDjE"}
@@ -0,0 +1,41 @@
1
+ //#region src/shared/assistant/voice/handsfree/vad.ts
2
+ var e = Object.freeze({
3
+ onsetFrames: 4,
4
+ hangoverMs: 600,
5
+ voicedAboveFloorDb: 10,
6
+ absFloorDb: -50,
7
+ zcrMin: .01,
8
+ zcrMax: .4,
9
+ floorWindowFrames: 100,
10
+ floorPercentile: .2,
11
+ frameMs: 20
12
+ }), t = 6, n = (e, t) => {
13
+ let n = [...e].sort((e, t) => e - t);
14
+ return n[Math.min(n.length - 1, Math.floor(t * n.length))] ?? -90;
15
+ };
16
+ function r(t = {}) {
17
+ let r = {
18
+ ...e,
19
+ ...t
20
+ }, i = r.onsetFrames, a = [], o = -90, s = 0, c = 0, l = !1;
21
+ return {
22
+ push(e, t) {
23
+ a.push(e.rmsDb), a.length > r.floorWindowFrames && a.shift(), l || (o = Math.max(-90, n(a, r.floorPercentile)));
24
+ let u = Math.max(o + r.voicedAboveFloorDb, r.absFloorDb), d = e.rmsDb > u && e.zcr > r.zcrMin && e.zcr < r.zcrMax, f = null;
25
+ return l ? (c = d ? 0 : c + r.frameMs, c >= r.hangoverMs && (l = !1, s = 0, f = "end")) : (s = d && t ? s + 1 : 0, s >= i && (l = !0, c = 0, f = "onset")), {
26
+ voiced: d,
27
+ event: f,
28
+ inSegment: l,
29
+ floorDb: o
30
+ };
31
+ },
32
+ reset() {
33
+ a = [], o = -90, s = 0, c = 0, l = !1;
34
+ },
35
+ setOnsetFrames(e) {
36
+ i = Math.max(1, Math.round(e));
37
+ }
38
+ };
39
+ }
40
+ //#endregion
41
+ export { e as DEFAULT_VAD_PARAMS, t as STRICT_ONSET_FRAMES, r as createVad };
@@ -0,0 +1,3 @@
1
+ import { SttTransport } from './sttTransport';
2
+ export declare function createWebSpeechTransport(): SttTransport;
3
+ //# sourceMappingURL=webSpeechTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webSpeechTransport.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/webSpeechTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,wBAAgB,wBAAwB,IAAI,YAAY,CAcvD"}
@@ -0,0 +1,16 @@
1
+ //#region src/shared/assistant/voice/handsfree/webSpeechTransport.ts
2
+ function e() {
3
+ return {
4
+ kind: "web-speech",
5
+ recognitionOwner: "session-hook",
6
+ keepsOpeningWords: !1,
7
+ async start() {},
8
+ openUtterance() {},
9
+ pushFrame() {},
10
+ closeUtterance() {},
11
+ cancelUtterance() {},
12
+ stop() {}
13
+ };
14
+ }
15
+ //#endregion
16
+ export { e as createWebSpeechTransport };
@@ -89,6 +89,15 @@ export type VoiceSessionEvent =
89
89
  at?: number;
90
90
  /** BOFF-8613: the language being spoken, so a bare "yes" is read in it. */
91
91
  language?: string;
92
+ /**
93
+ * BOFF-8613 H3: the AUDIO of this result was vetted by the acoustic echo
94
+ * gate (hands-free capture of our own, echo-cancelled microphone), so it
95
+ * is the user and not the speaker. The text guard `isEcho` must not drop
96
+ * it: a genuine correction repeats the assistant's words and quantities
97
+ * ("keep fifty, not fifteen") and a text comparison cannot tell that from
98
+ * leakage. Absent for the Web Speech path, whose audio is not vetted.
99
+ */
100
+ gated?: boolean;
92
101
  }
93
102
  /** Nothing heard for the person's grace (`resolveVoiceGraceMs`). */
94
103
  | {
@@ -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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"}
@@ -60,7 +60,7 @@ var h = Object.freeze({
60
60
  correcting: !1
61
61
  };
62
62
  function _(e, n, r) {
63
- if (p(n.transcript, r)) return e;
63
+ if (!n.gated && p(n.transcript, r)) return e;
64
64
  let i = t({
65
65
  transcript: n.transcript,
66
66
  submitted: e.submitted,
@@ -120,7 +120,7 @@ function v(t, r, i = null) {
120
120
  case "speech": {
121
121
  if (t.muted) return t;
122
122
  if (t.phase === "thinking") return _(t, r, i);
123
- if (t.phase !== "listening" || p(r.transcript, i)) return t;
123
+ if (t.phase !== "listening" || !r.gated && p(r.transcript, i)) return t;
124
124
  let a = t.correcting ? n(r.transcript, t.submitted) : r.transcript;
125
125
  if (t.correcting && a === "") return t;
126
126
  if (r.final) {