@burdenoff/fe-libs 2026.1014.4 → 2026.1015.1

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 (46) hide show
  1. package/dist/shared/assistant/avatar/avatarPreferences.d.ts +61 -14
  2. package/dist/shared/assistant/avatar/avatarPreferences.js +54 -21
  3. package/dist/shared/assistant/avatar/live/LiveAvatarTabView.d.ts +33 -0
  4. package/dist/shared/assistant/avatar/live/LiveAvatarTabView.js +278 -0
  5. package/dist/shared/assistant/avatar/live/avatarSessionClient.d.ts +5 -0
  6. package/dist/shared/assistant/avatar/live/avatarSessionClient.js +25 -6
  7. package/dist/shared/assistant/avatar/live/avatarVoice.d.ts +43 -0
  8. package/dist/shared/assistant/avatar/live/avatarVoice.js +45 -0
  9. package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.d.ts +21 -1
  10. package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.js +74 -24
  11. package/dist/shared/assistant/avatar/live/liveAvatarController.d.ts +47 -8
  12. package/dist/shared/assistant/avatar/live/liveAvatarController.js +244 -161
  13. package/dist/shared/assistant/avatar/live/liveAvatarStatus.d.ts +2 -2
  14. package/dist/shared/assistant/avatar/live/liveAvatarStatus.js +11 -4
  15. package/dist/shared/assistant/avatar/useAvatarCopy.d.ts +52 -21
  16. package/dist/shared/assistant/avatar/useAvatarCopy.js +93 -48
  17. package/dist/shared/assistant/i18nManifest.d.ts +24 -2
  18. package/dist/shared/assistant/i18nManifest.js +24 -2
  19. package/dist/shared/assistant/index.d.ts +5 -0
  20. package/dist/shared/assistant/speech/hostedVoiceCatalogue.d.ts +19 -0
  21. package/dist/shared/assistant/speech/hostedVoiceCatalogue.js +25 -18
  22. package/dist/shared/assistant/ui/AIAssistantPanel.js +136 -103
  23. package/dist/shared/assistant/ui/AssistantAvatarTabs.d.ts +10 -0
  24. package/dist/shared/assistant/ui/AssistantAvatarTabs.js +48 -0
  25. package/dist/shared/assistant/ui/AssistantChatArea.js +1260 -1199
  26. package/dist/shared/assistant/ui/assistantLiveAvatarSeam.d.ts +165 -5
  27. package/dist/shared/assistant/ui/assistantLiveAvatarSeam.js +141 -59
  28. package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.d.ts +13 -0
  29. package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.js +70 -0
  30. package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts +18 -0
  31. package/dist/shared/assistant/ui/composer/AssistantComposer.js +121 -102
  32. package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.d.ts +9 -0
  33. package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.js +28 -14
  34. package/dist/shared/assistant/ui/panelOverlays.d.ts +24 -3
  35. package/dist/shared/assistant/ui/panelOverlays.js +11 -10
  36. package/dist/shared/assistant/ui/useVoiceSession.js +234 -233
  37. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts +6 -0
  38. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +161 -149
  39. package/dist/shared/assistant/ui/voice/VoiceMiniController.js +7 -7
  40. package/dist/shared/assistant/ui/voice/VoiceStage.js +7 -7
  41. package/dist/shared/assistant/ui/voice/voiceStartGate.d.ts +57 -0
  42. package/dist/shared/assistant/ui/voice/voiceStartGate.js +9 -0
  43. package/dist/shared/assistant/voice/handsfree/handsFreeSetting.d.ts +7 -1
  44. package/dist/shared/assistant/voice/handsfree/handsFreeSetting.js +2 -2
  45. package/dist/shared-assistant.js +259 -254
  46. package/package.json +1 -1
@@ -3,253 +3,254 @@ import { planSubmitTimer as t, resolveVoiceGraceMs as n } from "../voice/handsFr
3
3
  import { readHandsFreeOverride as r, resolveHandsFreeEnabled as ee } from "../voice/handsfree/handsFreeSetting.js";
4
4
  import { silencePlaybackReference as te } from "../voice/handsfree/playbackReference.js";
