@burdenoff/website-sdk 2026.1102.2 → 2026.1102.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.
Files changed (46) hide show
  1. package/README.md +41 -2
  2. package/dist/avatar-live-view/index.d.mts +13 -4
  3. package/dist/avatar-live-view/index.d.ts +13 -4
  4. package/dist/avatar-live-view/index.js +1262 -257
  5. package/dist/avatar-live-view/index.js.map +1 -1
  6. package/dist/avatar-live-view/index.mjs +1260 -255
  7. package/dist/avatar-live-view/index.mjs.map +1 -1
  8. package/dist/{chunk-FQH3AJN3.js → chunk-7O2I32ZN.js} +2 -2
  9. package/dist/chunk-7O2I32ZN.js.map +1 -0
  10. package/dist/{chunk-R742FS5E.js → chunk-DZLUZKOX.js} +19 -17
  11. package/dist/{chunk-R742FS5E.js.map → chunk-DZLUZKOX.js.map} +1 -1
  12. package/dist/{chunk-SFT3WHN5.mjs → chunk-K3QZGJEH.mjs} +2 -2
  13. package/dist/chunk-K3QZGJEH.mjs.map +1 -0
  14. package/dist/{chunk-SK5UGG6A.js → chunk-P5GMVPR6.js} +76 -20
  15. package/dist/chunk-P5GMVPR6.js.map +1 -0
  16. package/dist/{chunk-EUPFS6MZ.mjs → chunk-SMD7MEEA.mjs} +76 -20
  17. package/dist/chunk-SMD7MEEA.mjs.map +1 -0
  18. package/dist/{chunk-ETI2HQEC.mjs → chunk-ZWEEBHXJ.mjs} +4 -4
  19. package/dist/{chunk-ETI2HQEC.mjs.map → chunk-ZWEEBHXJ.mjs.map} +1 -1
  20. package/dist/components/explore.d.mts +2 -2
  21. package/dist/components/explore.d.ts +2 -2
  22. package/dist/components/explore.js +14 -14
  23. package/dist/components/explore.mjs +2 -2
  24. package/dist/{explore-DUTNYUOm.d.mts → explore-DaSNdm4O.d.mts} +1 -1
  25. package/dist/{explore-DjQE7Xia.d.ts → explore-DtSPdlEy.d.ts} +1 -1
  26. package/dist/{explore-avatar-live-config-Cetx8-Zu.d.ts → explore-avatar-live-config-CAfN5eAX.d.ts} +6 -3
  27. package/dist/{explore-avatar-live-config-Bp3kQbU2.d.mts → explore-avatar-live-config-N4WhJzgS.d.mts} +6 -3
  28. package/dist/{explore-types-Bb2Ih3d8.d.mts → explore-types-Ol1Mm3dW.d.mts} +12 -1
  29. package/dist/{explore-types-Bb2Ih3d8.d.ts → explore-types-Ol1Mm3dW.d.ts} +12 -1
  30. package/dist/hooks/index.d.mts +2 -2
  31. package/dist/hooks/index.d.ts +2 -2
  32. package/dist/hooks/index.js +9 -9
  33. package/dist/hooks/index.mjs +1 -1
  34. package/dist/index.d.mts +15 -9
  35. package/dist/index.d.ts +15 -9
  36. package/dist/index.js +92 -63
  37. package/dist/index.js.map +1 -1
  38. package/dist/index.mjs +35 -6
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/{use-explore-chat-DunjG-3p.d.ts → use-explore-chat-B3dOOvJN.d.ts} +43 -3
  41. package/dist/{use-explore-chat-zRuoAin6.d.mts → use-explore-chat-CbfohA9O.d.mts} +43 -3
  42. package/package.json +1 -1
  43. package/dist/chunk-EUPFS6MZ.mjs.map +0 -1
  44. package/dist/chunk-FQH3AJN3.js.map +0 -1
  45. package/dist/chunk-SFT3WHN5.mjs.map +0 -1
  46. package/dist/chunk-SK5UGG6A.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { turnstileSiteKeyOf, isAvatarSite, isAvatarLiveLocaleReviewed, isAvatarVersion } from '../chunk-SFT3WHN5.mjs';
1
+ import { turnstileSiteKeyOf, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion } from '../chunk-K3QZGJEH.mjs';
2
2
  import { fill } from '../chunk-TT3MHN42.mjs';
3
3
  import { cn } from '../chunk-R7G6TWIS.mjs';
4
4
  import '../chunk-VNS5WDWO.mjs';
@@ -47,6 +47,15 @@ function readBotCheck(value) {
47
47
  }
48
48
  return mode === "off" ? "off" : "turnstile";
49
49
  }
