@burdenoff/fe-libs 2026.1029.6 → 2026.1029.7

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 (34) hide show
  1. package/dist/shared/assistant/index.d.ts +5 -0
  2. package/dist/shared/assistant/liveDeltas.d.ts +3 -0
  3. package/dist/shared/assistant/liveDeltas.js +17 -1
  4. package/dist/shared/assistant/liveOverlay.d.ts +4 -0
  5. package/dist/shared/assistant/liveOverlay.js +10 -1
  6. package/dist/shared/assistant/speech/appendSpeechQueue.d.ts +13 -0
  7. package/dist/shared/assistant/speech/appendSpeechQueue.js +75 -0
  8. package/dist/shared/assistant/speech/browserSpeechEngine.js +93 -46
  9. package/dist/shared/assistant/speech/hostedTtsSpeechEngine.js +173 -109
  10. package/dist/shared/assistant/speech/index.d.ts +1 -1
  11. package/dist/shared/assistant/speech/notifyCancellationSpeechEngine.js +53 -0
  12. package/dist/shared/assistant/speech/routingSpeechEngine.js +107 -23
  13. package/dist/shared/assistant/speech/speechFeed.d.ts +17 -2
  14. package/dist/shared/assistant/speech/speechFeed.js +35 -12
  15. package/dist/shared/assistant/speech/types.d.ts +20 -1
  16. package/dist/shared/assistant/turnTimeline.d.ts +3 -0
  17. package/dist/shared/assistant/turnTimeline.js +4 -1
  18. package/dist/shared/assistant/ui/AssistantChatArea.js +1410 -1393
  19. package/dist/shared/assistant/ui/AssistantSpeechProvider.js +351 -291
  20. package/dist/shared/assistant/ui/useVoiceSession.js +323 -288
  21. package/dist/shared/assistant/voice/livePhraseSpeech.d.ts +14 -0
  22. package/dist/shared/assistant/voice/livePhraseSpeech.js +72 -0
  23. package/dist/shared/assistant/voice/phraseGate.d.ts +11 -0
  24. package/dist/shared/assistant/voice/phraseGate.js +74 -0
  25. package/dist/shared/assistant/voice/phrasePlayback.d.ts +9 -0
  26. package/dist/shared/assistant/voice/phrasePlayback.js +78 -0
  27. package/dist/shared/assistant/voice/phraseSpeechConfig.d.ts +5 -0
  28. package/dist/shared/assistant/voice/phraseSpeechConfig.js +10 -0
  29. package/dist/shared/assistant/voice/speakableText.d.ts +1 -0
  30. package/dist/shared/assistant/voice/speakableText.js +1 -1
  31. package/dist/shared/assistant/voice/voiceSession.d.ts +5 -0
  32. package/dist/shared/assistant/voice/voiceSession.js +17 -1
  33. package/dist/shared-assistant.js +293 -288
  34. package/package.json +1 -1
@@ -1,39 +1,40 @@
1
- import { isPlaybackReferenceAttached as e, tapPlaybackElement as t } from "../voice/handsfree/playbackReference.js";
2
- import { HOSTED_TTS_TIER as n, HOSTED_VOICES as r, hostedLocaleFor as i } from "./hostedVoiceCatalogue.js";
3
- import { buildRequest as a, classifyHttpFailure as o, decodeAudioResponse as s, disableDurationMs as c, shouldDisableEngine as l, speakableChunks as u } from "./hostedTtsProtocol.js";
4
- import { createPieceSink as d, isOutputRefusal as f } from "./pieceSink.js";
1
+ import { createAppendSpeechQueue as e } from "./appendSpeechQueue.js";
2
+ import { isPlaybackReferenceAttached as t, tapPlaybackElement as n } from "../voice/handsfree/playbackReference.js";
3
+ import { HOSTED_TTS_TIER as r, HOSTED_VOICES as i, hostedLocaleFor as a } from "./hostedVoiceCatalogue.js";
4
+ import { buildRequest as o, classifyHttpFailure as s, decodeAudioResponse as c, disableDurationMs as l, shouldDisableEngine as u, speakableChunks as d } from "./hostedTtsProtocol.js";
5
+ import { createPieceSink as f, isOutputRefusal as p } from "./pieceSink.js";
5
6
  //#region src/shared/assistant/speech/hostedTtsSpeechEngine.ts