5
5
  import { speechFeed as ne } from "../speech/speechFeed.js";
6
- import { INITIAL_SESSION as re, INTERRUPT_MAX_MS as ie, NOTHING_HEARD as ae, advanceHeardClock as oe, isCapturing as se, isSubmittable as ce, planListeningHold as le, planReplyConsumption as ue, planVoiceAnnouncement as de, shouldRecognise as fe, spokenSoFar as i, voiceSessionReducer as pe } from "../voice/voiceSession.js";
7
- import { useHandsFreeInterrupt as me } from "../voice/handsfree/useHandsFreeInterrupt.js";
8
- import { isTurnSuperseded as a } from "../voice/supersededTurns.js";
9
- import { captionChunks as he } from "../voice/speechPlayback.js";
10
- import { turnClockMs as o } from "../turnTimeline.js";
11
- import { useAssistantSpeech as ge } from "./AssistantSpeechProvider.js";
12
- import { useCallback as s, useEffect as c, useLayoutEffect as _e, useMemo as ve, useReducer as ye, useRef as l, useState as u } from "react";
6
+ import { INITIAL_SESSION as re, INTERRUPT_MAX_MS as ie, NOTHING_HEARD as i, advanceHeardClock as ae, isCapturing as a, isSubmittable as oe, planListeningHold as se, planReplyConsumption as ce, planVoiceAnnouncement as le, shouldRecognise as ue, spokenSoFar as o, voiceSessionReducer as de } from "../voice/voiceSession.js";
7
+ import { useHandsFreeInterrupt as fe } from "../voice/handsfree/useHandsFreeInterrupt.js";
8
+ import { isTurnSuperseded as pe } from "../voice/supersededTurns.js";
9
+ import { captionChunks as me } from "../voice/speechPlayback.js";
10
+ import { turnClockMs as s } from "../turnTimeline.js";
11
+ import { useAssistantSpeech as he } from "./AssistantSpeechProvider.js";
12
+ import { useLiveAvatarOn as ge } from "./assistantLiveAvatarSeam.js";
13
+ import { useCallback as c, useEffect as l, useLayoutEffect as _e, useMemo as ve, useReducer as ye, useRef as u, useState as d } from "react";
13
14
  //#region src/shared/assistant/ui/useVoiceSession.ts
14
15
  var be = 4e3, xe = 2500, Se = 5e3, Ce = 12e3, we = "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=";