50
+ var QUESTION_MODES = /* @__PURE__ */ new Set([
51
+ "any",
52
+ "suggested"
53
+ ]);
54
+ function readQuestions(value) {
55
+ if (value === void 0) return "suggested";
56
+ if (typeof value !== "string" || !QUESTION_MODES.has(value)) return null;
57
+ return value === "any" ? "any" : "suggested";
58
+ }
50
59
  function readAvailability(status, body) {
51
60
  if (status !== 200 || !isRecord(body)) return INERT;
52
61
  const { available, reason } = body;
@@ -56,16 +65,21 @@ function readAvailability(status, body) {
56
65
  if (reason === "ok") {
57
66
  const { consentVersion, maxSessionSeconds } = body;
58
67
  const botCheck = readBotCheck(body.botCheck);
59
- if (available !== true || typeof consentVersion !== "string" || !isAvatarVersion(consentVersion) || typeof maxSessionSeconds !== "number" || !Number.isInteger(maxSessionSeconds) || maxSessionSeconds < 1 || botCheck === null) {
68
+ const questions = readQuestions(body.questions);
69
+ if (available !== true || typeof consentVersion !== "string" || !isAvatarVersion(consentVersion) || typeof maxSessionSeconds !== "number" || !Number.isInteger(maxSessionSeconds) || maxSessionSeconds < 1 || botCheck === null || questions === null) {
60
70
  return INERT;
61
71
  }
62
72
  return {
63
73
  kind: "available",
64
- offer: { consentVersion, maxSessionSeconds, botCheck }
74
+ offer: { consentVersion, maxSessionSeconds, botCheck, questions }
65
75
  };
66
76
  }
67
77
  const meaning = available ? void 0 : AVAILABILITY_REASONS.get(reason);
68
- return meaning === void 0 || meaning === "inert" ? INERT : { kind: "refused", reason: meaning };
78
+ return meaning === void 0 || meaning === "inert" ? INERT : {
79
+ kind: "refused",
80
+ reason: meaning,
81
+ questions: body.questions === "any" ? "any" : "suggested"
82
+ };
69
83
  }
70
84
  var CREATE_REFUSALS = /* @__PURE__ */ new Map([
71
85
  ["busy", "busy"],
@@ -285,7 +299,31 @@ var EN = {
285
299
  locale: "The live avatar isn't offered in this language yet.",
286
300
  paused: "The live avatar is paused right now.",
287
301
  notEligible: "The avatar reads the first answer to a suggested question, within fifteen minutes. Start a new chat and choose a suggested question.",
288
- answerClaimed: "The avatar has already read this answer."
302
+ answerClaimed: "The avatar has already read this answer.",
303
+ askHeadline: "Ask a question, and the avatar reads the answer aloud.",
304
+ askLabel: "Question for the avatar",
305
+ askPlaceholder: "Ask the avatar\u2026",
306
+ askFooter: "Answers are AI-generated and can be wrong. Don't include personal details.",
307
+ askNoFiles: "To attach files, use Chat.",
308
+ askBusy: "You can ask when the current answer is ready.",
309
+ askUnavailable: "Chat isn't available right now.",
310
+ gettingAnswer: "Getting the answer\u2026",
311
+ startWhenReady: "Start when ready",
312
+ armed: "The avatar will start when the answer is ready.",
313
+ cancel: "Cancel",
314
+ armedCancelled: "The avatar didn't start. Press Start when ready to try again.",
315
+ notSpoken: "This answer stays in Chat as text. The avatar reads only answers that pass its speech checks.",
316
+ answerFailed: "The assistant couldn't answer. Try asking again.",
317
+ declined: "No problem. The answer is in Chat.",
318
+ askHere: "To hear an answer, ask it here.",
319
+ newChatForAvatar: "New chat for the avatar",
320
+ newChatNote: "Your current chat stays in History.",
321
+ newChatStarted: "Started a new chat for the avatar.",
322
+ readInChat: "Read the answer and sources in Chat",
323
+ usedToday: "You've had today's avatar session. Answers will show here as text.",
324
+ needsAnswerAny: "Ask a question here, and the avatar reads the answer aloud.",
325
+ startNewChatDetailAny: "The avatar reads aloud only the first answer in a new chat started in the Avatar tab, provided it passes the speech checks.",
326
+ notEligibleAny: "The avatar can't read this answer aloud. The answer and sources are in Chat."
289
327
  };
290
328
  var ZH = {
291
329
  checking: "\u6B63\u5728\u68C0\u67E5\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u662F\u5426\u53EF\u7528\u2026",
@@ -319,7 +357,32 @@ var ZH = {
319
357
  paused: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u76EE\u524D\u5DF2\u6682\u505C\u3002",
320
358
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
321
359
  notEligible: "\u865A\u62DF\u5F62\u8C61\u53EA\u6717\u8BFB\u63A8\u8350\u95EE\u9898\u7684\u7B2C\u4E00\u4E2A\u56DE\u7B54\uFF0C\u4E14\u987B\u5728\u5341\u4E94\u5206\u949F\u5185\u3002\u8BF7\u5F00\u59CB\u65B0\u7684\u804A\u5929\uFF0C\u5E76\u9009\u62E9\u4E00\u4E2A\u63A8\u8350\u95EE\u9898\u3002",
322
- answerClaimed: "\u865A\u62DF\u5F62\u8C61\u5DF2\u7ECF\u6717\u8BFB\u8FC7\u8FD9\u4E2A\u56DE\u7B54\u3002"
360
+ answerClaimed: "\u865A\u62DF\u5F62\u8C61\u5DF2\u7ECF\u6717\u8BFB\u8FC7\u8FD9\u4E2A\u56DE\u7B54\u3002",
361
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
362
+ askHeadline: "\u63D0\u51FA\u95EE\u9898\uFF0C\u865A\u62DF\u5F62\u8C61\u4F1A\u6717\u8BFB\u56DE\u7B54\u3002",
363
+ askLabel: "\u5411\u865A\u62DF\u5F62\u8C61\u63D0\u7684\u95EE\u9898",
364
+ askPlaceholder: "\u5411\u865A\u62DF\u5F62\u8C61\u63D0\u95EE\u2026",
365
+ askFooter: "\u56DE\u7B54\u7531 AI \u751F\u6210\uFF0C\u53EF\u80FD\u6709\u8BEF\u3002\u8BF7\u52FF\u5305\u542B\u4E2A\u4EBA\u4FE1\u606F\u3002",
366
+ askNoFiles: "\u5982\u9700\u9644\u52A0\u6587\u4EF6\uFF0C\u8BF7\u4F7F\u7528\u804A\u5929\u3002",
367
+ askBusy: "\u5F53\u524D\u56DE\u7B54\u51C6\u5907\u597D\u540E\u5373\u53EF\u63D0\u95EE\u3002",
368
+ askUnavailable: "\u804A\u5929\u76EE\u524D\u4E0D\u53EF\u7528\u3002",
369
+ gettingAnswer: "\u6B63\u5728\u83B7\u53D6\u56DE\u7B54\u2026",
370
+ startWhenReady: "\u51C6\u5907\u597D\u540E\u5F00\u59CB",
371
+ armed: "\u56DE\u7B54\u51C6\u5907\u597D\u540E\uFF0C\u865A\u62DF\u5F62\u8C61\u5C06\u5F00\u59CB\u3002",
372
+ cancel: "\u53D6\u6D88",
373
+ armedCancelled: "\u865A\u62DF\u5F62\u8C61\u672A\u542F\u52A8\u3002\u53EF\u518D\u6B21\u6309\u201C\u51C6\u5907\u597D\u540E\u5F00\u59CB\u201D\u3002",
374
+ notSpoken: "\u6B64\u56DE\u7B54\u4EE5\u6587\u5B57\u5F62\u5F0F\u4FDD\u7559\u5728\u804A\u5929\u4E2D\u3002\u865A\u62DF\u5F62\u8C61\u53EA\u6717\u8BFB\u901A\u8FC7\u5176\u8BED\u97F3\u68C0\u67E5\u7684\u56DE\u7B54\u3002",
375
+ answerFailed: "\u52A9\u624B\u65E0\u6CD5\u56DE\u7B54\u3002\u8BF7\u91CD\u65B0\u63D0\u95EE\u3002",
376
+ declined: "\u6CA1\u5173\u7CFB\u3002\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
377
+ askHere: "\u5982\u9700\u542C\u53D6\u56DE\u7B54\uFF0C\u8BF7\u5728\u8FD9\u91CC\u63D0\u95EE\u3002",
378
+ newChatForAvatar: "\u4E3A\u865A\u62DF\u5F62\u8C61\u5F00\u59CB\u65B0\u804A\u5929",
379
+ newChatNote: "\u5F53\u524D\u804A\u5929\u4F1A\u4FDD\u7559\u5728\u5386\u53F2\u8BB0\u5F55\u4E2D\u3002",
380
+ newChatStarted: "\u5DF2\u4E3A\u865A\u62DF\u5F62\u8C61\u5F00\u59CB\u65B0\u7684\u804A\u5929\u3002",
381
+ readInChat: "\u5728\u804A\u5929\u4E2D\u67E5\u770B\u56DE\u7B54\u548C\u6765\u6E90",
382
+ usedToday: "\u60A8\u4ECA\u5929\u5DF2\u4F7F\u7528\u8FC7\u865A\u62DF\u5F62\u8C61\u3002\u56DE\u7B54\u5C06\u4EE5\u6587\u5B57\u663E\u793A\u5728\u8FD9\u91CC\u3002",
383
+ needsAnswerAny: "\u5728\u8FD9\u91CC\u63D0\u95EE\uFF0C\u865A\u62DF\u5F62\u8C61\u4F1A\u6717\u8BFB\u56DE\u7B54\u3002",
384
+ startNewChatDetailAny: "\u865A\u62DF\u5F62\u8C61\u53EA\u6717\u8BFB\u5728\u201C\u865A\u62DF\u5F62\u8C61\u201D\u6807\u7B7E\u9875\u4E2D\u5F00\u59CB\u7684\u65B0\u804A\u5929\u7684\u7B2C\u4E00\u4E2A\u56DE\u7B54\uFF0C\u4E14\u8BE5\u56DE\u7B54\u987B\u901A\u8FC7\u8BED\u97F3\u68C0\u67E5\u3002",
385
+ notEligibleAny: "\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u6717\u8BFB\u6B64\u56DE\u7B54\u3002\u56DE\u7B54\u548C\u6765\u6E90\u5728\u804A\u5929\u4E2D\u3002"
323
386
  };
324
387
  var HI = {
325
388
  checking: "\u091C\u093E\u0901\u091A \u0939\u094B \u0930\u0939\u0940 \u0939\u0948 \u0915\u093F \u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0909\u092A\u0932\u092C\u094D\u0927 \u0939\u0948 \u092F\u093E \u0928\u0939\u0940\u0902\u2026",
@@ -353,7 +416,32 @@ var HI = {
353
416
  paused: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0930\u0941\u0915\u093E \u0939\u0941\u0906 \u0939\u0948\u0964",
354
417
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
355
418
  notEligible: "\u0905\u0935\u0924\u093E\u0930 \u0938\u0941\u091D\u093E\u090F \u0917\u090F \u092A\u094D\u0930\u0936\u094D\u0928 \u0915\u093E \u092A\u0939\u0932\u093E \u0909\u0924\u094D\u0924\u0930 \u0939\u0940 \u092A\u0922\u093C\u0924\u093E \u0939\u0948, \u092A\u0902\u0926\u094D\u0930\u0939 \u092E\u093F\u0928\u091F \u0915\u0947 \u092D\u0940\u0924\u0930\u0964 \u0928\u0908 \u091A\u0948\u091F \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902 \u0914\u0930 \u0915\u094B\u0908 \u0938\u0941\u091D\u093E\u092F\u093E \u0917\u092F\u093E \u092A\u094D\u0930\u0936\u094D\u0928 \u091A\u0941\u0928\u0947\u0902\u0964",
356
- answerClaimed: "\u0905\u0935\u0924\u093E\u0930 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u092A\u0939\u0932\u0947 \u0939\u0940 \u092A\u0922\u093C \u091A\u0941\u0915\u093E \u0939\u0948\u0964"
419
+ answerClaimed: "\u0905\u0935\u0924\u093E\u0930 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u092A\u0939\u0932\u0947 \u0939\u0940 \u092A\u0922\u093C \u091A\u0941\u0915\u093E \u0939\u0948\u0964",
420
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
421
+ askHeadline: "\u0915\u094B\u0908 \u092A\u094D\u0930\u0936\u094D\u0928 \u092A\u0942\u091B\u0947\u0902, \u0914\u0930 \u0905\u0935\u0924\u093E\u0930 \u0909\u0938\u0915\u093E \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0947\u0917\u093E\u0964",
422
+ askLabel: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947 \u0932\u093F\u090F \u092A\u094D\u0930\u0936\u094D\u0928",
423
+ askPlaceholder: "\u0905\u0935\u0924\u093E\u0930 \u0938\u0947 \u092A\u0942\u091B\u0947\u0902\u2026",
424
+ askFooter: "\u0909\u0924\u094D\u0924\u0930 AI \u0926\u094D\u0935\u093E\u0930\u093E \u092C\u0928\u093E\u090F \u091C\u093E\u0924\u0947 \u0939\u0948\u0902 \u0914\u0930 \u0917\u0932\u0924 \u0939\u094B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902\u0964 \u0928\u093F\u091C\u0940 \u091C\u093E\u0928\u0915\u093E\u0930\u0940 \u0936\u093E\u092E\u093F\u0932 \u0928 \u0915\u0930\u0947\u0902\u0964",
425
+ askNoFiles: "\u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u091A\u0948\u091F \u0915\u093E \u0909\u092A\u092F\u094B\u0917 \u0915\u0930\u0947\u0902\u0964",
426
+ askBusy: "\u092E\u094C\u091C\u0942\u0926\u093E \u0909\u0924\u094D\u0924\u0930 \u0924\u0948\u092F\u093E\u0930 \u0939\u094B\u0928\u0947 \u092A\u0930 \u0906\u092A \u092A\u0942\u091B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902\u0964",
427
+ askUnavailable: "\u091A\u0948\u091F \u0905\u092D\u0940 \u0909\u092A\u0932\u092C\u094D\u0927 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964",
428
+ gettingAnswer: "\u0909\u0924\u094D\u0924\u0930 \u0932\u093E\u092F\u093E \u091C\u093E \u0930\u0939\u093E \u0939\u0948\u2026",
429
+ startWhenReady: "\u0924\u0948\u092F\u093E\u0930 \u0939\u094B\u0928\u0947 \u092A\u0930 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902",
430
+ armed: "\u0909\u0924\u094D\u0924\u0930 \u0924\u0948\u092F\u093E\u0930 \u0939\u094B\u0924\u0947 \u0939\u0940 \u0905\u0935\u0924\u093E\u0930 \u0936\u0941\u0930\u0942 \u0939\u094B\u0917\u093E\u0964",
431
+ cancel: "\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902",
432
+ armedCancelled: "\u0905\u0935\u0924\u093E\u0930 \u0936\u0941\u0930\u0942 \u0928\u0939\u0940\u0902 \u0939\u0941\u0906\u0964 \u092B\u093F\u0930 \u0938\u0947 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u201C\u0924\u0948\u092F\u093E\u0930 \u0939\u094B\u0928\u0947 \u092A\u0930 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902\u201D \u0926\u092C\u093E\u090F\u0901\u0964",
433
+ notSpoken: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u091F\u0947\u0915\u094D\u0938\u094D\u091F \u0915\u0947 \u0930\u0942\u092A \u092E\u0947\u0902 \u0930\u0939\u0947\u0917\u093E\u0964 \u0905\u0935\u0924\u093E\u0930 \u0915\u0947\u0935\u0932 \u0935\u0939\u0940 \u0909\u0924\u094D\u0924\u0930 \u092A\u0922\u093C\u0924\u093E \u0939\u0948 \u091C\u094B \u0909\u0938\u0915\u0940 \u0935\u093E\u0923\u0940 \u091C\u093E\u0901\u091A \u092E\u0947\u0902 \u092A\u093E\u0938 \u0939\u094B\u0924\u0947 \u0939\u0948\u0902\u0964",
434
+ answerFailed: "\u0938\u0939\u093E\u092F\u0915 \u0909\u0924\u094D\u0924\u0930 \u0928\u0939\u0940\u0902 \u0926\u0947 \u0938\u0915\u093E\u0964 \u092B\u093F\u0930 \u0938\u0947 \u092A\u0942\u091B\u0915\u0930 \u0926\u0947\u0916\u0947\u0902\u0964",
435
+ declined: "\u0915\u094B\u0908 \u092C\u093E\u0924 \u0928\u0939\u0940\u0902\u0964 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
436
+ askHere: "\u0909\u0924\u094D\u0924\u0930 \u0938\u0941\u0928\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F, \u092F\u0939\u093E\u0901 \u092A\u0942\u091B\u0947\u0902\u0964",
437
+ newChatForAvatar: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947 \u0932\u093F\u090F \u0928\u0908 \u091A\u0948\u091F",
438
+ newChatNote: "\u0906\u092A\u0915\u0940 \u092E\u094C\u091C\u0942\u0926\u093E \u091A\u0948\u091F \u0907\u0924\u093F\u0939\u093E\u0938 \u092E\u0947\u0902 \u0930\u0939\u0947\u0917\u0940\u0964",
439
+ newChatStarted: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947 \u0932\u093F\u090F \u0928\u0908 \u091A\u0948\u091F \u0936\u0941\u0930\u0942 \u0915\u0940 \u0917\u0908\u0964",
440
+ readInChat: "\u0909\u0924\u094D\u0924\u0930 \u0914\u0930 \u0938\u094D\u0930\u094B\u0924 \u091A\u0948\u091F \u092E\u0947\u0902 \u092A\u0922\u093C\u0947\u0902",
441
+ usedToday: "\u0906\u091C \u0915\u093E \u0905\u0935\u0924\u093E\u0930 \u0938\u0924\u094D\u0930 \u0906\u092A \u0932\u0947 \u091A\u0941\u0915\u0947 \u0939\u0948\u0902\u0964 \u0909\u0924\u094D\u0924\u0930 \u092F\u0939\u093E\u0901 \u091F\u0947\u0915\u094D\u0938\u094D\u091F \u0915\u0947 \u0930\u0942\u092A \u092E\u0947\u0902 \u0926\u093F\u0916\u0947\u0902\u0917\u0947\u0964",
442
+ needsAnswerAny: "\u092F\u0939\u093E\u0901 \u092A\u094D\u0930\u0936\u094D\u0928 \u092A\u0942\u091B\u0947\u0902, \u0914\u0930 \u0905\u0935\u0924\u093E\u0930 \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0947\u0917\u093E\u0964",
443
+ startNewChatDetailAny: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947\u0935\u0932 \u0905\u0935\u0924\u093E\u0930 \u091F\u0948\u092C \u092E\u0947\u0902 \u0936\u0941\u0930\u0942 \u0915\u0940 \u0917\u0908 \u0928\u0908 \u091A\u0948\u091F \u0915\u093E \u092A\u0939\u0932\u093E \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0924\u093E \u0939\u0948, \u092C\u0936\u0930\u094D\u0924\u0947 \u0935\u0939 \u0935\u093E\u0923\u0940 \u091C\u093E\u0901\u091A \u092E\u0947\u0902 \u092A\u093E\u0938 \u0939\u094B\u0964",
444
+ notEligibleAny: "\u0905\u0935\u0924\u093E\u0930 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u0928\u0939\u0940\u0902 \u092A\u0922\u093C \u0938\u0915\u0924\u093E\u0964 \u0909\u0924\u094D\u0924\u0930 \u0914\u0930 \u0938\u094D\u0930\u094B\u0924 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0902\u0964"
357
445
  };
358
446
  var ES = {
359
447
  checking: "Comprobando si el avatar en vivo est\xE1 disponible\u2026",
@@ -387,7 +475,32 @@ var ES = {
387
475
  paused: "El avatar en vivo est\xE1 en pausa en este momento.",
388
476
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
389
477
  notEligible: "El avatar lee la primera respuesta a una pregunta sugerida, en un plazo de quince minutos. Inicia un chat nuevo y elige una pregunta sugerida.",
390
- answerClaimed: "El avatar ya ha le\xEDdo esta respuesta."
478
+ answerClaimed: "El avatar ya ha le\xEDdo esta respuesta.",
479
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
480
+ askHeadline: "Haz una pregunta y el avatar leer\xE1 la respuesta en voz alta.",
481
+ askLabel: "Pregunta para el avatar",
482
+ askPlaceholder: "Pregunta al avatar\u2026",
483
+ askFooter: "Las respuestas las genera la IA y pueden contener errores. No incluyas datos personales.",
484
+ askNoFiles: "Para adjuntar archivos, usa el chat.",
485
+ askBusy: "Podr\xE1s preguntar cuando la respuesta actual est\xE9 lista.",
486
+ askUnavailable: "El chat no est\xE1 disponible en este momento.",
487
+ gettingAnswer: "Obteniendo la respuesta\u2026",
488
+ startWhenReady: "Iniciar cuando est\xE9 lista",
489
+ armed: "El avatar empezar\xE1 cuando la respuesta est\xE9 lista.",
490
+ cancel: "Cancelar",
491
+ armedCancelled: "El avatar no se ha iniciado. Pulsa Iniciar cuando est\xE9 lista para volver a intentarlo.",
492
+ notSpoken: "Esta respuesta se queda en el chat como texto. El avatar solo lee respuestas que superan sus comprobaciones de voz.",
493
+ answerFailed: "El asistente no pudo responder. Vuelve a preguntar.",
494
+ declined: "De acuerdo. La respuesta est\xE1 en el chat.",
495
+ askHere: "Para escuchar una respuesta, pregunta aqu\xED.",
496
+ newChatForAvatar: "Chat nuevo para el avatar",
497
+ newChatNote: "Tu chat actual se queda en el historial.",
498
+ newChatStarted: "Se ha iniciado un chat nuevo para el avatar.",
499
+ readInChat: "Leer la respuesta y las fuentes en el chat",
500
+ usedToday: "Ya has usado la sesi\xF3n de avatar de hoy. Las respuestas se mostrar\xE1n aqu\xED como texto.",
501
+ needsAnswerAny: "Haz una pregunta aqu\xED y el avatar leer\xE1 la respuesta en voz alta.",
502
+ startNewChatDetailAny: "El avatar solo lee en voz alta la primera respuesta de un chat nuevo iniciado en la pesta\xF1a Avatar, si supera las comprobaciones de voz.",
503
+ notEligibleAny: "El avatar no puede leer esta respuesta en voz alta. La respuesta y las fuentes est\xE1n en el chat."
391
504
  };
392
505
  var AR = {
393
506
  checking: "\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0642\u0642 \u0645\u0646 \u062A\u0648\u0641\u0631 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631\u2026",
@@ -421,7 +534,32 @@ var AR = {
421
534
  paused: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0645\u062A\u0648\u0642\u0641 \u0645\u0624\u0642\u062A\u064B\u0627 \u0627\u0644\u0622\u0646.",
422
535
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
423
536
  notEligible: "\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0623\u0648\u0644\u0649 \u0639\u0646 \u0633\u0624\u0627\u0644 \u0645\u0642\u062A\u0631\u062D\u060C \u062E\u0644\u0627\u0644 \u062E\u0645\u0633 \u0639\u0634\u0631\u0629 \u062F\u0642\u064A\u0642\u0629. \u0627\u0628\u062F\u0623 \u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0648\u0627\u062E\u062A\u0631 \u0633\u0624\u0627\u0644\u064B\u0627 \u0645\u0642\u062A\u0631\u062D\u064B\u0627.",
424
- answerClaimed: "\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0645\u0646 \u0642\u0628\u0644."
537
+ answerClaimed: "\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0645\u0646 \u0642\u0628\u0644.",
538
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
539
+ askHeadline: "\u0627\u0637\u0631\u062D \u0633\u0624\u0627\u0644\u064B\u0627\u060C \u0648\u0633\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D.",
540
+ askLabel: "\u0633\u0624\u0627\u0644 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631",
541
+ askPlaceholder: "\u0627\u0633\u0623\u0644 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631\u2026",
542
+ askFooter: "\u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A \u0645\u064F\u0648\u0644\u064E\u0651\u062F\u0629 \u0628\u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0627\u0635\u0637\u0646\u0627\u0639\u064A \u0648\u0642\u062F \u062A\u0643\u0648\u0646 \u062E\u0627\u0637\u0626\u0629. \u0644\u0627 \u062A\u0636\u0645\u0651\u0646 \u0628\u064A\u0627\u0646\u0627\u062A \u0634\u062E\u0635\u064A\u0629.",
543
+ askNoFiles: "\u0644\u0625\u0631\u0641\u0627\u0642 \u0645\u0644\u0641\u0627\u062A\u060C \u0627\u0633\u062A\u062E\u062F\u0645 \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
544
+ askBusy: "\u064A\u0645\u0643\u0646\u0643 \u0627\u0644\u0633\u0624\u0627\u0644 \u0639\u0646\u062F\u0645\u0627 \u062A\u0635\u0628\u062D \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u062D\u0627\u0644\u064A\u0629 \u062C\u0627\u0647\u0632\u0629.",
545
+ askUnavailable: "\u0627\u0644\u062F\u0631\u062F\u0634\u0629 \u063A\u064A\u0631 \u0645\u062A\u0627\u062D\u0629 \u0627\u0644\u0622\u0646.",
546
+ gettingAnswer: "\u062C\u0627\u0631\u064D \u0627\u0644\u062D\u0635\u0648\u0644 \u0639\u0644\u0649 \u0627\u0644\u0625\u062C\u0627\u0628\u0629\u2026",
547
+ startWhenReady: "\u0627\u0644\u0628\u062F\u0621 \u0639\u0646\u062F \u0627\u0644\u062C\u0627\u0647\u0632\u064A\u0629",
548
+ armed: "\u0633\u064A\u0628\u062F\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0639\u0646\u062F\u0645\u0627 \u062A\u0635\u0628\u062D \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u062C\u0627\u0647\u0632\u0629.",
549
+ cancel: "\u0625\u0644\u063A\u0627\u0621",
550
+ armedCancelled: "\u0644\u0645 \u064A\u0628\u062F\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631. \u0627\u0636\u063A\u0637 \u0639\u0644\u0649 \u0627\u0644\u0628\u062F\u0621 \u0639\u0646\u062F \u0627\u0644\u062C\u0627\u0647\u0632\u064A\u0629 \u0644\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.",
551
+ notSpoken: "\u062A\u0628\u0642\u0649 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629 \u0646\u0635\u064B\u0627. \u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0641\u0642\u0637 \u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u062C\u062A\u0627\u0632 \u0641\u062D\u0648\u0635 \u0627\u0644\u0646\u0637\u0642.",
552
+ answerFailed: "\u062A\u0639\u0630\u0651\u0631 \u0639\u0644\u0649 \u0627\u0644\u0645\u0633\u0627\u0639\u062F \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u062D\u0627\u0648\u0644 \u0627\u0644\u0633\u0624\u0627\u0644 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.",
553
+ declined: "\u0644\u0627 \u0628\u0623\u0633. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
554
+ askHere: "\u0644\u0633\u0645\u0627\u0639 \u0625\u062C\u0627\u0628\u0629\u060C \u0627\u0633\u0623\u0644 \u0647\u0646\u0627.",
555
+ newChatForAvatar: "\u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631",
556
+ newChatNote: "\u062A\u0628\u0642\u0649 \u062F\u0631\u062F\u0634\u062A\u0643 \u0627\u0644\u062D\u0627\u0644\u064A\u0629 \u0641\u064A \u0627\u0644\u0633\u062C\u0644.",
557
+ newChatStarted: "\u0628\u062F\u0623\u062A \u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631.",
558
+ readInChat: "\u0627\u0642\u0631\u0623 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0648\u0627\u0644\u0645\u0635\u0627\u062F\u0631 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629",
559
+ usedToday: "\u0644\u0642\u062F \u0627\u0633\u062A\u062E\u062F\u0645\u062A \u062C\u0644\u0633\u0629 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0644\u0647\u0630\u0627 \u0627\u0644\u064A\u0648\u0645. \u0633\u062A\u0638\u0647\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A \u0647\u0646\u0627 \u0646\u0635\u064B\u0627.",
560
+ needsAnswerAny: "\u0627\u0637\u0631\u062D \u0633\u0624\u0627\u0644\u064B\u0627 \u0647\u0646\u0627\u060C \u0648\u0633\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D.",
561
+ startNewChatDetailAny: "\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0623\u0648\u0644\u0649 \u0641\u0642\u0637 \u0641\u064A \u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0628\u062F\u0623\u062A \u0641\u064A \u0639\u0644\u0627\u0645\u0629 \u062A\u0628\u0648\u064A\u0628 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631\u060C \u0628\u0634\u0631\u0637 \u0623\u0646 \u062A\u062C\u062A\u0627\u0632 \u0641\u062D\u0648\u0635 \u0627\u0644\u0646\u0637\u0642.",
562
+ notEligibleAny: "\u0644\u0627 \u064A\u0645\u0643\u0646 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0642\u0631\u0627\u0621\u0629 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0648\u0627\u0644\u0645\u0635\u0627\u062F\u0631 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629."
425
563
  };
426
564
  var TA = {
427
565
  checking: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BBE \u0B8E\u0BA9\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1\u2026",
@@ -455,7 +593,32 @@ var TA = {
455
593
  paused: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B87\u0B9F\u0BC8\u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BC1\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
456
594
  // TRANSLATION REVIEW PENDING (BOFF-9797): draft.
457
595
  notEligible: "\u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0BAE\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7, \u0BAA\u0BA4\u0BBF\u0BA9\u0BC8\u0BA8\u0BCD\u0BA4\u0BC1 \u0BA8\u0BBF\u0BAE\u0BBF\u0B9F\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0BB3\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD. \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BBF, \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0B92\u0BB0\u0BC1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0BB0\u0BCD\u0BA8\u0BCD\u0BA4\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.",
458
- answerClaimed: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B8F\u0BB1\u0BCD\u0B95\u0BC6\u0BA9\u0BB5\u0BC7 \u0BAA\u0B9F\u0BBF\u0BA4\u0BCD\u0BA4\u0BC1\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1."
596
+ answerClaimed: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B8F\u0BB1\u0BCD\u0B95\u0BC6\u0BA9\u0BB5\u0BC7 \u0BAA\u0B9F\u0BBF\u0BA4\u0BCD\u0BA4\u0BC1\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
597
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the Avatar tab's question box.
598
+ askHeadline: "\u0B92\u0BB0\u0BC1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
599
+ askLabel: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF",
600
+ askPlaceholder: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BBF\u0B9F\u0BAE\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD\u2026",
601
+ askFooter: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD AI \u0B89\u0BB0\u0BC1\u0BB5\u0BBE\u0B95\u0BCD\u0B95\u0BBF\u0BAF\u0BB5\u0BC8, \u0BA4\u0BB5\u0BB1\u0BBE\u0B95 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BB2\u0BBE\u0BAE\u0BCD. \u0BA4\u0BA9\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0BB5\u0BBF\u0BB5\u0BB0\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0B9A\u0BCD \u0B9A\u0BC7\u0BB0\u0BCD\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BBE\u0BAE\u0BCD.",
602
+ askNoFiles: "\u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95, \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BC8\u0BAA\u0BCD \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BB5\u0BC1\u0BAE\u0BCD.",
603
+ askBusy: "\u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC8\u0BAF \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBE\u0BA9\u0BA4\u0BC1\u0BAE\u0BCD \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B95\u0BB2\u0BBE\u0BAE\u0BCD.",
604
+ askUnavailable: "\u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8 \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
605
+ gettingAnswer: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8\u0BAA\u0BCD \u0BAA\u0BC6\u0BB1\u0BC1\u0B95\u0BBF\u0BB1\u0BA4\u0BC1\u2026",
606
+ startWhenReady: "\u0BA4\u0BAF\u0BBE\u0BB0\u0BBE\u0BA9\u0BA4\u0BC1\u0BAE\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BC1",
607
+ armed: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBE\u0BA9\u0BA4\u0BC1\u0BAE\u0BCD \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
608
+ cancel: "\u0BB0\u0BA4\u0BCD\u0BA4\u0BC1\u0B9A\u0BC6\u0BAF\u0BCD",
609
+ armedCancelled: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB2, \u0BA4\u0BAF\u0BBE\u0BB0\u0BBE\u0BA9\u0BA4\u0BC1\u0BAE\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BC1 \u0B8E\u0BA9\u0BCD\u0BAA\u0BA4\u0BC8 \u0B85\u0BB4\u0BC1\u0BA4\u0BCD\u0BA4\u0BB5\u0BC1\u0BAE\u0BCD.",
610
+ notSpoken: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B95\u0BB5\u0BC7 \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD. \u0BAA\u0BC7\u0B9A\u0BCD\u0B9A\u0BC1\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BA4\u0BC7\u0BB1\u0BC1\u0BAE\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BC8 \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
611
+ answerFailed: "\u0B89\u0BA4\u0BB5\u0BBF\u0BAF\u0BBE\u0BB3\u0BB0\u0BBE\u0BB2\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BB3\u0BBF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B9F\u0BC1\u0BAA\u0BCD \u0BAA\u0BBE\u0BB0\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD.",
612
+ declined: "\u0BAA\u0BB0\u0BB5\u0BBE\u0BAF\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
613
+ askHere: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B95, \u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD.",
614
+ newChatForAvatar: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8",
615
+ newChatNote: "\u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC8\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8 \u0BB5\u0BB0\u0BB2\u0BBE\u0BB1\u0BCD\u0BB1\u0BBF\u0BB2\u0BCD \u0B87\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
616
+ newChatStarted: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0B95\u0BAA\u0BCD \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8 \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
617
+ readInChat: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0B86\u0BA4\u0BBE\u0BB0\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD",
618
+ usedToday: "\u0B87\u0BA9\u0BCD\u0BB1\u0BC8\u0BAF \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B85\u0BAE\u0BB0\u0BCD\u0BB5\u0BC8 \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BBF\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BC0\u0BB0\u0BCD\u0B95\u0BB3\u0BCD. \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD \u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0BAE\u0BCD.",
619
+ needsAnswerAny: "\u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B92\u0BB0\u0BC1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
620
+ startNewChatDetailAny: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BBE\u0BB5\u0BB2\u0BBF\u0BB2\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BBF\u0BAF \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BA9\u0BCD \u0BAE\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7, \u0B85\u0BA4\u0BC1 \u0BAA\u0BC7\u0B9A\u0BCD\u0B9A\u0BC1\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BA4\u0BC7\u0BB1\u0BBF\u0BA9\u0BBE\u0BB2\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
621
+ notEligibleAny: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BBE\u0BB2\u0BCD \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BBE\u0BA4\u0BC1. \u0BAA\u0BA4\u0BBF\u0BB2\u0BC1\u0BAE\u0BCD \u0B86\u0BA4\u0BBE\u0BB0\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0BAE\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA9."
459
622
  };
460
623
  var STRINGS = {
461
624
  en: EN,
@@ -479,7 +642,8 @@ var CONSENT = /* @__PURE__ */ new Map([
479
642
  processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Your browser connects to LiveKit, which sees your IP address. LiveKit fetches our temporary audio file and passes the voice to Protoface, which makes the avatar video streamed through LiveKit.",
480
643
  storage: "Your microphone and camera are not used. We do not record the live session. We temporarily store the generated voice file and keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
481
644
  privacyLink: "How we handle this",
482
- botCheck: "turnstile"
645
+ botCheck: "turnstile",
646
+ questions: "suggested"
483
647
  }
484
648
  }
485
649
  ],
@@ -494,7 +658,8 @@ var CONSENT = /* @__PURE__ */ new Map([
494
658
  processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
495
659
  storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
496
660
  privacyLink: "How we handle this",
497
- botCheck: "turnstile"
661
+ botCheck: "turnstile",
662
+ questions: "suggested"
498
663
  }
499
664
  }
500
665
  ],
@@ -510,7 +675,8 @@ var CONSENT = /* @__PURE__ */ new Map([
510
675
  processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
511
676
  storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
512
677
  privacyLink: "How we handle this",
513
- botCheck: "turnstile"
678
+ botCheck: "turnstile",
679
+ questions: "suggested"
514
680
  }
515
681
  }
516
682
  ],
@@ -526,7 +692,44 @@ var CONSENT = /* @__PURE__ */ new Map([
526
692
  processing: "The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
527
693
  storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
528
694
  privacyLink: "How we handle this",
529
- botCheck: "off"
695
+ botCheck: "off",
696
+ questions: "suggested"
697
+ }
698
+ }
699
+ ],
700
+ [
701
+ // The Avatar tab's own question box (contract v1.3, `questions: "any"`): the first answer in a new chat started in
702
+ // the Avatar tab is read whether the visitor chose a suggested question or typed their own, so the intro says so and
703
+ // warns against personal details in a typed one. Product-neutral, with the bot check: one notice and one digest for
704
+ // every site (gitops docs/avatar-web/en-web-consent-2026-11-05.txt).
705
+ "web-consent-2026-11-05",
706
+ {
707
+ en: {
708
+ title: "Live AI avatar (beta)",
709
+ introProduct: null,
710
+ intro: "This is an AI avatar, not a real person. It reads aloud, for up to a minute, the first answer in a new chat started in the Avatar tab, provided it passes the speech checks, whether you chose a suggested question or typed your own. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
711
+ processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
712
+ storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
713
+ privacyLink: "How we handle this",
714
+ botCheck: "turnstile",
715
+ questions: "any"
716
+ }
717
+ }
718
+ ],
719
+ [
720
+ // The words of web-consent-2026-11-05 without "When you start, Cloudflare checks for bots.", for a server that runs
721
+ // no bot check (gitops docs/avatar-web/en-web-consent-2026-11-06.txt).
722
+ "web-consent-2026-11-06",
723
+ {
724
+ en: {
725
+ title: "Live AI avatar (beta)",
726
+ introProduct: null,
727
+ intro: "This is an AI avatar, not a real person. It reads aloud, for up to a minute, the first answer in a new chat started in the Avatar tab, provided it passes the speech checks, whether you chose a suggested question or typed your own. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
728
+ processing: "The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
729
+ storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
730
+ privacyLink: "How we handle this",
731
+ botCheck: "off",
732
+ questions: "any"
530
733
  }
531
734
  }
532
735
  ]
@@ -657,6 +860,9 @@ var CLOCK_TOLERANCE_MS = 5e3;
657
860
  var SERVICE_MAX_AGE_MS = 15 * 6e4;
658
861
  var ANSWER_OFFER_MS = SERVICE_MAX_AGE_MS - 6e4;
659
862
  var MAX_TIMER_MS = 2147483647;
863
+ var ASK_MAX_LENGTH = 300;
864
+ var MAX_REFERENCES = 64;
865
+ var USED_ON_KEY = "boff.explore.avatarUsedOn";
660
866
  var PRIMARY = '[data-avatar-primary], [data-boff-explore="panel-continue-chat"]';
661
867
  var IDLE = { name: "idle" };
662
868
  var INERT2 = { name: "inert" };
@@ -669,12 +875,26 @@ var REFUSAL_TEXT = {
669
875
  not_eligible: "notEligible",
670
876
  answer_claimed: "answerClaimed"
671
877
  };
672
- var WAITING = { answerId: null, startOver: false, offerUntil: NaN };
673
- var START_OVER = {
878
+ var EMPTY = {
879
+ kind: "empty",
674
880
  answerId: null,
675
- startOver: true,
676
- offerUntil: NaN
881
+ startOver: false,
882
+ offerUntil: NaN,
883
+ question: null,
884
+ pendingAnswerId: null,
885
+ askedHere: false
677
886
  };
887
+ var START_OVER = { ...EMPTY, kind: "start-over", startOver: true };
888
+ var SUGGESTED_RULES = {
889
+ any: false,
890
+ askedHere: null,
891
+ token: null,
892
+ inFlight: false
893
+ };
894
+ function isAskedHere(question, rules) {
895
+ const asked = rules.askedHere;
896
+ return rules.any && asked !== null && question.id === asked.messageId && asked.token === rules.token;
897
+ }
678
898
  function createdAtOf(message) {
679
899
  const raw = message.createdAt;
680
900
  return typeof raw === "string" && raw !== "" ? Date.parse(raw) : NaN;
@@ -682,25 +902,110 @@ function createdAtOf(message) {
682
902
  function offeredAt(exchange, now) {
683
903
  return exchange.answerId !== null && !(now < exchange.offerUntil) ? START_OVER : exchange;
684
904
  }
685
- function firstExchange(messages) {
686
- if (!messages || messages.length === 0) return WAITING;
905
+ function readable(question, answer) {
906
+ const references = answer.references?.length ?? 0;
907
+ return answer.answered === true && references >= 1 && references <= MAX_REFERENCES && (question.attachments?.length ?? 0) === 0;
908
+ }
909
+ function firstExchange(messages, rules = SUGGESTED_RULES) {
910
+ if (!messages || messages.length === 0) return EMPTY;
687
911
  if (messages.length > 2) return START_OVER;
688
912
  const [question, answer] = messages;
689
913
  if (question?.role !== "USER") return START_OVER;
690
- if (answer === void 0) return WAITING;
914
+ const first = { question, askedHere: isAskedHere(question, rules) };
915
+ if (answer === void 0) {
916
+ if (rules.inFlight) return { ...EMPTY, ...first, kind: "asking" };
917
+ return rules.any ? { ...START_OVER, ...first, kind: "failed" } : EMPTY;
918
+ }
691
919
  if (answer.role !== "ASSISTANT") return START_OVER;
692
920
  if (answer.status === "PENDING" || answer.status === "RUNNING") {
693
- return WAITING;
921
+ return {
922
+ ...EMPTY,
923
+ ...first,
924
+ kind: "asking",
925
+ pendingAnswerId: isAvatarMessageId(answer.id) ? answer.id : null
926
+ };
927
+ }
928
+ if (rules.any && answer.status === "FAILED") {
929
+ return { ...START_OVER, ...first, kind: "failed" };
694
930
  }
695
931
  if (answer.status !== "COMPLETED" || answer.content.trim() === "" || !isAvatarMessageId(answer.id)) {
696
932
  return START_OVER;
697
933
  }
934
+ if (rules.any && !first.askedHere) {
935
+ return { ...START_OVER, ...first, kind: "ask-here" };
936
+ }
937
+ if (rules.any && !readable(question, answer)) {
938
+ return { ...START_OVER, ...first, kind: "text-only" };
939
+ }
698
940
  return {
941
+ ...EMPTY,
942
+ ...first,
943
+ kind: "answer",
699
944
  answerId: answer.id,
700
- startOver: false,
701
945
  offerUntil: createdAtOf(answer) + ANSWER_OFFER_MS
702
946
  };
703
947
  }
948
+ function inFlight(conversation) {
949
+ return conversation?.phase === "sending" || conversation?.phase === "streaming";
950
+ }
951
+ function utcToday() {
952
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
953
+ }
954
+ function usedTodayHere() {
955
+ try {
956
+ return window.localStorage.getItem(USED_ON_KEY) === utcToday();
957
+ } catch {
958
+ return false;
959
+ }
960
+ }
961
+ function noteUsedToday() {
962
+ try {
963
+ window.localStorage.setItem(USED_ON_KEY, utcToday());
964
+ } catch {
965
+ }
966
+ }
967
+ var silence = null;
968
+ function silentWav() {
969
+ if (silence !== null) return silence;
970
+ const rate = 8e3;
971
+ const samples = rate / 10;
972
+ const bytes = new Uint8Array(44 + samples);
973
+ const view = new DataView(bytes.buffer);
974
+ const text = (at, value) => {
975
+ for (let i = 0; i < value.length; i += 1) {
976
+ bytes[at + i] = value.charCodeAt(i);
977
+ }
978
+ };
979
+ text(0, "RIFF");
980
+ view.setUint32(4, 36 + samples, true);
981
+ text(8, "WAVE");
982
+ text(12, "fmt ");
983
+ view.setUint32(16, 16, true);
984
+ view.setUint16(20, 1, true);
985
+ view.setUint16(22, 1, true);
986
+ view.setUint32(24, rate, true);
987
+ view.setUint32(28, rate, true);
988
+ view.setUint16(32, 1, true);
989
+ view.setUint16(34, 8, true);
990
+ text(36, "data");
991
+ view.setUint32(40, samples, true);
992
+ bytes.fill(128, 44);
993
+ let binary = "";
994
+ for (const byte of bytes) binary += String.fromCharCode(byte);
995
+ silence = `data:audio/wav;base64,${btoa(binary)}`;
996
+ return silence;
997
+ }
998
+ function unlockSound(audio) {
999
+ if (audio === null || audio.srcObject) return;
1000
+ try {
1001
+ audio.src = silentWav();
1002
+ void Promise.resolve(audio.play()).then(
1003
+ () => audio.pause(),
1004
+ () => void 0
1005
+ );
1006
+ } catch {
1007
+ }
1008
+ }
704
1009
  function offering(offer, messageId, claimed) {
705
1010
  return claimed.has(messageId) ? { name: "refused", reason: "answer_claimed" } : { name: "consent", offer, messageId };
706
1011
  }
@@ -726,6 +1031,11 @@ function AvatarLiveView({
726
1031
  onContinueInChat,
727
1032
  continueInChat,
728
1033
  newChat,
1034
+ send,
1035
+ tryAsking,
1036
+ prompts,
1037
+ touchFirst,
1038
+ currentPath,
729
1039
  off,
730
1040
  base,
731
1041
  headers,
@@ -734,18 +1044,46 @@ function AvatarLiveView({
734
1044
  const S = avatarLiveStrings(locale);
735
1045
  const uid = useId();
736
1046
  const consentTitleId = `${uid}-consent`;
737
- const exchange = firstExchange(conversation?.messages);
1047
+ const [questions, setQuestions] = useState("suggested");
1048
+ const questionsRef = useRef("suggested");
1049
+ const askedHereRef = useRef(null);
1050
+ const askSeqRef = useRef(0);
1051
+ const [, setAskedHereTick] = useState(0);
1052
+ const setAskedHere = useCallback((next) => {
1053
+ if (next === null) {
1054
+ askSeqRef.current += 1;
1055
+ if (askedHereRef.current === null) return;
1056
+ }
1057
+ askedHereRef.current = next;
1058
+ setAskedHereTick((tick) => tick + 1);
1059
+ }, []);
1060
+ const token = conversation?.getConversationToken() ?? null;
1061
+ const exchange = firstExchange(conversation?.messages, {
1062
+ any: questions === "any",
1063
+ askedHere: askedHereRef.current,
1064
+ token,
1065
+ inFlight: inFlight(conversation)
1066
+ });
738
1067
  const [ageTick, setAgeTick] = useState(0);
739
- const { answerId, startOver } = offeredAt(exchange, Date.now());
1068
+ const shown = offeredAt(exchange, Date.now());
1069
+ const { answerId, startOver } = shown;
740
1070
  const offerUntil = answerId === null ? null : exchange.offerUntil;
741
1071
  const [phase, setPhase] = useState(IDLE);
742
1072
  const [blocked, setBlocked] = useState(false);
743
1073
  const [now, setNow] = useState(() => Date.now());
1074
+ const [draft, setDraft] = useState("");
1075
+ const chatMaxLength = conversation?.catalog.limits.maxMessageLength;
1076
+ const askMaxLength = chatMaxLength !== void 0 && Number.isFinite(chatMaxLength) && chatMaxLength >= 1 ? Math.min(ASK_MAX_LENGTH, Math.floor(chatMaxLength)) : ASK_MAX_LENGTH;
1077
+ const [note, setNote] = useState(null);
1078
+ const [usedToday, setUsedToday] = useState(false);
744
1079
  const phaseRef = useRef(IDLE);
745
- const latest = useRef({ live, locale, base, headers, exchange, off });
746
- latest.current = { live, locale, base, headers, exchange, off };
1080
+ const latest = useRef({ live, locale, base, headers, off, currentPath });
1081
+ latest.current = { live, locale, base, headers, off, currentPath };
747
1082
  const conversationRef = useRef(conversation);
748
1083
  conversationRef.current = conversation;
1084
+ const waitRef = useRef(null);
1085
+ const sendingRef = useRef(false);
1086
+ const textBoxRef = useRef(false);
749
1087
  const checkRef = useRef(null);
750
1088
  const askedLocale = useRef(locale);
751
1089
  const startRef = useRef(null);
@@ -759,8 +1097,28 @@ function AvatarLiveView({
759
1097
  phaseRef.current = next;
760
1098
  setPhase(next);
761
1099
  }, []);
1100
+ const setMode = useCallback((next) => {
1101
+ questionsRef.current = next;
1102
+ setQuestions(next);
1103
+ }, []);
1104
+ const exchangeNow = useCallback(
1105
+ () => offeredAt(
1106
+ firstExchange(conversationRef.current?.messages, {
1107
+ any: questionsRef.current === "any",
1108
+ askedHere: askedHereRef.current,
1109
+ token: conversationRef.current?.getConversationToken() ?? null,
1110
+ inFlight: inFlight(conversationRef.current)
1111
+ }),
1112
+ Date.now()
1113
+ ),
1114
+ []
1115
+ );
762
1116
  const offeredNow = useCallback(
763
- () => offeredAt(latest.current.exchange, Date.now()).answerId,
1117
+ () => exchangeNow().answerId,
1118
+ [exchangeNow]
1119
+ );
1120
+ const pathNow = useCallback(
1121
+ () => latest.current.currentPath ?? (typeof window === "undefined" ? "" : window.location.pathname),
764
1122
  []
765
1123
  );
766
1124
  const reoffer = useCallback(
@@ -800,6 +1158,36 @@ function AvatarLiveView({
800
1158
  run.cancelled = reason;
801
1159
  run.turnstile?.cancel();
802
1160
  }, []);
1161
+ const applyAvailability = useCallback(
1162
+ (result, locale2) => {
1163
+ const { live: live2 } = latest.current;
1164
+ if (result.kind === "inert") {
1165
+ setMode("suggested");
1166
+ go(INERT2);
1167
+ return;
1168
+ }
1169
+ if (result.kind === "refused") {
1170
+ setMode(result.questions);
1171
+ go({ name: "refused", reason: result.reason });
1172
+ return;
1173
+ }
1174
+ setUsedToday(usedTodayHere());
1175
+ const copy = avatarConsentCopy(result.offer.consentVersion, locale2);
1176
+ if (copy === null || copy.botCheck !== result.offer.botCheck || copy.questions !== result.offer.questions) {
1177
+ setMode("suggested");
1178
+ go(INERT2);
1179
+ return;
1180
+ }
1181
+ if (result.offer.botCheck === "turnstile" && turnstileSiteKeyOf(live2) === null) {
1182
+ setMode("suggested");
1183
+ go(INERT2);
1184
+ return;
1185
+ }
1186
+ setMode(result.offer.questions);
1187
+ go(reoffer({ ...result.offer, locale: locale2, copy }));
1188
+ },
1189
+ [go, reoffer, setMode]
1190
+ );
803
1191
  const check = useCallback(() => {
804
1192
  const { live: live2, locale: locale2, base: base2, headers: headers2, off: off2 } = latest.current;
805
1193
  checkRef.current?.abort();
@@ -821,26 +1209,9 @@ function AvatarLiveView({
821
1209
  }).then((result) => {
822
1210
  if (checkRef.current !== controller) return;
823
1211
  checkRef.current = null;
824
- if (result.kind === "inert") {
825
- go(INERT2);
826
- return;
827
- }
828
- if (result.kind === "refused") {
829
- go({ name: "refused", reason: result.reason });
830
- return;
831
- }
832
- const copy = avatarConsentCopy(result.offer.consentVersion, locale2);
833
- if (copy === null || copy.botCheck !== result.offer.botCheck) {
834
- go(INERT2);
835
- return;
836
- }
837
- if (result.offer.botCheck === "turnstile" && turnstileSiteKeyOf(live2) === null) {
838
- go(INERT2);
839
- return;
840
- }
841
- go(reoffer({ ...result.offer, locale: locale2, copy }));
1212
+ applyAvailability(result, locale2);
842
1213
  });
843
- }, [go, reoffer]);
1214
+ }, [applyAvailability, go]);
844
1215
  const begin = useCallback(
845
1216
  (session, module, offer, target) => {
846
1217
  const received = Date.now();
@@ -885,8 +1256,8 @@ function AvatarLiveView({
885
1256
  reason: run.cancelled
886
1257
  });
887
1258
  }
888
- const shown = phaseRef.current;
889
- if (claimed && shown.name === "consent" && shown.messageId === context.messageId) {
1259
+ const shown2 = phaseRef.current;
1260
+ if (claimed && shown2.name === "consent" && shown2.messageId === context.messageId) {
890
1261
  go({ name: "refused", reason: "answer_claimed" });
891
1262
  }
892
1263
  return;
@@ -921,86 +1292,186 @@ function AvatarLiveView({
921
1292
  },
922
1293
  [begin, check, go]
923
1294
  );
1295
+ const launch = useCallback(
1296
+ (offer, messageId, preloaded) => {
1297
+ const { live: live2, base: base2, headers: headers2 } = latest.current;
1298
+ if (base2 === null) return;
1299
+ const exchangeAtStart = exchangeNow();
1300
+ if (exchangeAtStart.answerId !== messageId) {
1301
+ go(reoffer(offer));
1302
+ return;
1303
+ }
1304
+ if (claimedRef.current.has(messageId)) {
1305
+ go({ name: "refused", reason: "answer_claimed" });
1306
+ return;
1307
+ }
1308
+ const refusedFrom = exchangeAtStart.offerUntil - ANSWER_OFFER_MS + SERVICE_MAX_AGE_MS;
1309
+ const siteKey = offer.botCheck === "turnstile" ? turnstileSiteKeyOf(live2) : null;
1310
+ if (offer.botCheck === "turnstile" && (siteKey === null || !canBindBotCheck())) {
1311
+ go(INERT2);
1312
+ return;
1313
+ }
1314
+ const conversationToken = conversationRef.current?.getConversationToken() ?? null;
1315
+ const idempotencyKey = newIdempotencyKey();
1316
+ if (conversationToken === null || !isAvatarConversationToken(conversationToken) || idempotencyKey === null) {
1317
+ go({ name: "ended", how: "failed" });
1318
+ return;
1319
+ }
1320
+ const body2 = {
1321
+ site: live2.site,
1322
+ locale: offer.locale,
1323
+ conversationToken,
1324
+ messageId,
1325
+ consentVersion: offer.consentVersion,
1326
+ manifestVersion: live2.manifestVersion
1327
+ };
1328
+ const run = { cancelled: null, turnstile: null };
1329
+ startRef.current = run;
1330
+ const module = preloaded ?? loadModule(live2.load);
1331
+ let turnstile = null;
1332
+ if (siteKey === null) {
1333
+ go({ name: "creating" });
1334
+ } else {
1335
+ go({ name: "bot-check", offer, messageId });
1336
+ turnstile = runTurnstile(
1337
+ botBoxRef.current,
1338
+ siteKey,
1339
+ "avatar_start",
1340
+ avatarBotBinding(body2)
1341
+ );
1342
+ run.turnstile = turnstile;
1343
+ }
1344
+ void (async () => {
1345
+ let loaded;
1346
+ let botToken;
1347
+ try {
1348
+ [loaded, botToken] = await Promise.all([module, turnstile?.token]);
1349
+ } catch {
1350
+ turnstile?.cancel();
1351
+ if (run.cancelled === null) {
1352
+ startRef.current = null;
1353
+ go(INERT2);
1354
+ }
1355
+ return;
1356
+ }
1357
+ turnstile?.cancel();
1358
+ if (run.cancelled !== null) return;
1359
+ if (!(Date.now() < refusedFrom)) {
1360
+ startRef.current = null;
1361
+ go({ name: "needs-answer", offer });
1362
+ return;
1363
+ }
1364
+ if (turnstile !== null) go({ name: "creating" });
1365
+ const result = await requestCreate({
1366
+ base: base2,
1367
+ headers: headers2,
1368
+ idempotencyKey,
1369
+ botToken,
1370
+ body: body2
1371
+ });
1372
+ if (startRef.current === run) startRef.current = null;
1373
+ settle(result, run, {
1374
+ module: loaded,
1375
+ offer,
1376
+ messageId,
1377
+ base: base2,
1378
+ headers: headers2
1379
+ });
1380
+ })();
1381
+ },
1382
+ [exchangeNow, go, reoffer, settle]
1383
+ );
924
1384
  const start = useCallback(() => {
925
1385
  const current = phaseRef.current;
926
1386
  if (current.name !== "consent") return;
927
- const { live: live2, base: base2, headers: headers2 } = latest.current;
928
- if (base2 === null) return;
929
- const { offer, messageId } = current;
930
- if (offeredNow() !== messageId) {
931
- go(reoffer(offer));
932
- return;
933
- }
934
- const refusedFrom = latest.current.exchange.offerUntil - ANSWER_OFFER_MS + SERVICE_MAX_AGE_MS;
935
- const siteKey = offer.botCheck === "turnstile" ? turnstileSiteKeyOf(live2) : null;
936
- if (offer.botCheck === "turnstile" && (siteKey === null || !canBindBotCheck())) {
937
- go(INERT2);
938
- return;
939
- }
940
- const conversationToken = conversationRef.current?.getConversationToken() ?? null;
941
- const idempotencyKey = newIdempotencyKey();
942
- if (conversationToken === null || !isAvatarConversationToken(conversationToken) || idempotencyKey === null) {
943
- go({ name: "ended", how: "failed" });
1387
+ if (current.offer.questions === "any") unlockSound(audioRef.current);
1388
+ launch(current.offer, current.messageId, null);
1389
+ }, [launch]);
1390
+ const cancelWaiting = useCallback(
1391
+ (told) => {
1392
+ const wait = waitRef.current;
1393
+ waitRef.current = null;
1394
+ wait?.check?.abort();
1395
+ const current = phaseRef.current;
1396
+ if (current.name !== "waiting") return;
1397
+ if (told) setNote("cancelled");
1398
+ go({ name: "needs-answer", offer: current.offer });
1399
+ },
1400
+ [go]
1401
+ );
1402
+ const bindingHolds = useCallback(
1403
+ (bound, exchange2) => {
1404
+ const { live: live2, locale: locale2 } = latest.current;
1405
+ return conversationRef.current?.getConversationToken() === bound.token && exchange2.question?.id === bound.questionId && live2.site === bound.site && locale2 === bound.locale && pathNow() === bound.path;
1406
+ },
1407
+ [pathNow]
1408
+ );
1409
+ const startWhenReady = useCallback(() => {
1410
+ const current = phaseRef.current;
1411
+ if (current.name !== "needs-answer") return;
1412
+ const { live: live2, locale: locale2 } = latest.current;
1413
+ const exchange2 = exchangeNow();
1414
+ const token2 = conversationRef.current?.getConversationToken() ?? null;
1415
+ if (exchange2.kind !== "asking" || !exchange2.askedHere || exchange2.question === null || exchange2.pendingAnswerId === null || token2 === null || !isAvatarConversationToken(token2)) {
944
1416
  return;
945
1417
  }
946
- const body2 = {
947
- site: live2.site,
948
- locale: offer.locale,
949
- conversationToken,
950
- messageId,
951
- consentVersion: offer.consentVersion,
952
- manifestVersion: live2.manifestVersion
953
- };
954
- const run = { cancelled: null, turnstile: null };
955
- startRef.current = run;
1418
+ unlockSound(audioRef.current);
956
1419
  const module = loadModule(live2.load);
957
- let turnstile = null;
958
- if (siteKey === null) {
959
- go({ name: "creating" });
960
- } else {
961
- go({ name: "bot-check", offer, messageId });
962
- turnstile = runTurnstile(
963
- botBoxRef.current,
964
- siteKey,
965
- "avatar_start",
966
- avatarBotBinding(body2)
967
- );
968
- run.turnstile = turnstile;
969
- }
970
- void (async () => {
971
- let loaded;
972
- let botToken;
973
- try {
974
- [loaded, botToken] = await Promise.all([module, turnstile?.token]);
975
- } catch {
976
- turnstile?.cancel();
977
- if (run.cancelled === null) {
978
- startRef.current = null;
979
- go(INERT2);
980
- }
981
- return;
982
- }
983
- turnstile?.cancel();
984
- if (run.cancelled !== null) return;
985
- if (!(Date.now() < refusedFrom)) {
986
- startRef.current = null;
987
- go({ name: "needs-answer", offer });
1420
+ module.catch(() => void 0);
1421
+ waitRef.current = {
1422
+ bound: {
1423
+ token: token2,
1424
+ questionId: exchange2.question.id,
1425
+ answerId: exchange2.pendingAnswerId,
1426
+ site: live2.site,
1427
+ locale: locale2,
1428
+ path: pathNow(),
1429
+ consentVersion: current.offer.consentVersion,
1430
+ botCheck: current.offer.botCheck
1431
+ },
1432
+ module,
1433
+ check: null
1434
+ };
1435
+ setNote(null);
1436
+ go({ name: "waiting", offer: current.offer });
1437
+ }, [exchangeNow, go, pathNow]);
1438
+ const confirm = useCallback(
1439
+ (offer, wait) => {
1440
+ const { live: live2, locale: locale2, base: base2, headers: headers2 } = latest.current;
1441
+ if (base2 === null) {
1442
+ cancelWaiting(true);
988
1443
  return;
989
1444
  }
990
- if (turnstile !== null) go({ name: "creating" });
991
- const result = await requestCreate({
1445
+ const controller = new AbortController();
1446
+ wait.check = controller;
1447
+ void requestAvailability({
992
1448
  base: base2,
993
1449
  headers: headers2,
994
- idempotencyKey,
995
- botToken,
996
- body: body2
1450
+ site: live2.site,
1451
+ locale: locale2,
1452
+ signal: controller.signal
1453
+ }).then((result) => {
1454
+ if (waitRef.current !== wait || phaseRef.current.name !== "waiting") {
1455
+ return;
1456
+ }
1457
+ waitRef.current = null;
1458
+ const exchange2 = exchangeNow();
1459
+ const same = result.kind === "available" && result.offer.consentVersion === wait.bound.consentVersion && result.offer.botCheck === wait.bound.botCheck && result.offer.questions === "any" && exchange2.kind === "answer" && exchange2.answerId === wait.bound.answerId && bindingHolds(wait.bound, exchange2);
1460
+ if (!same || result.kind !== "available") {
1461
+ applyAvailability(result, locale2);
1462
+ return;
1463
+ }
1464
+ launch({ ...offer, ...result.offer }, wait.bound.answerId, wait.module);
997
1465
  });
998
- if (startRef.current === run) startRef.current = null;
999
- settle(result, run, { module: loaded, offer, messageId, base: base2, headers: headers2 });
1000
- })();
1001
- }, [go, offeredNow, reoffer, settle]);
1466
+ },
1467
+ [applyAvailability, bindingHolds, cancelWaiting, exchangeNow, launch]
1468
+ );
1002
1469
  const stop = useCallback(() => {
1003
1470
  const current = phaseRef.current;
1471
+ if (current.name === "waiting") {
1472
+ cancelWaiting(false);
1473
+ return;
1474
+ }
1004
1475
  if (current.name === "bot-check") {
1005
1476
  cancelStart("user");
1006
1477
  go(reoffer(current.offer));
@@ -1014,7 +1485,7 @@ function AvatarLiveView({
1014
1485
  if (current.name === "pending" || current.name === "live") {
1015
1486
  finish("stopped", "user");
1016
1487
  }
1017
- }, [cancelStart, finish, go, reoffer]);
1488
+ }, [cancelStart, cancelWaiting, finish, go, reoffer]);
1018
1489
  const leave = useCallback(
1019
1490
  (reason) => {
1020
1491
  const current = phaseRef.current;
@@ -1028,6 +1499,9 @@ function AvatarLiveView({
1028
1499
  go(IDLE);
1029
1500
  return;
1030
1501
  }
1502
+ case "waiting":
1503
+ cancelWaiting(true);
1504
+ return;
1031
1505
  case "bot-check":
1032
1506
  cancelStart(reason);
1033
1507
  go(reason === "user" ? IDLE : reoffer(current.offer));
@@ -1044,7 +1518,7 @@ function AvatarLiveView({
1044
1518
  return;
1045
1519
  }
1046
1520
  },
1047
- [cancelStart, finish, go, reoffer]
1521
+ [cancelStart, cancelWaiting, finish, go, reoffer]
1048
1522
  );
1049
1523
  const showing = active && !off;
1050
1524
  useEffect(() => {
@@ -1059,7 +1533,7 @@ function AvatarLiveView({
1059
1533
  if (current.name === "refused" && current.reason === "answer_claimed" && used) {
1060
1534
  return;
1061
1535
  }
1062
- if (current.name === "idle" || current.name === "inert" || current.name === "refused" || current.name === "needs-answer" || current.name === "consent" || current.name === "ended" || // Asking, with nothing actually asking: React's strict mode unmounts and mounts a component again with the state it
1536
+ if (current.name === "idle" || current.name === "inert" || current.name === "refused" || current.name === "needs-answer" || current.name === "consent" || current.name === "declined" || current.name === "ended" || // Asking, with nothing actually asking: React's strict mode unmounts and mounts a component again with the state it
1063
1537
  // left, and the unmount in between dropped the question. (This view mounts already showing, the first time the
1064
1538
  // Avatar view opens.)
1065
1539
  current.name === "checking" && checkRef.current === null) {
@@ -1069,8 +1543,9 @@ function AvatarLiveView({
1069
1543
  useEffect(() => {
1070
1544
  if (askedLocale.current === locale) return;
1071
1545
  askedLocale.current = locale;
1546
+ if (phaseRef.current.name === "waiting") cancelWaiting(true);
1072
1547
  const current = phaseRef.current.name;
1073
- if (current !== "checking" && current !== "needs-answer" && current !== "consent" && current !== "refused" && current !== "inert") {
1548
+ if (current !== "checking" && current !== "needs-answer" && current !== "consent" && current !== "declined" && current !== "refused" && current !== "inert") {
1074
1549
  return;
1075
1550
  }
1076
1551
  if (active) {
@@ -1080,7 +1555,8 @@ function AvatarLiveView({
1080
1555
  checkRef.current = null;
1081
1556
  go(IDLE);
1082
1557
  }
1083
- }, [active, check, go, locale]);
1558
+ }, [active, cancelWaiting, check, go, locale]);
1559
+ const kind = shown.kind;
1084
1560
  useEffect(() => {
1085
1561
  const current = phaseRef.current;
1086
1562
  if (current.name === "needs-answer" && answerId !== null) {
@@ -1089,8 +1565,49 @@ function AvatarLiveView({
1089
1565
  go(
1090
1566
  answerId === null ? { name: "needs-answer", offer: current.offer } : { ...current, messageId: answerId }
1091
1567
  );
1568
+ } else if (current.name === "declined" && answerId === null) {
1569
+ if (kind !== "asking") go({ name: "needs-answer", offer: current.offer });
1092
1570
  }
1093
- }, [answerId, go]);
1571
+ }, [answerId, kind, go]);
1572
+ useEffect(() => {
1573
+ const current = phaseRef.current;
1574
+ const wait = waitRef.current;
1575
+ if (current.name !== "waiting" || wait === null || wait.check !== null) {
1576
+ return;
1577
+ }
1578
+ const now2 = exchangeNow();
1579
+ const holds = bindingHolds(wait.bound, now2);
1580
+ if (holds && now2.kind === "asking" && now2.pendingAnswerId === wait.bound.answerId) {
1581
+ return;
1582
+ }
1583
+ if (!holds || now2.kind !== "answer" || now2.answerId !== wait.bound.answerId) {
1584
+ cancelWaiting(now2.kind !== "failed" && now2.kind !== "text-only");
1585
+ return;
1586
+ }
1587
+ confirm(current.offer, wait);
1588
+ });
1589
+ const resent = conversation?.resent ?? null;
1590
+ useEffect(() => {
1591
+ const asked = askedHereRef.current;
1592
+ if (resent === null || asked === null || !resent.replacedMessageIds.includes(asked.messageId)) {
1593
+ return;
1594
+ }
1595
+ setAskedHere({
1596
+ messageId: resent.sent.userMessageId,
1597
+ token: resent.sent.conversationToken
1598
+ });
1599
+ }, [resent, setAskedHere]);
1600
+ const empty = (conversation?.messages.length ?? 0) === 0;
1601
+ useEffect(() => {
1602
+ if (empty) setAskedHere(null);
1603
+ }, [empty, setAskedHere]);
1604
+ useEffect(() => {
1605
+ const asked = askedHereRef.current;
1606
+ if (asked !== null && asked.token !== token) setAskedHere(null);
1607
+ }, [token, setAskedHere]);
1608
+ useEffect(() => {
1609
+ if (showing) setUsedToday(usedTodayHere());
1610
+ }, [showing]);
1094
1611
  useEffect(() => {
1095
1612
  if (offerUntil === null) return;
1096
1613
  const timer = setTimeout(
@@ -1224,6 +1741,9 @@ function AvatarLiveView({
1224
1741
  run.cancelled = "user";
1225
1742
  run.turnstile?.cancel();
1226
1743
  }
1744
+ const wait = waitRef.current;
1745
+ waitRef.current = null;
1746
+ wait?.check?.abort();
1227
1747
  const handle = sessionRef.current;
1228
1748
  sessionRef.current = null;
1229
1749
  if (handle && !handle.done) {
@@ -1240,17 +1760,82 @@ function AvatarLiveView({
1240
1760
  },
1241
1761
  []
1242
1762
  );
1763
+ const any = questions === "any";
1764
+ const textMode = any && (usedToday && (phase.name === "needs-answer" || phase.name === "consent" || phase.name === "declined" || phase.name === "ended") || phase.name === "refused" && phase.reason === "limits");
1765
+ textBoxRef.current = textMode;
1766
+ const askState = !any ? void 0 : textMode ? "text" : phase.name === "needs-answer" ? kind === "empty" ? "ready" : kind : phase.name;
1767
+ const notNow = useCallback(() => {
1768
+ const current = phaseRef.current;
1769
+ if ((current.name === "consent" || current.name === "needs-answer") && current.offer.questions === "any") {
1770
+ go({ name: "declined", offer: current.offer });
1771
+ return;
1772
+ }
1773
+ onContinueInChat();
1774
+ }, [go, onContinueInChat]);
1775
+ const ask = useCallback(
1776
+ (text) => {
1777
+ const conversation2 = conversationRef.current;
1778
+ const question = text.trim();
1779
+ if (conversation2 === null || question === "" || sendingRef.current) {
1780
+ return;
1781
+ }
1782
+ const spoken = !textBoxRef.current;
1783
+ if (spoken && conversation2.messages.length > 0) return;
1784
+ sendingRef.current = true;
1785
+ setAskedHere(null);
1786
+ const seq = askSeqRef.current;
1787
+ setNote(null);
1788
+ setDraft("");
1789
+ void conversation2.send(question, [], spoken ? { surface: "AVATAR" } : {}).then((added) => {
1790
+ if (added === null) {
1791
+ setDraft((current) => current === "" ? question : current);
1792
+ }
1793
+ if (!spoken || added === null || askSeqRef.current !== seq || added.conversationToken !== (conversationRef.current?.getConversationToken() ?? null)) {
1794
+ return;
1795
+ }
1796
+ setAskedHere({
1797
+ messageId: added.userMessageId,
1798
+ token: added.conversationToken
1799
+ });
1800
+ }).finally(() => {
1801
+ sendingRef.current = false;
1802
+ });
1803
+ },
1804
+ [setAskedHere]
1805
+ );
1806
+ const newChatForAvatar = useCallback(() => {
1807
+ const conversation2 = conversationRef.current;
1808
+ if (conversation2 === null) return;
1809
+ const now2 = exchangeNow();
1810
+ const failedQuestion = now2.kind === "failed" ? now2.question?.content ?? null : null;
1811
+ conversation2.reset();
1812
+ setAskedHere(null);
1813
+ setNote("new-chat");
1814
+ if (failedQuestion !== null) {
1815
+ setDraft((current2) => current2 === "" ? failedQuestion : current2);
1816
+ }
1817
+ const current = phaseRef.current;
1818
+ if (current.name === "needs-answer" || current.name === "consent" || current.name === "declined") {
1819
+ go({ name: "needs-answer", offer: current.offer });
1820
+ } else {
1821
+ check();
1822
+ }
1823
+ }, [check, exchangeNow, go, setAskedHere]);
1243
1824
  useEffect(() => {
1244
1825
  if (!active) return;
1245
1826
  const focused = document.activeElement;
1246
1827
  if (focused && focused !== document.body && focused.isConnected) return;
1247
1828
  rootRef.current?.querySelector(PRIMARY)?.focus();
1248
- }, [active, phase.name, blocked]);
1829
+ }, [active, phase.name, askState, shown.pendingAnswerId, blocked]);
1249
1830
  const onPlaying = useCallback(() => {
1250
1831
  const current = phaseRef.current;
1251
1832
  const handle = sessionRef.current;
1252
1833
  if (current.name !== "pending" || !handle) return;
1253
1834
  handle.speakerArrived = true;
1835
+ if (questionsRef.current === "any") {
1836
+ noteUsedToday();
1837
+ setUsedToday(true);
1838
+ }
1254
1839
  go({ name: "live", session: current.session });
1255
1840
  }, [go]);
1256
1841
  const enablePlayback = useCallback(() => {
@@ -1283,7 +1868,7 @@ function AvatarLiveView({
1283
1868
  height: small ? 64 : 128,
1284
1869
  className: cn(
1285
1870
  "shrink-0 rounded-full border border-border object-cover shadow-sm",
1286
- small ? "h-16 w-16" : "h-32 w-32"
1871
+ small ? "h-16 w-16" : any ? "h-[min(12rem,32dvh)] w-[min(12rem,32dvh)]" : "h-32 w-32"
1287
1872
  )
1288
1873
  }
1289
1874
  );
@@ -1332,12 +1917,440 @@ function AvatarLiveView({
1332
1917
  children: S.stop
1333
1918
  }
1334
1919
  );
1920
+ const readInChatButton = (primary) => /* @__PURE__ */ jsx(
1921
+ "button",
1922
+ {
1923
+ type: "button",
1924
+ "data-avatar-primary": primary ? "" : void 0,
1925
+ "data-boff-explore": "avatar-live-read-in-chat",
1926
+ className: primary ? primaryButton : secondaryButton,
1927
+ onClick: onContinueInChat,
1928
+ children: S.readInChat
1929
+ }
1930
+ );
1931
+ const consentCard = (copy) => /* @__PURE__ */ jsxs(
1932
+ "section",
1933
+ {
1934
+ "aria-labelledby": consentTitleId,
1935
+ "data-boff-explore": "avatar-live-consent",
1936
+ className: "w-full max-w-sm rounded-lg border border-border p-4 text-start",
1937
+ children: [
1938
+ /* @__PURE__ */ jsx("h2", { id: consentTitleId, className: "text-base font-semibold", children: copy.title }),
1939
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm", children: productName === null || copy.introProduct === null ? copy.intro : fill(copy.introProduct, { product: productName }) }),
1940
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.processing }),
1941
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.storage }),
1942
+ /* @__PURE__ */ jsxs(
1943
+ "a",
1944
+ {
1945
+ href: PRIVACY_HREF,
1946
+ target: "_blank",
1947
+ rel: "noopener noreferrer",
1948
+ "data-boff-explore": "avatar-live-privacy",
1949
+ className: "mt-2 inline-block text-sm font-medium text-primary underline underline-offset-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1950
+ children: [
1951
+ copy.privacyLink,
1952
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
1953
+ " ",
1954
+ S.opensInNewTab
1955
+ ] })
1956
+ ]
1957
+ }
1958
+ )
1959
+ ]
1960
+ }
1961
+ );
1962
+ const consentActions = (whenReady) => /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
1963
+ /* @__PURE__ */ jsx(
1964
+ "button",
1965
+ {
1966
+ type: "button",
1967
+ "data-avatar-primary": "",
1968
+ "data-boff-explore": whenReady ? "avatar-live-start-when-ready" : "avatar-live-start",
1969
+ className: primaryButton,
1970
+ onClick: whenReady ? startWhenReady : start,
1971
+ children: whenReady ? S.startWhenReady : S.start
1972
+ }
1973
+ ),
1974
+ /* @__PURE__ */ jsx(
1975
+ "button",
1976
+ {
1977
+ type: "button",
1978
+ "data-boff-explore": "avatar-live-not-now",
1979
+ className: secondaryButton,
1980
+ onClick: notNow,
1981
+ children: S.notNow
1982
+ }
1983
+ )
1984
+ ] });
1985
+ const liveMedia = (playing) => /* @__PURE__ */ jsxs(
1986
+ "div",
1987
+ {
1988
+ className: cn(
1989
+ "relative shrink-0 overflow-hidden rounded-xl border border-border bg-muted",
1990
+ any ? "h-[min(12rem,32dvh)] w-[min(12rem,32dvh)]" : "h-48 w-48"
1991
+ ),
1992
+ children: [
1993
+ /* @__PURE__ */ jsx(
1994
+ "video",
1995
+ {
1996
+ ref: videoRef,
1997
+ "aria-label": S.video,
1998
+ "data-boff-explore": "avatar-live-video",
1999
+ playsInline: true,
2000
+ autoPlay: true,
2001
+ muted: true,
2002
+ onPlaying,
2003
+ className: cn("h-full w-full object-cover", !playing && "opacity-0")
2004
+ }
2005
+ ),
2006
+ playing ? null : /* @__PURE__ */ jsx(
2007
+ "img",
2008
+ {
2009
+ src: still.src,
2010
+ alt: "",
2011
+ decoding: "async",
2012
+ className: "absolute inset-0 h-full w-full object-cover"
2013
+ }
2014
+ ),
2015
+ any ? null : /* @__PURE__ */ jsx("audio", { ref: audioRef, "data-boff-explore": "avatar-live-audio" })
2016
+ ]
2017
+ }
2018
+ );
2019
+ const liveBody = (session) => /* @__PURE__ */ jsxs(Fragment, { children: [
2020
+ /* @__PURE__ */ jsx(
2021
+ "section",
2022
+ {
2023
+ "aria-label": S.captions,
2024
+ "data-boff-explore": "avatar-live-captions",
2025
+ lang: session.captions.locale || void 0,
2026
+ dir: "auto",
2027
+ tabIndex: 0,
2028
+ className: "max-h-32 w-full max-w-sm overflow-y-auto rounded-lg bg-muted p-3 text-start text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2029
+ children: session.captions.text
2030
+ }
2031
+ ),
2032
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: S.answerInChat }),
2033
+ /* @__PURE__ */ jsxs("p", { className: "text-sm tabular-nums text-muted-foreground", children: [
2034
+ S.timeLeft,
2035
+ " ",
2036
+ /* @__PURE__ */ jsx("span", { role: "timer", "data-boff-explore": "avatar-live-countdown", children: clock(Math.max(0, (session.endsAt - now) / 1e3)) })
2037
+ ] })
2038
+ ] });
2039
+ const liveActions = (back) => /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
2040
+ blocked ? /* @__PURE__ */ jsx(
2041
+ "button",
2042
+ {
2043
+ type: "button",
2044
+ "data-boff-explore": "avatar-live-sound",
2045
+ className: primaryButton,
2046
+ onClick: enablePlayback,
2047
+ children: S.tapForSound
2048
+ }
2049
+ ) : null,
2050
+ stopButton,
2051
+ back
2052
+ ] });
2053
+ const badge = /* @__PURE__ */ jsx(
2054
+ "p",
2055
+ {
2056
+ "data-boff-explore": "avatar-live-badge",
2057
+ className: "rounded-full bg-muted px-3 py-1 text-xs font-medium text-foreground",
2058
+ children: S.badge
2059
+ }
2060
+ );
2061
+ if (any) {
2062
+ let status = "";
2063
+ let outcome2 = false;
2064
+ let lead = null;
2065
+ let top2 = null;
2066
+ let media2 = stillPicture(false);
2067
+ let body2 = null;
2068
+ let actions2 = null;
2069
+ let newChatOffer = false;
2070
+ let box = null;
2071
+ const first = exchange.question;
2072
+ const questionLine = first === null ? null : /* @__PURE__ */ jsx(
2073
+ "p",
2074
+ {
2075
+ "data-boff-explore": "avatar-live-question",
2076
+ dir: "auto",
2077
+ className: "line-clamp-2 w-full max-w-sm break-words text-sm font-medium",
2078
+ children: first.content
2079
+ }
2080
+ );
2081
+ const activity = conversation?.activity ?? null;
2082
+ const activityLine = activity === null ? null : /* @__PURE__ */ jsx(
2083
+ "p",
2084
+ {
2085
+ "data-boff-explore": "avatar-live-activity",
2086
+ className: "text-xs text-muted-foreground",
2087
+ children: activity
2088
+ }
2089
+ );
2090
+ if (textMode) {
2091
+ const messages = conversation?.messages ?? [];
2092
+ let questionAt = messages.length - 1;
2093
+ while (questionAt >= 0 && messages[questionAt]?.role !== "USER") {
2094
+ questionAt -= 1;
2095
+ }
2096
+ const lastQuestion = questionAt === -1 ? void 0 : messages[questionAt];
2097
+ const after = questionAt === -1 ? void 0 : messages[questionAt + 1];
2098
+ const lastAnswer = after?.role === "ASSISTANT" ? after : void 0;
2099
+ const chatPhase = conversation?.phase;
2100
+ const unanswered = lastQuestion === void 0 || lastAnswer !== void 0 ? null : chatPhase === "sending" || chatPhase === "streaming" ? "waiting" : chatPhase === "error" || chatPhase === "limited" ? "failed" : null;
2101
+ if (phase.name === "refused") {
2102
+ status = S[REFUSAL_TEXT[phase.reason]];
2103
+ outcome2 = true;
2104
+ } else if (phase.name === "ended") {
2105
+ status = S[phase.how];
2106
+ outcome2 = true;
2107
+ }
2108
+ body2 = /* @__PURE__ */ jsxs(Fragment, { children: [
2109
+ lastQuestion === void 0 ? null : /* @__PURE__ */ jsx(
2110
+ "p",
2111
+ {
2112
+ "data-boff-explore": "avatar-live-question",
2113
+ dir: "auto",
2114
+ className: "line-clamp-2 w-full max-w-sm break-words text-sm font-medium",
2115
+ children: lastQuestion.content
2116
+ }
2117
+ ),
2118
+ lastAnswer === void 0 ? unanswered === "waiting" ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : unanswered === "failed" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : null : lastAnswer.status === "PENDING" || lastAnswer.status === "RUNNING" ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : lastAnswer.status === "FAILED" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : /* @__PURE__ */ jsx(
2119
+ "p",
2120
+ {
2121
+ "data-boff-explore": "avatar-live-text-answer",
2122
+ dir: "auto",
2123
+ className: "line-clamp-6 w-full max-w-sm whitespace-pre-wrap break-words text-start text-sm",
2124
+ children: lastAnswer.content
2125
+ }
2126
+ )
2127
+ ] });
2128
+ const ended = phase.name === "ended";
2129
+ actions2 = lastAnswer === void 0 && unanswered !== "failed" && !ended ? null : readInChatButton(ended);
2130
+ box = "text";
2131
+ } else {
2132
+ switch (phase.name) {
2133
+ case "checking":
2134
+ status = S.checking;
2135
+ break;
2136
+ case "needs-answer":
2137
+ switch (shown.kind) {
2138
+ case "empty":
2139
+ status = note === "new-chat" ? S.newChatStarted : "";
2140
+ lead = /* @__PURE__ */ jsx("p", { className: "text-base font-semibold", children: S.askHeadline });
2141
+ box = "spoken";
2142
+ break;
2143
+ case "asking":
2144
+ case "answer": {
2145
+ const card = shown.askedHere && shown.pendingAnswerId !== null;
2146
+ status = note === "cancelled" ? S.armedCancelled : S.gettingAnswer;
2147
+ if (card) media2 = stillPicture(true);
2148
+ body2 = /* @__PURE__ */ jsxs(Fragment, { children: [
2149
+ questionLine,
2150
+ activityLine,
2151
+ card ? consentCard(phase.offer.copy) : null
2152
+ ] });
2153
+ actions2 = card ? consentActions(true) : null;
2154
+ break;
2155
+ }
2156
+ case "text-only":
2157
+ status = S.notSpoken;
2158
+ outcome2 = true;
2159
+ body2 = questionLine;
2160
+ actions2 = readInChatButton(false);
2161
+ newChatOffer = true;
2162
+ break;
2163
+ case "failed":
2164
+ status = S.answerFailed;
2165
+ outcome2 = true;
2166
+ body2 = questionLine;
2167
+ newChatOffer = true;
2168
+ break;
2169
+ case "ask-here":
2170
+ status = S.askHere;
2171
+ outcome2 = true;
2172
+ actions2 = readInChatButton(false);
2173
+ newChatOffer = true;
2174
+ break;
2175
+ default:
2176
+ status = S.startNewChat;
2177
+ outcome2 = true;
2178
+ body2 = /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: S.startNewChatDetailAny });
2179
+ actions2 = readInChatButton(false);
2180
+ newChatOffer = true;
2181
+ break;
2182
+ }
2183
+ break;
2184
+ case "consent":
2185
+ media2 = stillPicture(true);
2186
+ body2 = /* @__PURE__ */ jsxs(Fragment, { children: [
2187
+ questionLine,
2188
+ consentCard(phase.offer.copy)
2189
+ ] });
2190
+ actions2 = consentActions(false);
2191
+ break;
2192
+ case "declined":
2193
+ status = S.declined;
2194
+ actions2 = readInChatButton(true);
2195
+ break;
2196
+ case "waiting":
2197
+ status = S.armed;
2198
+ body2 = questionLine;
2199
+ actions2 = /* @__PURE__ */ jsx(
2200
+ "button",
2201
+ {
2202
+ type: "button",
2203
+ "data-avatar-primary": "",
2204
+ "data-boff-explore": "avatar-live-cancel",
2205
+ className: secondaryButton,
2206
+ onClick: stop,
2207
+ children: S.cancel
2208
+ }
2209
+ );
2210
+ break;
2211
+ case "refused":
2212
+ outcome2 = true;
2213
+ if (phase.reason === "not_eligible" || phase.reason === "answer_claimed") {
2214
+ status = phase.reason === "not_eligible" ? S.notEligibleAny : S.answerClaimed;
2215
+ actions2 = readInChatButton(false);
2216
+ newChatOffer = true;
2217
+ } else {
2218
+ status = S[REFUSAL_TEXT[phase.reason]];
2219
+ actions2 = continueButton;
2220
+ }
2221
+ break;
2222
+ case "bot-check":
2223
+ status = S.botCheck;
2224
+ actions2 = stopButton;
2225
+ break;
2226
+ case "creating":
2227
+ status = S.connecting;
2228
+ actions2 = stopButton;
2229
+ break;
2230
+ case "pending":
2231
+ case "live":
2232
+ status = phase.name === "live" ? S.speaking : S.connecting;
2233
+ top2 = badge;
2234
+ media2 = liveMedia(phase.name === "live");
2235
+ body2 = liveBody(phase.session);
2236
+ actions2 = liveActions(readInChatButton(false));
2237
+ break;
2238
+ case "ended":
2239
+ status = S[phase.how];
2240
+ outcome2 = true;
2241
+ actions2 = readInChatButton(true);
2242
+ newChatOffer = true;
2243
+ break;
2244
+ }
2245
+ }
2246
+ const reason = inFlight(conversation) ? S.askBusy : conversation?.canSend ? null : S.askUnavailable;
2247
+ const chips = box !== null && shown.kind === "empty" && prompts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
2248
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: tryAsking }),
2249
+ /* @__PURE__ */ jsx("div", { className: "flex max-h-28 flex-wrap gap-2 overflow-y-auto", children: prompts.map((prompt) => /* @__PURE__ */ jsx(
2250
+ "button",
2251
+ {
2252
+ type: "button",
2253
+ "data-boff-explore": "avatar-live-chip",
2254
+ "aria-disabled": reason !== null ? "true" : void 0,
2255
+ className: "min-h-11 rounded-full border border-border bg-background px-3 py-2 text-start text-sm text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-disabled:cursor-not-allowed aria-disabled:opacity-50 motion-reduce:transition-none",
2256
+ onClick: () => {
2257
+ if (reason === null) ask(prompt);
2258
+ },
2259
+ children: prompt
2260
+ },
2261
+ prompt
2262
+ )) })
2263
+ ] }) : null;
2264
+ const foot = box === null && !newChatOffer ? null : /* @__PURE__ */ jsxs(
2265
+ "div",
2266
+ {
2267
+ "data-boff-explore": "avatar-live-foot",
2268
+ className: "flex shrink-0 flex-col gap-2 border-t border-border bg-background p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]",
2269
+ children: [
2270
+ newChatOffer ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 text-center", children: [
2271
+ /* @__PURE__ */ jsx(
2272
+ "button",
2273
+ {
2274
+ type: "button",
2275
+ "data-avatar-primary": "",
2276
+ "data-boff-explore": "avatar-live-new-chat-avatar",
2277
+ className: cn(primaryButton, "min-h-11"),
2278
+ onClick: newChatForAvatar,
2279
+ children: S.newChatForAvatar
2280
+ }
2281
+ ),
2282
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: S.newChatNote })
2283
+ ] }) : null,
2284
+ chips,
2285
+ box !== null && usedToday ? /* @__PURE__ */ jsx(
2286
+ "p",
2287
+ {
2288
+ "data-boff-explore": "avatar-live-used-today",
2289
+ className: "text-xs text-muted-foreground",
2290
+ children: S.usedToday
2291
+ }
2292
+ ) : null,
2293
+ box === null ? null : /* @__PURE__ */ jsx(
2294
+ AskBox,
2295
+ {
2296
+ value: draft,
2297
+ maxLength: askMaxLength,
2298
+ onChange: setDraft,
2299
+ onAsk: ask,
2300
+ reason,
2301
+ label: S.askLabel,
2302
+ placeholder: S.askPlaceholder,
2303
+ send,
2304
+ footer: S.askFooter,
2305
+ noFiles: S.askNoFiles,
2306
+ hint: box === "spoken" ? S.needsAnswerAny : null,
2307
+ touchFirst
2308
+ }
2309
+ )
2310
+ ]
2311
+ }
2312
+ );
2313
+ return /* @__PURE__ */ jsxs(
2314
+ "div",
2315
+ {
2316
+ ref: rootRef,
2317
+ "data-boff-explore": "avatar-live",
2318
+ "data-phase": phase.name,
2319
+ "data-ask": askState,
2320
+ className: "absolute inset-0 flex flex-col bg-background",
2321
+ children: [
2322
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center gap-4 overflow-y-auto p-6 text-center", children: [
2323
+ top2,
2324
+ media2,
2325
+ lead,
2326
+ /* @__PURE__ */ jsx(
2327
+ "p",
2328
+ {
2329
+ role: "status",
2330
+ "data-boff-explore": "avatar-live-status",
2331
+ className: outcome2 ? "text-base font-semibold" : "text-sm text-muted-foreground",
2332
+ children: status
2333
+ }
2334
+ ),
2335
+ body2,
2336
+ /* @__PURE__ */ jsx("div", { ref: botBoxRef, "data-boff-explore": "avatar-live-bot-check" }),
2337
+ actions2
2338
+ ] }),
2339
+ foot,
2340
+ /* @__PURE__ */ jsx("audio", { ref: audioRef, "data-boff-explore": "avatar-live-audio" })
2341
+ ]
2342
+ }
2343
+ );
2344
+ }
1335
2345
  const headline = {
1336
2346
  idle: "",
1337
2347
  checking: S.checking,
1338
2348
  inert: "",
1339
- "needs-answer": startOver ? S.startNewChat : S.needsAnswer,
2349
+ // A question asked and its answer on its way: the answer is coming (the avatar is offered once it completes).
2350
+ "needs-answer": startOver ? S.startNewChat : shown.kind === "asking" ? S.gettingAnswer : S.needsAnswer,
1340
2351
  consent: "",
2352
+ declined: S.declined,
2353
+ waiting: S.armed,
1341
2354
  refused: phase.name === "refused" ? S[REFUSAL_TEXT[phase.reason]] : "",
1342
2355
  "bot-check": S.botCheck,
1343
2356
  creating: S.connecting,
@@ -1355,65 +2368,11 @@ function AvatarLiveView({
1355
2368
  body = /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: startOver ? S.startNewChatDetail : S.needsAnswerDetail });
1356
2369
  actions = startOver ? startOverActions : continueButton;
1357
2370
  break;
1358
- case "consent": {
1359
- const { copy } = phase.offer;
2371
+ case "consent":
1360
2372
  media = stillPicture(true);
1361
- body = /* @__PURE__ */ jsxs(
1362
- "section",
1363
- {
1364
- "aria-labelledby": consentTitleId,
1365
- "data-boff-explore": "avatar-live-consent",
1366
- className: "w-full max-w-sm rounded-lg border border-border p-4 text-start",
1367
- children: [
1368
- /* @__PURE__ */ jsx("h2", { id: consentTitleId, className: "text-base font-semibold", children: copy.title }),
1369
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm", children: productName === null || copy.introProduct === null ? copy.intro : fill(copy.introProduct, { product: productName }) }),
1370
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.processing }),
1371
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.storage }),
1372
- /* @__PURE__ */ jsxs(
1373
- "a",
1374
- {
1375
- href: PRIVACY_HREF,
1376
- target: "_blank",
1377
- rel: "noopener noreferrer",
1378
- "data-boff-explore": "avatar-live-privacy",
1379
- className: "mt-2 inline-block text-sm font-medium text-primary underline underline-offset-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1380
- children: [
1381
- copy.privacyLink,
1382
- /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
1383
- " ",
1384
- S.opensInNewTab
1385
- ] })
1386
- ]
1387
- }
1388
- )
1389
- ]
1390
- }
1391
- );
1392
- actions = /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
1393
- /* @__PURE__ */ jsx(
1394
- "button",
1395
- {
1396
- type: "button",
1397
- "data-avatar-primary": "",
1398
- "data-boff-explore": "avatar-live-start",
1399
- className: primaryButton,
1400
- onClick: start,
1401
- children: S.start
1402
- }
1403
- ),
1404
- /* @__PURE__ */ jsx(
1405
- "button",
1406
- {
1407
- type: "button",
1408
- "data-boff-explore": "avatar-live-not-now",
1409
- className: secondaryButton,
1410
- onClick: onContinueInChat,
1411
- children: S.notNow
1412
- }
1413
- )
1414
- ] });
2373
+ body = consentCard(phase.offer.copy);
2374
+ actions = consentActions(false);
1415
2375
  break;
