@personaai/react 0.6.0 → 0.7.0

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/README.md CHANGED
@@ -13,7 +13,7 @@ npm install @personaai/react
13
13
  ## Quickstart
14
14
 
15
15
  ```tsx
16
- import { PersonaProvider, useChat } from '@personaai/react';
16
+ import { PersonaProvider, useChat } from "@personaai/react";
17
17
 
18
18
  function App() {
19
19
  return (
@@ -46,14 +46,39 @@ function Chat() {
46
46
 
47
47
  ## Hooks
48
48
 
49
- | Hook | Purpose |
50
- | --- | --- |
51
- | `useChat` | Streaming chat — messages, send, stop, reload, interrupts, workspace files |
52
- | `useThreads` | Thread CRUD — list, create, delete, rename, archive |
53
- | `useFiles` | Upload management — list, upload, delete |
54
- | `useMemory` | Persistent memory — read, write, delete |
55
- | `useAgents` | Agent discovery — list available agents |
56
- | `useConnection` | Health check — backend connectivity status |
49
+ | Hook | Purpose |
50
+ | --------------- | -------------------------------------------------------------------------- |
51
+ | `useChat` | Streaming chat — messages, send, stop, reload, interrupts, workspace files |
52
+ | `useThreads` | Thread CRUD — list, create, delete, rename, reset, archive |
53
+ | `useFiles` | Upload management — list, upload, delete |
54
+ | `useMemory` | Persistent memory — read, write, delete |
55
+ | `useAgents` | Agent discovery — list available agents |
56
+ | `useConnection` | Health check — backend connectivity status |
57
+
58
+ ## Devtools
59
+
60
+ Floating panel for local debugging — inspect hooks, messages and threads with zero runtime changes. Dev-only, not bundled to production unless imported.
61
+
62
+ ```bash
63
+ npm install -D @personaai/devtools
64
+ ```
65
+
66
+ ```tsx
67
+ import { PersonaDevtools } from "@personaai/devtools/react";
68
+ import { useChat, useThreads } from "@personaai/react";
69
+
70
+ function Devtools() {
71
+ const { threads } = useThreads();
72
+ const { messages, files, todos } = useChat();
73
+ return <PersonaDevtools clientState={{ threads, messages, files, todos }} />;
74
+ }
75
+
76
+ {
77
+ process.env.NODE_ENV === "development" && <Devtools />;
78
+ }
79
+ ```
80
+
81
+ See `@personaai/devtools` `sdk/devtools/README.md` for `core`/`react`/`nextjs` subpaths and `baseUrl` polling option.
57
82
 
58
83
  ## Full documentation
59
84
 
package/dist/index.cjs CHANGED
@@ -36,7 +36,8 @@ __export(index_exports, {
36
36
  useMcpConnections: () => useMcpConnections,
37
37
  useMemory: () => useMemory,
38
38
  usePersonaContext: () => usePersonaContext,
39
- useThreads: () => useThreads
39
+ useThreads: () => useThreads,
40
+ useVoice: () => useVoice
40
41
  });
41
42
  module.exports = __toCommonJS(index_exports);
42
43
 
@@ -1252,15 +1253,438 @@ function useThreads(autoFetch = true) {
1252
1253
  };
1253
1254
  }
1254
1255
 
1255
- // src/hooks/useFiles.ts
1256
+ // src/hooks/useVoice.ts
1256
1257
  var import_react5 = require("react");
1258
+
1259
+ // src/hooks/voiceWorklets.ts
1260
+ var RECORDER_WORKLET_SOURCE = `
1261
+ class PCMRecorderProcessor extends AudioWorkletProcessor {
1262
+ constructor() {
1263
+ super();
1264
+ this._buffer = [];
1265
+ this._chunkSamples = 320; // 20ms @ 16kHz
1266
+ }
1267
+
1268
+ process(inputs) {
1269
+ const input = inputs[0];
1270
+ const channel = input && input[0];
1271
+ if (channel) {
1272
+ for (let i = 0; i < channel.length; i++) {
1273
+ this._buffer.push(channel[i]);
1274
+ }
1275
+ while (this._buffer.length >= this._chunkSamples) {
1276
+ const chunk = this._buffer.splice(0, this._chunkSamples);
1277
+ const int16 = new Int16Array(chunk.length);
1278
+ for (let i = 0; i < chunk.length; i++) {
1279
+ const s = Math.max(-1, Math.min(1, chunk[i]));
1280
+ int16[i] = s < 0 ? s * 0x8000 : s * 0x7fff;
1281
+ }
1282
+ this.port.postMessage(int16.buffer, [int16.buffer]);
1283
+ }
1284
+ }
1285
+ return true;
1286
+ }
1287
+ }
1288
+
1289
+ registerProcessor('pcm-recorder-processor', PCMRecorderProcessor);
1290
+ `;
1291
+ var PLAYER_WORKLET_SOURCE = `
1292
+ class PCMPlayerProcessor extends AudioWorkletProcessor {
1293
+ constructor() {
1294
+ super();
1295
+ this._queue = [];
1296
+ this._readOffset = 0;
1297
+ this.port.onmessage = (event) => {
1298
+ const msg = event.data;
1299
+ if (msg && msg.type === 'flush') {
1300
+ this._queue = [];
1301
+ this._readOffset = 0;
1302
+ return;
1303
+ }
1304
+ const int16 = new Int16Array(msg);
1305
+ const float32 = new Float32Array(int16.length);
1306
+ for (let i = 0; i < int16.length; i++) {
1307
+ float32[i] = int16[i] / 0x8000;
1308
+ }
1309
+ this._queue.push(float32);
1310
+ };
1311
+ }
1312
+
1313
+ process(_inputs, outputs) {
1314
+ const output = outputs[0][0];
1315
+ let outIdx = 0;
1316
+ while (outIdx < output.length) {
1317
+ if (this._queue.length === 0) {
1318
+ output[outIdx++] = 0;
1319
+ continue;
1320
+ }
1321
+ const current = this._queue[0];
1322
+ const remaining = current.length - this._readOffset;
1323
+ const toCopy = Math.min(remaining, output.length - outIdx);
1324
+ output.set(current.subarray(this._readOffset, this._readOffset + toCopy), outIdx);
1325
+ outIdx += toCopy;
1326
+ this._readOffset += toCopy;
1327
+ if (this._readOffset >= current.length) {
1328
+ this._queue.shift();
1329
+ this._readOffset = 0;
1330
+ }
1331
+ }
1332
+ return true;
1333
+ }
1334
+ }
1335
+
1336
+ registerProcessor('pcm-player-processor', PCMPlayerProcessor);
1337
+ `;
1338
+ function toModuleUrl(source) {
1339
+ const blob = new Blob([source], { type: "application/javascript" });
1340
+ return URL.createObjectURL(blob);
1341
+ }
1342
+ function recorderWorkletUrl() {
1343
+ return toModuleUrl(RECORDER_WORKLET_SOURCE);
1344
+ }
1345
+ function playerWorkletUrl() {
1346
+ return toModuleUrl(PLAYER_WORKLET_SOURCE);
1347
+ }
1348
+
1349
+ // src/hooks/useVoice.ts
1350
+ function useVoice(options = {}) {
1351
+ const { defaultAgentId, fetchWithAuth, logger } = usePersonaContext();
1352
+ const voiceLogger = (0, import_react5.useMemo)(() => logger.child("voice"), [logger]);
1353
+ const agentId = options.agentId || defaultAgentId;
1354
+ const [state, setState] = (0, import_react5.useState)("idle");
1355
+ const [isMuted, setIsMuted] = (0, import_react5.useState)(false);
1356
+ const [transcript, setTranscript] = (0, import_react5.useState)(
1357
+ []
1358
+ );
1359
+ const [partial, setPartial] = (0, import_react5.useState)(
1360
+ null
1361
+ );
1362
+ const [toolCalls, setToolCalls] = (0, import_react5.useState)([]);
1363
+ const [error, setError] = (0, import_react5.useState)(null);
1364
+ const [endReason, setEndReason] = (0, import_react5.useState)(
1365
+ null
1366
+ );
1367
+ const wsRef = (0, import_react5.useRef)(null);
1368
+ const streamRef = (0, import_react5.useRef)(null);
1369
+ const inputCtxRef = (0, import_react5.useRef)(null);
1370
+ const outputCtxRef = (0, import_react5.useRef)(null);
1371
+ const recorderNodeRef = (0, import_react5.useRef)(null);
1372
+ const playerNodeRef = (0, import_react5.useRef)(null);
1373
+ const acceptedTurnSeqRef = (0, import_react5.useRef)(0);
1374
+ const mountedRef = (0, import_react5.useRef)(true);
1375
+ (0, import_react5.useEffect)(() => {
1376
+ mountedRef.current = true;
1377
+ return () => {
1378
+ mountedRef.current = false;
1379
+ };
1380
+ }, []);
1381
+ const teardownAudio = (0, import_react5.useCallback)(() => {
1382
+ try {
1383
+ streamRef.current?.getTracks().forEach((track) => track.stop());
1384
+ } catch {
1385
+ }
1386
+ streamRef.current = null;
1387
+ try {
1388
+ recorderNodeRef.current?.disconnect();
1389
+ } catch {
1390
+ }
1391
+ recorderNodeRef.current = null;
1392
+ try {
1393
+ playerNodeRef.current?.disconnect();
1394
+ } catch {
1395
+ }
1396
+ playerNodeRef.current = null;
1397
+ try {
1398
+ void inputCtxRef.current?.close();
1399
+ } catch {
1400
+ }
1401
+ inputCtxRef.current = null;
1402
+ try {
1403
+ void outputCtxRef.current?.close();
1404
+ } catch {
1405
+ }
1406
+ outputCtxRef.current = null;
1407
+ }, []);
1408
+ const stop = (0, import_react5.useCallback)(() => {
1409
+ voiceLogger.debug("stop() called");
1410
+ try {
1411
+ wsRef.current?.close(1e3, "client_stop");
1412
+ } catch {
1413
+ }
1414
+ wsRef.current = null;
1415
+ teardownAudio();
1416
+ if (mountedRef.current) setState("idle");
1417
+ }, [teardownAudio, voiceLogger]);
1418
+ (0, import_react5.useEffect)(() => stop, [stop]);
1419
+ const startCapture = (0, import_react5.useCallback)(async (inputSampleRate) => {
1420
+ const stream = await navigator.mediaDevices.getUserMedia({
1421
+ audio: {
1422
+ echoCancellation: true,
1423
+ noiseSuppression: true,
1424
+ autoGainControl: true,
1425
+ channelCount: 1
1426
+ }
1427
+ });
1428
+ streamRef.current = stream;
1429
+ const inputCtx = new AudioContext({ sampleRate: inputSampleRate });
1430
+ inputCtxRef.current = inputCtx;
1431
+ await inputCtx.audioWorklet.addModule(recorderWorkletUrl());
1432
+ const source = inputCtx.createMediaStreamSource(stream);
1433
+ const recorderNode = new AudioWorkletNode(
1434
+ inputCtx,
1435
+ "pcm-recorder-processor"
1436
+ );
1437
+ recorderNode.port.onmessage = (event) => {
1438
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
1439
+ wsRef.current.send(event.data);
1440
+ }
1441
+ };
1442
+ recorderNodeRef.current = recorderNode;
1443
+ source.connect(recorderNode);
1444
+ }, []);
1445
+ const setupPlayback = (0, import_react5.useCallback)(async (outputSampleRate) => {
1446
+ const outputCtx = new AudioContext({ sampleRate: outputSampleRate });
1447
+ outputCtxRef.current = outputCtx;
1448
+ await outputCtx.audioWorklet.addModule(playerWorkletUrl());
1449
+ const playerNode = new AudioWorkletNode(outputCtx, "pcm-player-processor");
1450
+ playerNode.connect(outputCtx.destination);
1451
+ playerNodeRef.current = playerNode;
1452
+ }, []);
1453
+ const upsertToolCall = (0, import_react5.useCallback)(
1454
+ (id, patch) => {
1455
+ setToolCalls((prev) => {
1456
+ const idx = prev.findIndex((t) => t.id === id);
1457
+ if (idx === -1)
1458
+ return [...prev, { id, status: "running", ...patch }];
1459
+ const next = [...prev];
1460
+ next[idx] = { ...next[idx], ...patch };
1461
+ return next;
1462
+ });
1463
+ },
1464
+ []
1465
+ );
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
+ }
1478
+ },
1479
+ []
1480
+ );
1481
+ const handleCustomEvent = (0, import_react5.useCallback)(
1482
+ (name, value) => {
1483
+ switch (name) {
1484
+ case "voice_session_ready":
1485
+ voiceLogger.debug("voice_session_ready", value);
1486
+ Promise.all([
1487
+ setupPlayback(value.outputSampleRate),
1488
+ startCapture(value.inputSampleRate)
1489
+ ]).then(() => {
1490
+ if (mountedRef.current) setState("listening");
1491
+ }).catch((err) => {
1492
+ voiceLogger.error("audio graph setup failed", {
1493
+ error: err instanceof Error ? err.message : String(err)
1494
+ });
1495
+ if (mountedRef.current) {
1496
+ setError(err instanceof Error ? err : new Error(String(err)));
1497
+ setState("error");
1498
+ }
1499
+ });
1500
+ break;
1501
+ case "voice_activity":
1502
+ if (value.speaker === "user" && value.state === "start") {
1503
+ setState("listening");
1504
+ } else if (value.speaker === "user" && value.state === "end") {
1505
+ setState("thinking");
1506
+ } else if (value.speaker === "agent" && value.state === "start") {
1507
+ setState("speaking");
1508
+ } else if (value.speaker === "agent" && value.state === "end") {
1509
+ setState("listening");
1510
+ }
1511
+ break;
1512
+ case "voice_transcript":
1513
+ handleTranscript(
1514
+ value
1515
+ );
1516
+ break;
1517
+ case "voice_interrupted":
1518
+ acceptedTurnSeqRef.current = value.turnSeq;
1519
+ playerNodeRef.current?.port.postMessage({ type: "flush" });
1520
+ break;
1521
+ case "voice_session_resumed":
1522
+ voiceLogger.info("session transparently resumed");
1523
+ break;
1524
+ case "voice_session_ended":
1525
+ voiceLogger.info("session ended", { reason: value.reason });
1526
+ setState("ended");
1527
+ setEndReason(value.reason ?? null);
1528
+ teardownAudio();
1529
+ try {
1530
+ wsRef.current?.close();
1531
+ } catch {
1532
+ }
1533
+ wsRef.current = null;
1534
+ break;
1535
+ default:
1536
+ break;
1537
+ }
1538
+ },
1539
+ [handleTranscript, setupPlayback, startCapture, teardownAudio, voiceLogger]
1540
+ );
1541
+ const handleMessage = (0, import_react5.useCallback)(
1542
+ (event) => {
1543
+ if (typeof event.data !== "string") {
1544
+ const buf = event.data;
1545
+ const view = new DataView(buf);
1546
+ const turnSeq = view.getUint32(0, true);
1547
+ if (turnSeq >= acceptedTurnSeqRef.current) {
1548
+ acceptedTurnSeqRef.current = turnSeq;
1549
+ const pcmBytes = buf.slice(4);
1550
+ playerNodeRef.current?.port.postMessage(pcmBytes, [pcmBytes]);
1551
+ }
1552
+ return;
1553
+ }
1554
+ let msg;
1555
+ try {
1556
+ msg = JSON.parse(event.data);
1557
+ } catch {
1558
+ return;
1559
+ }
1560
+ switch (msg.type) {
1561
+ case "CUSTOM":
1562
+ handleCustomEvent(
1563
+ msg.name,
1564
+ msg.value
1565
+ );
1566
+ break;
1567
+ case "TOOL_CALL_CHUNK":
1568
+ upsertToolCall(msg.toolCallId, {
1569
+ name: msg.toolCallName,
1570
+ status: "running"
1571
+ });
1572
+ break;
1573
+ case "TOOL_CALL_RESULT": {
1574
+ let parsed = null;
1575
+ try {
1576
+ parsed = JSON.parse(msg.content);
1577
+ } catch {
1578
+ parsed = { output: msg.content };
1579
+ }
1580
+ upsertToolCall(msg.toolCallId, {
1581
+ status: parsed?.error ? "error" : "done",
1582
+ summary: parsed?.error || (typeof parsed?.output === "string" ? parsed.output : JSON.stringify(parsed?.output ?? ""))
1583
+ });
1584
+ break;
1585
+ }
1586
+ case "RUN_ERROR":
1587
+ voiceLogger.warn("RUN_ERROR", { message: msg.message });
1588
+ setError(new Error(msg.message || "The agent run failed."));
1589
+ setState("error");
1590
+ break;
1591
+ default:
1592
+ break;
1593
+ }
1594
+ },
1595
+ [handleCustomEvent, upsertToolCall, voiceLogger]
1596
+ );
1597
+ const start = (0, import_react5.useCallback)(async () => {
1598
+ if (!agentId) {
1599
+ const err = new Error(
1600
+ "useVoice: no agentId provided and no defaultAgentId set on PersonaProvider"
1601
+ );
1602
+ setError(err);
1603
+ setState("error");
1604
+ return;
1605
+ }
1606
+ setError(null);
1607
+ setEndReason(null);
1608
+ setTranscript([]);
1609
+ setPartial(null);
1610
+ setToolCalls([]);
1611
+ acceptedTurnSeqRef.current = 0;
1612
+ setState("connecting");
1613
+ voiceLogger.debug("start() called", { agentId });
1614
+ try {
1615
+ const res = await fetchWithAuth("/voice/sessions", {
1616
+ method: "POST",
1617
+ headers: { "Content-Type": "application/json" },
1618
+ body: JSON.stringify({ agentId })
1619
+ });
1620
+ if (!res.ok) {
1621
+ throw new Error(`Failed to start voice session: ${res.statusText}`);
1622
+ }
1623
+ const data = await res.json();
1624
+ const ticket = data?.data ?? data;
1625
+ if (!ticket?.wsUrl) {
1626
+ throw new Error("Server did not return a voice session URL.");
1627
+ }
1628
+ const ws = new WebSocket(ticket.wsUrl);
1629
+ ws.binaryType = "arraybuffer";
1630
+ wsRef.current = ws;
1631
+ ws.onmessage = handleMessage;
1632
+ ws.onerror = () => {
1633
+ voiceLogger.warn("WebSocket error");
1634
+ if (mountedRef.current) {
1635
+ setError(new Error("Voice connection error."));
1636
+ setState("error");
1637
+ }
1638
+ };
1639
+ ws.onclose = () => {
1640
+ if (mountedRef.current && wsRef.current === ws) {
1641
+ setState((prev) => prev === "error" ? prev : "idle");
1642
+ }
1643
+ };
1644
+ } catch (err) {
1645
+ const errorObj = err instanceof Error ? err : new Error(String(err));
1646
+ voiceLogger.error("start() failed", { error: errorObj.message });
1647
+ if (mountedRef.current) {
1648
+ setError(errorObj);
1649
+ setState("error");
1650
+ }
1651
+ teardownAudio();
1652
+ }
1653
+ }, [agentId, fetchWithAuth, handleMessage, teardownAudio, voiceLogger]);
1654
+ const mute = (0, import_react5.useCallback)((muted) => {
1655
+ setIsMuted(muted);
1656
+ streamRef.current?.getAudioTracks().forEach((track) => {
1657
+ track.enabled = !muted;
1658
+ });
1659
+ }, []);
1660
+ const sendText = (0, import_react5.useCallback)((text) => {
1661
+ if (!text?.trim() || wsRef.current?.readyState !== WebSocket.OPEN) return;
1662
+ wsRef.current.send(JSON.stringify({ type: "voice.text", text }));
1663
+ }, []);
1664
+ return {
1665
+ state,
1666
+ isMuted,
1667
+ transcript,
1668
+ partial,
1669
+ toolCalls,
1670
+ error,
1671
+ endReason,
1672
+ start,
1673
+ stop,
1674
+ mute,
1675
+ sendText
1676
+ };
1677
+ }
1678
+
1679
+ // src/hooks/useFiles.ts
1680
+ var import_react6 = require("react");
1257
1681
  function useFiles(autoFetch = true) {
1258
1682
  const { fetchWithAuth } = usePersonaContext();
1259
- const [files, setFiles] = (0, import_react5.useState)([]);
1260
- const [isLoading, setIsLoading] = (0, import_react5.useState)(false);
1261
- const [isUploading, setIsUploading] = (0, import_react5.useState)(false);
1262
- const [error, setError] = (0, import_react5.useState)(null);
1263
- const fetchFiles = (0, import_react5.useCallback)(async () => {
1683
+ const [files, setFiles] = (0, import_react6.useState)([]);
1684
+ const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
1685
+ const [isUploading, setIsUploading] = (0, import_react6.useState)(false);
1686
+ const [error, setError] = (0, import_react6.useState)(null);
1687
+ const fetchFiles = (0, import_react6.useCallback)(async () => {
1264
1688
  setIsLoading(true);
1265
1689
  setError(null);
1266
1690
  try {
@@ -1278,7 +1702,7 @@ function useFiles(autoFetch = true) {
1278
1702
  setIsLoading(false);
1279
1703
  }
1280
1704
  }, [fetchWithAuth]);
1281
- const uploadFile = (0, import_react5.useCallback)(
1705
+ const uploadFile = (0, import_react6.useCallback)(
1282
1706
  async (fileOrFormData) => {
1283
1707
  setIsUploading(true);
1284
1708
  setError(null);
@@ -1311,7 +1735,7 @@ function useFiles(autoFetch = true) {
1311
1735
  },
1312
1736
  [fetchWithAuth, fetchFiles]
1313
1737
  );
1314
- const deleteFile = (0, import_react5.useCallback)(
1738
+ const deleteFile = (0, import_react6.useCallback)(
1315
1739
  async (fileId) => {
1316
1740
  const res = await fetchWithAuth(`/files/${fileId}`, { method: "DELETE" });
1317
1741
  if (!res.ok) throw new Error(`Failed to delete file: ${res.statusText}`);
@@ -1319,7 +1743,7 @@ function useFiles(autoFetch = true) {
1319
1743
  },
1320
1744
  [fetchWithAuth]
1321
1745
  );
1322
- const bulkDeleteFiles = (0, import_react5.useCallback)(
1746
+ const bulkDeleteFiles = (0, import_react6.useCallback)(
1323
1747
  async (fileIds) => {
1324
1748
  const res = await fetchWithAuth("/files/bulk-delete", {
1325
1749
  method: "POST",
@@ -1334,10 +1758,10 @@ function useFiles(autoFetch = true) {
1334
1758
  },
1335
1759
  [fetchWithAuth]
1336
1760
  );
1337
- const getDownloadUrl = (0, import_react5.useCallback)((fileId) => {
1761
+ const getDownloadUrl = (0, import_react6.useCallback)((fileId) => {
1338
1762
  return `/files/${fileId}`;
1339
1763
  }, []);
1340
- (0, import_react5.useEffect)(() => {
1764
+ (0, import_react6.useEffect)(() => {
1341
1765
  if (autoFetch) {
1342
1766
  void fetchFiles();
1343
1767
  }
@@ -1356,13 +1780,13 @@ function useFiles(autoFetch = true) {
1356
1780
  }
1357
1781
 
1358
1782
  // src/hooks/useAgents.ts
1359
- var import_react6 = require("react");
1783
+ var import_react7 = require("react");
1360
1784
  function useAgents(autoFetch = true) {
1361
1785
  const { fetchWithAuth } = usePersonaContext();
1362
- const [agents, setAgents] = (0, import_react6.useState)([]);
1363
- const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
1364
- const [error, setError] = (0, import_react6.useState)(null);
1365
- const fetchAgents = (0, import_react6.useCallback)(async () => {
1786
+ const [agents, setAgents] = (0, import_react7.useState)([]);
1787
+ const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
1788
+ const [error, setError] = (0, import_react7.useState)(null);
1789
+ const fetchAgents = (0, import_react7.useCallback)(async () => {
1366
1790
  setIsLoading(true);
1367
1791
  setError(null);
1368
1792
  try {
@@ -1380,7 +1804,7 @@ function useAgents(autoFetch = true) {
1380
1804
  setIsLoading(false);
1381
1805
  }
1382
1806
  }, [fetchWithAuth]);
1383
- (0, import_react6.useEffect)(() => {
1807
+ (0, import_react7.useEffect)(() => {
1384
1808
  if (autoFetch) {
1385
1809
  void fetchAgents();
1386
1810
  }
@@ -1394,13 +1818,13 @@ function useAgents(autoFetch = true) {
1394
1818
  }
1395
1819
 
1396
1820
  // src/hooks/useConnection.ts
1397
- var import_react7 = require("react");
1821
+ var import_react8 = require("react");
1398
1822
  function useConnection(autoCheck = true) {
1399
1823
  const { fetchWithAuth } = usePersonaContext();
1400
- const [health, setHealth] = (0, import_react7.useState)(null);
1401
- const [isConnected, setIsConnected] = (0, import_react7.useState)(false);
1402
- const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
1403
- const checkHealth = (0, import_react7.useCallback)(async () => {
1824
+ const [health, setHealth] = (0, import_react8.useState)(null);
1825
+ const [isConnected, setIsConnected] = (0, import_react8.useState)(false);
1826
+ const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
1827
+ const checkHealth = (0, import_react8.useCallback)(async () => {
1404
1828
  setIsLoading(true);
1405
1829
  try {
1406
1830
  const res = await fetchWithAuth("/health");
@@ -1419,7 +1843,7 @@ function useConnection(autoCheck = true) {
1419
1843
  setIsLoading(false);
1420
1844
  }
1421
1845
  }, [fetchWithAuth]);
1422
- (0, import_react7.useEffect)(() => {
1846
+ (0, import_react8.useEffect)(() => {
1423
1847
  if (autoCheck) {
1424
1848
  void checkHealth();
1425
1849
  }
@@ -1433,15 +1857,15 @@ function useConnection(autoCheck = true) {
1433
1857
  }
1434
1858
 
1435
1859
  // src/hooks/useMcpConnections.ts
1436
- var import_react8 = require("react");
1860
+ var import_react9 = require("react");
1437
1861
  function useMcpConnections(options = {}) {
1438
1862
  const { defaultAgentId, fetchWithAuth } = usePersonaContext();
1439
1863
  const agentId = options.agentId ?? defaultAgentId;
1440
1864
  const autoFetch = options.autoFetch ?? true;
1441
- const [connections, setConnections] = (0, import_react8.useState)([]);
1442
- const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
1443
- const [error, setError] = (0, import_react8.useState)(null);
1444
- const fetchConnections = (0, import_react8.useCallback)(async () => {
1865
+ const [connections, setConnections] = (0, import_react9.useState)([]);
1866
+ const [isLoading, setIsLoading] = (0, import_react9.useState)(false);
1867
+ const [error, setError] = (0, import_react9.useState)(null);
1868
+ const fetchConnections = (0, import_react9.useCallback)(async () => {
1445
1869
  if (!agentId) return [];
1446
1870
  setIsLoading(true);
1447
1871
  setError(null);
@@ -1465,7 +1889,7 @@ function useMcpConnections(options = {}) {
1465
1889
  setIsLoading(false);
1466
1890
  }
1467
1891
  }, [agentId, fetchWithAuth, options.returnTo]);
1468
- (0, import_react8.useEffect)(() => {
1892
+ (0, import_react9.useEffect)(() => {
1469
1893
  if (autoFetch) void fetchConnections();
1470
1894
  }, [autoFetch, fetchConnections]);
1471
1895
  return {
@@ -1480,7 +1904,7 @@ function useMcpConnections(options = {}) {
1480
1904
 
1481
1905
  // src/index.ts
1482
1906
  var import_logger2 = require("@personaai/logger");
1483
- var VERSION = "0.6.0";
1907
+ var VERSION = "0.7.0";
1484
1908
  // Annotate the CommonJS export names for ESM import in node:
1485
1909
  0 && (module.exports = {
1486
1910
  PersonaProvider,
@@ -1499,6 +1923,7 @@ var VERSION = "0.6.0";
1499
1923
  useMcpConnections,
1500
1924
  useMemory,
1501
1925
  usePersonaContext,
1502
- useThreads
1926
+ useThreads,
1927
+ useVoice
1503
1928
  });
1504
1929
  //# sourceMappingURL=index.cjs.map