@burdenoff/website-sdk 2026.1104.2 → 2026.1104.4

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.
@@ -1,5 +1,5 @@
1
1
  import { turnstileSiteKeyOf, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion } from '../chunk-7MSB3EUI.mjs';
2
- import { fill } from '../chunk-TT3MHN42.mjs';
2
+ import { answerDisplayText, fill } from '../chunk-JZS6FQT6.mjs';
3
3
  import { cn } from '../chunk-R7G6TWIS.mjs';
4
4
  import '../chunk-VNS5WDWO.mjs';
5
5
  import { useId, useState, useRef, useCallback, useEffect } from 'react';
@@ -119,7 +119,8 @@ function readCreated(body) {
119
119
  endSecret,
120
120
  endsAt,
121
121
  join: { livekitUrl, participantToken, workerIdentity },
122
- captions: { locale, text }
122
+ captions: { locale, text },
123
+ excerpt: body.excerpt === true
123
124
  }
124
125
  };
125
126
  }
@@ -179,7 +180,7 @@ async function requestAvailability(target) {
179
180
  timer.done();
180
181
  }
181
182
  }
182
- async function requestCreate(target) {
183
+ function requestCreate(target) {
183
184
  const { body } = target;
184
185
  const payload = JSON.stringify({
185
186
  site: body.site,
@@ -189,27 +190,45 @@ async function requestCreate(target) {
189
190
  consentVersion: body.consentVersion,
190
191
  manifestVersion: body.manifestVersion
191
192
  });
192
- const timer = deadline(CREATE_TIMEOUT_MS);
193
- try {
194
- const response = await fetch(`${target.base}/sessions`, {
195
- method: "POST",
196
- credentials: "omit",
197
- cache: "no-store",
198
- headers: {
199
- ...target.headers,
200
- "Content-Type": "application/json",
201
- "Idempotency-Key": target.idempotencyKey,
202
- ...target.botToken === void 0 ? {} : { "x-web-avatar-bot-token": target.botToken }
203
- },
204
- body: payload,
205
- signal: timer.signal
193
+ const controller = new AbortController();
194
+ let answered = false;
195
+ const answer = (async () => {
196
+ try {
197
+ const response = await fetch(`${target.base}/sessions`, {
198
+ method: "POST",
199
+ credentials: "omit",
200
+ cache: "no-store",
201
+ headers: {
202
+ ...target.headers,
203
+ "Content-Type": "application/json",
204
+ "Idempotency-Key": target.idempotencyKey,
205
+ ...target.botToken === void 0 ? {} : { "x-web-avatar-bot-token": target.botToken }
206
+ },
207
+ body: payload,
208
+ signal: controller.signal
209
+ });
210
+ answered = true;
211
+ return readCreate(response.status, await readJson(response));
212
+ } catch {
213
+ return FAILED;
214
+ }
215
+ })();
216
+ return new Promise((resolve) => {
217
+ let late = false;
218
+ const timer = setTimeout(() => {
219
+ late = true;
220
+ if (!answered) controller.abort();
221
+ resolve(FAILED);
222
+ }, CREATE_TIMEOUT_MS);
223
+ void answer.then((result) => {
224
+ if (late) {
225
+ target.onLate?.(result);
226
+ return;
227
+ }
228
+ clearTimeout(timer);
229
+ resolve(result);
206
230
  });
207
- return readCreate(response.status, await readJson(response));
208
- } catch {
209
- return INERT;
210
- } finally {
211
- timer.done();
212
- }
231
+ });
213
232
  }
214
233
  function sendEnd(target) {
215
234
  try {
@@ -292,6 +311,7 @@ var EN = {
292
311
  failed: "The live avatar couldn't start.",
293
312
  interrupted: "The live avatar stopped early.",
294
313
  answerInChat: "The full answer is in Chat.",
314
+ excerpt: "The avatar reads the first part of this answer. The full answer is in Chat.",
295
315
  backToChat: "Back to Chat",
296
316
  busy: "The live avatar is busy right now. Please try again in a few minutes.",
297
317
  limits: "The live avatar has reached its limit for now. Please try again later.",
@@ -349,6 +369,8 @@ var ZH = {
349
369
  failed: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u542F\u52A8\u3002",
350
370
  interrupted: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u63D0\u524D\u505C\u6B62\u4E86\u3002",
351
371
  answerInChat: "\u5B8C\u6574\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
372
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
373
+ excerpt: "\u865A\u62DF\u5F62\u8C61\u6717\u8BFB\u8FD9\u4E2A\u56DE\u7B54\u7684\u7B2C\u4E00\u90E8\u5206\u3002\u5B8C\u6574\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
352
374
  backToChat: "\u8FD4\u56DE\u804A\u5929",
353
375
  busy: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u76EE\u524D\u7E41\u5FD9\uFF0C\u8BF7\u51E0\u5206\u949F\u540E\u518D\u8BD5\u3002",
354
376
  limits: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u6682\u65F6\u5DF2\u8FBE\u5230\u4F7F\u7528\u4E0A\u9650\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002",
@@ -408,6 +430,8 @@ var HI = {
408
430
  failed: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0936\u0941\u0930\u0942 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u093E\u0964",
409
431
  interrupted: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u092C\u0940\u091A \u092E\u0947\u0902 \u0939\u0940 \u0930\u0941\u0915 \u0917\u092F\u093E\u0964",
410
432
  answerInChat: "\u092A\u0942\u0930\u093E \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
433
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
434
+ excerpt: "\u0905\u0935\u0924\u093E\u0930 \u0907\u0938 \u0909\u0924\u094D\u0924\u0930 \u0915\u093E \u092A\u0939\u0932\u093E \u092D\u093E\u0917 \u092A\u0922\u093C\u0924\u093E \u0939\u0948\u0964 \u092A\u0942\u0930\u093E \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
411
435
  backToChat: "\u091A\u0948\u091F \u092A\u0930 \u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0901",
412
436
  busy: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0935\u094D\u092F\u0938\u094D\u0924 \u0939\u0948\u0964 \u0915\u0943\u092A\u092F\u093E \u0915\u0941\u091B \u092E\u093F\u0928\u091F \u092C\u093E\u0926 \u092B\u093F\u0930 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
413
437
  limits: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0905\u092A\u0928\u0940 \u0938\u0940\u092E\u093E \u0924\u0915 \u092A\u0939\u0941\u0901\u091A \u0917\u092F\u093E \u0939\u0948\u0964 \u0915\u0943\u092A\u092F\u093E \u092C\u093E\u0926 \u092E\u0947\u0902 \u092B\u093F\u0930 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
@@ -467,6 +491,8 @@ var ES = {
467
491
  failed: "No se pudo iniciar el avatar en vivo.",
468
492
  interrupted: "El avatar en vivo se detuvo antes de tiempo.",
469
493
  answerInChat: "La respuesta completa est\xE1 en el chat.",
494
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
495
+ excerpt: "El avatar lee la primera parte de esta respuesta. La respuesta completa est\xE1 en el chat.",
470
496
  backToChat: "Volver al chat",
471
497
  busy: "El avatar en vivo est\xE1 ocupado en este momento. Vuelve a intentarlo en unos minutos.",
472
498
  limits: "El avatar en vivo ha alcanzado su l\xEDmite por ahora. Vuelve a intentarlo m\xE1s tarde.",
@@ -526,6 +552,8 @@ var AR = {
526
552
  failed: "\u062A\u0639\u0630\u0651\u0631 \u0628\u062F\u0621 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631.",
527
553
  interrupted: "\u062A\u0648\u0642\u0641 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0642\u0628\u0644 \u0623\u0646 \u064A\u0646\u062A\u0647\u064A.",
528
554
  answerInChat: "\u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0643\u0627\u0645\u0644\u0629 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
555
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
556
+ excerpt: "\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u062C\u0632\u0621 \u0627\u0644\u0623\u0648\u0644 \u0645\u0646 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0643\u0627\u0645\u0644\u0629 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
529
557
  backToChat: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0625\u0644\u0649 \u0627\u0644\u062F\u0631\u062F\u0634\u0629",
530
558
  busy: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0645\u0634\u063A\u0648\u0644 \u0627\u0644\u0622\u0646. \u064A\u064F\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649 \u0628\u0639\u062F \u0628\u0636\u0639 \u062F\u0642\u0627\u0626\u0642.",
531
559
  limits: "\u0628\u0644\u063A \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u062D\u062F\u0651\u0647 \u0641\u064A \u0627\u0644\u0648\u0642\u062A \u0627\u0644\u062D\u0627\u0644\u064A. \u064A\u064F\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0644\u0627\u062D\u0642\u064B\u0627.",
@@ -585,6 +613,8 @@ var TA = {
585
613
  failed: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
586
614
  interrupted: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BC7\u0BAF\u0BC7 \u0BA8\u0BBF\u0BA9\u0BCD\u0BB1\u0BC1\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
587
615
  answerInChat: "\u0BAE\u0BC1\u0BB4\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
616
+ // TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
617
+ excerpt: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BBF\u0BA9\u0BCD \u0BAE\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0B95\u0BC1\u0BA4\u0BBF\u0BAF\u0BC8\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1. \u0BAE\u0BC1\u0BB4\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
588
618
  backToChat: "\u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BC1\u0BA4\u0BCD \u0BA4\u0BBF\u0BB0\u0BC1\u0BAE\u0BCD\u0BAA\u0BC1",
589
619
  busy: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0BB5\u0BC7\u0BB1\u0BC1 \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0BBE\u0B9F\u0BCD\u0B9F\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1. \u0B9A\u0BBF\u0BB2 \u0BA8\u0BBF\u0BAE\u0BBF\u0B9F\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB2\u0BB5\u0BC1\u0BAE\u0BCD.",
590
620
  limits: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC8\u0B95\u0BCD\u0B95\u0BC1\u0BA4\u0BCD \u0BA4\u0BA9\u0BCD \u0BB5\u0BB0\u0BAE\u0BCD\u0BAA\u0BC8 \u0B8E\u0B9F\u0BCD\u0B9F\u0BBF\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1. \u0BAA\u0BBF\u0BB1\u0B95\u0BC1 \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB2\u0BB5\u0BC1\u0BAE\u0BCD.",
@@ -732,6 +762,42 @@ var CONSENT = /* @__PURE__ */ new Map([
732
762
  questions: "any"
733
763
  }
734
764
  }
765
+ ],
766
+ [
767
+ // Stage B (operator decision 2026-11-04): web-consent-2026-11-05 with only its timing sentence changed. A session
768
+ // lasts up to three minutes, sized by the server to the answer's audio; an answer longer than that is read in part,
769
+ // which the avatar says and the Avatar tab notes (`excerpt`), and the full answer stays in Chat. A cap still
770
+ // applies, so the words never say every answer is read whole (gitops docs/avatar-web/en-web-consent-2026-11-12-b.txt).
771
+ "web-consent-2026-11-12-b",
772
+ {
773
+ en: {
774
+ title: "Live AI avatar (beta)",
775
+ introProduct: null,
776
+ intro: "This is an AI avatar, not a real person. It reads aloud 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. It reads for up to three minutes; if an answer is longer, it reads the first part, says so, and the full answer stays in Chat. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
777
+ 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.",
778
+ 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.",
779
+ privacyLink: "How we handle this",
780
+ botCheck: "turnstile",
781
+ questions: "any"
782
+ }
783
+ }
784
+ ],
785
+ [
786
+ // The words of web-consent-2026-11-12-b without "When you start, Cloudflare checks for bots.", for a server that runs
787
+ // no bot check (gitops docs/avatar-web/en-web-consent-2026-11-13-b.txt).
788
+ "web-consent-2026-11-13-b",
789
+ {
790
+ en: {
791
+ title: "Live AI avatar (beta)",
792
+ introProduct: null,
793
+ intro: "This is an AI avatar, not a real person. It reads aloud 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. It reads for up to three minutes; if an answer is longer, it reads the first part, says so, and the full answer stays in Chat. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
794
+ 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.",
795
+ 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.",
796
+ privacyLink: "How we handle this",
797
+ botCheck: "off",
798
+ questions: "any"
799
+ }
800
+ }
735
801
  ]
736
802
  ]);
737
803
  function avatarConsentCopy(version, locale) {
@@ -1301,27 +1367,31 @@ function AvatarLiveView({
1301
1367
  setNow(received);
1302
1368
  go({
1303
1369
  name: "pending",
1304
- session: { endsAt, captions: session.captions }
1370
+ session: {
1371
+ endsAt,
1372
+ captions: session.captions,
1373
+ excerpt: session.excerpt
1374
+ }
1305
1375
  });
1306
1376
  },
1307
1377
  [go]
1308
1378
  );
1309
1379
  const settle = useCallback(
1310
- (result, run, context) => {
1380
+ (result, givenUp, context) => {
1311
1381
  const created = result.kind === "created" ? {
1312
1382
  sessionId: result.session.sessionId,
1313
1383
  secret: result.session.endSecret
1314
1384
  } : result.kind === "unusable" ? { sessionId: result.sessionId, secret: result.endSecret } : null;
1315
1385
  const claimed = created !== null || result.kind === "refused" && result.reason === "answer_claimed";
1316
1386
  if (claimed) claimedRef.current.add(context.messageId);
1317
- if (run.cancelled !== null) {
1387
+ if (givenUp !== null) {
1318
1388
  if (created !== null) {
1319
1389
  sendEnd({
1320
1390
  base: context.base,
1321
1391
  headers: context.headers,
1322
1392
  sessionId: created.sessionId,
1323
1393
  secret: created.secret,
1324
- reason: run.cancelled
1394
+ reason: givenUp
1325
1395
  });
1326
1396
  }
1327
1397
  const shown2 = phaseRef.current;
@@ -1430,21 +1500,21 @@ function AvatarLiveView({
1430
1500
  return;
1431
1501
  }
1432
1502
  if (turnstile !== null) go({ name: "creating" });
1503
+ const context = { module: loaded, offer, messageId, base: base2, headers: headers2 };
1433
1504
  const result = await requestCreate({
1434
1505
  base: base2,
1435
1506
  headers: headers2,
1436
1507
  idempotencyKey,
1437
1508
  botToken,
1438
- body: body2
1509
+ body: body2,
1510
+ // An answer past the deadline, after the view has said the live avatar couldn't start: a session it made is
1511
+ // ended at once with its own secret, and never joined. The reason is the visitor's own where they gave the
1512
+ // start up first, else `client_error`. It reads `run` and never writes it, so the deadline's `failed` below is
1513
+ // shown whichever of the two is handled first.
1514
+ onLate: (late) => settle(late, run.cancelled ?? "client_error", context)
1439
1515
  });
1440
1516
  if (startRef.current === run) startRef.current = null;
1441
- settle(result, run, {
1442
- module: loaded,
1443
- offer,
1444
- messageId,
1445
- base: base2,
1446
- headers: headers2
1447
- });
1517
+ settle(result, run.cancelled, context);
1448
1518
  })();
1449
1519
  },
1450
1520
  [exchangeNow, go, reoffer, settle]
@@ -2123,6 +2193,7 @@ function AvatarLiveView({
2123
2193
  ]
2124
2194
  }
2125
2195
  );
2196
+ const speakingLine = (session) => session.excerpt ? S.excerpt : S.speaking;
2126
2197
  const liveBody = (session) => /* @__PURE__ */ jsxs(Fragment, { children: [
2127
2198
  /* @__PURE__ */ jsx(
2128
2199
  "section",
@@ -2222,14 +2293,21 @@ function AvatarLiveView({
2222
2293
  children: lastQuestion.content
2223
2294
  }
2224
2295
  ),
2225
- 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(
2226
- "p",
2227
- {
2228
- "data-boff-explore": "avatar-live-text-answer",
2229
- dir: "auto",
2230
- className: "line-clamp-6 w-full max-w-sm whitespace-pre-wrap break-words text-start text-sm",
2231
- children: lastAnswer.content
2232
- }
2296
+ 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 }) : (
2297
+ // The answer's words, not its markdown: `content` is written for the chat's renderer, and shown as it is
2298
+ // here a link reads `[label](https://…)`. In its spoken form, as the chat's read-aloud says it: a link is its
2299
+ // label (the address is in Chat, one tap away), a table its rows, and the markers of emphasis, headings,
2300
+ // quotes and list items go (`answerDisplayText`). The words are the ones the chat shows, citation markers
2301
+ // included, which the sources in Chat answer to.
2302
+ /* @__PURE__ */ jsx(
2303
+ "p",
2304
+ {
2305
+ "data-boff-explore": "avatar-live-text-answer",
2306
+ dir: "auto",
2307
+ className: "line-clamp-6 w-full max-w-sm whitespace-pre-wrap break-words text-start text-sm",
2308
+ children: answerDisplayText(lastAnswer.content)
2309
+ }
2310
+ )
2233
2311
  )
2234
2312
  ] });
2235
2313
  const ended = phase.name === "ended";
@@ -2336,7 +2414,7 @@ function AvatarLiveView({
2336
2414
  break;
2337
2415
  case "pending":
2338
2416
  case "live":
2339
- status = phase.name === "live" ? S.speaking : S.connecting;
2417
+ status = phase.name === "live" ? speakingLine(phase.session) : S.connecting;
2340
2418
  top2 = badge;
2341
2419
  media2 = liveMedia(phase.name === "live");
2342
2420
  body2 = liveBody(phase.session);
@@ -2462,7 +2540,7 @@ function AvatarLiveView({
2462
2540
  "bot-check": S.botCheck,
2463
2541
  creating: S.connecting,
2464
2542
  pending: S.connecting,
2465
- live: S.speaking,
2543
+ live: phase.name === "live" ? speakingLine(phase.session) : "",
2466
2544
  ended: phase.name === "ended" ? S[phase.how] : ""
2467
2545
  };
2468
2546
  const outcome = phase.name === "needs-answer" || phase.name === "refused" || phase.name === "ended";