@rqmii_immersive/agent-react-sdk 1.0.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.frameworks.md +244 -0
- package/README.md +430 -0
- package/README.simple.md +114 -0
- package/dist/index.d.ts +285 -0
- package/dist/rqmii-react-agent-sdk.cjs +2938 -0
- package/dist/rqmii-react-agent-sdk.cjs.map +1 -0
- package/dist/rqmii-react-agent-sdk.css +1 -0
- package/dist/rqmii-react-agent-sdk.js +17085 -0
- package/dist/rqmii-react-agent-sdk.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Rqmii React Agent SDK - Framework Recipes
|
|
2
|
+
|
|
3
|
+
This guide shows integration patterns for Vite, Next.js, and CRA.
|
|
4
|
+
|
|
5
|
+
## 1. Vite
|
|
6
|
+
|
|
7
|
+
### Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @rqmii_immersive/agent-react-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Env
|
|
14
|
+
|
|
15
|
+
`.env`:
|
|
16
|
+
|
|
17
|
+
```env
|
|
18
|
+
VITE_FASTAPI_BACKEND_URL=https://api.example.com
|
|
19
|
+
VITE_WS_AUDIO_URL=wss://realtime.example.com
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### App Example
|
|
23
|
+
|
|
24
|
+
```jsx
|
|
25
|
+
import {
|
|
26
|
+
RqmiiAgentRoom,
|
|
27
|
+
useRqmiiMessages,
|
|
28
|
+
} from "@rqmii_immersive/agent-react-sdk";
|
|
29
|
+
|
|
30
|
+
function UI() {
|
|
31
|
+
const { sendTextMessage } = useRqmiiMessages();
|
|
32
|
+
return <button onClick={() => sendTextMessage("Hi")}>Send</button>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default function App() {
|
|
36
|
+
return (
|
|
37
|
+
<RqmiiAgentRoom
|
|
38
|
+
wsUrl={import.meta.env.VITE_WS_AUDIO_URL}
|
|
39
|
+
restUrl={import.meta.env.VITE_FASTAPI_BACKEND_URL}
|
|
40
|
+
session={{ mode: "initialize", apiKey: "YOUR_API_KEY", language: "en" }}
|
|
41
|
+
connect
|
|
42
|
+
>
|
|
43
|
+
<UI />
|
|
44
|
+
</RqmiiAgentRoom>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 2. Next.js (App Router)
|
|
50
|
+
|
|
51
|
+
Use client components for SDK usage.
|
|
52
|
+
|
|
53
|
+
### Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install @rqmii_immersive/agent-react-sdk
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Env
|
|
60
|
+
|
|
61
|
+
`.env.local`:
|
|
62
|
+
|
|
63
|
+
```env
|
|
64
|
+
NEXT_PUBLIC_FASTAPI_BACKEND_URL=https://api.example.com
|
|
65
|
+
NEXT_PUBLIC_WS_AUDIO_URL=wss://realtime.example.com
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Client Component
|
|
69
|
+
|
|
70
|
+
`app/agent/page.jsx`:
|
|
71
|
+
|
|
72
|
+
```jsx
|
|
73
|
+
"use client";
|
|
74
|
+
|
|
75
|
+
import {
|
|
76
|
+
RqmiiAgentRoom,
|
|
77
|
+
useRqmiiConnection,
|
|
78
|
+
useRqmiiMessages,
|
|
79
|
+
} from "@rqmii_immersive/agent-react-sdk";
|
|
80
|
+
|
|
81
|
+
function UI() {
|
|
82
|
+
const { connectionState } = useRqmiiConnection();
|
|
83
|
+
const { messages, sendTextMessage } = useRqmiiMessages();
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<div>
|
|
87
|
+
<div>{connectionState}</div>
|
|
88
|
+
<button onClick={() => sendTextMessage("Hello")}>Send</button>
|
|
89
|
+
<pre>{JSON.stringify(messages, null, 2)}</pre>
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export default function AgentPage() {
|
|
95
|
+
return (
|
|
96
|
+
<RqmiiAgentRoom
|
|
97
|
+
wsUrl={process.env.NEXT_PUBLIC_WS_AUDIO_URL}
|
|
98
|
+
restUrl={process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}
|
|
99
|
+
session={{ mode: "initialize", apiKey: "YOUR_API_KEY", language: "en" }}
|
|
100
|
+
connect
|
|
101
|
+
>
|
|
102
|
+
<UI />
|
|
103
|
+
</RqmiiAgentRoom>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Next.js Notes
|
|
109
|
+
|
|
110
|
+
- Do not use SDK in server components.
|
|
111
|
+
- Keep all SDK consumers under `'use client'`.
|
|
112
|
+
- For cloud avatar player, render it only on client.
|
|
113
|
+
|
|
114
|
+
## 3. Create React App (CRA)
|
|
115
|
+
|
|
116
|
+
### Install
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npm install @rqmii_immersive/agent-react-sdk
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Env
|
|
123
|
+
|
|
124
|
+
`.env`:
|
|
125
|
+
|
|
126
|
+
```env
|
|
127
|
+
REACT_APP_FASTAPI_BACKEND_URL=https://api.example.com
|
|
128
|
+
REACT_APP_WS_AUDIO_URL=wss://realtime.example.com
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### App Example
|
|
132
|
+
|
|
133
|
+
```jsx
|
|
134
|
+
import {
|
|
135
|
+
RqmiiAgentRoom,
|
|
136
|
+
useRqmiiMessages,
|
|
137
|
+
} from "@rqmii_immersive/agent-react-sdk";
|
|
138
|
+
|
|
139
|
+
function UI() {
|
|
140
|
+
const { sendTextMessage } = useRqmiiMessages();
|
|
141
|
+
return <button onClick={() => sendTextMessage("Hello")}>Send</button>;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export default function App() {
|
|
145
|
+
return (
|
|
146
|
+
<RqmiiAgentRoom
|
|
147
|
+
wsUrl={process.env.REACT_APP_WS_AUDIO_URL}
|
|
148
|
+
restUrl={process.env.REACT_APP_FASTAPI_BACKEND_URL}
|
|
149
|
+
session={{ mode: "initialize", apiKey: "YOUR_API_KEY", language: "en" }}
|
|
150
|
+
connect
|
|
151
|
+
>
|
|
152
|
+
<UI />
|
|
153
|
+
</RqmiiAgentRoom>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## 4. Common Recipes
|
|
159
|
+
|
|
160
|
+
### Cloud Avatar
|
|
161
|
+
|
|
162
|
+
```jsx
|
|
163
|
+
import {
|
|
164
|
+
RqmiiCloudAvatarPlayer,
|
|
165
|
+
useRqmiiAvatar,
|
|
166
|
+
} from "@rqmii_immersive/agent-react-sdk";
|
|
167
|
+
|
|
168
|
+
function AvatarPanel() {
|
|
169
|
+
const { cloudStreamState, isAvatarSpeaking } = useRqmiiAvatar();
|
|
170
|
+
return (
|
|
171
|
+
<>
|
|
172
|
+
<div>stream: {cloudStreamState}</div>
|
|
173
|
+
<div>speaking: {String(isAvatarSpeaking)}</div>
|
|
174
|
+
<RqmiiCloudAvatarPlayer muted={false} />
|
|
175
|
+
</>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Desktop Avatar Join
|
|
181
|
+
|
|
182
|
+
```jsx
|
|
183
|
+
<RqmiiAgentRoom
|
|
184
|
+
wsUrl={WS_URL}
|
|
185
|
+
restUrl={REST_URL}
|
|
186
|
+
session={{ mode: "join_desktop", uniqueId: "A1B2C3" }}
|
|
187
|
+
connect
|
|
188
|
+
>
|
|
189
|
+
<UI />
|
|
190
|
+
</RqmiiAgentRoom>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Manual Provider Control
|
|
194
|
+
|
|
195
|
+
```jsx
|
|
196
|
+
import {
|
|
197
|
+
RqmiiAgentProvider,
|
|
198
|
+
useRqmiiConnection,
|
|
199
|
+
} from "@rqmii_immersive/agent-react-sdk";
|
|
200
|
+
|
|
201
|
+
function Controls() {
|
|
202
|
+
const { initializeSession, disconnect } = useRqmiiConnection();
|
|
203
|
+
return (
|
|
204
|
+
<>
|
|
205
|
+
<button
|
|
206
|
+
onClick={() => initializeSession({ apiKey: "KEY", language: "en" })}
|
|
207
|
+
>
|
|
208
|
+
Init
|
|
209
|
+
</button>
|
|
210
|
+
<button onClick={disconnect}>Disconnect</button>
|
|
211
|
+
</>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export default function App() {
|
|
216
|
+
return (
|
|
217
|
+
<RqmiiAgentProvider wsUrl={WS_URL} restUrl={REST_URL}>
|
|
218
|
+
<Controls />
|
|
219
|
+
</RqmiiAgentProvider>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 5. Troubleshooting by Framework
|
|
225
|
+
|
|
226
|
+
### Vite
|
|
227
|
+
|
|
228
|
+
- Ensure env keys start with `VITE_`.
|
|
229
|
+
- Restart dev server after env changes.
|
|
230
|
+
|
|
231
|
+
### Next.js
|
|
232
|
+
|
|
233
|
+
- Ensure page/component is client-side (`'use client'`).
|
|
234
|
+
- Use `NEXT_PUBLIC_` env keys.
|
|
235
|
+
|
|
236
|
+
### CRA
|
|
237
|
+
|
|
238
|
+
- Ensure env keys start with `REACT_APP_`.
|
|
239
|
+
- Restart `npm start` after env changes.
|
|
240
|
+
|
|
241
|
+
## 6. Where to Read More
|
|
242
|
+
|
|
243
|
+
- Full technical docs: `README.md`
|
|
244
|
+
- Quick docs: `README.simple.md`
|
package/README.md
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# Rqmii React Agent SDK
|
|
2
|
+
|
|
3
|
+
Standalone React SDK for integrating React apps with:
|
|
4
|
+
|
|
5
|
+
- `RqmiiAgentBackendAPI` REST endpoints (`/sessions/init`, `/sessions/join`)
|
|
6
|
+
- `RqmiiAgentBackendJs` realtime Socket.IO server
|
|
7
|
+
|
|
8
|
+
Quick navigation:
|
|
9
|
+
|
|
10
|
+
- Full guide: `README.md` (this file)
|
|
11
|
+
- Simple guide: `README.simple.md`
|
|
12
|
+
- Framework recipes (Vite/Next.js/CRA): `README.frameworks.md`
|
|
13
|
+
|
|
14
|
+
This SDK gives you a LiveKit-style integration model:
|
|
15
|
+
|
|
16
|
+
- room wrapper component (`RqmiiAgentRoom`)
|
|
17
|
+
- provider (`RqmiiAgentProvider`)
|
|
18
|
+
- hooks usable by any child component (`useRqmiiConnection`, `useRqmiiMessages`, `useRqmiiVoice`, `useRqmiiAvatar`)
|
|
19
|
+
|
|
20
|
+
## 1. Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @rqmii_immersive/agent-react-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If you are testing locally from this mono-repo:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install file:../RqmiiAgentReactSDK
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 2. Required Backend Configuration
|
|
33
|
+
|
|
34
|
+
You must provide both URLs to the SDK:
|
|
35
|
+
|
|
36
|
+
- `restUrl`: FastAPI backend base URL (for session init/join)
|
|
37
|
+
- `wsUrl`: realtime coordinator Socket.IO URL
|
|
38
|
+
|
|
39
|
+
Typical env values:
|
|
40
|
+
|
|
41
|
+
```env
|
|
42
|
+
VITE_FASTAPI_BACKEND_URL=https://api.example.com
|
|
43
|
+
VITE_WS_AUDIO_URL=wss://realtime.example.com
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 3. Import Surface
|
|
47
|
+
|
|
48
|
+
From the package root:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import {
|
|
52
|
+
RqmiiAgentProvider,
|
|
53
|
+
RqmiiAgentRoom,
|
|
54
|
+
RqmiiCloudAvatarPlayer,
|
|
55
|
+
EpicPixelStreamingPlayer,
|
|
56
|
+
useRqmiiAgent,
|
|
57
|
+
useRqmiiConnection,
|
|
58
|
+
useRqmiiMessages,
|
|
59
|
+
useRqmiiVoice,
|
|
60
|
+
useRqmiiAvatar,
|
|
61
|
+
useRqmiiAudioElement,
|
|
62
|
+
useRqmiiPressToTalk,
|
|
63
|
+
useRqmiiVAD,
|
|
64
|
+
AGENT_TYPES,
|
|
65
|
+
CONNECTION_STATE,
|
|
66
|
+
CLOUD_STREAM_STATE,
|
|
67
|
+
SOCKET_EVENTS,
|
|
68
|
+
} from "@rqmii_immersive/agent-react-sdk";
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If your bundler requires explicit style import, also import:
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
import "@rqmii_immersive/agent-react-sdk/style.css";
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 4. Quick Start (Room Wrapper)
|
|
78
|
+
|
|
79
|
+
```jsx
|
|
80
|
+
import {
|
|
81
|
+
RqmiiAgentRoom,
|
|
82
|
+
RqmiiCloudAvatarPlayer,
|
|
83
|
+
useRqmiiConnection,
|
|
84
|
+
useRqmiiMessages,
|
|
85
|
+
useRqmiiAvatar,
|
|
86
|
+
} from "@rqmii_immersive/agent-react-sdk";
|
|
87
|
+
|
|
88
|
+
function ChatUI() {
|
|
89
|
+
const { messages, sendTextMessage } = useRqmiiMessages();
|
|
90
|
+
const { connectionState, isSessionReady, error } = useRqmiiConnection();
|
|
91
|
+
const { isAvatarSpeaking, cloudStreamState } = useRqmiiAvatar();
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div>
|
|
95
|
+
<div>Conn: {connectionState}</div>
|
|
96
|
+
<div>Ready: {String(isSessionReady)}</div>
|
|
97
|
+
<div>Avatar Speaking: {String(isAvatarSpeaking)}</div>
|
|
98
|
+
<div>Cloud Stream: {cloudStreamState}</div>
|
|
99
|
+
{error && <div style={{ color: "red" }}>{error}</div>}
|
|
100
|
+
|
|
101
|
+
<button onClick={() => sendTextMessage("Hello")}>Send</button>
|
|
102
|
+
<pre>{JSON.stringify(messages, null, 2)}</pre>
|
|
103
|
+
|
|
104
|
+
<RqmiiCloudAvatarPlayer muted={false} />
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export default function App() {
|
|
110
|
+
return (
|
|
111
|
+
<RqmiiAgentRoom
|
|
112
|
+
wsUrl={import.meta.env.VITE_WS_AUDIO_URL}
|
|
113
|
+
restUrl={import.meta.env.VITE_FASTAPI_BACKEND_URL}
|
|
114
|
+
session={{ mode: "initialize", apiKey: "YOUR_API_KEY", language: "en" }}
|
|
115
|
+
connect
|
|
116
|
+
onError={(e) => console.error(e)}
|
|
117
|
+
onInitialized={(data) => console.log("session initialized", data)}
|
|
118
|
+
>
|
|
119
|
+
<ChatUI />
|
|
120
|
+
</RqmiiAgentRoom>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 5. Agent-Type Integration Flows
|
|
126
|
+
|
|
127
|
+
### 5.1 Cloud Avatar
|
|
128
|
+
|
|
129
|
+
Use `session.mode = 'initialize'` with `apiKey` (or `publicChatId` / `agentId`).
|
|
130
|
+
|
|
131
|
+
- backend returns `streaming_url`
|
|
132
|
+
- render `RqmiiCloudAvatarPlayer`
|
|
133
|
+
- speaking state comes from avatar events, not audio chunks
|
|
134
|
+
|
|
135
|
+
```jsx
|
|
136
|
+
<RqmiiAgentRoom
|
|
137
|
+
wsUrl={WS_URL}
|
|
138
|
+
restUrl={REST_URL}
|
|
139
|
+
session={{ mode: "initialize", apiKey: API_KEY, language: "en" }}
|
|
140
|
+
connect
|
|
141
|
+
>
|
|
142
|
+
<RqmiiCloudAvatarPlayer muted={false} />
|
|
143
|
+
</RqmiiAgentRoom>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 5.2 Desktop Avatar (User Join)
|
|
147
|
+
|
|
148
|
+
User joins existing desktop avatar session by `uniqueId`:
|
|
149
|
+
|
|
150
|
+
```jsx
|
|
151
|
+
<RqmiiAgentRoom
|
|
152
|
+
wsUrl={WS_URL}
|
|
153
|
+
restUrl={REST_URL}
|
|
154
|
+
session={{ mode: "join_desktop", uniqueId: "A1B2C3" }}
|
|
155
|
+
connect
|
|
156
|
+
>
|
|
157
|
+
<DesktopUI />
|
|
158
|
+
</RqmiiAgentRoom>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 5.3 Text Agent
|
|
162
|
+
|
|
163
|
+
- initialize session
|
|
164
|
+
- send text using `sendTextMessage`
|
|
165
|
+
- read assistant chunks/final from `messages`
|
|
166
|
+
|
|
167
|
+
### 5.4 Voice / Text-and-Voice Agent
|
|
168
|
+
|
|
169
|
+
- send microphone chunks via `sendAudioChunk`
|
|
170
|
+
- signal utterance end via `endAudioStream`
|
|
171
|
+
- audio playback handled internally via `pcm-stream-player`
|
|
172
|
+
|
|
173
|
+
## 6. Avatar State Model (Important)
|
|
174
|
+
|
|
175
|
+
`isAvatarSpeaking` is server-event driven only:
|
|
176
|
+
|
|
177
|
+
- starts on `avatar_speaking`
|
|
178
|
+
- ends on `avatar_speaking_done`
|
|
179
|
+
|
|
180
|
+
This means avatar speaking state is independent from PCM playback.
|
|
181
|
+
|
|
182
|
+
For cloud avatar rendering lifecycle, `useRqmiiAvatar()` exposes:
|
|
183
|
+
|
|
184
|
+
- `cloudStreamState`
|
|
185
|
+
- `cloudStreamError`
|
|
186
|
+
- `isCloudStreamConnected`
|
|
187
|
+
- `isCloudStreamLoading`
|
|
188
|
+
|
|
189
|
+
`cloudStreamState` values:
|
|
190
|
+
|
|
191
|
+
- `idle`
|
|
192
|
+
- `connecting`
|
|
193
|
+
- `loading`
|
|
194
|
+
- `connected`
|
|
195
|
+
- `disconnected`
|
|
196
|
+
- `error`
|
|
197
|
+
|
|
198
|
+
## 7. Reconnection Model
|
|
199
|
+
|
|
200
|
+
The backend uses one-time session JWTs, so default Socket.IO auto-reconnect with the same token is not enough.
|
|
201
|
+
|
|
202
|
+
This SDK implements the coordinator reconnect contract:
|
|
203
|
+
|
|
204
|
+
1. connect using initial `session_token`
|
|
205
|
+
2. server emits `reconnect_credential` with `{ sessionId, reconnectToken, role }`
|
|
206
|
+
3. on disconnect, SDK reconnects with reconnect handshake auth
|
|
207
|
+
4. on success, server emits `reconnect_success` and rotates token
|
|
208
|
+
|
|
209
|
+
Configurable with `reconnectOptions` on provider/room:
|
|
210
|
+
|
|
211
|
+
```jsx
|
|
212
|
+
<RqmiiAgentRoom
|
|
213
|
+
wsUrl={WS_URL}
|
|
214
|
+
restUrl={REST_URL}
|
|
215
|
+
reconnectOptions={{
|
|
216
|
+
enabled: true,
|
|
217
|
+
maxAttempts: 8,
|
|
218
|
+
initialDelayMs: 500,
|
|
219
|
+
maxDelayMs: 5000,
|
|
220
|
+
timeoutMs: 8000,
|
|
221
|
+
}}
|
|
222
|
+
session={{ mode: "initialize", apiKey: API_KEY }}
|
|
223
|
+
connect
|
|
224
|
+
>
|
|
225
|
+
<UI />
|
|
226
|
+
</RqmiiAgentRoom>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## 8. Provider-Only Integration (No Room Wrapper)
|
|
230
|
+
|
|
231
|
+
Use this when you need full manual control:
|
|
232
|
+
|
|
233
|
+
```jsx
|
|
234
|
+
import {
|
|
235
|
+
RqmiiAgentProvider,
|
|
236
|
+
useRqmiiConnection,
|
|
237
|
+
} from "@rqmii_immersive/agent-react-sdk";
|
|
238
|
+
|
|
239
|
+
function Controller() {
|
|
240
|
+
const { initializeSession, joinDesktopSession, disconnect } =
|
|
241
|
+
useRqmiiConnection();
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<div>
|
|
245
|
+
<button
|
|
246
|
+
onClick={() => initializeSession({ apiKey: API_KEY, language: "en" })}
|
|
247
|
+
>
|
|
248
|
+
Init
|
|
249
|
+
</button>
|
|
250
|
+
<button onClick={() => joinDesktopSession({ uniqueId: "A1B2C3" })}>
|
|
251
|
+
Join Desktop
|
|
252
|
+
</button>
|
|
253
|
+
<button onClick={disconnect}>Disconnect</button>
|
|
254
|
+
</div>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export default function App() {
|
|
259
|
+
return (
|
|
260
|
+
<RqmiiAgentProvider wsUrl={WS_URL} restUrl={REST_URL}>
|
|
261
|
+
<Controller />
|
|
262
|
+
</RqmiiAgentProvider>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## 9. Hook Reference
|
|
268
|
+
|
|
269
|
+
### `useRqmiiConnection()`
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
|
|
273
|
+
- `connectionState`
|
|
274
|
+
- `isConnected`
|
|
275
|
+
- `isSessionReady`
|
|
276
|
+
- `error`
|
|
277
|
+
- `reconnectAttempt`
|
|
278
|
+
- `session`
|
|
279
|
+
- `initializeSession(args)`
|
|
280
|
+
- `joinDesktopSession(args)`
|
|
281
|
+
- `disconnect()`
|
|
282
|
+
|
|
283
|
+
### `useRqmiiMessages()`
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
|
|
287
|
+
- `messages`
|
|
288
|
+
- `sendTextMessage(text)`
|
|
289
|
+
- `clearMessages()`
|
|
290
|
+
|
|
291
|
+
Message stream behavior:
|
|
292
|
+
|
|
293
|
+
- server chunks update streaming assistant message (`agent_response_chunk`)
|
|
294
|
+
- final response completes that message (`agent_response`)
|
|
295
|
+
|
|
296
|
+
### `useRqmiiVoice()`
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
|
|
300
|
+
- `sendAudioChunk(audio)`
|
|
301
|
+
- `endAudioStream()`
|
|
302
|
+
- `isAudioPlaying`
|
|
303
|
+
- `transcript`
|
|
304
|
+
- `partialTranscript`
|
|
305
|
+
- `interrupt()`
|
|
306
|
+
- `resumeAudioPlayback()`
|
|
307
|
+
- `attachAudioElement(element)`
|
|
308
|
+
|
|
309
|
+
### `useRqmiiAvatar()`
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
|
|
313
|
+
- `streamingUrl`
|
|
314
|
+
- `isAvatarSpeaking`
|
|
315
|
+
- `speakingSource` (`'avatar_events'`)
|
|
316
|
+
- `isCloudAvatar`
|
|
317
|
+
- `isDesktopAvatar`
|
|
318
|
+
- `cloudStreamState`
|
|
319
|
+
- `cloudStreamError`
|
|
320
|
+
- `isCloudStreamConnected`
|
|
321
|
+
- `isCloudStreamLoading`
|
|
322
|
+
- `setCloudStreamState(nextState, error?)`
|
|
323
|
+
|
|
324
|
+
### `useRqmiiAudioElement(audioRef)`
|
|
325
|
+
|
|
326
|
+
Optional helper to bind an audio element and improve autoplay unlock UX.
|
|
327
|
+
|
|
328
|
+
Note: voice playback does not require HTML audio element because SDK uses WebAudio (`pcm-stream-player`).
|
|
329
|
+
|
|
330
|
+
### `useRqmiiPressToTalk(options?)`
|
|
331
|
+
|
|
332
|
+
Built-in press-and-release voice input mode.
|
|
333
|
+
|
|
334
|
+
- streams mic chunks to backend (`audio_chunk`)
|
|
335
|
+
- sends `audio_end` automatically on release
|
|
336
|
+
- exposes ready-to-spread button handlers via `eventHandlers`
|
|
337
|
+
|
|
338
|
+
Minimal usage:
|
|
339
|
+
|
|
340
|
+
```jsx
|
|
341
|
+
const { eventHandlers, isRecording } = useRqmiiPressToTalk();
|
|
342
|
+
<button {...eventHandlers}>
|
|
343
|
+
{isRecording ? "Recording..." : "Hold to Talk"}
|
|
344
|
+
</button>;
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### `useRqmiiVAD(options?)`
|
|
348
|
+
|
|
349
|
+
Built-in VAD (voice activity detection) mode using `@ricky0123/vad-react`.
|
|
350
|
+
|
|
351
|
+
- toggle VAD listening with `toggle()`
|
|
352
|
+
- auto interrupts on speech start (configurable)
|
|
353
|
+
- handles pre-speech padding and streaming chunks/end events
|
|
354
|
+
|
|
355
|
+
Minimal usage:
|
|
356
|
+
|
|
357
|
+
```jsx
|
|
358
|
+
const { toggle, isListening, isSpeaking } = useRqmiiVAD();
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## 10. Cloud Player Wrapper API
|
|
362
|
+
|
|
363
|
+
`RqmiiCloudAvatarPlayer` props:
|
|
364
|
+
|
|
365
|
+
- `className`
|
|
366
|
+
- `style`
|
|
367
|
+
- `autoConnect` (default `true`)
|
|
368
|
+
- `muted` (default `false`)
|
|
369
|
+
- `onConnected()`
|
|
370
|
+
- `onDisconnected()`
|
|
371
|
+
- `onError(error)`
|
|
372
|
+
|
|
373
|
+
Internally it forwards cloud stream lifecycle to context state.
|
|
374
|
+
|
|
375
|
+
## 11. Error Handling Strategy
|
|
376
|
+
|
|
377
|
+
- fatal session/socket errors populate `error` in connection state
|
|
378
|
+
- `TTS_ERROR` socket errors are treated as non-fatal by default
|
|
379
|
+
- reconnect failures transition to `connectionState = failed`
|
|
380
|
+
|
|
381
|
+
Recommended UI behavior:
|
|
382
|
+
|
|
383
|
+
- show persistent banner for `error`
|
|
384
|
+
- show reconnect indicator while `connectionState === reconnecting`
|
|
385
|
+
- offer retry button that calls `initializeSession` again
|
|
386
|
+
|
|
387
|
+
## 12. Production Checklist
|
|
388
|
+
|
|
389
|
+
- use secure `https/wss` URLs in production
|
|
390
|
+
- ensure CORS allows browser origins for REST and Socket.IO
|
|
391
|
+
- pass correct API key/public chat id per environment
|
|
392
|
+
- monitor reconnect failures and auth errors in logs
|
|
393
|
+
- handle browser autoplay policies with user gesture before first audio
|
|
394
|
+
|
|
395
|
+
## 13. Troubleshooting
|
|
396
|
+
|
|
397
|
+
### Session initializes but socket fails auth
|
|
398
|
+
|
|
399
|
+
Check:
|
|
400
|
+
|
|
401
|
+
- `wsUrl` points to `RqmiiAgentBackendJs`
|
|
402
|
+
- token is passed via SDK flow (do not manually override connect handshake)
|
|
403
|
+
- backend clocks are synchronized for JWT expiry
|
|
404
|
+
|
|
405
|
+
### Cloud avatar not visible
|
|
406
|
+
|
|
407
|
+
Check:
|
|
408
|
+
|
|
409
|
+
- `/sessions/init` response includes `streaming_url`
|
|
410
|
+
- `RqmiiCloudAvatarPlayer` is rendered
|
|
411
|
+
- network allows signaling/WebRTC paths
|
|
412
|
+
|
|
413
|
+
### Avatar speaking UI not updating
|
|
414
|
+
|
|
415
|
+
Check:
|
|
416
|
+
|
|
417
|
+
- server emits `avatar_speaking` and `avatar_speaking_done`
|
|
418
|
+
- your UI reads `isAvatarSpeaking` from `useRqmiiAvatar()`
|
|
419
|
+
|
|
420
|
+
### Voice playback missing for text-and-voice
|
|
421
|
+
|
|
422
|
+
Check:
|
|
423
|
+
|
|
424
|
+
- agent type is not avatar (`cloud_avatar`/`desktop_avatar`)
|
|
425
|
+
- browser has user interaction to unlock audio context
|
|
426
|
+
- `agent_audio_chunk` events are arriving from server
|
|
427
|
+
|
|
428
|
+
## 14. Current Scope
|
|
429
|
+
|
|
430
|
+
This SDK currently targets React integration and browser runtime. If you need Next.js SSR-specific wrappers or TypeScript declaration generation (`.d.ts`), add them in your package pipeline as a next step.
|