@burdenoff/fe-libs 2026.1029.2 → 2026.1029.3

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.
@@ -15,57 +15,67 @@ import { useCallback as o, useEffect as s, useLayoutEffect as be, useMemo as xe,
15
15
  //#region src/shared/assistant/ui/useVoiceSession.ts
16
16
  var Ce = 4e3, we = 2500, Te = 5e3, Ee = 12e3;
17
17
  function De({ onSubmit: De, latestReply: u, language: d, graceMs: Oe, onSupersede: ke, handsFreeInterrupt: Ae, handsFreeStreamNoticeAccepted: je, onAcceptHandsFreeStreamNotice: Me, onBargeIn: Ne }) {
18
- let f = n(Oe), p = c(null), [m, h] = Se(o((e, t) => me(e, t, p.current), []), ie), g = ve(), { setSessionSpeaking: _, setSessionMicOpen: v, speakingMessageId: y, stop: b } = g, x = c(g.toggle), Pe = g.toggle;
18
+ let f = n(Oe), p = c(null), [m, h] = Se(o((e, t) => me(e, t, p.current), []), ie), g = ve(), { setSessionSpeaking: _, setSessionMicOpen: v, speakingMessageId: y, stop: b } = g, Pe = c(g.toggle), Fe = g.toggle;
19
19
  be(() => {
20
- x.current = Pe;
21
- }, [Pe]);
22
- let S = c(null), C = c({}), w = c(oe), T = c(void 0), E = c(void 0);
20
+ Pe.current = Fe;
21
+ }, [Fe]);
22
+ let x = c(null), S = c({}), C = c(oe), w = c(void 0), T = c(void 0), E = c(0), D = c(void 0), O = c(/* @__PURE__ */ new Map()), Ie = c(void 0);
23
23
  s(() => {
24
- (m.phase === "idle" || m.phase === "ended") && (T.current = void 0, E.current = void 0);
25
- }, [m.phase]);
26
- let D = c(null), O = c(!1), k = c(null), [Fe, A] = l(null), [j, M] = l(!1), [Ie, N] = l(!1), [P, F] = l(!1), I = c(m);
27
- I.current = m;
28
- let L = c([]), R = c(null), z = c(!1), B = o(() => {
29
- L.current = [], R.current = null, z.current = !1;
30
- }, []), V = o(() => {
24
+ let e = m.correctionTimingDecision;
25
+ if (e && e !== Ie.current) {
26
+ Ie.current = e;
27
+ for (let [t, n] of O.current) e.accepted && t >= e.candidateId && (w.current = n.lastSpeechFrame ?? w.current, T.current = n.recognizerSpeechEnded ?? T.current), (e.accepted || t <= e.candidateId) && O.current.delete(t);
28
+ D.current !== void 0 && D.current <= e.candidateId && (D.current = void 0);
29
+ }
30
+ (m.phase !== "thinking" || m.muted) && (O.current.clear(), D.current = void 0), (m.phase === "idle" || m.phase === "ended") && (w.current = void 0, T.current = void 0);
31
+ }, [
32
+ m.phase,
33
+ m.muted,
34
+ m.correctionTimingDecision
35
+ ]);
36
+ let k = c(null), A = c(!1), Le = c(null), [Re, j] = l(null), [M, N] = l(!1), [ze, P] = l(!1), [F, I] = l(!1), L = c(m);
37
+ L.current = m;
38
+ let R = c([]), z = c(null), B = c(!1), V = o(() => {
39
+ R.current = [], z.current = null, B.current = !1;
40
+ }, []), H = o(() => {
31
41
  for (;;) {
32
- let e = L.current.shift();
42
+ let e = R.current.shift();
33
43
  if (!e) return !1;
34
44
  if (!(e.stillWanted && !e.stillWanted())) {
35
- R.current = e, p.current = p.current ? `${p.current} ${e.text}` : e.text;
45
+ z.current = e, p.current = p.current ? `${p.current} ${e.text}` : e.text;
36
46
  try {
37
- x.current(e.id, e.text, e.lang);
47
+ Pe.current(e.id, e.text, e.lang);
38
48
  } catch {
39
- R.current = null;
49
+ z.current = null;
40
50
  continue;
41
51
  }
42
52
  return !0;
43
53
  }
44
54
  }
45
- }, []), H = c(!1), Le = o((e) => {
55
+ }, []), U = c(!1), Be = o((e) => {
46
56
  let t = ue({
47
57
  requested: e,
48
- held: H.current,
49
- muted: I.current.muted
58
+ held: U.current,
59
+ muted: L.current.muted
50
60
  });
51
- H.current = t.held, t.mute !== null && h({
61
+ U.current = t.held, t.mute !== null && h({
52
62
  type: "mute",
53
63
  muted: t.mute
54
64
  });
55
- }, []), U = o((e) => {
56
- let t = fe(I.current);
57
- 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" }))));
58
- }, []), Re = o((e) => {
59
- if (I.current.phase !== "thinking") {
60
- U(e);
65
+ }, []), W = o((e) => {
66
+ let t = fe(L.current);
67
+ 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, h({ type: "announce" }))));
68
+ }, []), Ve = o((e) => {
69
+ if (L.current.phase !== "thinking") {
70
+ W(e);
61
71
  return;
62
72
  }
63
- L.current.push(e), z.current = !0, h({ type: "answered-locally" });
64
- }, [U]), ze = c(u);
65
- ze.current = u, s(() => {
73
+ R.current.push(e), B.current = !0, h({ type: "answered-locally" });
74
+ }, [W]), He = c(u);
75
+ He.current = u, s(() => {
66
76
  if (m.phase === "speaking") {
67
- let e = k.current;
68
- p.current = e && D.current === e.id && u?.id !== e.id ? e.text : u?.text ?? null;
77
+ let e = Le.current;
78
+ p.current = e && k.current === e.id && u?.id !== e.id ? e.text : u?.text ?? null;
69
79
  return;
70
80
  }
71
81
  if (p.current === null) return;
@@ -74,68 +84,82 @@ function De({ onSubmit: De, latestReply: u, language: d, graceMs: Oe, onSupersed
74
84
  }, we);
75
85
  return () => clearTimeout(e);
76
86
  }, [m.phase, u]);
