Beta: The SDK is in beta and actively being improved. Check npm for latest version.
Installation
npm install @upliftai/assistants-react @livekit/components-react livekit-client
Core Components
<UpliftAIRoom>
The main wrapper component that establishes connection to the assistant.
import { UpliftAIRoom } from '@upliftai/assistants-react';
<UpliftAIRoom
token={sessionToken}
serverUrl={wsUrl}
connect={true}
audio={true}
video={false}
tools={toolsArray}
onConnectionChange={(connected, agentIdentity) => {}}
onToolsChange={(tools) => {}}
>
<YourComponents />
</UpliftAIRoom>
Props
Prop | Type | Required | Description |
---|
token | string | Yes | JWT session token from createSession |
serverUrl | string | Yes | WebSocket URL for LiveKit server |
connect | boolean | No | Auto-connect on mount (default: true) |
audio | boolean | No | Enable audio (default: true) |
video | boolean | No | Enable video (default: false) |
tools | ToolConfig[] | No | Array of tool configurations |
onConnectionChange | function | No | Connection status callback |
onToolsChange | function | No | Tools change callback |
Hooks
useUpliftAIRoom()
Access room functionality and state.
const {
// Methods
addTool,
updateTool,
removeTool,
upsertTools,
updateInstruction,
// State
isConnected,
agentParticipant,
room
} = useUpliftAIRoom();
Methods
addTool(config: ToolConfig): Promise<void>
Add a new tool to the assistant.
await addTool({
name: 'calculator',
description: 'Perform calculations',
parameters: { /* ... */ },
handler: async (data) => { /* ... */ }
});
updateTool(config: ToolConfig): Promise<void>
Update an existing tool configuration.
await updateTool({
name: 'calculator',
description: 'Updated description',
// ... new configuration
});
removeTool(name: string): Promise<void>
Remove a tool by name.
await removeTool('calculator');
upsertTools(configs: ToolConfig[]): Promise<void>
Replace all tools with new set.
await upsertTools([tool1, tool2, tool3]);
updateInstruction(instruction: string): Promise<void>
Update assistant’s system instructions.
await updateInstruction('You are now a pirate. Speak accordingly.');
useVoiceAssistant()
Get voice assistant state.
const { state, participant } = useVoiceAssistant();
// state: 'listening' | 'thinking' | 'speaking'
useTracks()
Access audio/video tracks.
import { useTracks } from '@upliftai/assistants-react';
import { Track } from 'livekit-client';
const tracks = useTracks([Track.Source.Microphone], {
onlySubscribed: true,
});
const agentTrack = tracks.find(t => !t.participant.isLocal);
useConnectionState()
Monitor connection status.
const { state, error } = useConnectionState();
// state: 'disconnected' | 'connecting' | 'connected' | 'reconnecting'
UI Components
Audio Components
<AudioTrack>
Renders audio output for a track.
<AudioTrack trackRef={agentTrack} />
<BarVisualizer>
Animated audio visualization bars.
<BarVisualizer
state={agentState}
trackRef={agentTrack}
barCount={20}
className="visualizer"
/>
Props:
state
: Voice assistant state
trackRef
: Audio track reference
barCount
: Number of bars (default: 7)
className
: CSS class name
Control Components
<TrackToggle>
Toggle microphone or camera.
<TrackToggle source={Track.Source.Microphone}>
Microphone
</TrackToggle>
End the session.
<DisconnectButton>
End Call
</DisconnectButton>
<ControlBar>
Full control bar with all controls.
Type Definitions
interface ToolConfig {
name: string;
description: string;
parameters: {
type: 'object';
properties: Record<string, ParameterConfig>;
required?: string[];
};
timeout: number;
handler: (data: ToolInvocationData) => Promise<string>;
}
ParameterConfig
interface ParameterConfig {
type: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object';
description?: string;
enum?: any[];
items?: ParameterConfig;
properties?: Record<string, ParameterConfig>;
required?: string[];
}
interface ToolInvocationData {
requestId: string;
callerIdentity: string;
payload: string; // JSON string to parse
responseTimeout: number;
}
Complete Examples
Basic Voice Assistant
import React from 'react';
import {
UpliftAIRoom,
useUpliftAIRoom,
useVoiceAssistant,
BarVisualizer,
TrackToggle,
DisconnectButton,
AudioTrack,
useTracks
} from '@upliftai/assistants-react';
import { Track } from 'livekit-client';
function VoiceAssistant({ token, wsUrl }) {
return (
<UpliftAIRoom
token={token}
serverUrl={wsUrl}
connect={true}
audio={true}
>
<AssistantUI />
</UpliftAIRoom>
);
}
function AssistantUI() {
const { isConnected, agentParticipant } = useUpliftAIRoom();
const { state } = useVoiceAssistant();
const tracks = useTracks([Track.Source.Microphone], {
onlySubscribed: true
});
const agentTrack = tracks.find(t => !t.participant.isLocal);
return (
<div>
<h2>Status: {isConnected ? 'Connected' : 'Disconnected'}</h2>
{agentTrack && (
<>
<AudioTrack trackRef={agentTrack} />
<BarVisualizer
state={state}
trackRef={agentTrack}
/>
</>
)}
<p>
{state === 'listening' && 'Listening...'}
{state === 'thinking' && 'Thinking...'}
{state === 'speaking' && 'Speaking...'}
</p>
<TrackToggle source={Track.Source.Microphone} />
<DisconnectButton>End</DisconnectButton>
</div>
);
}
function AssistantWithTools({ token, wsUrl }) {
const tools = [
{
name: 'search',
description: 'Search for information',
parameters: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query'
}
},
required: ['query']
},
timeout: 10,
handler: async (data) => {
const { query } = JSON.parse(data.payload).arguments.raw_arguments;
const results = await searchAPI(query);
return JSON.stringify({
result: results,
presentationInstructions: `Found ${results.length} results`
});
}
}
];
return (
<UpliftAIRoom
token={token}
serverUrl={wsUrl}
tools={tools}
>
<AssistantUI />
</UpliftAIRoom>
);
}
function DynamicToolManager() {
const { addTool, removeTool, isConnected } = useUpliftAIRoom();
const [activeTools, setActiveTools] = useState([]);
const handleAddTool = async (toolConfig) => {
try {
await addTool(toolConfig);
setActiveTools([...activeTools, toolConfig.name]);
} catch (error) {
console.error('Failed to add tool:', error);
}
};
const handleRemoveTool = async (toolName) => {
try {
await removeTool(toolName);
setActiveTools(activeTools.filter(name => name !== toolName));
} catch (error) {
console.error('Failed to remove tool:', error);
}
};
return (
<div>
<h3>Active Tools: {activeTools.join(', ')}</h3>
<button
onClick={() => handleAddTool(weatherTool)}
disabled={!isConnected}
>
Add Weather Tool
</button>
<button
onClick={() => handleRemoveTool('weather')}
disabled={!isConnected}
>
Remove Weather Tool
</button>
</div>
);
}
Error Handling
function RobustAssistant({ token, wsUrl }) {
const [error, setError] = useState(null);
return (
<UpliftAIRoom
token={token}
serverUrl={wsUrl}
onConnectionChange={(connected, agentIdentity) => {
if (!connected && agentIdentity) {
setError('Connection lost');
}
}}
>
{error ? (
<ErrorView error={error} onRetry={() => setError(null)} />
) : (
<AssistantUI />
)}
</UpliftAIRoom>
);
}
LiveKit Components
The SDK re-exports all LiveKit components for convenience:
import {
// Audio/Video
AudioTrack,
VideoTrack,
// Controls
ControlBar,
TrackToggle,
DisconnectButton,
// Chat
Chat,
ChatEntry,
// Layout
GridLayout,
FocusLayout,
// Utilities
RoomAudioRenderer,
ConnectionStateToast,
// ... and more
} from '@upliftai/assistants-react';
- Memoize tool handlers to prevent recreating on each render
- Use React.memo for components that don’t need frequent updates
- Batch tool operations when adding/removing multiple tools
- Lazy load tool implementations for better initial load time