15
- function Te({ onSubmit: Te, latestReply: d, language: f, graceMs: Ee, onSupersede: De, handsFreeInterrupt: Oe, handsFreeStreamNoticeAccepted: ke, onAcceptHandsFreeStreamNotice: Ae, onBargeIn: je }) {
16
- let Me = n(Ee), p = l(null), [m, h] = ye(s((e, t) => pe(e, t, p.current), []), re), g = ge(), { setSessionSpeaking: _, setSessionMicOpen: v, speakingMessageId: y, stop: b } = g, x = l(g.toggle), S = g.toggle;
16
+ function Te({ onSubmit: Te, latestReply: f, language: p, graceMs: Ee, onSupersede: De, handsFreeInterrupt: Oe, handsFreeStreamNoticeAccepted: ke, onAcceptHandsFreeStreamNotice: Ae, onBargeIn: m }) {
17
+ let h = n(Ee), g = u(null), [_, v] = ye(c((e, t) => de(e, t, g.current), []), re), y = he(), { setSessionSpeaking: b, setSessionMicOpen: x, speakingMessageId: S, stop: C } = y, w = u(y.toggle), je = y.toggle;
17
18
  _e(() => {
18
- x.current = S;
19
- }, [S]);
20
- let C = l(null), w = l({}), T = l(ae), E = l(null), D = l(!1), O = l(null), [k, A] = u(null), [j, M] = u(!1), [Ne, N] = u(!1), [P, F] = u(!1), I = l(m);
21
- I.current = m;
22
- let L = l([]), R = l(null), z = l(!1), B = s(() => {
23
- L.current = [], R.current = null, z.current = !1;
24
- }, []), V = s(() => {
19
+ w.current = je;
20
+ }, [je]);
21
+ let T = u(null), E = u({}), D = u(i), O = u(null), k = u(!1), A = u(null), [Me, j] = d(null), [M, N] = d(!1), [Ne, P] = d(!1), [F, I] = d(!1), L = u(_);
22
+ L.current = _;
23
+ let R = u([]), z = u(null), B = u(!1), V = c(() => {
24
+ R.current = [], z.current = null, B.current = !1;
25
+ }, []), H = c(() => {
25
26
  for (;;) {
26
- let e = L.current.shift();
27
+ let e = R.current.shift();
27
28
  if (!e) return !1;
28
29
  if (!(e.stillWanted && !e.stillWanted())) {
29
- R.current = e, p.current = p.current ? `${p.current} ${e.text}` : e.text;
30
+ z.current = e, g.current = g.current ? `${g.current} ${e.text}` : e.text;
30
31
  try {
31
- x.current(e.id, e.text, e.lang);
32
+ w.current(e.id, e.text, e.lang);
32
33
  } catch {
33
- R.current = null;
34
+ z.current = null;
34
35
  continue;
35
36
  }
36
37
  return !0;
37
38
  }
38
39
  }
39
- }, []), H = l(!1), Pe = s((e) => {
40
- let t = le({
40
+ }, []), U = u(!1), Pe = c((e) => {
41
+ let t = se({
41
42
  requested: e,
42
- held: H.current,
43
- muted: I.current.muted
43
+ held: U.current,
44
+ muted: L.current.muted
44
45
  });
45
- H.current = t.held, t.mute !== null && h({
46
+ U.current = t.held, t.mute !== null && v({
46
47
  type: "mute",
47
48
  muted: t.mute
48
49
  });
49
- }, []), U = s((e) => {
50
- let t = de(I.current);
51
- t !== "drop" && (R.current?.id === e.id || L.current.some((t) => t.id === e.id) || (L.current.push(e), t === "start" && !z.current && (z.current = !0, h({ type: "announce" }))));
52
- }, []), Fe = s((e) => {
53
- if (I.current.phase !== "thinking") {
54
- U(e);
50
+ }, []), W = c((e) => {
51
+ let t = le(L.current);
52
+ t !== "drop" && (z.current?.id === e.id || R.current.some((t) => t.id === e.id) || (R.current.push(e), t === "start" && !B.current && (B.current = !0, v({ type: "announce" }))));
53
+ }, []), Fe = c((e) => {
54
+ if (L.current.phase !== "thinking") {
55
+ W(e);
55
56
  return;
56
57
  }
57
- L.current.push(e), z.current = !0, h({ type: "answered-locally" });
58
- }, [U]), Ie = l(d);
59
- Ie.current = d, c(() => {
60
- if (m.phase === "speaking") {
61
- let e = O.current;
62
- p.current = e && E.current === e.id && d?.id !== e.id ? e.text : d?.text ?? null;
58
+ R.current.push(e), B.current = !0, v({ type: "answered-locally" });
59
+ }, [W]), Ie = u(f);
60
+ Ie.current = f, l(() => {
61
+ if (_.phase === "speaking") {
62
+ let e = A.current;
63
+ g.current = e && O.current === e.id && f?.id !== e.id ? e.text : f?.text ?? null;
63
64
  return;
64
65
  }
65
- if (p.current === null) return;
66
+ if (g.current === null) return;
66
67
  let e = setTimeout(() => {
67
- p.current = null;
68
+ g.current = null;
68
69
  }, xe);
69
70
  return () => clearTimeout(e);
70
- }, [m.phase, d]);
71
- let W = l(f);
72
- W.current = f;
73
- let G = s((e, t) => {
74
- h({
71
+ }, [_.phase, f]);
72
+ let G = u(p);
73
+ G.current = p;
74
+ let K = c((e, t) => {
75
+ v({
75
76
  type: "speech",
76
77
  transcript: e,
77
78
  final: t,
78
79
  at: Date.now(),
79
- language: W.current
80
+ language: G.current
80
81
  });
81
- }, []), Le = s((e, t, n) => {
82
- h({
82
+ }, []), Le = c((e, t, n) => {
83
+ v({
83
84
  type: "speech",
84
85
  transcript: e,
85
86
  final: t,
86
87
  at: Date.now(),
87
- language: n ?? W.current,
88
+ language: n ?? G.current,
88
89
  gated: !0
89
90
  });
90
- }, []), K = l(0), Re = s(() => {
91
- B(), b(), K.current = Date.now(), M(!0), h({ type: "interrupt" });
92
- }, [b, B]), q = e({
93
- onFinalize: s((e) => G(e, !0), [G]),
94
- language: f
95
- }), ze = l(je);
96
- ze.current = je;
97
- let Be = s(() => {
98
- B(), te(), b(), K.current = Date.now(), M(!0), h({ type: "interrupt" }), ze.current?.();
99
- }, [b, B]), J = me({
100
- enabled: ee(Oe, r()),
101
- phase: m.phase,
102
- muted: m.muted,
103
- language: f,
91
+ }, []), q = u(0), Re = c(() => {
92
+ V(), C(), q.current = Date.now(), N(!0), v({ type: "interrupt" });
93
+ }, [C, V]), J = e({
94
+ onFinalize: c((e) => K(e, !0), [K]),
95
+ language: p
96
+ }), ze = u(m);
97
+ ze.current = m;
98
+ let Be = c(() => {
99
+ V(), te(), C(), q.current = Date.now(), N(!0), v({ type: "interrupt" }), ze.current?.();
100
+ }, [C, V]), Ve = ge(), Y = fe({
101
+ enabled: ee(Oe, r(), Ve),
102
+ phase: _.phase,
103
+ muted: _.muted,
104
+ language: p,
104
105
  streamNoticeAccepted: ke ?? null,
105
106
  onAcceptStreamNotice: Ae,
106
107
  onBargeIn: Be,
107
108
  onTranscript: Le
108
- }), Ve = J.mode === "notice", Y = q.isListening || J.suppressWebSpeech && J.mode === "active";
109
- c(() => {
110
- q.interim && G(q.interim, !1);
111
- }, [q.interim, G]), c(() => {
112
- C.current && clearTimeout(C.current), N(!1), T.current = oe(T.current, m, o());
109
+ }), He = Y.mode === "notice", X = J.isListening || Y.suppressWebSpeech && Y.mode === "active";
110
+ l(() => {
111
+ J.interim && K(J.interim, !1);
112
+ }, [J.interim, K]), l(() => {
113
+ T.current && clearTimeout(T.current), P(!1), D.current = ae(D.current, _, s());
113
114
  let e = t({
114
- phase: m.phase,
115
- muted: m.muted,
116
- spoken: i(m),
117
- holding: P,
118
- graceMs: Me
115
+ phase: _.phase,
116
+ muted: _.muted,
117
+ spoken: o(_),
118
+ holding: F,
119
+ graceMs: h
119
120
  });
120
121
  if (!e.arm) return;
121
- let n = setTimeout(() => N(!0), Math.min(800, e.delayMs)), r = o();
122
- return C.current = setTimeout(() => {
123
- w.current = {
124
- speechEnded: T.current.at ?? r,
122
+ let n = setTimeout(() => P(!0), Math.min(800, e.delayMs)), r = s();
123
+ return T.current = setTimeout(() => {
124
+ E.current = {
125
+ speechEnded: D.current.at ?? r,
125
126
  graceStarted: r,
126
- graceEnded: o()
127
- }, h({
127
+ graceEnded: s()
128
+ }, v({
128
129
  type: "silence",
129
130
  at: Date.now()
130
131
  });
131
132
  }, e.delayMs), () => {
132
- clearTimeout(n), C.current && clearTimeout(C.current);
133
+ clearTimeout(n), T.current && clearTimeout(T.current);
133
134
  };
134
135
  }, [
135
- m,
136
- P,
137
- Me
138
- ]), c(() => {
139
- (m.phase !== "listening" || m.muted) && F(!1);
140
- }, [m.phase, m.muted]), c(() => {
141
- if (!j) return;
142
- let e = Date.now() - K.current, t = Y ? Math.max(0, 500 - e) : Math.max(0, ie - e), n = setTimeout(() => M(!1), t);
136
+ _,
137
+ F,
138
+ h
139
+ ]), l(() => {
140
+ (_.phase !== "listening" || _.muted) && I(!1);
141
+ }, [_.phase, _.muted]), l(() => {
142
+ if (!M) return;
143
+ let e = Date.now() - q.current, t = X ? Math.max(0, 500 - e) : Math.max(0, ie - e), n = setTimeout(() => N(!1), t);
143
144
  return () => clearTimeout(n);
144
- }, [j, Y]);
145
- let He = l("");
146
- m.phase === "listening" && (He.current = i(m)), c(() => {
147
- if (m.phase !== "thinking") return;
148
- v(!1), B();
149
- let e = He.current.trim();
150
- e && Te(e, Z.current ?? `vs-orphan-${Date.now().toString(36)}`, w.current, { correction: I.current.correcting }), w.current = {}, T.current = ae;
151
- }, [m.phase]), c(() => {
152
- let e = ue(d?.id, m.phase, E.current, a(d?.id));
153
- e.claim && (E.current = d?.id ?? null, e.advance && d && h({
145
+ }, [M, X]);
146
+ let Ue = u("");
147
+ _.phase === "listening" && (Ue.current = o(_)), l(() => {
148
+ if (_.phase !== "thinking") return;
149
+ x(!1), V();
150
+ let e = Ue.current.trim();
151
+ e && Te(e, Q.current ?? `vs-orphan-${Date.now().toString(36)}`, E.current, { correction: L.current.correcting }), E.current = {}, D.current = i;
152
+ }, [_.phase]), l(() => {
153
+ let e = ce(f?.id, _.phase, O.current, pe(f?.id));
154
+ e.claim && (O.current = f?.id ?? null, e.advance && f && v({
154
155
  type: "reply",
155
- text: d.text
156
+ text: f.text
156
157
  }));
157
- }, [d, m.phase]), c(() => {
158
- if (y === null || m.phase !== "thinking" || E.current === y) return;
159
- if (a(y)) {
160
- b();
158
+ }, [f, _.phase]), l(() => {
159
+ if (S === null || _.phase !== "thinking" || O.current === S) return;
160
+ if (pe(S)) {
161
+ C();
161
162
  return;
162
163
  }
163
- let e = ne.peek(y);
164
- !e || e.channel !== "voice" || e.voiceSessionId === void 0 || e.voiceSessionId !== Z.current || (E.current = y, O.current = {
165
- id: y,
164
+ let e = ne.peek(S);
165
+ !e || e.channel !== "voice" || e.voiceSessionId === void 0 || e.voiceSessionId !== Q.current || (O.current = S, A.current = {
166
+ id: S,
166
167
  text: e.text
167
- }, h({
168
+ }, v({
168
169
  type: "reply-audio-started",
169
- replyId: y
170
+ replyId: S
170
171
  }));
171
172
  }, [
172
- y,
173
- m.phase,
174
- b
175
- ]), c(() => {
176
- let e = y !== null;
177
- D.current && !e && (R.current = null, (I.current.phase !== "speaking" || !V()) && h({ type: "speech-ended" })), D.current = e;
178
- }, [y, V]), c(() => {
179
- m.phase !== "listening" && A((e) => e === "nothing-heard" ? null : e);
180
- }, [m.phase]), c(() => {
181
- if (m.phase !== "speaking" || y !== null) return;
173
+ S,
174
+ _.phase,
175
+ C
176
+ ]), l(() => {
177
+ let e = S !== null;
178
+ k.current && !e && (z.current = null, (L.current.phase !== "speaking" || !H()) && v({ type: "speech-ended" })), k.current = e;
179
+ }, [S, H]), l(() => {
180
+ _.phase !== "listening" && j((e) => e === "nothing-heard" ? null : e);
181
+ }, [_.phase]), l(() => {
182
+ if (_.phase !== "speaking" || S !== null) return;
182
183
  let e = setTimeout(() => {
183
- D.current || (B(), h({ type: "speech-ended" }));
184
+ k.current || (V(), v({ type: "speech-ended" }));
184
185
  }, be);
185
186
  return () => clearTimeout(e);
186
187
  }, [
187
- m.phase,
188
- y,
189
- B
188
+ _.phase,
189
+ S,
190
+ V
190
191
  ]);
191
- let X = g.outputNotCleared;
192
- c(() => {
193
- if (X === null || E.current !== X.messageId) return;
194
- let { phase: e } = I.current;
195
- e === "idle" || e === "ended" || e === "thinking" || A("reply-not-heard");
196
- }, [X]), c(() => {
197
- m.phase === "listening" || m.phase === "thinking" || A((e) => e === "reply-not-heard" ? null : e);
198
- }, [m.phase]);
199
- let Ue = l(De);
200
- Ue.current = De;
201
- let We = l(0);
202
- c(() => {
203
- let e = m.superseded;
204
- e !== We.current && (We.current = e, e !== 0 && (B(), b(), Ue.current?.()));
192
+ let Z = y.outputNotCleared;
193
+ l(() => {
194
+ if (Z === null || O.current !== Z.messageId) return;
195
+ let { phase: e } = L.current;
196
+ e === "idle" || e === "ended" || e === "thinking" || j("reply-not-heard");
197
+ }, [Z]), l(() => {
198
+ _.phase === "listening" || _.phase === "thinking" || j((e) => e === "reply-not-heard" ? null : e);
199
+ }, [_.phase]);
200
+ let We = u(De);
201
+ We.current = De;
202
+ let Ge = u(0);
203
+ l(() => {
204
+ let e = _.superseded;
205
+ e !== Ge.current && (Ge.current = e, e !== 0 && (V(), C(), We.current?.()));
205
206
  }, [
206
- m.superseded,
207
- B,
208
- b
209
- ]), c(() => {
210
- v(se(m)), fe(m) && !J.suppressWebSpeech ? q.isActive || q.start("auto") : q.isActive && q.stop();
207
+ _.superseded,
208
+ V,
209
+ C
210
+ ]), l(() => {
211
+ x(a(_)), ue(_) && !Y.suppressWebSpeech ? J.isActive || J.start("auto") : J.isActive && J.stop();
211
212
  }, [
212
- m,
213
- q,
214
- v,
215
- J.suppressWebSpeech
216
- ]), c(() => {
217
- m.phase !== "speaking" || !z.current || (z.current = !1, V() || h({ type: "speech-ended" }));
218
- }, [m.phase, V]), c(() => {
219
- q.error === "not-allowed" || q.error === "audio-capture" ? h({
213
+ _,
214
+ J,
215
+ x,
216
+ Y.suppressWebSpeech
217
+ ]), l(() => {
218
+ _.phase !== "speaking" || !B.current || (B.current = !1, H() || v({ type: "speech-ended" }));
219
+ }, [_.phase, H]), l(() => {
220
+ J.error === "not-allowed" || J.error === "audio-capture" ? v({
220
221
  type: "fail",
221
222
  error: "mic-denied"
222
- }) : q.error === "language-not-supported" ? h({
223
+ }) : J.error === "language-not-supported" ? v({
223
224
  type: "fail",
224
225
  error: "no-speech-support"
225
- }) : q.error === "network" ? A("network") : q.error === "unknown" && A("recognition-failed");
226
- }, [q.error]), c(() => {
227
- q.error !== null || !Y || A((e) => e === "network" || e === "recognition-failed" ? null : e);
228
- }, [q.error, Y]), c(() => {
229
- if (Y && A((e) => e === "not-capturing" ? null : e), !se(m) || Y || Ve) return;
230
- let e = setTimeout(() => A("not-capturing"), Se);
226
+ }) : J.error === "network" ? j("network") : J.error === "unknown" && j("recognition-failed");
227
+ }, [J.error]), l(() => {
228
+ J.error !== null || !X || j((e) => e === "network" || e === "recognition-failed" ? null : e);
229
+ }, [J.error, X]), l(() => {
230
+ if (X && j((e) => e === "not-capturing" ? null : e), !a(_) || X || He) return;
231
+ let e = setTimeout(() => j("not-capturing"), Se);
231
232
  return () => clearTimeout(e);
232
233
  }, [
233
- m,
234
- Y,
235
- Ve
236
- ]), c(() => {
237
- if (m.phase !== "listening" || m.muted || !Y || i(m) !== "") return;
238
- let e = setTimeout(() => A("nothing-heard"), Ce);
234
+ _,
235
+ X,
236
+ He
237
+ ]), l(() => {
238
+ if (_.phase !== "listening" || _.muted || !X || o(_) !== "") return;
239
+ let e = setTimeout(() => j("nothing-heard"), Ce);
239
240
  return () => clearTimeout(e);
240
- }, [m, Y]), c(() => {
241
- i(m) !== "" && A(null);
242
- }, [m]);
243
- let Z = l(null), Ge = s(() => {
244
- if (M(!1), N(!1), F(!1), B(), H.current = !1, !q.isSupported) {
245
- h({
241
+ }, [_, X]), l(() => {
242
+ o(_) !== "" && j(null);
243
+ }, [_]);
244
+ let Q = u(null), Ke = c(() => {
245
+ if (N(!1), P(!1), I(!1), V(), U.current = !1, !J.isSupported) {
246
+ v({
246
247
  type: "fail",
247
248
  error: "no-speech-support"
248
249
  });
249
250
  return;
250
251
  }
251
- if (g.isBlocked) {
252
- h({
252
+ if (y.isBlocked) {
253
+ v({
253
254
  type: "fail",
254
255
  error: "no-voice-support"
255
256
  });
@@ -268,95 +269,95 @@ function Te({ onSubmit: Te, latestReply: d, language: f, graceMs: Ee, onSupersed
268
269
  e.volume = 0, e.play().catch(() => {});
269
270
  }
270
271
  } catch {}
271
- _(!0), A(null), E.current = Ie.current?.id ?? null, O.current = null, Z.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, h({ type: "start" });
272
+ b(!0), j(null), O.current = Ie.current?.id ?? null, A.current = null, Q.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, v({ type: "start" });
272
273
  }, [
273
- q.isSupported,
274
- g.isBlocked,
275
- _,
276
- B
277
- ]), Q = s(() => {
278
- M(!1), N(!1), F(!1), B(), H.current = !1, Z.current = null, h({ type: "end" }), b(), _(!1);
274
+ J.isSupported,
275
+ y.isBlocked,
276
+ b,
277
+ V
278
+ ]), qe = c(() => {
279
+ N(!1), P(!1), I(!1), V(), U.current = !1, Q.current = null, v({ type: "end" }), C(), b(!1);
279
280
  }, [
281
+ C,
280
282
  b,
281
- _,
282
- B
283
- ]), Ke = s((e) => Z.current === e, []), qe = s(() => {
284
- let e = I.current;
285
- e.phase !== "listening" || e.muted || F(!0);
286
- }, []), Je = s(() => {
287
- F(!1);
288
- let e = I.current;
289
- if (e.phase !== "listening" || e.muted || !ce(i(e))) return;
290
- let t = o();
291
- w.current = {
292
- speechEnded: T.current.at ?? t,
283
+ V
284
+ ]), Je = c((e) => Q.current === e, []), Ye = c(() => {
285
+ let e = L.current;
286
+ e.phase !== "listening" || e.muted || I(!0);
287
+ }, []), Xe = c(() => {
288
+ I(!1);
289
+ let e = L.current;
290
+ if (e.phase !== "listening" || e.muted || !oe(o(e))) return;
291
+ let t = s();
292
+ E.current = {
293
+ speechEnded: D.current.at ?? t,
293
294
  graceStarted: t,
294
295
  graceEnded: t
295
- }, h({
296
+ }, v({
296
297
  type: "silence",
297
298
  at: Date.now()
298
299
  });
299
- }, []), Ye = s(() => {
300
- h({
300
+ }, []), Ze = c(() => {
301
+ v({
301
302
  type: "mute",
302
- muted: !I.current.muted
303
+ muted: !L.current.muted
303
304
  });
304
305
  }, []);
305
- c(() => () => {
306
- _(!1), v(!1);
307
- }, [_, v]);
308
- let $ = he(g.spokenChunks, m.phase, y);
306
+ l(() => () => {
307
+ b(!1), x(!1);
308
+ }, [b, x]);
309
+ let $ = me(y.spokenChunks, _.phase, S);
309
310
  return ve(() => ({
310
- session: m,
311
- notice: k ?? (J.fallbackReason !== null && J.fallbackReason !== "notice-declined" ? "hands-free-fallback" : J.nothingHeard ? "hands-free-nothing-heard" : null),
311
+ session: _,
312
+ notice: Me ?? (Y.fallbackReason !== null && Y.fallbackReason !== "notice-declined" ? "hands-free-fallback" : Y.nothingHeard ? "hands-free-nothing-heard" : null),
312
313
  spokenChunks: $,
313
- capturing: Y,
314
- active: m.phase !== "idle" && (m.phase !== "ended" || m.error !== null),
315
- interrupting: j,
314
+ capturing: X,
315
+ active: _.phase !== "idle" && (_.phase !== "ended" || _.error !== null),
316
+ interrupting: M,
316
317
  awaitingEndpoint: Ne,
317
- holding: P,
318
- correcting: m.correcting,
318
+ holding: F,
319
+ correcting: _.correcting,
319
320
  handsFree: {
320
- mode: J.mode,
321
- nothingHeard: J.nothingHeard,
322
- transportKind: J.transportKind,
323
- fallbackReason: J.fallbackReason,
324
- privacyNotice: J.privacyNotice
321
+ mode: Y.mode,
322
+ nothingHeard: Y.nothingHeard,
323
+ transportKind: Y.transportKind,
324
+ fallbackReason: Y.fallbackReason,
325
+ privacyNotice: Y.privacyNotice
325
326
  },
326
- available: q.isSupported && !g.isBlocked,
327
- start: Ge,
328
- end: Q,
329
- isCurrentSession: Ke,
330
- toggleMute: Ye,
327
+ available: J.isSupported && !y.isBlocked,
328
+ start: Ke,
329
+ end: qe,
330
+ isCurrentSession: Je,
331
+ toggleMute: Ze,
331
332
  interrupt: Re,
332
- letMeFinish: qe,
333
- imDone: Je,
334
- announce: U,
333
+ letMeFinish: Ye,
334
+ imDone: Xe,
335
+ announce: W,
335
336
  holdListening: Pe,
336
337
  answerLocally: Fe
337
338
  }), [
338
- m,
339
- k,
340
- j,
339
+ _,
340
+ Me,
341
+ M,
341
342
  Ne,
342
- P,
343
- Y,
344
- J.mode,
345
- J.nothingHeard,
346
- J.transportKind,
347
- J.fallbackReason,
348
- J.privacyNotice,
349
- q.isSupported,
350
- g.isBlocked,
343
+ F,
344
+ X,
345
+ Y.mode,
346
+ Y.nothingHeard,
347
+ Y.transportKind,
348
+ Y.fallbackReason,
349
+ Y.privacyNotice,
350
+ J.isSupported,
351
+ y.isBlocked,
351
352
  $,
352
- Ge,
353
- Q,
354
353
  Ke,
355
- Ye,
356
- Re,
357
354
  qe,
358
355
  Je,
359
- U,
356
+ Ze,
357
+ Re,
358
+ Ye,
359
+ Xe,
360
+ W,
360
361
  Pe,
361
362
  Fe
362
363
  ]);
@@ -98,6 +98,12 @@ interface Props {
98
98
  * — the page the model offered in that voice turn.
99
99
  */
100
100
  renderAfterTurn?: (turnId: string) => ReactNode;
101
+ /**
102
+ * ★ BOFF-9341: told the view shown, while the panel has the Avatar tab: an
103
+ * enlarged session covers the tab, which then is no stage (D4). Absent, the
104
+ * session reports nothing.
105
+ */
106
+ onViewChange?: (view: VoiceView) => void;
101
107
  }
102
108
  /**
103
109
  * Full-screen voice conversation (BOFF-7120).