1416
- }
1417
2376
  case "refused":
1418
2377
  actions = phase.reason === "not_eligible" ? startOverActions : continueButton;
1419
2378
  break;
@@ -1422,77 +2381,11 @@ function AvatarLiveView({
1422
2381
  actions = stopButton;
1423
2382
  break;
1424
2383
  case "pending":
1425
- case "live": {
1426
- const playing = phase.name === "live";
1427
- const left = Math.max(0, (phase.session.endsAt - now) / 1e3);
1428
- top = /* @__PURE__ */ jsx(
1429
- "p",
1430
- {
1431
- "data-boff-explore": "avatar-live-badge",
1432
- className: "rounded-full bg-muted px-3 py-1 text-xs font-medium text-foreground",
1433
- children: S.badge
1434
- }
1435
- );
1436
- media = /* @__PURE__ */ jsxs("div", { className: "relative h-48 w-48 shrink-0 overflow-hidden rounded-xl border border-border bg-muted", children: [
1437
- /* @__PURE__ */ jsx(
1438
- "video",
1439
- {
1440
- ref: videoRef,
1441
- "aria-label": S.video,
1442
- "data-boff-explore": "avatar-live-video",
1443
- playsInline: true,
1444
- autoPlay: true,
1445
- muted: true,
1446
- onPlaying,
1447
- className: cn(
1448
- "h-full w-full object-cover",
1449
- !playing && "opacity-0"
1450
- )
1451
- }
1452
- ),
1453
- playing ? null : /* @__PURE__ */ jsx(
1454
- "img",
1455
- {
1456
- src: still.src,
1457
- alt: "",
1458
- decoding: "async",
1459
- className: "absolute inset-0 h-full w-full object-cover"
1460
- }
1461
- ),
1462
- /* @__PURE__ */ jsx("audio", { ref: audioRef, "data-boff-explore": "avatar-live-audio" })
1463
- ] });
1464
- body = /* @__PURE__ */ jsxs(Fragment, { children: [
1465
- /* @__PURE__ */ jsx(
1466
- "section",
1467
- {
1468
- "aria-label": S.captions,
1469
- "data-boff-explore": "avatar-live-captions",
1470
- lang: phase.session.captions.locale || void 0,
1471
- dir: "auto",
1472
- tabIndex: 0,
1473
- className: "max-h-32 w-full max-w-sm overflow-y-auto rounded-lg bg-muted p-3 text-start text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1474
- children: phase.session.captions.text
1475
- }
1476
- ),
1477
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: S.answerInChat }),
1478
- /* @__PURE__ */ jsxs("p", { className: "text-sm tabular-nums text-muted-foreground", children: [
1479
- S.timeLeft,
1480
- " ",
1481
- /* @__PURE__ */ jsx("span", { role: "timer", "data-boff-explore": "avatar-live-countdown", children: clock(left) })
1482
- ] })
1483
- ] });
1484
- actions = /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
1485
- blocked ? /* @__PURE__ */ jsx(
1486
- "button",
1487
- {
1488
- type: "button",
1489
- "data-boff-explore": "avatar-live-sound",
1490
- className: primaryButton,
1491
- onClick: enablePlayback,
1492
- children: S.tapForSound
1493
- }
1494
- ) : null,
1495
- stopButton,
2384
+ case "live":
2385
+ top = badge;
2386
+ media = liveMedia(phase.name === "live");
2387
+ body = liveBody(phase.session);
2388
+ actions = liveActions(
1496
2389
  /* @__PURE__ */ jsx(
1497
2390
  "button",
1498
2391
  {
@@ -1503,9 +2396,8 @@ function AvatarLiveView({
1503
2396
  children: continueInChat
1504
2397
  }
1505
2398
  )
1506
- ] });
2399
+ );
1507
2400
  break;
