@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.
@@ -0,0 +1,114 @@
1
+ # Rqmii React Agent SDK (Simple Guide)
2
+
3
+ Minimal guide to integrate quickly.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @rqmii_immersive/agent-react-sdk
9
+ ```
10
+
11
+ ## Required Config
12
+
13
+ You need:
14
+
15
+ - `restUrl` -> FastAPI backend URL
16
+ - `wsUrl` -> realtime Socket.IO URL
17
+
18
+ Example env:
19
+
20
+ ```env
21
+ VITE_FASTAPI_BACKEND_URL=https://api.example.com
22
+ VITE_WS_AUDIO_URL=wss://realtime.example.com
23
+ ```
24
+
25
+ ## Basic Usage
26
+
27
+ ```jsx
28
+ import {
29
+ RqmiiAgentRoom,
30
+ useRqmiiConnection,
31
+ useRqmiiMessages,
32
+ useRqmiiPressToTalk,
33
+ } from "@rqmii_immersive/agent-react-sdk";
34
+
35
+ function ChatUI() {
36
+ const { connectionState, isSessionReady, error } = useRqmiiConnection();
37
+ const { messages, sendTextMessage } = useRqmiiMessages();
38
+ const { eventHandlers, isRecording } = useRqmiiPressToTalk();
39
+
40
+ return (
41
+ <div>
42
+ <div>{connectionState}</div>
43
+ <div>ready: {String(isSessionReady)}</div>
44
+ {error && <div style={{ color: "red" }}>{error}</div>}
45
+
46
+ <button onClick={() => sendTextMessage("Hello")}>Send</button>
47
+ <button {...eventHandlers}>
48
+ {isRecording ? "Recording..." : "Hold to Talk"}
49
+ </button>
50
+ <pre>{JSON.stringify(messages, null, 2)}</pre>
51
+ </div>
52
+ );
53
+ }
54
+
55
+ export default function App() {
56
+ return (
57
+ <RqmiiAgentRoom
58
+ wsUrl={import.meta.env.VITE_WS_AUDIO_URL}
59
+ restUrl={import.meta.env.VITE_FASTAPI_BACKEND_URL}
60
+ session={{ mode: "initialize", apiKey: "YOUR_API_KEY", language: "en" }}
61
+ connect
62
+ >
63
+ <ChatUI />
64
+ </RqmiiAgentRoom>
65
+ );
66
+ }
67
+ ```
68
+
69
+ ## Cloud Avatar
70
+
71
+ ```jsx
72
+ import {
73
+ RqmiiCloudAvatarPlayer,
74
+ useRqmiiAvatar,
75
+ } from "@rqmii_immersive/agent-react-sdk";
76
+
77
+ function CloudAvatarUI() {
78
+ const { isAvatarSpeaking, cloudStreamState } = useRqmiiAvatar();
79
+
80
+ return (
81
+ <>
82
+ <div>speaking: {String(isAvatarSpeaking)}</div>
83
+ <div>stream: {cloudStreamState}</div>
84
+ <RqmiiCloudAvatarPlayer muted={false} />
85
+ </>
86
+ );
87
+ }
88
+ ```
89
+
90
+ ## Desktop Avatar Join
91
+
92
+ ```jsx
93
+ <RqmiiAgentRoom
94
+ wsUrl={WS_URL}
95
+ restUrl={REST_URL}
96
+ session={{ mode: "join_desktop", uniqueId: "A1B2C3" }}
97
+ connect
98
+ >
99
+ <YourUI />
100
+ </RqmiiAgentRoom>
101
+ ```
102
+
103
+ ## Voice Input / Output
104
+
105
+ - send mic chunks: `sendAudioChunk(chunk)`
106
+ - end utterance: `endAudioStream()`
107
+ - interrupt: `interrupt()`
108
+ - SDK plays output audio internally using `pcm-stream-player`
109
+
110
+ ## Notes
111
+
112
+ - Reconnection is built-in and follows backend reconnect credential flow.
113
+ - Avatar speaking state comes from backend avatar events.
114
+ - For full docs, see `README.md`.
@@ -0,0 +1,285 @@
1
+ import * as React from 'react';
2
+
3
+ export type AgentType =
4
+ | 'text'
5
+ | 'voice'
6
+ | 'text_and_voice'
7
+ | 'cloud_avatar'
8
+ | 'desktop_avatar'
9
+ | (string & {});
10
+
11
+ export type ConnectionState =
12
+ | 'idle'
13
+ | 'initializing'
14
+ | 'connecting'
15
+ | 'connected'
16
+ | 'reconnecting'
17
+ | 'failed'
18
+ | 'ended'
19
+ | (string & {});
20
+
21
+ export type CloudStreamState =
22
+ | 'idle'
23
+ | 'connecting'
24
+ | 'loading'
25
+ | 'connected'
26
+ | 'disconnected'
27
+ | 'error'
28
+ | (string & {});
29
+
30
+ export interface RqmiiSessionInfo {
31
+ sessionId: string | null;
32
+ role: string | null;
33
+ agentType: AgentType | null;
34
+ streamingUrl: string | null;
35
+ uniqueId: string | null;
36
+ }
37
+
38
+ export interface RqmiiMessage {
39
+ id: string;
40
+ role: 'assistant' | 'user' | string;
41
+ text: string;
42
+ streaming?: boolean;
43
+ timestamp?: string;
44
+ }
45
+
46
+ export interface RqmiiReconnectOptions {
47
+ enabled?: boolean;
48
+ maxAttempts?: number;
49
+ initialDelayMs?: number;
50
+ maxDelayMs?: number;
51
+ timeoutMs?: number;
52
+ }
53
+
54
+ export interface RqmiiPCMOptions {
55
+ encoding?: string;
56
+ channels?: number;
57
+ sampleRate?: number;
58
+ }
59
+
60
+ export interface InitializeSessionArgs {
61
+ apiKey?: string;
62
+ publicChatId?: string;
63
+ agentId?: string;
64
+ language?: string;
65
+ }
66
+
67
+ export interface JoinDesktopSessionArgs {
68
+ uniqueId: string;
69
+ }
70
+
71
+ export interface RqmiiAgentProviderProps {
72
+ children?: React.ReactNode;
73
+ wsUrl: string;
74
+ restUrl: string;
75
+ reconnectOptions?: RqmiiReconnectOptions;
76
+ enableAudio?: boolean;
77
+ pcmOptions?: RqmiiPCMOptions;
78
+ debug?: boolean;
79
+ }
80
+
81
+ export interface RqmiiAgentRoomSessionInitialize {
82
+ mode?: 'initialize';
83
+ apiKey?: string;
84
+ publicChatId?: string;
85
+ agentId?: string;
86
+ language?: string;
87
+ }
88
+
89
+ export interface RqmiiAgentRoomSessionJoinDesktop {
90
+ mode: 'join_desktop';
91
+ uniqueId: string;
92
+ }
93
+
94
+ export type RqmiiAgentRoomSession =
95
+ | RqmiiAgentRoomSessionInitialize
96
+ | RqmiiAgentRoomSessionJoinDesktop;
97
+
98
+ export interface RqmiiAgentRoomProps extends RqmiiAgentProviderProps {
99
+ session?: RqmiiAgentRoomSession;
100
+ connect?: boolean;
101
+ onError?: (error: unknown) => void;
102
+ onInitialized?: (data: any) => void;
103
+ }
104
+
105
+ export interface RqmiiCloudAvatarPlayerProps {
106
+ className?: string;
107
+ style?: React.CSSProperties;
108
+ autoConnect?: boolean;
109
+ muted?: boolean;
110
+ onConnected?: () => void;
111
+ onDisconnected?: () => void;
112
+ onError?: (error: unknown) => void;
113
+ }
114
+
115
+ export interface EpicPixelStreamingPlayerProps {
116
+ signallingUrl?: string;
117
+ autoConnect?: boolean;
118
+ width?: string | number;
119
+ height?: string | number;
120
+ onConnecting?: () => void;
121
+ onLoading?: () => void;
122
+ onConnected?: () => void;
123
+ onDisconnected?: () => void;
124
+ onError?: (error: unknown) => void;
125
+ muted?: boolean;
126
+ }
127
+
128
+ export interface UseRqmiiConnectionReturn {
129
+ connectionState: ConnectionState;
130
+ isConnected: boolean;
131
+ isSessionReady: boolean;
132
+ error: string | null;
133
+ reconnectAttempt: number;
134
+ session: RqmiiSessionInfo;
135
+ initializeSession: (args?: InitializeSessionArgs) => Promise<any>;
136
+ joinDesktopSession: (args: JoinDesktopSessionArgs) => Promise<any>;
137
+ disconnect: () => void;
138
+ }
139
+
140
+ export interface UseRqmiiMessagesReturn {
141
+ messages: RqmiiMessage[];
142
+ sendTextMessage: (text: string) => boolean;
143
+ clearMessages: () => void;
144
+ }
145
+
146
+ export interface UseRqmiiVoiceReturn {
147
+ sendAudioChunk: (audio: ArrayBuffer | Uint8Array | unknown) => boolean;
148
+ endAudioStream: () => boolean;
149
+ isAudioPlaying: boolean;
150
+ transcript: unknown;
151
+ partialTranscript: unknown;
152
+ interrupt: () => boolean;
153
+ resumeAudioPlayback: () => Promise<void>;
154
+ attachAudioElement: (element: HTMLAudioElement | null) => void;
155
+ }
156
+
157
+ export interface UseRqmiiAvatarReturn {
158
+ streamingUrl: string | null;
159
+ isAvatarSpeaking: boolean;
160
+ speakingSource: 'avatar_events';
161
+ isCloudAvatar: boolean;
162
+ isDesktopAvatar: boolean;
163
+ cloudStreamState: CloudStreamState;
164
+ cloudStreamError: string | null;
165
+ isCloudStreamConnected: boolean;
166
+ isCloudStreamLoading: boolean;
167
+ setCloudStreamState: (nextState: CloudStreamState, error?: unknown) => void;
168
+ }
169
+
170
+ export interface UseRqmiiPressToTalkOptions {
171
+ onAudioChunk?: (chunk: ArrayBuffer) => void;
172
+ onAudioEnd?: () => void;
173
+ onError?: (error: unknown) => void;
174
+ holdDelayMs?: number;
175
+ timesliceMs?: number;
176
+ interruptOnHoldStart?: boolean;
177
+ audioConstraints?: MediaTrackConstraints;
178
+ }
179
+
180
+ export interface UseRqmiiPressToTalkReturn {
181
+ isPressing: boolean;
182
+ isRecording: boolean;
183
+ micError: string | null;
184
+ startRecording: () => Promise<boolean>;
185
+ stopRecording: (args?: { discard?: boolean }) => boolean;
186
+ startPress: () => void;
187
+ stopPress: () => void;
188
+ eventHandlers: React.HTMLAttributes<HTMLElement>;
189
+ }
190
+
191
+ export interface UseRqmiiVADOptions {
192
+ onAudioChunk?: (chunk: ArrayBuffer) => void;
193
+ onAudioEnd?: () => void;
194
+ onSpeechStart?: () => void;
195
+ onSpeechEnd?: () => void;
196
+ onVADMisfire?: () => void;
197
+ onError?: (error: unknown) => void;
198
+ interruptOnSpeechStart?: boolean;
199
+ forceAudioMp4?: boolean;
200
+ }
201
+
202
+ export interface UseRqmiiVADReturn {
203
+ isListening: boolean;
204
+ isLoading: boolean;
205
+ isSpeaking: boolean;
206
+ micError: string | null;
207
+ toggle: () => void;
208
+ start: () => void;
209
+ pause: () => void;
210
+ userSpeaking: boolean;
211
+ }
212
+
213
+ export interface RqmiiAgentContextValue extends UseRqmiiConnectionReturn {
214
+ isAudioPlaying: boolean;
215
+ isAvatarSpeaking: boolean;
216
+ cloudStream: {
217
+ state: CloudStreamState;
218
+ error: string | null;
219
+ };
220
+ transcript: unknown;
221
+ partialTranscript: unknown;
222
+ messages: RqmiiMessage[];
223
+ initializeSession: (args?: InitializeSessionArgs) => Promise<any>;
224
+ joinDesktopSession: (args: JoinDesktopSessionArgs) => Promise<any>;
225
+ disconnect: () => void;
226
+ emit: (event: string, payload?: unknown) => boolean;
227
+ sendTextMessage: (text: string) => boolean;
228
+ sendAudioChunk: (audio: ArrayBuffer | Uint8Array | unknown) => boolean;
229
+ endAudioStream: () => boolean;
230
+ interrupt: () => boolean;
231
+ refreshSessionActivity: () => boolean;
232
+ clearSessionHistory: () => boolean;
233
+ clearMessages: () => void;
234
+ resumeAudioPlayback: () => Promise<void>;
235
+ attachAudioElement: (element: HTMLAudioElement | null) => void;
236
+ setCloudStreamState: (nextState: CloudStreamState, error?: unknown) => void;
237
+ audioElement: HTMLAudioElement | null;
238
+ socket: any;
239
+ }
240
+
241
+ export const AGENT_TYPES: {
242
+ readonly TEXT: 'text';
243
+ readonly VOICE: 'voice';
244
+ readonly TEXT_AND_VOICE: 'text_and_voice';
245
+ readonly CLOUD_AVATAR: 'cloud_avatar';
246
+ readonly DESKTOP_AVATAR: 'desktop_avatar';
247
+ };
248
+
249
+ export const SOCKET_EVENTS: Record<string, string>;
250
+
251
+ export const CONNECTION_STATE: {
252
+ readonly IDLE: 'idle';
253
+ readonly INITIALIZING: 'initializing';
254
+ readonly CONNECTING: 'connecting';
255
+ readonly CONNECTED: 'connected';
256
+ readonly RECONNECTING: 'reconnecting';
257
+ readonly FAILED: 'failed';
258
+ readonly ENDED: 'ended';
259
+ };
260
+
261
+ export const CLOUD_STREAM_STATE: {
262
+ readonly IDLE: 'idle';
263
+ readonly CONNECTING: 'connecting';
264
+ readonly LOADING: 'loading';
265
+ readonly CONNECTED: 'connected';
266
+ readonly DISCONNECTED: 'disconnected';
267
+ readonly ERROR: 'error';
268
+ };
269
+
270
+ export function RqmiiAgentProvider(props: RqmiiAgentProviderProps): React.JSX.Element;
271
+ export function useRqmiiAgentContext(): RqmiiAgentContextValue;
272
+
273
+ export function useRqmiiAgent(): RqmiiAgentContextValue;
274
+ export function useRqmiiConnection(): UseRqmiiConnectionReturn;
275
+ export function useRqmiiMessages(): UseRqmiiMessagesReturn;
276
+ export function useRqmiiVoice(): UseRqmiiVoiceReturn;
277
+ export function useRqmiiAvatar(): UseRqmiiAvatarReturn;
278
+ export function useRqmiiAudioElement(audioRef: React.RefObject<HTMLAudioElement | null>): void;
279
+ export function useRqmiiPressToTalk(options?: UseRqmiiPressToTalkOptions): UseRqmiiPressToTalkReturn;
280
+ export function useRqmiiVAD(options?: UseRqmiiVADOptions): UseRqmiiVADReturn;
281
+
282
+ export function RqmiiAgentRoom(props: RqmiiAgentRoomProps): React.JSX.Element;
283
+ export function RqmiiCloudAvatarPlayer(props: RqmiiCloudAvatarPlayerProps): React.JSX.Element | null;
284
+ export const EpicPixelStreamingPlayer: React.ComponentType<EpicPixelStreamingPlayerProps>;
285
+