77
- let W = c(d);
78
- W.current = d;
79
- let G = o((e, t) => {
87
+ let G = c(d);
88
+ G.current = d;
89
+ let Ue = o((e, t) => {
90
+ let n = L.current;
91
+ if (!n.muted) if (n.phase === "thinking") {
92
+ e === "lastSpeechFrame" && (D.current = void 0);
93
+ let n = D.current ?? E.current, r = O.current.get(n) ?? {};
94
+ r[e] = t, O.current.set(n, r);
95
+ } else n.phase === "listening" && (e === "lastSpeechFrame" ? w.current = t : T.current = t);
96
+ }, []), K = o((e) => {
97
+ let t = L.current;
98
+ if (t.phase !== "thinking" || t.muted) return;
99
+ let n = E.current;
100
+ return e && (D.current = n, E.current += 1), n;
101
+ }, []), q = o((e, t) => {
80
102
  h({
81
103
  type: "speech",
82
104
  transcript: e,
83
105
  final: t,
84
106
  at: Date.now(),
85
- language: W.current
107
+ language: G.current,
108
+ timingCandidateId: K(t)
86
109
  });
87
- }, []), Be = o((e, t, n) => {
110
+ }, [K]), We = o((e, t, n) => {
88
111
  h({
89
112
  type: "speech",
90
113
  transcript: e,
91
114
  final: t,
92
115
  at: Date.now(),
93
- language: n ?? W.current,
94
- gated: !0
116
+ language: n ?? G.current,
117
+ gated: !0,
118
+ timingCandidateId: K(t)
95
119
  });
96
- }, []), K = c(0), Ve = o(() => {
97
- B(), b(), K.current = Date.now(), M(!0), h({ type: "interrupt" });
98
- }, [b, B]), q = e({
99
- onFinalize: o((e) => G(e, !0), [G]),
120
+ }, [K]), J = c(0), Ge = o(() => {
121
+ V(), b(), J.current = Date.now(), N(!0), h({ type: "interrupt" });
122
+ }, [b, V]), Y = e({
123
+ onFinalize: o((e) => q(e, !0), [q]),
100
124
  language: d,
101
125
  onSpeechEnd: (e) => {
102
- I.current.phase === "listening" && (E.current = e);
126
+ Ue("recognizerSpeechEnded", e);
103
127
  }
104
- }), He = c(Ne);
105
- He.current = Ne;
106
- let Ue = o(() => {
107
- B(), te(), b(), K.current = Date.now(), M(!0), h({ type: "interrupt" }), He.current?.();
108
- }, [b, B]), We = ye(), J = he({
109
- enabled: ee(Ae, r(), We),
128
+ }), Ke = c(Ne);
129
+ Ke.current = Ne;
130
+ let qe = o(() => {
131
+ V(), te(), b(), J.current = Date.now(), N(!0), h({ type: "interrupt" }), Ke.current?.();
132
+ }, [b, V]), Je = ye(), X = he({
133
+ enabled: ee(Ae, r(), Je),
110
134
  phase: m.phase,
111
135
  muted: m.muted,
112
136
  language: d,
113
137
  streamNoticeAccepted: je ?? null,
114
138
  onAcceptStreamNotice: Me,
115
- onBargeIn: Ue,
116
- onTranscript: Be,
139
+ onBargeIn: qe,
140
+ onTranscript: We,
117
141
  onSpeechFrame: (e) => {
118
- I.current.phase === "listening" && !I.current.muted && (T.current = e);
142
+ Ue("lastSpeechFrame", e);
119
143
  }
120
- }), Ge = J.mode === "notice", Y = q.isListening || J.suppressWebSpeech && J.mode === "active";
144
+ }), Ye = X.mode === "notice", Z = Y.isListening || X.suppressWebSpeech && X.mode === "active";
121
145
  s(() => {
122
- q.interim && G(q.interim, !1);
123
- }, [q.interim, G]), s(() => {
124
- S.current && clearTimeout(S.current), N(!1), w.current = se(w.current, m, a());
146
+ Y.interim && q(Y.interim, !1);
147
+ }, [Y.interim, q]), s(() => {
148
+ x.current && clearTimeout(x.current), P(!1), C.current = se(C.current, m, a());
125
149
  let e = t({
126
150
  phase: m.phase,
127
151
  muted: m.muted,
128
152
  spoken: i(m),
129
- holding: P,
153
+ holding: F,
130
154
  graceMs: f
131
155
  });
132
156
  if (!e.arm) return;
133
- let n = setTimeout(() => N(!0), Math.min(800, e.delayMs)), r = a();
134
- return S.current = setTimeout(() => {
135
- C.current = {
136
- speechEnded: w.current.at ?? r,
137
- lastSpeechFrame: T.current,
138
- recognizerSpeechEnded: E.current,
157
+ let n = setTimeout(() => P(!0), Math.min(800, e.delayMs)), r = a();
158
+ return x.current = setTimeout(() => {
159
+ S.current = {
160
+ speechEnded: C.current.at ?? r,
161
+ lastSpeechFrame: w.current,
162
+ recognizerSpeechEnded: T.current,
139
163
  selectedGraceMs: f,
140
164
  graceStarted: r,
141
165
  graceEnded: a()
@@ -144,28 +168,28 @@ function De({ onSubmit: De, latestReply: u, language: d, graceMs: Oe, onSupersed
144
168
  at: Date.now()
145
169
  });
146
170
  }, e.delayMs), () => {
147
- clearTimeout(n), S.current && clearTimeout(S.current);
171
+ clearTimeout(n), x.current && clearTimeout(x.current);
148
172
  };
149
173
  }, [
150
174
  m,
151
- P,
175
+ F,
152
176
  f
153
177
  ]), s(() => {
154
- (m.phase !== "listening" || m.muted) && F(!1);
178
+ (m.phase !== "listening" || m.muted) && I(!1);
155
179
  }, [m.phase, m.muted]), s(() => {
156
- if (!j) return;
157
- let e = Date.now() - K.current, t = Y ? Math.max(0, 500 - e) : Math.max(0, ae - e), n = setTimeout(() => M(!1), t);
180
+ if (!M) return;
181
+ let e = Date.now() - J.current, t = Z ? Math.max(0, 500 - e) : Math.max(0, ae - e), n = setTimeout(() => N(!1), t);
158
182
  return () => clearTimeout(n);
159
- }, [j, Y]);
160
- let Ke = c("");
161
- m.phase === "listening" && (Ke.current = i(m)), s(() => {
183
+ }, [M, Z]);
184
+ let Xe = c("");
185
+ m.phase === "listening" && (Xe.current = i(m)), s(() => {
162
186
  if (m.phase !== "thinking") return;
163
- v(!1), B(), A((e) => typeof e == "object" && e ? null : e);
164
- let e = Ke.current.trim();
165
- e && De(e, Q.current ?? `vs-orphan-${Date.now().toString(36)}`, C.current, { correction: I.current.correcting }), C.current = {}, w.current = oe, T.current = void 0, E.current = void 0;
187
+ v(!1), V(), j((e) => typeof e == "object" && e ? null : e);
188
+ let e = Xe.current.trim();
189
+ e && De(e, $.current ?? `vs-orphan-${Date.now().toString(36)}`, S.current, { correction: L.current.correcting }), S.current = {}, C.current = oe, w.current = void 0, T.current = void 0;
166
190
  }, [m.phase]), s(() => {
167
- let e = de(u?.id, m.phase, D.current, ge(u?.id));
168
- e.claim && (D.current = u?.id ?? null, e.advance && u && (u.refused ? (B(), A({
191
+ let e = de(u?.id, m.phase, k.current, ge(u?.id));
192
+ e.claim && (k.current = u?.id ?? null, e.advance && u && (u.refused ? (V(), j({
169
193
  kind: "turn-refused",
170
194
  text: u.text
171
195
  }), h({ type: "turn-refused" })) : h({
@@ -175,15 +199,15 @@ function De({ onSubmit: De, latestReply: u, language: d, graceMs: Oe, onSupersed
175
199
  }, [
176
200
  u,
177
201
  m.phase,
178
- B
202
+ V
179
203
  ]), s(() => {
180
- if (y === null || m.phase !== "thinking" || D.current === y) return;
204
+ if (y === null || m.phase !== "thinking" || k.current === y) return;
181
205
  if (ge(y)) {
182
206
  b();
183
207
  return;
184
208
  }
185
209
  let e = re.peek(y);
186
- !e || e.channel !== "voice" || e.voiceSessionId === void 0 || e.voiceSessionId !== Q.current || (D.current = y, k.current = {
210
+ !e || e.channel !== "voice" || e.voiceSessionId === void 0 || e.voiceSessionId !== $.current || (k.current = y, Le.current = {
187
211
  id: y,
188
212
  text: e.text
189
213
  }, h({
@@ -196,74 +220,74 @@ function De({ onSubmit: De, latestReply: u, language: d, graceMs: Oe, onSupersed
196
220
  b
197
221
  ]), s(() => {
198
222
  let e = y !== null;
199
- O.current && !e && (R.current = null, (I.current.phase !== "speaking" || !V()) && h({ type: "speech-ended" })), O.current = e;
200
- }, [y, V]), s(() => {
201
- m.phase !== "listening" && A((e) => e === "nothing-heard" ? null : e);
223
+ A.current && !e && (z.current = null, (L.current.phase !== "speaking" || !H()) && h({ type: "speech-ended" })), A.current = e;
224
+ }, [y, H]), s(() => {
225
+ m.phase !== "listening" && j((e) => e === "nothing-heard" ? null : e);
202
226
  }, [m.phase]), s(() => {
203
227
  if (m.phase !== "speaking" || y !== null) return;
204
228
  let e = setTimeout(() => {
205
- O.current || (B(), h({ type: "speech-ended" }));
229
+ A.current || (V(), h({ type: "speech-ended" }));
206
230
  }, Ce);
207
231
  return () => clearTimeout(e);
208
232
  }, [
209
233
  m.phase,
210
234
  y,
211
- B
235
+ V
212
236
  ]);
213
- let X = g.outputNotCleared;
237
+ let Q = g.outputNotCleared;
214
238
  s(() => {
215
- if (X === null || D.current !== X.messageId) return;
216
- let { phase: e } = I.current;
217
- e === "idle" || e === "ended" || e === "thinking" || A("reply-not-heard");
218
- }, [X]), s(() => {
219
- m.phase === "listening" || m.phase === "thinking" || A((e) => e === "reply-not-heard" ? null : e);
239
+ if (Q === null || k.current !== Q.messageId) return;
240
+ let { phase: e } = L.current;
241
+ e === "idle" || e === "ended" || e === "thinking" || j("reply-not-heard");
242
+ }, [Q]), s(() => {
243
+ m.phase === "listening" || m.phase === "thinking" || j((e) => e === "reply-not-heard" ? null : e);
220
244
  }, [m.phase]);
221
- let Z = c(ke);
222
- Z.current = ke;
223
- let qe = c(0);
245
+ let Ze = c(ke);
246
+ Ze.current = ke;
247
+ let Qe = c(0);
224
248
  s(() => {
225
249
  let e = m.superseded;
226
- e !== qe.current && (qe.current = e, e !== 0 && (B(), b(), Z.current?.()));
250
+ e !== Qe.current && (Qe.current = e, e !== 0 && (V(), b(), Ze.current?.()));
227
251
  }, [
228
252
  m.superseded,
229
- B,
253
+ V,
230
254
  b
231
255
  ]), s(() => {
232
- v(ce(m)), pe(m) && !J.suppressWebSpeech ? q.isActive || q.start("auto") : q.isActive && q.stop();
256
+ v(ce(m)), pe(m) && !X.suppressWebSpeech ? Y.isActive || Y.start("auto") : Y.isActive && Y.stop();
233
257
  }, [
234
258
  m,
235
- q,
259
+ Y,
236
260
  v,
237
- J.suppressWebSpeech
261
+ X.suppressWebSpeech
238
262
  ]), s(() => {
239
- m.phase !== "speaking" || !z.current || (z.current = !1, V() || h({ type: "speech-ended" }));
240
- }, [m.phase, V]), s(() => {
241
- q.error === "not-allowed" || q.error === "audio-capture" ? h({
263
+ m.phase !== "speaking" || !B.current || (B.current = !1, H() || h({ type: "speech-ended" }));
264
+ }, [m.phase, H]), s(() => {
265
+ Y.error === "not-allowed" || Y.error === "audio-capture" ? h({
242
266
  type: "fail",
243
267
  error: "mic-denied"
244
- }) : q.error === "language-not-supported" ? h({
268
+ }) : Y.error === "language-not-supported" ? h({
245
269
  type: "fail",
246
270
  error: "no-speech-support"
247
- }) : q.error === "network" ? A("network") : q.error === "unknown" && A("recognition-failed");
248
- }, [q.error]), s(() => {
249
- q.error !== null || !Y || A((e) => e === "network" || e === "recognition-failed" ? null : e);
250
- }, [q.error, Y]), s(() => {
251
- if (Y && A((e) => e === "not-capturing" ? null : e), !ce(m) || Y || Ge) return;
252
- let e = setTimeout(() => A("not-capturing"), Te);
271
+ }) : Y.error === "network" ? j("network") : Y.error === "unknown" && j("recognition-failed");
272
+ }, [Y.error]), s(() => {
273
+ Y.error !== null || !Z || j((e) => e === "network" || e === "recognition-failed" ? null : e);
274
+ }, [Y.error, Z]), s(() => {
275
+ if (Z && j((e) => e === "not-capturing" ? null : e), !ce(m) || Z || Ye) return;
276
+ let e = setTimeout(() => j("not-capturing"), Te);
253
277
  return () => clearTimeout(e);
254
278
  }, [
255
279
  m,
256
- Y,
257
- Ge
280
+ Z,
281
+ Ye
258
282
  ]), s(() => {
259
- if (m.phase !== "listening" || m.muted || !Y || i(m) !== "") return;
260
- let e = setTimeout(() => A("nothing-heard"), Ee);
283
+ if (m.phase !== "listening" || m.muted || !Z || i(m) !== "") return;
284
+ let e = setTimeout(() => j("nothing-heard"), Ee);
261
285
  return () => clearTimeout(e);
262
- }, [m, Y]), s(() => {
263
- i(m) !== "" && A(null);
286
+ }, [m, Z]), s(() => {
287
+ i(m) !== "" && j(null);
264
288
  }, [m]);
265
- let Q = c(null), Je = o(() => {
266
- if (M(!1), N(!1), F(!1), B(), H.current = !1, !q.isSupported) {
289
+ let $ = c(null), $e = o(() => {
290
+ if (N(!1), P(!1), I(!1), V(), U.current = !1, !Y.isSupported) {
267
291
  h({
268
292
  type: "fail",
269
293
  error: "no-speech-support"
@@ -284,30 +308,30 @@ function De({ onSubmit: De, latestReply: u, language: d, graceMs: Oe, onSupersed
284
308
  t.volume = 0, e.speak(t);
285
309
  }
286
310
  } catch {}
287
- ne(), _(!0), A(null), D.current = ze.current?.id ?? null, k.current = null, Q.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, h({ type: "start" });
311
+ ne(), _(!0), j(null), k.current = He.current?.id ?? null, Le.current = null, $.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, h({ type: "start" });
288
312
  }, [
289
- q.isSupported,
313
+ Y.isSupported,
290
314
  g.isBlocked,
291
315
  _,
292
- B
293
- ]), Ye = o(() => {
294
- M(!1), N(!1), F(!1), B(), H.current = !1, Q.current = null, h({ type: "end" }), b(), _(!1);
316
+ V
317
+ ]), et = o(() => {
318
+ N(!1), P(!1), I(!1), V(), U.current = !1, $.current = null, h({ type: "end" }), b(), _(!1);
295
319
  }, [
296
320
  b,
297
321
  _,
298
- B
299
- ]), Xe = o((e) => Q.current === e, []), Ze = o(() => {
300
- let e = I.current;
301
- e.phase !== "listening" || e.muted || F(!0);
302
- }, []), Qe = o(() => {
303
- F(!1);
304
- let e = I.current;
322
+ V
323
+ ]), tt = o((e) => $.current === e, []), nt = o(() => {
324
+ let e = L.current;
325
+ e.phase !== "listening" || e.muted || I(!0);
326
+ }, []), rt = o(() => {
327
+ I(!1);
328
+ let e = L.current;
305
329
  if (e.phase !== "listening" || e.muted || !le(i(e))) return;
306
330
  let t = a();
307
- C.current = {
308
- speechEnded: w.current.at ?? t,
309
- lastSpeechFrame: T.current,
310
- recognizerSpeechEnded: E.current,
331
+ S.current = {
332
+ speechEnded: C.current.at ?? t,
333
+ lastSpeechFrame: w.current,
334
+ recognizerSpeechEnded: T.current,
311
335
  selectedGraceMs: f,
312
336
  graceStarted: t,
313
337
  graceEnded: t
@@ -315,69 +339,69 @@ function De({ onSubmit: De, latestReply: u, language: d, graceMs: Oe, onSupersed
315
339
  type: "silence",
316
340
  at: Date.now()
317
341
  });
318
- }, [f]), $e = o(() => {
342
+ }, [f]), it = o(() => {
319
343
  h({
320
344
  type: "mute",
321
- muted: !I.current.muted
345
+ muted: !L.current.muted
322
346
  });
323
347
  }, []);
324
348
  s(() => () => {
325
349
  _(!1), v(!1);
326
350
  }, [_, v]);
327
- let $ = _e(g.spokenChunks, m.phase, y);
351
+ let at = _e(g.spokenChunks, m.phase, y);
328
352
  return xe(() => ({
329
353
  session: m,
330
- notice: Fe ?? (J.fallbackReason !== null && J.fallbackReason !== "notice-declined" ? "hands-free-fallback" : J.nothingHeard ? "hands-free-nothing-heard" : null),
331
- spokenChunks: $,
332
- capturing: Y,
354
+ notice: Re ?? (X.fallbackReason !== null && X.fallbackReason !== "notice-declined" ? "hands-free-fallback" : X.nothingHeard ? "hands-free-nothing-heard" : null),
355
+ spokenChunks: at,
356
+ capturing: Z,
333
357
  active: m.phase !== "idle" && (m.phase !== "ended" || m.error !== null),
334
- interrupting: j,
335
- awaitingEndpoint: Ie,
336
- holding: P,
358
+ interrupting: M,
359
+ awaitingEndpoint: ze,
360
+ holding: F,
337
361
  correcting: m.correcting,
338
362
  handsFree: {
339
- mode: J.mode,
340
- nothingHeard: J.nothingHeard,
341
- transportKind: J.transportKind,
342
- fallbackReason: J.fallbackReason,
343
- privacyNotice: J.privacyNotice
363
+ mode: X.mode,
364
+ nothingHeard: X.nothingHeard,
365
+ transportKind: X.transportKind,
366
+ fallbackReason: X.fallbackReason,
367
+ privacyNotice: X.privacyNotice
344
368
  },
345
- available: q.isSupported && !g.isBlocked,
346
- start: Je,
347
- end: Ye,
348
- isCurrentSession: Xe,
349
- toggleMute: $e,
350
- interrupt: Ve,
351
- letMeFinish: Ze,
352
- imDone: Qe,
353
- announce: U,
354
- holdListening: Le,
355
- answerLocally: Re
369
+ available: Y.isSupported && !g.isBlocked,
370
+ start: $e,
371
+ end: et,
372
+ isCurrentSession: tt,
373
+ toggleMute: it,
374
+ interrupt: Ge,
375
+ letMeFinish: nt,
376
+ imDone: rt,
377
+ announce: W,
378
+ holdListening: Be,
379
+ answerLocally: Ve
356
380
  }), [
357
381
  m,
358
- Fe,
359
- j,
360
- Ie,
361
- P,
362
- Y,
363
- J.mode,
364
- J.nothingHeard,
365
- J.transportKind,
366
- J.fallbackReason,
367
- J.privacyNotice,
368
- q.isSupported,
382
+ Re,
383
+ M,
384
+ ze,
385
+ F,
386
+ Z,
387
+ X.mode,
388
+ X.nothingHeard,
389
+ X.transportKind,
390
+ X.fallbackReason,
391
+ X.privacyNotice,
392
+ Y.isSupported,
369
393
  g.isBlocked,
370
- $,
371
- Je,
372
- Ye,
373
- Xe,
394
+ at,
374
395
  $e,
375
- Ve,
376
- Ze,
377
- Qe,
378
- U,
379
- Le,
380
- Re
396
+ et,
397
+ tt,
398
+ it,
399
+ Ge,
400
+ nt,
401
+ rt,
402
+ W,
403
+ Be,
404
+ Ve
381
405
  ]);
382
406
  }
383
407
  //#endregion
@@ -68,6 +68,11 @@ export interface VoiceSessionSnapshot {
68
68
  * doing anything impure. Reset by `start`.
69
69
  */
70
70
  superseded: number;
71
+ /** Timing-only receipt; the hook keeps acoustic samples until classification finishes. */
72
+ correctionTimingDecision?: {
73
+ candidateId: number;
74
+ accepted: boolean;
75
+ };
71
76
  }
72
77
  /**
73
78
  * Deliberately does NOT include a "playback blocked" variant. Nothing can
@@ -98,6 +103,8 @@ export type VoiceSessionEvent =
98
103
  * leakage. Absent for the Web Speech path, whose audio is not vetted.
99
104
  */
100
105
  gated?: boolean;
106
+ /** Identifies pending acoustic timing, without putting per-frame updates in React state. */
107
+ timingCandidateId?: number;
101
108
  }
102
109
  /** Nothing heard for the person's grace (`resolveVoiceGraceMs`). */
103
110
  | {
@@ -119,7 +119,16 @@ function v(t, r, i = null) {
119
119
  } : t;
120
120
  case "speech": {
121
121
  if (t.muted) return t;
122
- if (t.phase === "thinking") return _(t, r, i);
122
+ if (t.phase === "thinking") {
123
+ let e = _(t, r, i);
124
+ return r.timingCandidateId !== void 0 && (e !== t || r.final) ? {
125
+ ...e,
126
+ correctionTimingDecision: {
127
+ candidateId: r.timingCandidateId,
128
+ accepted: e !== t
129
+ }
130
+ } : e;
131
+ }
123
132
  if (t.phase !== "listening" || !r.gated && p(r.transcript, i)) return t;
124
133
  let a = t.correcting ? n(r.transcript, t.submitted) : r.transcript;
125
134
  if (t.correcting && a === "") return t;