@burdenoff/fe-libs 2026.1016.2 → 2026.1017.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 (49) hide show
  1. package/dist/shared/assistant/avatar/live/AvatarFace.d.ts +13 -0
  2. package/dist/shared/assistant/avatar/live/AvatarFace.js +46 -0
  3. package/dist/shared/assistant/avatar/live/LiveAvatarTabView.d.ts +2 -0
  4. package/dist/shared/assistant/avatar/live/LiveAvatarTabView.js +172 -145
  5. package/dist/shared/assistant/avatar/live/avatarFaces.d.ts +31 -0
  6. package/dist/shared/assistant/avatar/live/avatarFaces.js +33 -0
  7. package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.d.ts +12 -0
  8. package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.js +142 -75
  9. package/dist/shared/assistant/avatar/live/liveAvatarController.d.ts +5 -0
  10. package/dist/shared/assistant/avatar/live/liveAvatarController.js +3 -1
  11. package/dist/shared/assistant/avatar/live/liveAvatarStatus.d.ts +14 -0
  12. package/dist/shared/assistant/avatar/live/liveAvatarStatus.js +11 -2
  13. package/dist/shared/assistant/avatar/useAvatarCopy.d.ts +42 -0
  14. package/dist/shared/assistant/avatar/useAvatarCopy.js +113 -75
  15. package/dist/shared/assistant/i18nManifest.d.ts +29 -0
  16. package/dist/shared/assistant/i18nManifest.js +29 -0
  17. package/dist/shared/assistant/index.d.ts +8 -0
  18. package/dist/shared/assistant/speech/hostedTtsSpeechEngine.d.ts +6 -0
  19. package/dist/shared/assistant/speech/hostedTtsSpeechEngine.js +118 -101
  20. package/dist/shared/assistant/speech/notifyCancellationSpeechEngine.js +3 -0
  21. package/dist/shared/assistant/speech/replySpeechRequests.d.ts +84 -0
  22. package/dist/shared/assistant/speech/replySpeechRequests.js +70 -0
  23. package/dist/shared/assistant/speech/routingSpeechEngine.js +13 -9
  24. package/dist/shared/assistant/speech/types.d.ts +39 -1
  25. package/dist/shared/assistant/ui/AIAssistantPanel.js +128 -119
  26. package/dist/shared/assistant/ui/AssistantChatArea.js +1572 -1430
  27. package/dist/shared/assistant/ui/AssistantMessageItem.js +110 -100
  28. package/dist/shared/assistant/ui/AssistantSpeechProvider.d.ts +10 -0
  29. package/dist/shared/assistant/ui/AssistantSpeechProvider.js +286 -225
  30. package/dist/shared/assistant/ui/assistantLiveAvatarSeam.d.ts +40 -0
  31. package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.d.ts +6 -0
  32. package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.js +99 -52
  33. package/dist/shared/assistant/ui/avatar/AvatarTabAskBox.d.ts +8 -0
  34. package/dist/shared/assistant/ui/avatar/AvatarTabAskBox.js +87 -0
  35. package/dist/shared/assistant/ui/avatar/AvatarTabLastExchange.d.ts +13 -0
  36. package/dist/shared/assistant/ui/avatar/AvatarTabLastExchange.js +97 -0
  37. package/dist/shared/assistant/ui/avatar/avatarAskGate.d.ts +104 -0
  38. package/dist/shared/assistant/ui/avatar/avatarAskGate.js +39 -0
  39. package/dist/shared/assistant/ui/avatar/avatarTabDraft.d.ts +17 -0
  40. package/dist/shared/assistant/ui/avatar/avatarTabDraft.js +22 -0
  41. package/dist/shared/assistant/ui/avatar/avatarTabExchange.d.ts +47 -0
  42. package/dist/shared/assistant/ui/avatar/avatarTabExchange.js +50 -0
  43. package/dist/shared/assistant/ui/panelOverlays.d.ts +8 -1
  44. package/dist/shared/assistant/ui/panelOverlays.js +1 -1
  45. package/dist/shared/assistant/ui/useVoiceSession.js +222 -227
  46. package/dist/shared/assistant/voice/handsfree/playbackReference.d.ts +15 -4
  47. package/dist/shared/assistant/voice/handsfree/playbackReference.js +9 -6
  48. package/dist/shared-assistant.js +270 -262
  49. package/package.json +1 -1
