@centive/aria-sdk 0.5.9 → 0.6.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
@@ -1,906 +1,375 @@
1
1
  # Aria React SDK
2
2
 
3
- A production-ready React SDK for [Anam AI](https://docs.anam.ai/) with dual-mode operation, WebSocket integration, and comprehensive message accumulation for seamless AI assistant experiences.
3
+ A production-ready React SDK for [Anam AI](https://docs.anam.ai/) with simple initialization, automatic session management, and a beautiful AI assistant interface.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@centive/aria-sdk.svg)](https://www.npmjs.com/package/@centive/aria-sdk)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- ## Key Features
9
-
10
- ### 🎯 Dual-Mode Operation
11
- - **Floating Button Mode** - Always-visible button for user-initiated conversations
12
- - **Center Modal Mode** - Auto-opens when WebSocket events arrive (e.g., incoming calls)
13
- - **Both modes work simultaneously** - Maximum flexibility for any use case
14
-
15
- ### 🚀 Global Session Management
16
- - **Lazy Session Initialization** - Greeting plays exactly when user opens widget (not preloaded)
17
- - **Session Persistence** - Session survives page navigation in SPAs
18
- - **Widget Toggle Persistence** - Keep session alive when widget is closed/reopened (optional)
19
- - **Minimized Widget State** - Click outside to minimize, keeping session active
20
- - **Proactive Refresh** - Automatically refreshes session before expiration
21
- - **Tab Visibility Awareness** - Only refreshes when tab is active
22
- - **Error Recovery** - Exponential backoff retry on failures
23
-
24
- ### 🔌 WebSocket Integration
25
- - Real-time bidirectional communication
26
- - Automatic session management
27
- - Message accumulation and persistence
28
- - Auto-save and circuit breaker patterns
29
-
30
- ### 💬 Full-Featured Communication
31
- - Real-time video streaming with AI personas
32
- - Toggle-able chat panel with conversation history
33
- - Mute/unmute audio controls
34
- - Live transcription display
35
- - Message history tracking
36
- - **Tool Call Indicators** - Visual feedback when AI is executing tools/functions
37
-
38
- ### 🎨 Modern UI
39
- - Video-call-style interface
40
- - Light and dark theme support
41
- - Landscape video (16:9) optimization
42
- - Built with Shad/CN UI components
43
- - Fully responsive design
44
-
45
- ### 🔧 Developer-Friendly
46
- - TypeScript support with full type safety
47
- - Simple React components and hooks
48
- - Comprehensive documentation
49
- - Example servers included
50
-
51
- ## 📦 Installation
8
+ ## Quick Start
52
9
 
53
- ```bash
54
- npm install @centive/aria-sdk
55
- ```
56
-
57
- ### Peer Dependencies
58
-
59
- The SDK requires React 18+ as a peer dependency:
60
-
61
- ```bash
62
- npm install react@^18.0.0 react-dom@^18.0.0
63
- ```
64
-
65
- ## 🚀 Quick Start
66
-
67
- ### 1. Simple Integration (Recommended)
68
-
69
- The SDK provides an all-in-one container that handles WebSocket connection, state management, and the UI. Just import and drop it in! By default, this includes both the floating trigger button and the assistant widget.
70
-
71
- > **Important:** Place `Aria` (or `AriaProvider`) at your app's root level, **above your router**. This ensures the session persists across page navigation and provides instant response when users click the trigger button.
72
-
73
- ```tsx
10
+ ```typescript
74
11
  import { Aria } from '@centive/aria-sdk';
75
- import '@centive/aria-sdk/styles.css';
76
- import { BrowserRouter, Routes, Route } from 'react-router-dom';
77
12
 
78
- function App() {
79
- const config = {
80
- websocketUrl: 'ws://localhost:8000/ws',
81
- userId: 'user_123',
82
- theme: 'light', // or 'dark'
83
- // Session preloading is enabled by default
84
- preloadSession: true,
85
- // Refresh session 5 minutes before expiry (default)
86
- sessionRefreshBuffer: 5,
87
- };
13
+ // Initialize with just 3 lines
14
+ Aria.init({
15
+ websocketUrl: 'wss://your-server.com/ws',
16
+ userId: 'user_123',
17
+ });
88
18
 
89
- return (
90
- // Place Aria at the root, ABOVE the router for session persistence
91
- <Aria config={config}>
92
- <BrowserRouter>
93
- <Routes>
94
- <Route path="/" element={<Home />} />
95
- <Route path="/dashboard" element={<Dashboard />} />
96
- </Routes>
97
- </BrowserRouter>
98
- </Aria>
99
- );
100
- }
19
+ // That's it! The floating button appears automatically.
101
20
  ```
102
21
 
103
- ### 2. Advanced Integration (Manual Placement)
22
+ ## Installation
104
23
 
105
- If you need full control over where components are rendered, you can disable the automatic rendering and place the component yourself:
106
-
107
- ```tsx
108
- import { AriaProvider, AriaAssistant } from '@centive/aria-sdk';
109
- import { BrowserRouter, Routes, Route } from 'react-router-dom';
24
+ ```bash
25
+ npm install @centive/aria-sdk
26
+ ```
110
27
 
111
- function App() {
112
- const config = {
113
- websocketUrl: 'ws://localhost:8000/ws',
114
- userId: 'user_123',
115
- showAssistant: false, // Disable automatic rendering
116
- };
28
+ ### Peer Dependencies
117
29
 
118
- return (
119
- // Always place AriaProvider at the root, above the router
120
- <AriaProvider config={config}>
121
- <BrowserRouter>
122
- <Routes>
123
- <Route path="/" element={<Home />} />
124
- <Route path="/dashboard" element={<Dashboard />} />
125
- </Routes>
126
- </BrowserRouter>
127
-
128
- {/* AriaAssistant includes both the trigger button and the widget */}
129
- <AriaAssistant
130
- showTrigger={true} // Show floating trigger button
131
- showAvatar={true} // Show avatar in trigger
132
- triggerLabel="Chat" // Custom button label
133
- />
134
- </AriaProvider>
135
- );
136
- }
30
+ ```bash
31
+ npm install react@^18.0.0 react-dom@^18.0.0
137
32
  ```
138
33
 
139
- ### 3. Trigger Button Only (No Auto-Popup)
34
+ ## Features
140
35
 
141
- If you only want the trigger button without the automatic assistant:
36
+ | Feature | Description |
37
+ |---------|-------------|
38
+ | **Simple Init** | Single function call to set up everything |
39
+ | **Auto Session Management** | WebSocket connection, token refresh, reconnection - all automatic |
40
+ | **Dual-Mode UI** | Floating button + center modal for WebSocket-triggered events |
41
+ | **Session Persistence** | Sessions survive page navigation and widget close/reopen |
42
+ | **Error Recovery** | Automatic reconnection with exponential backoff |
43
+ | **Tool Call Indicators** | Visual feedback when AI executes functions |
44
+ | **Theme Support** | Light and dark themes |
142
45
 
143
- ```tsx
144
- import { AriaProvider, AriaTriggerButton } from '@centive/aria-sdk';
46
+ ## Configuration Options
145
47
 
146
- function App() {
147
- return (
148
- <AriaProvider config={config}>
149
- <YourApp />
150
- <AriaTriggerButton showAvatar={true} label="Help" />
151
- </AriaProvider>
152
- );
48
+ ```typescript
49
+ interface AriaInitConfig {
50
+ // Required
51
+ websocketUrl: string; // Your backend WebSocket URL
52
+ userId: string; // Unique user identifier
53
+
54
+ // Optional
55
+ theme?: 'light' | 'dark'; // UI theme (default: 'light')
56
+ triggerLabel?: string; // Button label (e.g., 'Help', 'Chat')
57
+ onError?: (error: Error) => void; // Error callback
153
58
  }
154
59
  ```
155
60
 
156
- ### 2. Import Styles
61
+ ### Example with All Options
157
62
 
158
- Make sure to import the CSS file in your app:
63
+ ```typescript
64
+ import { Aria } from '@centive/aria-sdk';
159
65
 
160
- ```tsx
161
- import '@centive/aria-sdk/styles.css';
66
+ Aria.init({
67
+ websocketUrl: 'wss://api.example.com/ws',
68
+ userId: 'user_123',
69
+ theme: 'dark',
70
+ triggerLabel: 'Talk to Aria',
71
+ onError: (error) => {
72
+ console.error('Aria SDK error:', error);
73
+ // Send to your error tracking service
74
+ },
75
+ });
162
76
  ```
163
77
 
164
- ### 3. Set Up Backend WebSocket Server
78
+ ## Programmatic Control
165
79
 
166
- The SDK requires a backend WebSocket server that:
167
- - **Configures AI persona** based on user context (role, permissions, etc.)
168
- - Handles session token generation via Anam AI API
169
- - Manages WebSocket connections
170
- - Accumulates and persists messages
171
- - Handles trigger events
80
+ ```typescript
81
+ import { Aria } from '@centive/aria-sdk';
172
82
 
173
- **Important:** Persona configuration (avatar, voice, LLM, system prompt) is now controlled by the backend, not the frontend. This allows for:
174
- - Security: Frontend cannot manipulate AI behavior
175
- - Flexibility: Change personas based on user roles, context, or A/B testing
176
- - Centralization: Manage all persona configurations in one place
83
+ // Open the assistant
84
+ Aria.open();
177
85
 
178
- See the included example servers:
179
- - `example-ws-server.js` - WebSocket server with backend persona configuration
180
- - `example-server.js` - HTTP server for session tokens
86
+ // Open in center mode (like incoming call)
87
+ Aria.open('websocket');
181
88
 
182
- ## 📖 Core Concepts
89
+ // Close the assistant
90
+ Aria.close();
183
91
 
184
- ### Dual-Mode Operation
92
+ // Minimize to compact floating state
93
+ Aria.minimize();
185
94
 
186
- #### User-Initiated Mode (Floating Button)
187
- ```tsx
188
- // User clicks the floating button
189
- <AriaTriggerButton showAvatar={true} label="Chat with Aria" />
190
- ```
95
+ // Maximize from minimized state
96
+ Aria.maximize();
191
97
 
192
- Opens in bottom-right corner with landscape video display.
98
+ // Check status
99
+ Aria.isInitialized(); // true/false
100
+ Aria.isOpen(); // true/false
101
+ Aria.isConnected(); // true/false
102
+ Aria.getSessionId(); // string | null
193
103
 
194
- #### WebSocket-Triggered Mode (Center Modal)
195
- ```tsx
196
- // Server sends trigger event
197
- {
198
- "type": "trigger_event",
199
- "data": {
200
- "message": "Incoming call",
201
- "caller": "John Doe"
202
- }
203
- }
104
+ // Cleanup (when removing from app)
105
+ Aria.destroy();
204
106
  ```
205
107
 
206
- Automatically opens in center with large display.
207
-
208
- ### Message Accumulation
108
+ ---
209
109
 
210
- The SDK automatically:
211
- - Sends message history to your backend via WebSocket
212
- - Tracks real-time message streams
213
- - Handles session end events
214
- - Supports auto-save for long sessions
215
- - Includes circuit breaker for API failures
110
+ ## Backend Requirements
216
111
 
217
- ## 🎨 Components
112
+ The SDK connects to your backend via WebSocket. Your backend is responsible for:
218
113
 
219
- ### AriaProvider
114
+ ### 1. WebSocket Server
220
115
 
221
- Main provider component that wraps your application.
116
+ Provide a WebSocket endpoint that the SDK connects to.
222
117
 
223
- ```tsx
224
- <AriaProvider config={config}>
225
- {children}
226
- </AriaProvider>
227
118
  ```
228
-
229
- ### AriaAssistant
230
-
231
- Complete assistant component that includes both the floating trigger button and the assistant widget.
232
-
233
- ```tsx
234
- <AriaAssistant
235
- showTrigger={true} // Show floating trigger button (default: true)
236
- showAvatar={true} // Show avatar in trigger button (default: true)
237
- triggerLabel="Chat" // Optional custom label for trigger button
238
- />
119
+ wss://your-server.com/ws
239
120
  ```
240
121
 
241
- ### AriaTriggerButton
242
-
243
- Floating trigger button for user-initiated mode.
122
+ ### 2. Session Token Generation
244
123
 
245
- ```tsx
246
- <AriaTriggerButton
247
- showAvatar={true}
248
- label="Talk to Aria"
249
- variant="default"
250
- size="default"
251
- />
252
- ```
124
+ When a user connects, your backend should:
125
+ 1. Authenticate the user
126
+ 2. Call the Anam AI API to create a session
127
+ 3. Return the session token to the SDK
253
128
 
254
- ### useAria Hook
129
+ **Expected Response Format:**
255
130
 
256
- Access SDK state and methods from any component.
257
-
258
- ```tsx
259
- import { useAria } from '@centive/aria-sdk';
260
-
261
- function MyComponent() {
262
- const {
263
- // UI State
264
- isOpen,
265
- isMinimized, // True when widget is minimized (compact floating state)
266
- isConnected,
267
- isLoading,
268
- displayMode,
269
- triggerMode,
270
- theme,
271
- chatMessages,
272
- liveTranscript,
273
- isChatVisible,
274
- isMuted,
275
- error,
276
-
277
- // Tool Call State
278
- toolCallState, // { isActive: boolean, toolName: string | null, toolData: object | null }
279
-
280
- // Session State
281
- sessionState,
282
- sessionManagerStatus, // 'idle' | 'connecting' | 'connected' | 'preloading' | 'ready' | 'refreshing' | 'error'
283
- isSessionPreloaded, // True when session token is ready
284
- isSessionPaused, // True when session is paused (widget closed with persistSession: true)
285
-
286
- // Actions
287
- openAssistant,
288
- closeAssistant,
289
- minimizeAssistant, // Minimize widget to compact floating state
290
- maximizeAssistant, // Restore widget from minimized state
291
- toggleChat,
292
- sendMessage,
293
- toggleMute,
294
- startSession,
295
- stopSession, // Ends session (ignores persistSession setting)
296
- triggerSession,
297
- refreshSession, // Manually refresh the session
298
- setVideoElement,
299
-
300
- // Utilities
301
- getSessionId,
302
- config,
303
- } = useAria();
304
-
305
- // Use the methods and state
131
+ ```json
132
+ {
133
+ "status": "success",
134
+ "message": "Session created successfully",
135
+ "session_data": {
136
+ "session_id": "sess_abc123",
137
+ "token": "eyJhbGciOiJIUzI1NiIs...",
138
+ "expires_at": "2026-01-23T12:00:00Z"
139
+ },
140
+ "time_taken": 1234
306
141
  }
307
142
  ```
308
143
 
309
- ### 🔑 Token Utilities
310
-
311
- The SDK provides utilities to extract session IDs from tokens, supporting both JWT and opaque tokens.
312
-
313
- #### In React Components (via useAria hook)
314
-
315
- ```tsx
316
- import { useAria } from '@centive/aria-sdk';
317
-
318
- function MyComponent() {
319
- const { getSessionIdFromToken, sessionState } = useAria();
320
-
321
- // Get session ID from current state
322
- const currentSessionId = getSessionIdFromToken();
323
-
324
- // Extract session ID from a stored token (e.g., JWT)
325
- const storedToken = localStorage.getItem('token');
326
- const sessionId = getSessionIdFromToken(storedToken);
327
-
328
- return <div>Session: {currentSessionId}</div>;
329
- }
330
- ```
144
+ ### 3. Persona Configuration
331
145
 
332
- #### In External Code (non-React)
146
+ **Important:** Persona configuration (avatar, voice, LLM, system prompt) is controlled by your backend, not the frontend. This provides:
333
147
 
334
- ```tsx
335
- import {
336
- extractSessionIdFromToken,
337
- isJWT,
338
- decodeJWT,
339
- getTokenInfo,
340
- isTokenExpired
341
- } from '@centive/aria-sdk';
342
-
343
- // Check if token is a JWT
344
- if (isJWT(token)) {
345
- // Extract session ID
346
- const sessionId = extractSessionIdFromToken(token);
347
-
348
- // Get full token information
349
- const tokenInfo = getTokenInfo(token);
350
- console.log('Session ID:', tokenInfo.sessionId);
351
- console.log('Expires:', tokenInfo.exp ? new Date(tokenInfo.exp * 1000) : 'N/A');
352
-
353
- // Check if expired
354
- if (isTokenExpired(token)) {
355
- console.log('Token expired, need to refresh');
356
- }
357
-
358
- // Decode full payload
359
- const payload = decodeJWT(token);
360
- console.log('Payload:', payload);
361
- }
362
- ```
148
+ - **Security**: Frontend cannot manipulate AI behavior
149
+ - **Flexibility**: Change personas based on user roles, context, or A/B testing
150
+ - **Centralization**: Manage all configurations in one place
363
151
 
364
- **Supported JWT Claims** (checked in order):
365
- - `session_id`
366
- - `sessionId`
367
- - `sid`
368
- - `jti` (JWT ID)
369
- - `sub` (Subject)
152
+ **Backend Example (Node.js):**
370
153
 
371
- **Note:** JWT decoding is done client-side without signature verification. Only use for extracting public information.
154
+ ```javascript
155
+ const WebSocket = require('ws');
156
+ const axios = require('axios');
372
157
 
373
- ## ⚙️ Configuration
158
+ const wss = new WebSocket.Server({ port: 8000 });
374
159
 
375
- ### AriaSDKConfig
160
+ wss.on('connection', (ws) => {
161
+ ws.on('message', async (message) => {
162
+ const data = JSON.parse(message);
163
+
164
+ if (data.user_trigger !== undefined) {
165
+ // Create Anam session with persona config
166
+ const session = await createAnamSession(data.userId);
167
+
168
+ ws.send(JSON.stringify({
169
+ status: 'success',
170
+ message: 'Session created',
171
+ session_data: {
172
+ session_id: session.id,
173
+ token: session.token,
174
+ expires_at: session.expiresAt,
175
+ },
176
+ time_taken: Date.now() - startTime,
177
+ }));
178
+ }
179
+ });
180
+ });
376
181
 
377
- ```typescript
378
- interface AriaSDKConfig {
379
- websocketUrl: string; // WebSocket server URL
380
- userId?: string; // User ID for backend persona selection & message accumulation
381
- theme?: 'light' | 'dark'; // Initial theme (default: 'light')
382
- triggerLabel?: string; // Button label text
383
-
384
- // Event callbacks
385
- onError?: (error: Error) => void;
386
- onSessionReady?: () => void;
387
- onConnectionStateChange?: (connected: boolean) => void;
388
- onWebSocketEvent?: (event: any) => void;
182
+ async function createAnamSession(userId) {
183
+ // Get persona config based on user context
184
+ const personaConfig = getPersonaForUser(userId);
389
185
 
390
- // Message accumulation callbacks
391
- onMessageHistoryAck?: (messageCount: number) => void;
392
- onMessageStreamAck?: () => void;
393
- onSessionEndAck?: (savedCount: number) => void;
394
- onSessionEndError?: (error: string, errorType: string) => void;
186
+ const response = await axios.post('https://api.anam.ai/v1/sessions', {
187
+ persona: personaConfig,
188
+ }, {
189
+ headers: { 'Authorization': `Bearer ${process.env.ANAM_API_KEY}` }
190
+ });
395
191
 
396
- // Session preloading options (Global Session Management)
397
- preloadSession?: boolean; // Enable session preloading on mount (default: true)
398
- sessionRefreshBuffer?: number; // Minutes before expiry to refresh (default: 5)
399
- onSessionPreloaded?: () => void; // Callback when session is preloaded and ready
400
- onSessionRefresh?: () => void; // Callback when session is refreshed
401
- onSessionRefreshError?: (error: Error) => void; // Callback when refresh fails
402
-
403
- // Session persistence options (Widget Toggle Persistence)
404
- persistSession?: boolean; // Keep session alive when widget closes (default: false)
405
- keepWebSocketAlive?: boolean; // Keep WebSocket connected when paused (default: true)
406
- onSessionPaused?: () => void; // Callback when session is paused (widget closed)
407
- onSessionResumed?: () => void; // Callback when session is resumed (widget reopened)
408
-
409
- // Rendering options
410
- showFloatingButton?: boolean; // Show the default floating button (default: true)
411
- showAssistant?: boolean; // Show the assistant widget (default: true)
192
+ return response.data;
412
193
  }
413
- ```
414
-
415
- ### Backend Persona Configuration
416
194
 
417
- **Persona configuration is now handled entirely by your backend server.** This provides:
418
-
419
- - **Security**: Frontend cannot manipulate AI behavior or system prompts
420
- - **Flexibility**: Dynamically select personas based on user roles, context, subscription tier, or A/B testing
421
- - **Centralization**: Manage all persona configurations in one secure location
422
-
423
- Your backend should configure personas when creating Anam sessions:
424
-
425
- ```javascript
426
- // Backend example: Configure persona based on user context
427
- const getPersonaConfig = (userId, userRole) => {
195
+ function getPersonaForUser(userId) {
428
196
  // Your business logic here
429
197
  return {
430
- name: 'Aria - AI Assistant',
198
+ name: 'Aria',
431
199
  avatarId: 'your-avatar-id',
432
200
  voiceId: 'your-voice-id',
433
201
  llmId: 'your-llm-id',
434
202
  systemPrompt: 'You are Aria, a helpful AI assistant.',
435
203
  };
436
- };
437
-
438
- // Use this config when calling Anam AI API
439
- const personaConfig = getPersonaConfig(userId, userRole);
204
+ }
440
205
  ```
441
206
 
442
- See `example-ws-server.js` for a complete implementation.
443
-
444
- ## 🌐 WebSocket Events
445
-
446
- ### Automatic Session Trigger (Backend → Frontend)
207
+ ### 4. WebSocket Message Types
447
208
 
448
- ```json
449
- {
450
- "status": "success",
451
- "message": "Session created successfully",
452
- "session_data": {
453
- "session_id": "sess_abc123",
454
- "token": "tok_xyz789",
455
- "expires_at": "2025-12-30T12:00:00Z"
456
- }
457
- }
458
- ```
209
+ **Frontend → Backend:**
459
210
 
460
- ### Manual Session Trigger (Frontend → Backend)
211
+ | Message | Description |
212
+ |---------|-------------|
213
+ | `{ user_trigger: true }` | User clicked trigger button |
214
+ | `{ user_trigger: false }` | Auto-preload session |
215
+ | `{ type: 'message_history', ... }` | Conversation history |
216
+ | `{ type: 'session_end', ... }` | User ended session |
461
217
 
462
- ```json
463
- {
464
- "user_trigger": true
465
- }
466
- ```
218
+ **Backend → Frontend:**
467
219
 
468
- ### Message History Event (Frontend → Backend)
220
+ | Message | Description |
221
+ |---------|-------------|
222
+ | Session response | Token and session data |
223
+ | `{ type: 'trigger_event', data: {...} }` | Open assistant in center mode |
224
+ | Acknowledgments | Confirm message receipt |
469
225
 
470
- ```json
471
- {
472
- "type": "message_history",
473
- "session_id": "sess_abc123",
474
- "user_id": "user_123",
475
- "messages": [
476
- {
477
- "role": "user",
478
- "content": "Hello",
479
- "timestamp": "2026-01-06T10:00:00Z"
480
- },
481
- {
482
- "role": "persona",
483
- "content": "Hi! How can I help?",
484
- "timestamp": "2026-01-06T10:00:02Z"
485
- }
486
- ]
487
- }
488
- ```
226
+ ### 5. Trigger Events (Optional)
489
227
 
490
- ### Session End Event (Frontend Backend)
228
+ Send events from your backend to open the assistant automatically:
491
229
 
492
230
  ```json
493
231
  {
494
- "type": "session_end",
495
- "session_id": "sess_abc123",
496
- "user_id": "user_123"
232
+ "type": "trigger_event",
233
+ "data": {
234
+ "message": "Incoming support request",
235
+ "caller": "John Doe",
236
+ "eventType": "support_call"
237
+ }
497
238
  }
498
239
  ```
499
240
 
500
- ## 🔄 Session Management
501
-
502
- ### Global Session Architecture
503
-
504
- The SDK uses a singleton pattern to maintain session state globally, ensuring:
505
-
506
- 1. **Lazy Session Initialization** - When `AriaProvider` mounts, it automatically:
507
- - Connects to WebSocket
508
- - Requests a session token (token is ready)
509
- - **Does NOT initialize Anam client yet** (lazy mode)
510
-
511
- 2. **Greeting Plays on Open** - When users click the trigger button:
512
- - Anam client initializes at this moment
513
- - **Greeting plays exactly when user sees the widget**
514
- - No missed greetings from preloading
515
-
516
- 3. **Session Persistence** - During page navigation:
517
- - Session survives component unmounts/remounts
518
- - No reconnection needed when navigating between pages
519
-
520
- 4. **Minimized Widget State** - When users click outside the widget:
521
- - Widget minimizes to a compact floating state
522
- - Session stays active (no interruption)
523
- - Click to restore full widget
524
-
525
- ### Provider Placement (Critical)
526
-
527
- **Correct:** Place at app root, above router:
528
- ```tsx
529
- function App() {
530
- return (
531
- <AriaProvider config={config}>
532
- <BrowserRouter>
533
- <Routes>...</Routes>
534
- </BrowserRouter>
535
- </AriaProvider>
536
- );
537
- }
538
- ```
241
+ ---
539
242
 
540
- **Incorrect:** Inside route (session lost on navigation):
541
- ```tsx
542
- function App() {
543
- return (
544
- <BrowserRouter>
545
- <Routes>
546
- <Route path="/" element={
547
- <AriaProvider config={config}> {/* Don't do this! */}
548
- <Home />
549
- </AriaProvider>
550
- } />
551
- </Routes>
552
- </BrowserRouter>
553
- );
554
- }
555
- ```
243
+ ## What the SDK Handles Automatically
556
244
 
557
- > **Note:** Even if placed incorrectly, the SDK's singleton pattern provides a safety net to maintain session continuity.
245
+ You don't need to manage any of these - the SDK handles them internally:
558
246
 
559
- ### Minimized Widget State
247
+ | Feature | How It Works |
248
+ |---------|--------------|
249
+ | **WebSocket Connection** | Connects on `init()`, maintains connection |
250
+ | **Auto-Reconnect** | Exponential backoff (1s → 30s max), up to 10 attempts |
251
+ | **Session Refresh** | Refreshes 5 minutes before expiry |
252
+ | **Tab Visibility** | Only refreshes when tab is active |
253
+ | **Session Persistence** | Survives page navigation, widget close/reopen |
254
+ | **Error Recovery** | Automatic retries with backoff |
255
+ | **UI Rendering** | Mounts trigger button and widget to DOM |
560
256
 
561
- When users click outside the widget (on the backdrop), the widget minimizes to a compact floating state instead of closing completely. This allows users to:
257
+ ---
562
258
 
563
- - Navigate the platform while keeping the session active
564
- - See a preview of the live transcript
565
- - Quickly resume the conversation with one click
259
+ ## Security Best Practices
566
260
 
567
- ```tsx
568
- function WidgetController() {
569
- const {
570
- isMinimized,
571
- minimizeAssistant,
572
- maximizeAssistant,
573
- closeAssistant,
574
- } = useAria();
575
-
576
- return (
577
- <div>
578
- <p>Minimized: {isMinimized ? 'Yes' : 'No'}</p>
579
-
580
- {/* Programmatic control */}
581
- <button onClick={minimizeAssistant}>Minimize</button>
582
- <button onClick={maximizeAssistant}>Maximize</button>
583
- <button onClick={closeAssistant}>Close (End Session)</button>
584
- </div>
585
- );
586
- }
587
- ```
261
+ ### Do
588
262
 
589
- **Behavior:**
590
- | Action | Result |
591
- |--------|--------|
592
- | Click outside widget (backdrop) | Widget minimizes, session stays active |
593
- | Click minimized widget | Widget maximizes |
594
- | Click "End Call" button | Session ends completely |
595
- | Click X on minimized widget | Session ends completely |
263
+ - Use secure WebSocket connections (`wss://`) in production
264
+ - Validate user IDs on your backend
265
+ - Store Anam API keys only on the backend
266
+ - Implement proper CORS configuration
267
+ - Use environment variables for sensitive data
596
268
 
597
- ### Tool Call Indicators
269
+ ### Don't
598
270
 
599
- When Aria executes tool calls (function calling), the widget displays a visual indicator showing:
600
- - The tool name being executed
601
- - An animated "processing" state
602
- - Auto-clears when the tool completes
271
+ - Expose Anam API keys in frontend code
272
+ - Trust user-provided data without validation
273
+ - Allow arbitrary persona configuration from frontend
603
274
 
604
- ```tsx
605
- function ToolCallMonitor() {
606
- const { toolCallState } = useAria();
607
-
608
- return (
609
- <div>
610
- {toolCallState.isActive && (
611
- <p>
612
- Running tool: {toolCallState.toolName}
613
- Data: {JSON.stringify(toolCallState.toolData)}
614
- </p>
615
- )}
616
- </div>
617
- );
618
- }
619
- ```
275
+ ---
620
276
 
621
- ### Session Persistence (Widget Toggle)
277
+ ## Legacy React Provider API
622
278
 
623
- By default, the SDK ends the session when the widget is closed. With `persistSession: true`, the session stays alive across widget open/close cycles:
279
+ For existing applications using the Provider pattern, it's still supported but deprecated:
624
280
 
625
281
  ```tsx
626
- const config = {
627
- websocketUrl: 'ws://localhost:8000/ws',
628
- userId: 'user_123',
629
-
630
- // Enable session persistence
631
- persistSession: true, // Keep session alive when widget closes
632
- keepWebSocketAlive: true, // Keep WebSocket connected (default: true)
633
-
634
- // Callbacks
635
- onSessionPaused: () => {
636
- console.log('Session paused - widget closed');
637
- },
638
- onSessionResumed: () => {
639
- console.log('Session resumed - widget reopened');
640
- },
641
- };
642
- ```
282
+ // Deprecated - will be removed in v2.0
283
+ import { AriaProvider } from '@centive/aria-sdk';
643
284
 
644
- **Behavior with `persistSession: true`:**
645
-
646
- | Action | Result |
647
- |--------|--------|
648
- | User opens widget | Uses existing session (or creates new if none) |
649
- | User closes widget | Session paused, stays alive |
650
- | User reopens widget | Session resumed instantly |
651
- | User calls `stopSession()` | Session ends (explicit action) |
652
- | Tab/window closes | Session ends (beforeunload) |
653
- | Session token expires | New session created on next open |
654
-
655
- **Use Cases:**
656
- - Customer support chat - User minimizes to browse, reopens to continue
657
- - Sales assistant - Persistent context across multiple page views
658
- - Onboarding flow - AI maintains context as user navigates steps
659
- - Dashboard help - Toggle help widget without losing conversation
660
-
661
- ```tsx
662
- function SessionController() {
663
- const {
664
- isSessionPaused,
665
- stopSession,
666
- } = useAria();
667
-
285
+ function App() {
668
286
  return (
669
- <div>
670
- <p>Session paused: {isSessionPaused ? 'Yes' : 'No'}</p>
671
-
672
- {/* Explicitly end session (ignores persistSession) */}
673
- <button onClick={stopSession}>
674
- End Session
675
- </button>
676
- </div>
287
+ <AriaProvider config={{
288
+ websocketUrl: 'ws://localhost:8000/ws',
289
+ userId: 'user_123',
290
+ }}>
291
+ <YourApp />
292
+ </AriaProvider>
677
293
  );
678
294
  }
679
295
  ```
680
296
 
681
- ### Session Refresh
682
-
683
- The SDK automatically refreshes sessions before they expire:
297
+ **Migration:** Replace `AriaProvider` with `Aria.init()` for simpler integration.
684
298
 
685
- ```tsx
686
- const config = {
687
- websocketUrl: 'ws://localhost:8000/ws',
688
- userId: 'user_123',
689
-
690
- // Session refresh configuration
691
- sessionRefreshBuffer: 5, // Refresh 5 minutes before expiry (default)
692
-
693
- // Callbacks
694
- onSessionPreloaded: () => {
695
- console.log('Session is preloaded and ready!');
696
- },
697
- onSessionRefresh: () => {
698
- console.log('Session refreshed successfully');
699
- },
700
- onSessionRefreshError: (error) => {
701
- console.error('Session refresh failed:', error);
702
- },
703
- };
704
- ```
299
+ ---
705
300
 
706
- ### Manual Session Control
301
+ ## Browser Support
707
302
 
708
- ```tsx
709
- function SessionController() {
710
- const {
711
- sessionState,
712
- sessionManagerStatus,
713
- isSessionPreloaded,
714
- refreshSession,
715
- } = useAria();
716
-
717
- return (
718
- <div>
719
- <p>Status: {sessionManagerStatus}</p>
720
- <p>Preloaded: {isSessionPreloaded ? 'Yes' : 'No'}</p>
721
- <p>Session ID: {sessionState.session_id}</p>
722
- <p>Expires: {sessionState.expires_at}</p>
723
-
724
- {/* Manual refresh if needed */}
725
- <button onClick={refreshSession}>
726
- Refresh Session
727
- </button>
728
- </div>
729
- );
730
- }
731
- ```
303
+ - Chrome/Edge (latest)
304
+ - Firefox (latest)
305
+ - Safari (latest)
306
+ - Opera (latest)
732
307
 
733
- ## 💡 Advanced Usage
308
+ Requires WebRTC support for video streaming.
734
309
 
735
- ### Programmatic Control
310
+ ---
736
311
 
737
- ```tsx
738
- function CustomController() {
739
- const {
740
- openAssistant,
741
- closeAssistant,
742
- minimizeAssistant,
743
- maximizeAssistant,
744
- triggerSession,
745
- isMinimized,
746
- } = useAria();
747
-
748
- return (
749
- <div>
750
- {/* Open in user mode */}
751
- <button onClick={() => openAssistant('user')}>
752
- Start Chat
753
- </button>
754
-
755
- {/* Open in center mode */}
756
- <button onClick={() => openAssistant('websocket')}>
757
- Start Video Call
758
- </button>
759
-
760
- {/* Minimize/Maximize widget */}
761
- <button onClick={isMinimized ? maximizeAssistant : minimizeAssistant}>
762
- {isMinimized ? 'Maximize' : 'Minimize'}
763
- </button>
764
-
765
- {/* Close widget (ends session) */}
766
- <button onClick={closeAssistant}>
767
- End Session
768
- </button>
769
-
770
- {/* Manually trigger session */}
771
- <button onClick={triggerSession}>
772
- Create New Session
773
- </button>
774
- </div>
775
- );
776
- }
777
- ```
312
+ ## Troubleshooting
778
313
 
779
- ### Custom Event Handling
314
+ ### "WebSocket connection failed"
780
315
 
781
- ```tsx
782
- // Note: Persona configuration is handled by the backend
783
- const config = {
784
- websocketUrl: 'ws://localhost:8000/ws',
785
- userId: 'user_123', // Backend uses this for persona selection
786
-
787
- onWebSocketEvent: (event) => {
788
- if (event.data.eventType === 'incoming_call') {
789
- showNotification(`Call from ${event.data.caller}`);
790
- playRingtone();
791
- }
792
- },
793
-
794
- onSessionReady: () => {
795
- console.log('AI assistant is ready!');
796
- },
797
-
798
- onError: (error) => {
799
- captureError(error);
800
- },
801
-
802
- // Message accumulation callbacks
803
- onMessageHistoryAck: (messageCount) => {
804
- console.log(`Conversation saved: ${messageCount} messages`);
805
- updateUI({ messagesSaved: true });
806
- },
807
-
808
- onSessionEndAck: (savedCount) => {
809
- console.log(`Session completed: ${savedCount} messages persisted`);
810
- showSuccessNotification('Conversation saved successfully');
811
- },
812
-
813
- onSessionEndError: (error, errorType) => {
814
- console.error(`Failed to save: ${errorType}`, error);
815
- if (errorType === 'CIRCUIT_BREAKER_OPEN') {
816
- showWarning('Saving temporarily unavailable, will retry automatically');
817
- } else {
818
- showError('Failed to save conversation');
819
- }
820
- },
821
- };
822
- ```
316
+ - Check that your backend WebSocket server is running
317
+ - Verify the `websocketUrl` is correct
318
+ - Check browser console for CORS errors
823
319
 
824
- ### Access Session State
320
+ ### "Session token expired"
825
321
 
826
- ```tsx
827
- function SessionMonitor() {
828
- const { sessionState } = useAria();
829
-
830
- return (
831
- <div>
832
- <p>Session ID: {sessionState.session_id}</p>
833
- <p>Expires: {sessionState.expires_at}</p>
834
- <p>Ready: {sessionState.isSessionReady ? 'Yes' : 'No'}</p>
835
- {sessionState.lastError && <p>Error: {sessionState.lastError}</p>}
836
- </div>
837
- );
838
- }
839
- ```
322
+ - The SDK auto-refreshes tokens, but if you see this:
323
+ - Check your backend is returning valid `expires_at` timestamps
324
+ - Ensure your Anam API key is valid
840
325
 
841
- ## 🎯 Use Cases
326
+ ### "Not initialized" errors
842
327
 
843
- - **Customer Support** - Floating help button + proactive agent-initiated conversations
844
- - **Healthcare** - Patient consultations + appointment reminders
845
- - **Financial Services** - Account questions + market alert notifications
846
- - **E-commerce** - Product inquiries + order status updates
847
- - **Education** - Student support + class notifications
848
- - **Sales** - Lead qualification + follow-up calls
328
+ - Call `Aria.init()` before using other methods
329
+ - Check that `init()` completed without errors
849
330
 
850
- ## 📋 Requirements
331
+ ### UI not appearing
851
332
 
852
- - React 18.0.0 or higher
853
- - React DOM 18.0.0 or higher
854
- - Node.js 18+ (for backend server)
855
- - Modern browser with WebRTC support
856
- - Anam AI API key ([Get one here](https://docs.anam.ai/get-your-api-key))
333
+ - Ensure you're not blocking the SDK's DOM elements with CSS
334
+ - Check browser console for React rendering errors
857
335
 
858
- ## 🌍 Browser Support
336
+ ---
859
337
 
860
- - Chrome/Edge (latest)
861
- - Firefox (latest)
862
- - Safari (latest)
863
- - Opera (latest)
338
+ ## API Reference
864
339
 
865
- ## 🔒 Security Best Practices
340
+ ### Aria (Static Class)
866
341
 
867
- - Never expose your Anam API key in frontend code
868
- - Use secure WebSocket connections (WSS) in production
869
- - Implement proper CORS configuration
870
- - Validate user IDs on the backend
871
- - Use environment variables for sensitive data
342
+ | Method | Description |
343
+ |--------|-------------|
344
+ | `init(config)` | Initialize the SDK |
345
+ | `destroy()` | Cleanup and remove SDK |
346
+ | `open(mode?)` | Open assistant widget |
347
+ | `close()` | Close assistant widget |
348
+ | `minimize()` | Minimize to compact state |
349
+ | `maximize()` | Restore from minimized |
350
+ | `isInitialized()` | Check if SDK is initialized |
351
+ | `isOpen()` | Check if widget is open |
352
+ | `isConnected()` | Check WebSocket connection |
353
+ | `getSessionId()` | Get current session ID |
354
+ | `refreshSession()` | Manually refresh session |
872
355
 
873
- ## 📚 Documentation
356
+ ---
874
357
 
875
- For more detailed documentation, see:
876
- - [Type Reference](./TYPE_REFERENCE.md) - Complete TypeScript type reference
877
- - [WebSocket Events Guide](./WEBSOCKET_EVENTS.md) - Complete WebSocket message specification
878
- - [WebSocket Guide](./WEBSOCKET_GUIDE.md) - WebSocket integration details
879
- - [Publishing Guide](./PUBLISHING_GUIDE.md) - npm publishing instructions
880
- - [Setup Summary](./SETUP_SUMMARY.md) - Complete setup overview
358
+ ## Documentation
881
359
 
882
- ## 🤝 Contributing
360
+ - [Type Reference](./TYPE_REFERENCE.md) - Complete TypeScript types
361
+ - [WebSocket Events](./WEBSOCKET_EVENTS.md) - Message specifications
362
+ - [Anam AI Docs](https://docs.anam.ai/) - Anam AI platform documentation
883
363
 
884
- Contributions are welcome! Please feel free to submit a Pull Request.
364
+ ---
885
365
 
886
- ## 📄 License
366
+ ## License
887
367
 
888
368
  MIT © Centive
889
369
 
890
- ## 🆘 Support
891
-
892
- - 📚 [Anam AI Documentation](https://docs.anam.ai/)
893
- - 🐛 [GitHub Issues](https://github.com/centive/aria-sdk/issues)
894
-
895
- ## 🙏 Acknowledgments
896
-
897
- Built with:
898
- - [Anam AI](https://anam.ai/) - AI persona platform
899
- - [Shad/CN UI](https://ui.shadcn.com/) - UI components
900
- - [Tailwind CSS](https://tailwindcss.com/) - Styling
901
- - [Lucide Icons](https://lucide.dev/) - Icons
902
- - [React](https://react.dev/) - UI framework
903
-
904
370
  ---
905
371
 
906
- **Made with ❤️ by Centive**
372
+ ## Support
373
+
374
+ - [GitHub Issues](https://github.com/centive/aria-sdk/issues)
375
+ - [Anam AI Documentation](https://docs.anam.ai/)