6
- function p(e) {
7
+ function m(e) {
7
8
  let t = Object.entries(e).map(([e, t]) => `${e.toLowerCase()}:${t}`).sort().join("\n"), n = 5381;
8
9
  for (let e = 0; e < t.length; e += 1) n = (n << 5) + n + t.charCodeAt(e) | 0;
9
10
  return `${t.length}:${n >>> 0}`;
10
11
  }
11
- var m = new Set([
12
+ var h = new Set([
12
13
  429,
13
14
  502,
14
15
  503,
15
16
  504
16
- ]), h = 3, g = 400, _ = 2e3;
17
- function v(e, t) {
17
+ ]), g = 3, _ = 400, v = 2e3;
18
+ function y(e, t) {
18
19
  let n = e === null ? NaN : Number(e);
19
- return Math.min(Number.isFinite(n) && n >= 0 ? n * 1e3 : g * 2 ** (t - 1), _);
20
+ return Math.min(Number.isFinite(n) && n >= 0 ? n * 1e3 : _ * 2 ** (t - 1), v);
20
21
  }
21
- var y = 6e4, b = 2, x = 1e3;
22
- function S(e) {
23
- return y + e / x * 2 * 1e3;
22
+ var b = 6e4, x = 2, S = 1e3;
23
+ function C(e) {
24
+ return b + e / S * 2 * 1e3;
24
25
  }
25
- var C = class extends Error {
26
+ var w = class extends Error {
26
27
  reason = "unknown";
27
28
  constructor() {
28
29
  super("audio output made no progress"), this.name = "OutputStalledError";
29
30
  }
30
31
  };
31
- function w(e) {
32
+ function T(e) {
32
33
  let t = 0, n = !1, r = null, i = () => {
33
34
  let n = r;
34
35
  n !== null && (n.cancel(), n.cancel = e(() => {
35
- r === n && (r = null, n.fail(new C()));
36
- }, S(t)));
36
+ r === n && (r = null, n.fail(new w()));
37
+ }, C(t)));
37
38
  };
38
39
  return {
39
40
  handed(e) {
@@ -64,14 +65,14 @@ function w(e) {
64
65
  }
65
66
  };
66
67
  }
67
- var T = "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=", E = [], D = 4;
68
- function O() {
69
- for (let e of [...E]) e();
70
- }
68
+ var E = "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=", D = [], O = 4;
71
69
  function k() {
72
- E.length = 0;
70
+ for (let e of [...D]) e();
71
+ }
72
+ function A() {
73
+ D.length = 0;
73
74
  }
74
- function A(e, t) {
75
+ function j(e, t) {
75
76
  return new Promise((n) => {
76
77
  if (t.aborted) {
77
78
  n();
@@ -86,100 +87,100 @@ function A(e, t) {
86
87
  t.addEventListener("abort", i, { once: !0 });
87
88
  });
88
89
  }
89
- function j(g) {
90
- let _ = g.fetchImpl ?? ((...e) => fetch(...e)), y = g.now ?? (() => Date.now()), b = g.setTimer ?? ((e, t) => {
90
+ function M(_) {
91
+ let v = _.fetchImpl ?? ((...e) => fetch(...e)), b = _.now ?? (() => Date.now()), x = _.setTimer ?? ((e, t) => {
91
92
  let n = setTimeout(e, t);
92
93
  return () => clearTimeout(n);
93
- }), x = null, S = null, O = null, k = !1, j = () => {
94
- if (!(k || typeof Audio != "function")) try {
95
- let e = O ?? new Audio();
96
- if (O = e, x === e) return;
97
- e.muted = !0, e.src = T, Promise.resolve(e.play()).then(() => {
98
- O === e && x !== e && e.pause();
94
+ }), S = null, C = null, k = null, A = !1, M = () => {
95
+ if (!(A || typeof Audio != "function")) try {
96
+ let e = k ?? new Audio();
97
+ if (k = e, S === e) return;
98
+ e.muted = !0, e.src = E, Promise.resolve(e.play()).then(() => {
99
+ k === e && S !== e && e.pause();
99
100
  }, () => {});
100
101
  } catch {}
101
102
  };
102
- E.push(j), E.length > D && E.shift();
103
- let M = 0, N = null, P = null, F = null, I = 0, L = null, R = null, z = () => {
103
+ D.push(M), D.length > O && D.shift();
104
+ let N = 0, P = null, F = null, I = null, L = null, R = 0, z = null, B = null, V = () => {
104
105
  try {
105
- return g.getHeaders?.() ?? {};
106
+ return _.getHeaders?.() ?? {};
106
107
  } catch {
107
108
  return {};
108
109
  }
109
- }, B = () => y() >= I ? !1 : R === null ? !0 : p(z()) === R, V = /* @__PURE__ */ new Set(), H = () => {
110
- for (let e of [...V]) e();
111
- }, U = () => {
112
- L !== null && clearTimeout(L), L = null;
113
- }, W = (e) => {
114
- U(), L = setTimeout(() => {
115
- L = null;
116
- let e = I - y();
110
+ }, H = () => b() >= R ? !1 : B === null ? !0 : m(V()) === B, U = /* @__PURE__ */ new Set(), W = () => {
111
+ for (let e of [...U]) e();
112
+ }, G = () => {
113
+ z !== null && clearTimeout(z), z = null;
114
+ }, K = (e) => {
115
+ G(), z = setTimeout(() => {
116
+ z = null;
117
+ let e = R - b();
117
118
  if (e > 0) {
118
- W(e);
119
+ K(e);
119
120
  return;
120
121
  }
121
- H();
122
+ W();
122
123
  }, e);
123
- }, G = (e, t) => {
124
- I = y() + e, R = t, W(e), H();
125
- }, K = () => {
126
- S &&= (URL.revokeObjectURL(S), null);
127
- }, q = () => {
128
- if (x) {
129
- x.onended = null, x.onerror = null;
124
+ }, q = (e, t) => {
125
+ R = b() + e, B = t, K(e), W();
126
+ }, J = () => {
127
+ C &&= (URL.revokeObjectURL(C), null);
128
+ }, Y = () => {
129
+ if (S) {
130
+ S.onended = null, S.onerror = null;
130
131
  try {
131
- x.pause();
132
+ S.pause();
132
133
  } catch {}
133
- x = null;
134
+ S = null;
134
135
  }
135
- K();
136
+ J();
136
137
  };
137
- async function J(e, t, r) {
138
- let c = a(e, i(t.lang) ?? t.lang, n, t.voice?.name ?? null, t.rate), l = g.getHeaders?.() ?? {}, u;
139
- for (let e = 1; u = await _(g.endpoint, {
138
+ async function X(e, t, n, i = !1) {
139
+ let l = o(e, a(t.lang) ?? t.lang, r, t.voice?.name ?? null, t.rate), u = _.getHeaders?.() ?? {}, d;
140
+ for (let e = 1; n.throwIfAborted(), d = await v(_.endpoint, {
140
141
  method: "POST",
141
- signal: r,
142
+ signal: n,
142
143
  headers: {
143
144
  "content-type": "application/json",
144
- ...l
145
+ ...u
145
146
  },
146
- body: JSON.stringify(c)
147
- }), !u.ok; e += 1) {
148
- if (!(m.has(u.status) && e < h && !r.aborted)) {
149
- let e = /* @__PURE__ */ Error(`hosted tts ${u.status}`);
150
- throw e.reason = o(u.status), e.headers = p(l), e;
147
+ body: JSON.stringify(l)
148
+ }), !d.ok; e += 1) {
149
+ if (!(h.has(d.status) && e < g && !n.aborted)) {
150
+ let e = /* @__PURE__ */ Error(`hosted tts ${d.status}`);
151
+ throw e.reason = i && d.status === 429 ? "rate-limited" : s(d.status), e.headers = m(u), e;
151
152
  }
152
- await A(v(u.headers.get("retry-after"), e), r);
153
+ await j(y(d.headers.get("retry-after"), e), n);
153
154
  }
154
- let d = u.headers.get("content-type"), f = s(d, d?.includes("json") ? await u.json() : await u.arrayBuffer());
155
- if (!f) {
155
+ let f = d.headers.get("content-type"), p = c(f, f?.includes("json") ? await d.json() : await d.arrayBuffer());
156
+ if (!p) {
156
157
  let e = /* @__PURE__ */ Error("hosted tts returned no audio");
157
158
  throw e.reason = "unknown", e;
158
159
  }
159
- return f;
160
+ return p;
160
161
  }
161
- function Y(n, r, i) {
162
+ function Z(e, r, i) {
162
163
  return new Promise((a, o) => {
163
- if (r !== M) {
164
+ if (r !== N) {
164
165
  a();
165
166
  return;
166
167
  }
167
- let s = new Blob([n.slice().buffer], { type: "audio/mpeg" });
168
- K(), S = URL.createObjectURL(s);
168
+ let s = new Blob([e.slice().buffer], { type: "audio/mpeg" });
169
+ J(), C = URL.createObjectURL(s);
169
170
  let c;
170
- e() ? (c = new Audio(S), t(c)) : (c = O ?? new Audio(), O = c, c.muted = !1, c.src = S), x = c, c.onended = () => {
171
- r === M && a();
171
+ t() ? (c = new Audio(C), n(c)) : (c = k ?? new Audio(), k = c, c.muted = !1, c.src = C), S = c, c.onended = () => {
172
+ r === N && a();
172
173
  }, c.onerror = () => {
173
- if (r !== M) {
174
+ if (r !== N) {
174
175
  a();
175
176
  return;
176
177
  }
177
178
  let e = /* @__PURE__ */ Error("audio playback failed");
178
179
  e.reason = "unknown", o(e);
179
180
  }, c.play().then(() => {
180
- c === O && !c.muted && (k = !0), r === M && i?.();
181
+ c === k && !c.muted && (A = !0), r === N && i?.();
181
182
  }, (e) => {
182
- if (r !== M) {
183
+ if (r !== N) {
183
184
  a();
184
185
  return;
185
186
  }
@@ -188,91 +189,154 @@ function j(g) {
188
189
  });
189
190
  });
190
191
  }
191
- return {
192
+ let Q = {
192
193
  id: "hosted-tts",
193
194
  isSupported() {
194
- return B() ? !1 : typeof window < "u" && typeof window.Audio == "function" && typeof fetch == "function";
195
+ return H() ? !1 : typeof window < "u" && typeof window.Audio == "function" && typeof fetch == "function";
195
196
  },
196
197
  listVoices() {
197
- return B() ? [] : [...r];
198
+ return H() ? [] : [...i];
198
199
  },
199
200
  subscribeVoices(e) {
200
- return V.add(e), () => {
201
- V.delete(e);
201
+ return U.add(e), () => {
202
+ U.delete(e);
202
203
  };
203
204
  },
204
205
  speak(e, t, n = {}) {
205
- let r = u(e);
206
+ F?.cancel(), F = null;
207
+ let r = d(e);
206
208
  if (r.length === 0) {
207
209
  n.onEnd?.();
208
210
  return;
209
211
  }
210
- M += 1;
211
- let i = M;
212
- q(), P?.cancel(), F?.stop(), j();
212
+ N += 1;
213
+ let i = N;
214
+ Y(), I?.cancel(), L?.stop(), M();
213
215
  let a = new AbortController();
214
- N = a;
216
+ P = a;
215
217
  let o = !1, s = () => {
216
218
  o || (o = !0, n.onStart?.());
217
- }, p = (e) => {
218
- let n = J(e, t, a.signal);
219
+ }, c = (e) => {
220
+ let n = X(e, t, a.signal);
219
221
  return n.catch(() => {}), n;
220
- }, m = t.audioOutput ? w(b) : null, h = t.audioOutput ? d(t.audioOutput, {
221
- play: (e) => Y(e, i, s),
222
- isCurrent: () => i === M,
222
+ }, m = t.audioOutput ? T(x) : null, h = t.audioOutput ? f(t.audioOutput, {
223
+ play: (e) => Z(e, i, s),
224
+ isCurrent: () => i === N,
223
225
  onChunkStart: (e) => {
224
226
  m?.progress(), n.onChunkStart?.(e);
225
227
  },
226
228
  onStart: s
227
229
  }) : null;
228
- P = h, F = m;
230
+ I = h, L = m;
229
231
  let g = (e) => m ? m.guard(e) : e, _ = () => {
230
- h && (m?.stop(), F === m && (F = null), P === h && (P = null));
232
+ h && (m?.stop(), L === m && (L = null), I === h && (I = null));
231
233
  };
232
234
  (async () => {
233
235
  try {
234
- let e = p(r[0]);
236
+ let e = c(r[0]);
235
237
  for (let t = 0; t < r.length; t += 1) {
236
- if (i !== M) return;
238
+ if (i !== N) return;
237
239
  let a = await e;
238
- if (i !== M) return;
240
+ if (i !== N) return;
239
241
  let o = r[t + 1];
240
- if (o !== void 0 && (e = p(o)), h) {
242
+ if (o !== void 0 && (e = c(o)), h) {
241
243
  m?.handed(a.byteLength), await g(h.write(a));
242
244
  continue;
243
245
  }
244
- n.onChunkStart?.(t), await Y(a, i, s);
246
+ n.onChunkStart?.(t), await Z(a, i, s);
245
247
  }
246
248
  if (h) {
247
249
  let e = await g(h.drain());
248
- if (i !== M) return;
250
+ if (i !== N) return;
249
251
  if (!e) throw Object.assign(/* @__PURE__ */ Error("audio output did not finish"), { reason: "unknown" });
250
252
  }
251
- i === M && (_(), n.onEnd?.());
253
+ i === N && (_(), n.onEnd?.());
252
254
  } catch (e) {
253
- if (a.abort(), i !== M) return;
255
+ if (a.abort(), i !== N) return;
254
256
  let t = null;
255
257
  if (h) {
256
- let n = e instanceof C ? null : await g(h.drain()).then(() => null, (e) => e);
257
- if (i !== M) return;
258
- h.cancel(), f(e) ? t = e : f(n) && (t = n);
258
+ let n = e instanceof w ? null : await g(h.drain()).then(() => null, (e) => e);
259
+ if (i !== N) return;
260
+ h.cancel(), p(e) ? t = e : p(n) && (t = n);
259
261
  }
260
- if (M += 1, q(), _(), t) {
262
+ if (N += 1, Y(), _(), t) {
261
263
  n.onError?.("output-not-cleared");
262
264
  return;
263
265
  }
264
266
  let r = e?.reason;
265
- l(r, e?.transient === !0) && G(c(r), r === "not-allowed" ? e.headers ?? null : null), n.onError?.(r === "not-allowed" || r === "unsupported" || r === "cancelled" ? r : "unknown");
267
+ u(r, e?.transient === !0) && q(l(r), r === "not-allowed" ? e.headers ?? null : null), n.onError?.(r === "not-allowed" || r === "unsupported" || r === "cancelled" ? r : "unknown");
266
268
  }
267
269
  })();
268
270
  },
271
+ open(t, n = {}) {
272
+ Q.cancel();
273
+ let r = ++N;
274
+ M();
275
+ let i = t.audioOutput ? T(x) : null, a, o = -1, s = -1, c = -1, d = null, m = t.audioOutput ? f(t.audioOutput, {
276
+ play: (e) => Z(e, r, () => a?.()),
277
+ isCurrent: () => r === N,
278
+ onChunkStart: () => {},
279
+ onStart: () => a?.()
280
+ }) : null;
281
+ I = m, L = i;
282
+ let h = (e) => i ? i.guard(e) : e, g = async () => {
283
+ if (m && !await h(m.drain())) throw Error("audio output did not finish");
284
+ }, _ = () => {
285
+ i?.stop(), L === i && (L = null), I === m && (I = null), F === v && (F = null);
286
+ }, v = e({
287
+ prepare: async (e, n) => {
288
+ try {
289
+ return await X(e, t, n, !0);
290
+ } catch (e) {
291
+ if (n.aborted) throw e;
292
+ try {
293
+ await g();
294
+ } catch (e) {
295
+ if (p(e)) throw e;
296
+ }
297
+ throw e;
298
+ }
299
+ },
300
+ play: async (e, t, n) => {
301
+ if (!m) {
302
+ c = t;
303
+ let i = new Promise((e) => {
304
+ d = e;
305
+ });
306
+ await Promise.race([Z(e, r, n), i]), d = null;
307
+ return;
308
+ }
309
+ a = n, o += 1, s = t, i?.handed(e.byteLength), await h(m.write(e));
310
+ },
311
+ drain: g,
312
+ retract: (e) => {
313
+ m && s >= e ? m.retract(o) : !m && c >= e && (Y(), d?.());
314
+ },
315
+ cancel: () => {
316
+ N += 1, Y(), d?.(), m?.cancel(), _();
317
+ },
318
+ failed: (e) => {
319
+ if (p(e)) return "output-not-cleared";
320
+ let t = e, n = t?.reason;
321
+ return u(n, t?.transient === !0) && q(l(n), n === "not-allowed" ? t?.headers ?? null : null), n === "not-allowed" || n === "unsupported" || n === "cancelled" || n === "rate-limited" ? n : "unknown";
322
+ }
323
+ }, {
324
+ ...n,
325
+ onEnd: () => {
326
+ _(), n.onEnd?.();
327
+ }
328
+ });
329
+ return F = v, v;
330
+ },
269
331
  headersChanged() {
270
- y() >= I || R === null || B() || (I = 0, R = null, U(), H());
332
+ b() >= R || B === null || H() || (R = 0, B = null, G(), W());
271
333
  },
272
334
  cancel() {
273
- M += 1, N?.abort(), N = null, q(), P?.cancel(), P = null, F?.stop(), F = null;
335
+ let e = F;
336
+ F = null, e?.cancel(), N += 1, P?.abort(), P = null, Y(), I?.cancel(), I = null, L?.stop(), L = null;
274
337
  }
275
338
  };
339
+ return Q;
276
340
  }
277
341
  //#endregion
278
- export { x as HOSTED_OUTPUT_MIN_AUDIO_BYTES_PER_SECOND, b as HOSTED_OUTPUT_STALL_AUDIO_RATIO, y as HOSTED_OUTPUT_STALL_BASE_MS, T as SILENT_WAV_DATA_URI, j as createHostedTtsEngine, S as hostedOutputStallMs, O as primeHostedPlayback, k as resetHostedPlaybackForTest, v as retryDelayMs };
342
+ export { S as HOSTED_OUTPUT_MIN_AUDIO_BYTES_PER_SECOND, x as HOSTED_OUTPUT_STALL_AUDIO_RATIO, b as HOSTED_OUTPUT_STALL_BASE_MS, E as SILENT_WAV_DATA_URI, M as createHostedTtsEngine, C as hostedOutputStallMs, k as primeHostedPlayback, A as resetHostedPlaybackForTest, y as retryDelayMs };
@@ -4,4 +4,4 @@ export { configureSpeechEngine, createSpeechEngines, getSpeechEngine, readSpeech
4
4
  export { createRoutingSpeechEngine } from './routingSpeechEngine';
5
5
  export type { SpeechEngineConfig } from './createSpeechEngine';
6
6
  export { HOSTED_VOICES, HOSTED_TTS_TIER, hostedSupportsLanguage } from './hostedVoiceCatalogue';
7
- export type { SpeechEngine, SpeechErrorReason, SpeechSpeakHandlers, SpeechSpeakOptions, SpeechVoiceLike, } from './types';
7
+ export type { SpeechEngine, SpeechQueue, SpeechErrorReason, SpeechSpeakHandlers, SpeechSpeakOptions, SpeechVoiceLike, } from './types';
@@ -10,6 +10,59 @@ function e(e) {
10
10
  listVoices: () => e.listVoices(),
11
11
  subscribeVoices: (t) => e.subscribeVoices(t),
12
12
  cancel: n,
13
+ ...e.open ? { open(r, i = {}) {
14
+ n();
15
+ let a = { handlers: i };
16
+ t = a;
17
+ let o = {
18
+ onStart: () => {
19
+ t === a && i.onStart?.();
20
+ },
21
+ onChunkStart: (e) => {
22
+ t === a && i.onChunkStart?.(e);
23
+ },
24
+ onChunkEnd: (e) => {
25
+ t === a && i.onChunkEnd?.(e);
26
+ },
27
+ onRetract: (e) => {
28
+ t === a && i.onRetract?.(e);
29
+ },
30
+ onPause: () => {
31
+ t === a && i.onPause?.();
32
+ },
33
+ onDeviceFallback: () => {
34
+ t === a && i.onDeviceFallback?.();
35
+ },
36
+ onEnd: () => {
37
+ t === a && (t = null, i.onEnd?.());
38
+ },
39
+ onError: (e) => {
40
+ t === a && (t = null, i.onError?.(e));
41
+ }
42
+ }, s;
43
+ try {
44
+ s = e.open(r, o);
45
+ } catch {
46
+ return o.onError?.("unknown"), {
47
+ append: () => !1,
48
+ end() {},
49
+ retract() {},
50
+ cancel() {}
51
+ };
52
+ }
53
+ return {
54
+ append: (e) => t === a && s.append(e),
55
+ end: () => {
56
+ t === a && s.end();
57
+ },
58
+ retract: () => {
59
+ t === a && s.retract();
60
+ },
61
+ cancel: () => {
62
+ t === a && n();
63
+ }
64
+ };
65
+ } } : {},
13
66
  speak(r, i, a = {}) {
14
67
  n();
15
68
  let o = { handlers: a };
@@ -4,6 +4,7 @@ import { selectVoiceForLocale as n } from "../voice/speechVoices.js";
4
4
  //#region src/shared/assistant/speech/routingSpeechEngine.ts
5
5
  function r(e) {
6
6
  switch (e) {
7
+ case "rate-limited":
7
8
  case "cancelled":
8
9
  case "output-not-cleared":
9
10
  case "output-left": return !1;
@@ -15,11 +16,11 @@ function r(e) {
15
16
  }
16
17
  function i({ device: i, hosted: a }) {
17
18
  if (!a) return i;
18
- let o = new Set(a.listVoices().map((e) => e.name)), s = (e) => e.source === "hosted" || o.has(e.name), c = (e, t, r, a = !1) => {
19
+ let o = null, s = new Set(a.listVoices().map((e) => e.name)), c = (e) => e.source === "hosted" || s.has(e.name), l = (e, t, r, a = !1) => {
19
20
  let o = () => {
20
21
  a && r?.onDeviceFallback?.();
21
22
  };
22
- if (!t.voice || !s(t.voice)) {
23
+ if (!t.voice || !c(t.voice)) {
23
24
  o(), i.speak(e, t, r);
24
25
  return;
25
26
  }
@@ -27,16 +28,16 @@ function i({ device: i, hosted: a }) {
27
28
  r?.onError?.("unsupported");
28
29
  return;
29
30
  }
30
- let c = n(i.listVoices(), t.lang);
31
- if (!c) {
31
+ let s = n(i.listVoices(), t.lang);
32
+ if (!s) {
32
33
  r?.onError?.("unsupported");
33
34
  return;
34
35
  }
35
36
  o(), i.speak(e, {
36
37
  ...t,
37
- voice: c
38
+ voice: s
38
39
  }, r);
39
- }, l = (t) => a.isSupported() ? t.voice ? o.has(t.voice.name) ? a : i : e(t.lang) ? a : i : i;
40
+ }, u = (t) => a.isSupported() ? t.voice ? s.has(t.voice.name) ? a : i : e(t.lang) ? a : i : i;
40
41
  return {
41
42
  id: `routing(${a.id}+${i.id})`,
42
43
  isSupported() {
@@ -51,45 +52,128 @@ function i({ device: i, hosted: a }) {
51
52
  t(), n();
52
53
  };
53
54
  },
54
- speak(e, n, o) {
55
- if (i.cancel(), a.cancel(), l(n) !== a) {
56
- c(e, n, o);
55
+ speak(e, n, s) {
56
+ if (o?.cancel(), o = null, i.cancel(), a.cancel(), u(n) !== a) {
57
+ l(e, n, s);
57
58
  return;
58
59
  }
59
- let s = !1, u = -1;
60
+ let c = !1, d = -1;
60
61
  a.speak(e, n, {
61
- ...o,
62
+ ...s,
62
63
  onStart: () => {
63
- s = !0, o?.onStart?.();
64
+ c = !0, s?.onStart?.();
64
65
  },
65
66
  onChunkStart: (e) => {
66
- u = e, o?.onChunkStart?.(e);
67
+ d = e, s?.onChunkStart?.(e);
67
68
  },
68
69
  onError: (i) => {
69
70
  if (!r(i) || n.fallback === !1) {
70
- o?.onError?.(i);
71
+ s?.onError?.(i);
71
72
  return;
72
73
  }
73
- if (!s) {
74
- c(e, n, o, !0);
74
+ if (!c) {
75
+ l(e, n, s, !0);
75
76
  return;
76
77
  }
77
- let a = u >= 0 ? t(e).slice(u + 1) : [];
78
+ let a = d >= 0 ? t(e).slice(d + 1) : [];
78
79
  if (a.length === 0) {
79
- o?.onError?.(i);
80
+ s?.onError?.(i);
80
81
  return;
81
82
  }
82
- let l = u + 1;
83
- c(a, n, {
84
- ...o,
83
+ let o = d + 1;
84
+ l(a, n, {
85
+ ...s,
85
86
  onStart: void 0,
86
- onChunkStart: (e) => o?.onChunkStart?.(l + e)
87
+ onChunkStart: (e) => s?.onChunkStart?.(o + e)
87
88
  }, !0);
88
89
  }
89
90
  });
90
91
  },
92
+ ...i.open && a.open ? { open(e, t = {}) {
93
+ o?.cancel(), i.cancel(), a.cancel();
94
+ let s = u(e), l = !1, d = !1, f = !1, p = 0, m = [], h = [], g, _ = () => {
95
+ if (!e.voice || !c(e.voice)) return e;
96
+ if (e.fallback === !1) return null;
97
+ let t = n(i.listVoices(), e.lang);
98
+ return t ? {
99
+ ...e,
100
+ voice: t
101
+ } : null;
102
+ }, v = (e) => {
103
+ d || (d = !0, h = [], t.onError?.(e));
104
+ }, y = {
105
+ ...t,
106
+ onStart: () => {
107
+ d || (l = !0, h = [], t.onStart?.());
108
+ },
109
+ onChunkStart: (e) => {
110
+ if (d) return;
111
+ l = !0, h = [];
112
+ let n = m[e];
113
+ n !== void 0 && t.onChunkStart?.(n);
114
+ },
115
+ onChunkEnd: (e) => {
116
+ let n = m[e];
117
+ !d && n !== void 0 && t.onChunkEnd?.(n);
118
+ },
119
+ onRetract: (e) => {
120
+ let n = e.flatMap((e) => m[e] === void 0 ? [] : [m[e]]), r = new Set(n);
121
+ h = h.filter((e) => !r.has(e.index)), t.onRetract?.(n);
122
+ },
123
+ onPause: () => {
124
+ d || t.onPause?.();
125
+ },
126
+ onEnd: () => {
127
+ d || (d = !0, h = [], t.onEnd?.());
128
+ },
129
+ onError: (n) => {
130
+ if (d) return;
131
+ if (s === i || l || !r(n) || e.fallback === !1) {
132
+ v(n);
133
+ return;
134
+ }
135
+ let a = _();
136
+ if (!a || !i.open) {
137
+ v("unsupported");
138
+ return;
139
+ }
140
+ if (g.cancel(), s = i, m = h.map((e) => e.index), g = i.open(a, y), t.onDeviceFallback?.(), !g.append(h.map((e) => e.text))) {
141
+ v("unknown");
142
+ return;
143
+ }
144
+ f && g.end();
145
+ }
146
+ }, b = s === i ? _() : e;
147
+ if (!b || !s.open) return v("unsupported"), {
148
+ append: () => !1,
149
+ end: () => {},
150
+ retract: () => {},
151
+ cancel: () => {}
152
+ };
153
+ g = s.open(b, y);
154
+ let x = {
155
+ append(e) {
156
+ if (d || f) return !1;
157
+ let t = e.filter((e) => e.trim()), n = t.map((e, t) => ({
158
+ index: p + t,
159
+ text: e
160
+ })), r = m.length;
161
+ return m.push(...n.map((e) => e.index)), l || h.push(...n), g.append(t) ? (p += n.length, !0) : (m.splice(r), h = h.filter((e) => e.index < p), !1);
162
+ },
163
+ end() {
164
+ d || (f = !0, g.end());
165
+ },
166
+ retract() {
167
+ d || g.retract();
168
+ },
169
+ cancel() {
170
+ d || (d = !0, h = [], g.cancel());
171
+ }
172
+ };
173
+ return o = x, x;
174
+ } } : {},
91
175
  cancel() {
92
- i.cancel(), a.cancel();
176
+ o?.cancel(), o = null, i.cancel(), a.cancel();
93
177
  }
94
178
  };
95
179
  }