@@ -7,54 +7,54 @@ import { copyToClipboard as i } from "../clipboard.js";
7
7
  import { AssistantMarkdownRenderer as a } from "./AssistantMarkdownRenderer.js";
8
8
  import { downloadAssistantArtifact as o } from "../api.js";
9
9
  import { languageConfirmationCopy as s } from "../appControls/languageReply.js";
10
- import { getAssistantDisplayContent as ee } from "../displayContent.js";
11
- import { AssistantToolActivity as te, parseToolActivity as c } from "./AssistantToolActivity.js";
10
+ import { getAssistantDisplayContent as c } from "../displayContent.js";
11
+ import { AssistantToolActivity as ee, parseToolActivity as te } from "./AssistantToolActivity.js";
12
12
  import { usePrefersReducedMotion as l } from "./usePrefersReducedMotion.js";
13
- import { AssistantAvatar as ne } from "./AssistantAvatar.js";
14
- import { useAssistantSpeech as re } from "./AssistantSpeechProvider.js";
15
- import { AssistantMessageAttachments as ie } from "./AssistantMessageAttachments.js";
16
- import { AssistantPendingWriteCard as ae } from "./AssistantPendingWriteCard.js";
17
- import { AssistantSpeakButton as oe } from "./AssistantSpeakButton.js";
18
- import { SaveToFilesButton as u } from "../../../storage/SaveToFilesButton.js";
13
+ import { AssistantAvatar as u } from "./AssistantAvatar.js";
14
+ import { useAssistantSpeech as d } from "./AssistantSpeechProvider.js";
15
+ import { AssistantMessageAttachments as ne } from "./AssistantMessageAttachments.js";
16
+ import { AssistantPendingWriteCard as re } from "./AssistantPendingWriteCard.js";
17
+ import { AssistantSpeakButton as ie } from "./AssistantSpeakButton.js";
18
+ import { SaveToFilesButton as ae } from "../../../storage/SaveToFilesButton.js";
19
19
  import "../../../storage/index.js";
20
- import { AssistantTurnActivity as se } from "./AssistantTurnActivity.js";
21
- import { useMemo as d, useRef as f, useState as p } from "react";
22
- import { Check as ce, Copy as m, RotateCcw as h } from "lucide-react";
23
- import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
20
+ import { AssistantTurnActivity as f } from "./AssistantTurnActivity.js";
21
+ import { useMemo as p, useRef as m, useState as h } from "react";
22
+ import { Check as oe, Copy as g, RotateCcw as se } from "lucide-react";
23
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
24
24
  //#region src/shared/assistant/ui/AssistantMessageItem.tsx