1508
- }
1509
2401
  case "ended":
1510
2402
  body = /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: S.answerInChat });
1511
2403
  actions = /* @__PURE__ */ jsx(
@@ -1547,6 +2439,119 @@ function AvatarLiveView({
1547
2439
  }
1548
2440
  );
1549
2441
  }
2442
+ function AskBox({
2443
+ value,
2444
+ maxLength,
2445
+ onChange,
2446
+ onAsk,
2447
+ reason,
2448
+ label,
2449
+ placeholder,
2450
+ send,
2451
+ footer,
2452
+ noFiles,
2453
+ hint,
2454
+ touchFirst
2455
+ }) {
2456
+ const uid = useId();
2457
+ const reasonId = `${uid}-reason`;
2458
+ const hintId = `${uid}-hint`;
2459
+ const footerId = `${uid}-footer`;
2460
+ const [refusedFiles, setRefusedFiles] = useState(false);
2461
+ const empty = value.trim() === "";
2462
+ const submit = () => {
2463
+ if (reason !== null || empty) return;
2464
+ onAsk(value);
2465
+ };
2466
+ const onKeyDown = (event) => {
2467
+ if (event.nativeEvent.isComposing || event.keyCode === 229) {
2468
+ if (event.key === "Escape") event.stopPropagation();
2469
+ return;
2470
+ }
2471
+ if (event.key === "Enter" && !event.shiftKey) {
2472
+ event.preventDefault();
2473
+ submit();
2474
+ }
2475
+ };
2476
+ const onPaste = (event) => {
2477
+ if (event.clipboardData.files.length === 0) return;
2478
+ event.preventDefault();
2479
+ setRefusedFiles(true);
2480
+ };
2481
+ const onDrop = (event) => {
2482
+ if (!Array.from(event.dataTransfer.types).includes("Files")) return;
2483
+ event.preventDefault();
2484
+ setRefusedFiles(true);
2485
+ };
2486
+ return /* @__PURE__ */ jsxs(
2487
+ "form",
2488
+ {
2489
+ "data-boff-explore": "avatar-live-ask",
2490
+ className: "flex w-full flex-col gap-1",
2491
+ onSubmit: (event) => {
2492
+ event.preventDefault();
2493
+ submit();
2494
+ },
2495
+ children: [
2496
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
2497
+ /* @__PURE__ */ jsx(
2498
+ "textarea",
2499
+ {
2500
+ value,
2501
+ rows: 1,
2502
+ maxLength,
2503
+ "aria-label": label,
2504
+ "aria-describedby": hint === null ? footerId : `${hintId} ${footerId}`,
2505
+ placeholder,
2506
+ dir: "auto",
2507
+ "data-avatar-primary": touchFirst ? void 0 : "",
2508
+ "data-boff-explore": "avatar-live-ask-input",
2509
+ className: "max-h-32 min-h-11 flex-1 resize-none rounded-md border border-border bg-background px-3 py-2.5 text-base text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:text-sm",
2510
+ onChange: (event) => {
2511
+ setRefusedFiles(false);
2512
+ onChange(event.target.value);
2513
+ },
2514
+ onKeyDown,
2515
+ onPaste,
2516
+ onDrop
2517
+ }
2518
+ ),
2519
+ /* @__PURE__ */ jsx(
2520
+ "button",
2521
+ {
2522
+ type: "submit",
2523
+ "aria-disabled": reason !== null || empty ? "true" : void 0,
2524
+ "aria-describedby": reason !== null ? reasonId : void 0,
2525
+ "data-avatar-primary": touchFirst ? "" : void 0,
2526
+ "data-boff-explore": "avatar-live-ask-send",
2527
+ className: "inline-flex h-11 min-w-11 shrink-0 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background aria-disabled:cursor-not-allowed aria-disabled:opacity-50 motion-reduce:transition-none",
2528
+ children: send
2529
+ }
2530
+ )
2531
+ ] }),
2532
+ reason === null ? null : /* @__PURE__ */ jsx(
2533
+ "p",
2534
+ {
2535
+ id: reasonId,
2536
+ "data-boff-explore": "avatar-live-ask-reason",
2537
+ className: "text-xs text-muted-foreground",
2538
+ children: reason
2539
+ }
2540
+ ),
2541
+ refusedFiles ? /* @__PURE__ */ jsx(
2542
+ "p",
2543
+ {
2544
+ "data-boff-explore": "avatar-live-ask-files",
2545
+ className: "text-xs text-muted-foreground",
2546
+ children: noFiles
2547
+ }
2548
+ ) : null,
2549
+ hint === null ? null : /* @__PURE__ */ jsx("p", { id: hintId, className: "sr-only", children: hint }),
2550
+ /* @__PURE__ */ jsx("p", { id: footerId, className: "text-xs text-muted-foreground", children: footer })
2551
+ ]
2552
+ }
2553
+ );
2554
+ }
1550
2555
 
1551
2556
  export { AvatarLiveView };
1552
2557
  //# sourceMappingURL=index.mjs.map