@personaai/react 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/index.cjs +11 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/package.json +82 -82
package/README.md
CHANGED
|
@@ -49,12 +49,51 @@ function Chat() {
|
|
|
49
49
|
| Hook | Purpose |
|
|
50
50
|
| --------------- | -------------------------------------------------------------------------- |
|
|
51
51
|
| `useChat` | Streaming chat — messages, send, stop, reload, interrupts, workspace files |
|
|
52
|
+
| `useVoice` | Real-time voice calls (Gemini Live) — start/stop/mute, live transcript, tool calls |
|
|
52
53
|
| `useThreads` | Thread CRUD — list, create, delete, rename, reset, archive |
|
|
53
54
|
| `useFiles` | Upload management — list, upload, delete |
|
|
54
55
|
| `useMemory` | Persistent memory — read, write, delete |
|
|
55
56
|
| `useAgents` | Agent discovery — list available agents |
|
|
56
57
|
| `useConnection` | Health check — backend connectivity status |
|
|
57
58
|
|
|
59
|
+
## Voice
|
|
60
|
+
|
|
61
|
+
Real-time voice calls with an Agent, powered by Gemini Live. Requires your backend to be running
|
|
62
|
+
`@personaai/runtime@^0.7.0` (or a framework adapter on top of it) so `POST /voice/sessions` exists
|
|
63
|
+
to mint tickets — see that package's README for why the actual call bypasses your backend and
|
|
64
|
+
goes straight to Persona instead of relaying through it like `useChat` does.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { useVoice } from "@personaai/react";
|
|
68
|
+
|
|
69
|
+
function VoiceCall() {
|
|
70
|
+
const { state, transcript, partial, toolCalls, start, stop, mute, isMuted } = useVoice();
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div>
|
|
74
|
+
<p>State: {state}</p>
|
|
75
|
+
{state === "idle" ? (
|
|
76
|
+
<button onClick={start}>Start call</button>
|
|
77
|
+
) : (
|
|
78
|
+
<>
|
|
79
|
+
<button onClick={() => mute(!isMuted)}>{isMuted ? "Unmute" : "Mute"}</button>
|
|
80
|
+
<button onClick={stop}>End call</button>
|
|
81
|
+
</>
|
|
82
|
+
)}
|
|
83
|
+
{transcript.map((line) => (
|
|
84
|
+
<p key={line.id}>
|
|
85
|
+
<b>{line.speaker}:</b> {line.text}
|
|
86
|
+
</p>
|
|
87
|
+
))}
|
|
88
|
+
{partial && <p style={{ opacity: 0.6 }}>{partial.text}</p>}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Requires a browser with `AudioWorklet` support (every current evergreen browser). Needs an HTTPS
|
|
95
|
+
page in production — browsers refuse an insecure `ws://` connection from an `https:` page.
|
|
96
|
+
|
|
58
97
|
## Devtools
|
|
59
98
|
|
|
60
99
|
Floating panel for local debugging — inspect hooks, messages and threads with zero runtime changes. Dev-only, not bundled to production unless imported.
|
package/dist/index.cjs
CHANGED
|
@@ -1351,6 +1351,7 @@ function useVoice(options = {}) {
|
|
|
1351
1351
|
const { defaultAgentId, fetchWithAuth, logger } = usePersonaContext();
|
|
1352
1352
|
const voiceLogger = (0, import_react5.useMemo)(() => logger.child("voice"), [logger]);
|
|
1353
1353
|
const agentId = options.agentId || defaultAgentId;
|
|
1354
|
+
const threadId = options.threadId;
|
|
1354
1355
|
const [state, setState] = (0, import_react5.useState)("idle");
|
|
1355
1356
|
const [isMuted, setIsMuted] = (0, import_react5.useState)(false);
|
|
1356
1357
|
const [transcript, setTranscript] = (0, import_react5.useState)(
|
|
@@ -1454,8 +1455,7 @@ function useVoice(options = {}) {
|
|
|
1454
1455
|
(id, patch) => {
|
|
1455
1456
|
setToolCalls((prev) => {
|
|
1456
1457
|
const idx = prev.findIndex((t) => t.id === id);
|
|
1457
|
-
if (idx === -1)
|
|
1458
|
-
return [...prev, { id, status: "running", ...patch }];
|
|
1458
|
+
if (idx === -1) return [...prev, { id, status: "running", ...patch }];
|
|
1459
1459
|
const next = [...prev];
|
|
1460
1460
|
next[idx] = { ...next[idx], ...patch };
|
|
1461
1461
|
return next;
|
|
@@ -1585,7 +1585,9 @@ function useVoice(options = {}) {
|
|
|
1585
1585
|
}
|
|
1586
1586
|
case "RUN_ERROR":
|
|
1587
1587
|
voiceLogger.warn("RUN_ERROR", { message: msg.message });
|
|
1588
|
-
setError(
|
|
1588
|
+
setError(
|
|
1589
|
+
new Error(msg.message || "The agent run failed.")
|
|
1590
|
+
);
|
|
1589
1591
|
setState("error");
|
|
1590
1592
|
break;
|
|
1591
1593
|
default:
|
|
@@ -1610,12 +1612,15 @@ function useVoice(options = {}) {
|
|
|
1610
1612
|
setToolCalls([]);
|
|
1611
1613
|
acceptedTurnSeqRef.current = 0;
|
|
1612
1614
|
setState("connecting");
|
|
1613
|
-
voiceLogger.debug("start() called", { agentId });
|
|
1615
|
+
voiceLogger.debug("start() called", { agentId, threadId });
|
|
1614
1616
|
try {
|
|
1615
1617
|
const res = await fetchWithAuth("/voice/sessions", {
|
|
1616
1618
|
method: "POST",
|
|
1617
1619
|
headers: { "Content-Type": "application/json" },
|
|
1618
|
-
body: JSON.stringify({
|
|
1620
|
+
body: JSON.stringify({
|
|
1621
|
+
agentId,
|
|
1622
|
+
...threadId ? { threadId } : {}
|
|
1623
|
+
})
|
|
1619
1624
|
});
|
|
1620
1625
|
if (!res.ok) {
|
|
1621
1626
|
throw new Error(`Failed to start voice session: ${res.statusText}`);
|
|
@@ -1650,7 +1655,7 @@ function useVoice(options = {}) {
|
|
|
1650
1655
|
}
|
|
1651
1656
|
teardownAudio();
|
|
1652
1657
|
}
|
|
1653
|
-
}, [agentId, fetchWithAuth, handleMessage, teardownAudio, voiceLogger]);
|
|
1658
|
+
}, [agentId, threadId, fetchWithAuth, handleMessage, teardownAudio, voiceLogger]);
|
|
1654
1659
|
const mute = (0, import_react5.useCallback)((muted) => {
|
|
1655
1660
|
setIsMuted(muted);
|
|
1656
1661
|
streamRef.current?.getAudioTracks().forEach((track) => {
|