25
- function le(e) {
25
+ function b(e) {
26
26
  return e.role === "assistant" ? e.metadata : void 0;
27
27
  }
28
- function y(e) {
28
+ function ce(e) {
29
29
  return e?.artifacts ?? [];
30
30
  }
31
- function b(e) {
31
+ function x(e) {
32
32
  return window.atob(e);
33
33
  }
34
- function x(e, t, n) {
35
- let r = b(e), i = new Uint8Array(r.length);
34
+ function S(e, t, n) {
35
+ let r = x(e), i = new Uint8Array(r.length);
36
36
  for (let e = 0; e < r.length; e += 1) i[e] = r.charCodeAt(e);
37
37
  let a = new Blob([i], { type: n }), o = URL.createObjectURL(a), s = document.createElement("a");
38
38
  s.href = o, s.download = t, document.body.appendChild(s), s.click(), document.body.removeChild(s), URL.revokeObjectURL(o);
39
39
  }
40
- var S = () => /* @__PURE__ */ _("span", {
40
+ var C = () => /* @__PURE__ */ v("span", {
41
41
  "aria-hidden": "true",
42
42
  "data-testid": "assistant-streaming-caret",
43
43
  className: "ml-0.5 inline-block h-4 w-1.5 rounded-sm bg-text-secondary align-middle" + (l() ? "" : " motion-safe:animate-pulse")
44
- }), C = ({ onApprovePendingWrite: l, approvingWriteRef: b = null, pendingWriteExpired: C = !1, pendingWriteApproved: ue = !1, pendingWriteGoAheadSent: de = !1, message: w, processing: T, isStreaming: E, isFailed: D, isLastAssistant: O, isNewestAssistant: k, onRetry: A, legacyWriteCardHidden: j = !1, writeProposals: M, uiOffers: N }) => {
45
- let P = r(), { locale: F } = e(), I = s(w, P), L = I ? I.translated ? F : "en" : w.metadata?.lang, R = I ? `${w.id}:language:${L}` : w.id, z = f(R), B = n(), { getAccessToken: V, getWorkspaceToken: fe } = t(), H = re(), [pe, U] = p(null), [W, G] = p(!1), K = w.role === "user", q = d(() => le(w), [w]), J = d(() => y(q), [q]), Y = T === void 0 ? E ? {
44
+ }), w = ({ onApprovePendingWrite: l, approvingWriteRef: x = null, pendingWriteExpired: w = !1, pendingWriteApproved: le = !1, pendingWriteGoAheadSent: ue = !1, message: T, processing: E, isStreaming: D, isFailed: O, isLastAssistant: k, isNewestAssistant: A, onRetry: j, legacyWriteCardHidden: M = !1, writeProposals: N, uiOffers: P }) => {
45
+ let F = r(), { locale: I } = e(), L = s(T, F), R = L ? L.translated ? I : "en" : T.metadata?.lang, z = L ? `${T.id}:language:${R}` : T.id, B = m(z), V = n(), { getAccessToken: H, getWorkspaceToken: de } = t(), U = d(), [fe, W] = h(null), [pe, G] = h(!1), K = T.role === "user", q = p(() => b(T), [T]), J = p(() => ce(q), [q]), Y = E === void 0 ? D ? {
46
46
  status: "streaming",
47
- messageId: w.id,
48
- updatedAt: w.timestamp
49
- } : null : T, X = ee(w, Y, P), { steps: Z, text: Q } = d(() => K ? {
47
+ messageId: T.id,
48
+ updatedAt: T.timestamp
49
+ } : null : E, X = c(T, Y, F), { steps: Z, text: Q } = p(() => K ? {
50
50
  steps: [],
51
- text: w.content
52
- } : X.kind === "output" ? c(X.text) : {
51
+ text: T.content
52
+ } : X.kind === "output" ? te(X.text) : {
53
53
  steps: [],
54
54
  text: ""
55
55
  }, [
56
56
  K,
57
- w.content,
57
+ T.content,
58
58
  X.kind,
59
59
  X.text
60
60
  ]), me = () => {
@@ -65,50 +65,50 @@ var S = () => /* @__PURE__ */ _("span", {
65
65
  if (!q?.sandboxId || !q.sessionId) return;
66
66
  let t = new URLSearchParams(window.location.search).get("workspace") ?? "";
67
67
  if (t) {
68
- U(e.path);
68
+ W(e.path);
69
69
  try {
70
70
  let n = await o(q.sandboxId, t, q.sessionId, e.path, q.mode, {
71
- accessToken: V(),
72
- workspaceToken: fe()
71
+ accessToken: H(),
72
+ workspaceToken: de()
73
73
  });
74
- x(n.contentBase64, n.filename, n.mimeType);
74
+ S(n.contentBase64, n.filename, n.mimeType);
75
75
  } finally {
76
- U(null);
76
+ W(null);
77
77
  }
78
78
  }
79
- }, $ = new Date(w.timestamp).toLocaleTimeString([], {
79
+ }, $ = new Date(T.timestamp).toLocaleTimeString([], {
80
80
  hour: "2-digit",
81
81
  minute: "2-digit"
82
82
  });
83
- if (w.role === "system") return /* @__PURE__ */ _("div", {
83
+ if (T.role === "system") return /* @__PURE__ */ v("div", {
84
84
  className: "flex justify-center px-2 py-1",
85
85
  "data-testid": "assistant-message-system",
86
- children: w.metadata?.localAction?.kind === "navigate" ? /* @__PURE__ */ _("div", {
86
+ children: T.metadata?.localAction?.kind === "navigate" ? /* @__PURE__ */ v("div", {
87
87
  className: "max-w-[90%] break-words rounded-lg border border-border-subtle bg-bg-sunken/60 px-3 py-2 text-center text-xs leading-relaxed text-text-muted",
88
88
  "data-testid": "assistant-message-system-navigation",
89
- children: /* @__PURE__ */ _(a, { content: w.content })
90
- }) : /* @__PURE__ */ _("p", {
89
+ children: /* @__PURE__ */ v(a, { content: T.content })
90
+ }) : /* @__PURE__ */ v("p", {
91
91
  className: "max-w-[90%] whitespace-pre-wrap break-words rounded-lg border border-border-subtle bg-bg-sunken/60 px-3 py-2 text-center text-xs leading-relaxed text-text-muted",
92
- children: w.content
92
+ children: T.content
93
93
  })
94
94
  });
95
95
  if (K) {
96
- let e = w.metadata?.attachments ?? [];
97
- return /* @__PURE__ */ _("div", {
96
+ let e = T.metadata?.attachments ?? [];
97
+ return /* @__PURE__ */ v("div", {
98
98
  className: "flex justify-end",
99
99
  "data-testid": "assistant-message-user",
100
- children: /* @__PURE__ */ v("div", {
100
+ children: /* @__PURE__ */ y("div", {
101
101
  className: "max-w-[85%]",
102
102
  children: [
103
- w.content && /* @__PURE__ */ _("div", {
103
+ T.content && /* @__PURE__ */ v("div", {
104
104
  className: "rounded-2xl rounded-br-md bg-action-primary-bg/12 px-3.5 py-2.5 text-[15px] leading-relaxed text-text-primary",
105
- children: /* @__PURE__ */ _("p", {
105
+ children: /* @__PURE__ */ v("p", {
106
106
  className: "whitespace-pre-wrap",
107
- children: w.content
107
+ children: T.content
108
108
  })
109
109
  }),
110
- /* @__PURE__ */ _(ie, { attachments: e }),
111
- /* @__PURE__ */ _("div", {
110
+ /* @__PURE__ */ v(ne, { attachments: e }),
111
+ /* @__PURE__ */ v("div", {
112
112
  className: "mt-1 pr-1 text-right text-[10px] text-text-muted",
113
113
  children: $
114
114
  })
@@ -116,47 +116,47 @@ var S = () => /* @__PURE__ */ _("span", {
116
116
  })
117
117
  });
118
118
  }
119
- return /* @__PURE__ */ v("div", {
119
+ return /* @__PURE__ */ y("div", {
120
120
  className: "flex gap-2.5",
121
121
  "data-testid": "assistant-message-assistant",
122
- children: [/* @__PURE__ */ _(ne, { active: E }), /* @__PURE__ */ v("div", {
122
+ children: [/* @__PURE__ */ v(u, { active: D }), /* @__PURE__ */ y("div", {
123
123
  className: "min-w-0 flex-1",
124
124
  children: [
125
- Z.length > 0 && /* @__PURE__ */ _(te, { steps: Z }),
126
- q?.pendingWrite && !j ? /* @__PURE__ */ _(ae, {
125
+ Z.length > 0 && /* @__PURE__ */ v(ee, { steps: Z }),
126
+ q?.pendingWrite && !M ? /* @__PURE__ */ v(re, {
127
127
  pendingWrite: q.pendingWrite,
128
128
  onApprove: l,
129
- approving: b !== null && b === q.pendingWrite.reference,
130
- expired: C,
131
- approved: ue,
132
- goAheadSent: de,
133
- awaitingTurn: !!E
129
+ approving: x !== null && x === q.pendingWrite.reference,
130
+ expired: w,
131
+ approved: le,
132
+ goAheadSent: ue,
133
+ awaitingTurn: !!D
134
134
  }) : null,
135
- M,
136
- Q && /* @__PURE__ */ _("div", {
135
+ N,
136
+ Q && /* @__PURE__ */ v("div", {
137
137
  className: "text-[15px] leading-relaxed text-text-primary",
138
- children: /* @__PURE__ */ _(a, { content: Q })
138
+ children: /* @__PURE__ */ v(a, { content: Q })
139
139
  }),
140
- X.kind === "working" && /* @__PURE__ */ _(se, { processing: Y }),
141
- X.kind === "stopped" && /* @__PURE__ */ _("p", {
140
+ X.kind === "working" && /* @__PURE__ */ v(f, { processing: Y }),
141
+ X.kind === "stopped" && /* @__PURE__ */ v("p", {
142
142
  className: "text-[15px] leading-relaxed text-text-secondary",
143
143
  "data-testid": "assistant-turn-stopped",
144
144
  children: X.text
145
145
  }),
146
- E && /* @__PURE__ */ _(S, {}),
147
- N,
148
- J.length > 0 && q?.sandboxId && q.sessionId && /* @__PURE__ */ v("div", {
146
+ D && /* @__PURE__ */ v(C, {}),
147
+ P,
148
+ J.length > 0 && q?.sandboxId && q.sessionId && /* @__PURE__ */ y("div", {
149
149
  className: "mt-3 space-y-2 border-t border-border-subtle pt-2",
150
- children: [/* @__PURE__ */ _("p", {
150
+ children: [/* @__PURE__ */ v("p", {
151
151
  className: "text-[10px] font-medium uppercase tracking-wide text-text-muted",
152
- children: P("message.downloads", "Downloads")
153
- }), /* @__PURE__ */ _("div", {
152
+ children: F("message.downloads", "Downloads")
153
+ }), /* @__PURE__ */ v("div", {
154
154
  className: "flex flex-wrap gap-2",
155
155
  children: J.map((e) => {
156
156
  let t = `${e.name}${e.type === "directory" ? ".tar.gz" : ""}`;
157
- return /* @__PURE__ */ _(u, {
157
+ return /* @__PURE__ */ v(ae, {
158
158
  label: t,
159
- disabled: pe === e.path,
159
+ disabled: fe === e.path,
160
160
  testId: `assistant-artifact-${e.name}`,
161
161
  source: {
162
162
  kind: "sandbox-artifact",
@@ -165,59 +165,69 @@ var S = () => /* @__PURE__ */ _("span", {
165
165
  path: e.path,
166
166
  filename: t
167
167
  },
168
- defaultFolderPath: B.artifacts,
168
+ defaultFolderPath: V.artifacts,
169
169
  onDownload: () => he(e)
170
170
  }, e.path);
171
171
  })
172
172
  })]
173
173
  }),
174
- !E && (Q || D || O) && /* @__PURE__ */ v("div", {
174
+ !D && (Q || O || k) && /* @__PURE__ */ y("div", {
175
175
  className: "mt-1.5 flex items-center gap-1",
176
176
  children: [
177
- Q && /* @__PURE__ */ _("button", {
177
+ Q && /* @__PURE__ */ v("button", {
178
178
  type: "button",
179
179
  onClick: me,
180
180
  className: "flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] text-text-muted transition-colors hover:bg-bg-elevated hover:text-text-secondary",
181
- "aria-label": P("message.copy", "Copy message"),
181
+ "aria-label": F("message.copy", "Copy message"),
182
182
  "data-testid": "assistant-message-copy",
183
- children: W ? /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(ce, { className: "size-3 text-status-success-text" }), /* @__PURE__ */ _("span", { children: P("message.copied", "Copied") })] }) : /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(m, { className: "size-3" }), /* @__PURE__ */ _("span", { children: P("message.copyShort", "Copy") })] })
183
+ children: pe ? /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(oe, { className: "size-3 text-status-success-text" }), /* @__PURE__ */ v("span", { children: F("message.copied", "Copied") })] }) : /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(g, { className: "size-3" }), /* @__PURE__ */ v("span", { children: F("message.copyShort", "Copy") })] })
184
184
  }),
185
- Q && H.isSupported && (() => {
186
- let e = H.blockedFor(R) ?? H.disabledReason, t = H.isSpeaking(w.id) || H.isSpeaking(z.current), n = !!e && !!k, r = n ? `speak-reason-${w.id}` : void 0;
187
- return /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(oe, {
188
- isSpeaking: t,
189
- disabled: e !== null,
190
- disabledReason: e,
191
- describedById: r,
192
- onClick: () => {
193
- if (t) {
194
- H.stop();
195
- return;
185
+ Q && U.isSupported && (() => {
186
+ let e = U.blockedFor(z) ?? U.disabledReason, t = U.isSpeaking(T.id) || U.isSpeaking(B.current), n = !!e && !!A, r = n ? `speak-reason-${T.id}` : void 0, i = n ? null : U.deviceFallbackFor(z), a = i ? `speak-fallback-${T.id}` : void 0;
187
+ return /* @__PURE__ */ y(_, { children: [
188
+ /* @__PURE__ */ v(ie, {
189
+ isSpeaking: t,
190
+ disabled: e !== null,
191
+ disabledReason: e,
192
+ describedById: r ?? a,
193
+ onClick: () => {
194
+ if (t) {
195
+ U.stop();
196
+ return;
197
+ }
198
+ B.current = z, U.toggle(z, Q, R);
196
199
  }
197
- z.current = R, H.toggle(R, Q, L);
198
- }
199
- }), n && /* @__PURE__ */ _("span", {
200
- id: r,
201
- className: "text-[11px] text-text-muted",
202
- "data-testid": "assistant-speak-reason",
203
- children: e
204
- })] });
200
+ }),
201
+ n && /* @__PURE__ */ v("span", {
202
+ id: r,
203
+ className: "text-[11px] text-text-muted",
204
+ "data-testid": "assistant-speak-reason",
205
+ children: e
206
+ }),
207
+ i && /* @__PURE__ */ v("span", {
208
+ id: a,
209
+ role: "status",
210
+ className: "text-[11px] text-text-muted",
211
+ "data-testid": "assistant-speak-fallback",
212
+ children: i
213
+ })
214
+ ] });
205
215
  })(),
206
- (D || O) && A && !w.metadata?.localAction && /* @__PURE__ */ v("button", {
216
+ (O || k) && j && !T.metadata?.localAction && /* @__PURE__ */ y("button", {
207
217
  type: "button",
208
- onClick: A,
209
- className: `flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] transition-colors hover:bg-bg-elevated ${D ? "text-status-error-text" : "text-text-muted hover:text-text-secondary"}`,
210
- "aria-label": P("message.retry", "Retry"),
218
+ onClick: j,
219
+ className: `flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] transition-colors hover:bg-bg-elevated ${O ? "text-status-error-text" : "text-text-muted hover:text-text-secondary"}`,
220
+ "aria-label": F("message.retry", "Retry"),
211
221
  "data-testid": "assistant-message-retry",
212
- children: [/* @__PURE__ */ _(h, { className: "size-3" }), /* @__PURE__ */ _("span", { children: P("message.retry", "Retry") })]
222
+ children: [/* @__PURE__ */ v(se, { className: "size-3" }), /* @__PURE__ */ v("span", { children: F("message.retry", "Retry") })]
213
223
  })
214
224
  ]
215
225
  }),
216
- /* @__PURE__ */ v("div", {
226
+ /* @__PURE__ */ y("div", {
217
227
  className: "mt-1 text-[10px] text-text-muted",
218
- children: [$, w.tokens && /* @__PURE__ */ v("span", {
228
+ children: [$, T.tokens && /* @__PURE__ */ y("span", {
219
229
  className: "ml-2",
220
- children: [w.tokens.input + w.tokens.output, " tokens"]
230
+ children: [T.tokens.input + T.tokens.output, " tokens"]
221
231
  })]
222
232
  })
223
233
  ]
@@ -225,4 +235,4 @@ var S = () => /* @__PURE__ */ _("span", {
225
235
  });
226
236
  };
227
237
  //#endregion
228
- export { C as AssistantMessageItem, S as StreamingCaret };
238
+ export { w as AssistantMessageItem, C as StreamingCaret };
@@ -21,6 +21,16 @@ export interface AssistantSpeechContextValue {
21
21
  * is the dead-button bug all over again (BOFF-7106).
22
22
  */
23
23
  blockedFor: (messageId: string) => string | null;
24
+ /**
25
+ * ★ BOFF-9408: why THIS message was (or is being) read on the device voice,
26
+ * when the hosted voice could not play it. `null` otherwise.
27
+ *
28
+ * Said on screen because the user otherwise hears a different, flatter voice
29
+ * with no explanation; on iPhone that read as "the hosted voice is broken".
30
+ * It changes nothing the user chose: the saved voice stays, and pressing
31
+ * Listen again tries the hosted voice first.
32
+ */
33
+ deviceFallbackFor: (messageId: string) => string | null;
24
34
  /**
25
35
  * Every installed voice that can read the language the user speaks, best
26
36
  * first. Empty when there is no choice to offer — the picker hides itself