@personaai/react 0.7.1 → 0.7.2

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.
package/dist/index.cjs CHANGED
@@ -1347,6 +1347,14 @@ function playerWorkletUrl() {
1347
1347
  }
1348
1348
 
1349
1349
  // src/hooks/useVoice.ts
1350
+ function mergeTranscriptText(prev, next) {
1351
+ if (!prev) return next;
1352
+ if (!next) return prev;
1353
+ if (next === prev || prev.endsWith(next)) return prev;
1354
+ if (next.startsWith(prev)) return next;
1355
+ const needSpace = !/\s$/.test(prev) && !/^\s/.test(next);
1356
+ return prev + (needSpace ? " " : "") + next;
1357
+ }
1350
1358
  function useVoice(options = {}) {
1351
1359
  const { defaultAgentId, fetchWithAuth, logger } = usePersonaContext();
1352
1360
  const voiceLogger = (0, import_react5.useMemo)(() => logger.child("voice"), [logger]);
@@ -1373,6 +1381,9 @@ function useVoice(options = {}) {
1373
1381
  const playerNodeRef = (0, import_react5.useRef)(null);
1374
1382
  const acceptedTurnSeqRef = (0, import_react5.useRef)(0);
1375
1383
  const mountedRef = (0, import_react5.useRef)(true);
1384
+ const lastFinalTurnRef = (0, import_react5.useRef)(
1385
+ null
1386
+ );
1376
1387
  (0, import_react5.useEffect)(() => {
1377
1388
  mountedRef.current = true;
1378
1389
  return () => {
@@ -1463,21 +1474,28 @@ function useVoice(options = {}) {
1463
1474
  },
1464
1475
  []
1465
1476
  );
1466
- const handleTranscript = (0, import_react5.useCallback)(
1467
- (value) => {
1468
- const { speaker, text, isFinal } = value;
1469
- if (isFinal) {
1470
- setPartial((prev) => prev?.speaker === speaker ? null : prev);
1471
- setTranscript((prev) => [
1472
- ...prev,
1473
- { id: `${speaker}-${prev.length}`, speaker, text }
1474
- ]);
1475
- } else {
1476
- setPartial({ id: "partial", speaker, text });
1477
+ const handleTranscript = (0, import_react5.useCallback)((value) => {
1478
+ const { speaker, text, isFinal, turnSeq } = value;
1479
+ if (!isFinal) {
1480
+ setPartial({ id: "partial", speaker, text });
1481
+ return;
1482
+ }
1483
+ setPartial((prev) => prev?.speaker === speaker ? null : prev);
1484
+ const last = lastFinalTurnRef.current;
1485
+ const sameUtterance = last && last.speaker === speaker && last.turnSeq === turnSeq;
1486
+ setTranscript((prev) => {
1487
+ const tail = prev[prev.length - 1];
1488
+ if (sameUtterance && tail?.speaker === speaker) {
1489
+ const merged = mergeTranscriptText(tail.text, text);
1490
+ if (merged === tail.text) return prev;
1491
+ return prev.map(
1492
+ (l, i) => i === prev.length - 1 ? { ...l, text: merged } : l
1493
+ );
1477
1494
  }
1478
- },
1479
- []
1480
- );
1495
+ return [...prev, { id: `${speaker}-${prev.length}`, speaker, text }];
1496
+ });
1497
+ lastFinalTurnRef.current = { speaker, turnSeq };
1498
+ }, []);
1481
1499
  const handleCustomEvent = (0, import_react5.useCallback)(
1482
1500
  (name, value) => {
1483
1501
  switch (name) {
@@ -1510,9 +1528,7 @@ function useVoice(options = {}) {
1510
1528
  }
1511
1529
  break;
1512
1530
  case "voice_transcript":
1513
- handleTranscript(
1514
- value
1515
- );
1531
+ handleTranscript(value);
1516
1532
  break;
1517
1533
  case "voice_interrupted":
1518
1534
  acceptedTurnSeqRef.current = value.turnSeq;
@@ -1909,7 +1925,7 @@ function useMcpConnections(options = {}) {
1909
1925
 
1910
1926
  // src/index.ts
1911
1927
  var import_logger2 = require("@personaai/logger");
1912
- var VERSION = "0.7.0";
1928
+ var VERSION = "0.7.2";
1913
1929
  // Annotate the CommonJS export names for ESM import in node:
1914
1930
  0 && (module.exports = {
1915
1931
  PersonaProvider,