React

React hooks for voice AI integration

Installation

npm install @ai-chans/sdk-react

useVoiceAgent Hook

The recommended way to add voice to React apps.

import { useVoiceAgent } from "@ai-chans/sdk-react"
function VoiceChat() {
const { state, isConnected, error, connect, disconnect } = useVoiceAgent(
{ agentToken: "agt_xxx" },
{
onTranscript: (text) => console.log("User:", text),
onResponse: (text) => console.log("Agent:", text),
}
)
const handleClick = () => {
if (state === "idle") {
connect()
} else {
disconnect()
}
}
return (
<div>
{error && <p style={{ color: "red" }}>{error}</p>}
<button onClick={handleClick} disabled={state === "connecting"}>
{state === "idle" ? "Start" : state === "connecting" ? "Connecting..." : "Stop"}
</button>
<p>Status: {state}</p>
</div>
)
}

Options

interface UseVoiceAgentOptions {
agentToken: string // Required: Agent token from dashboard
apiUrl?: string // Optional: API URL (default: https://api.chans.ai)
userId?: string // Optional: User ID for conversation segmentation
}

Callbacks

interface UseVoiceAgentCallbacks {
onStateChange?: (state: ChansState) => void
onConnected?: () => void
onAgentConnected?: (agent: AgentInfo) => void
onAgentDisconnected?: () => void
onTranscript?: (text: string) => void // Interim transcription
onUserTurnComplete?: (text: string) => void // Final transcription
onResponse?: (text: string) => void // Agent response
onDisconnected?: () => void
onError?: (error: Error) => void
}

Return Value

interface UseVoiceAgentReturn {
state: ChansState // Current connection state
isConnected: boolean // Whether connected
error: string | null // Error message if any
connect: () => Promise<void> // Start connection
disconnect: () => Promise<void> // End connection
}

Full Example

import { useState } from "react"
import { useVoiceAgent, type ChansState } from "@ai-chans/sdk-react"
interface Message {
role: "user" | "agent"
text: string
}
function VoiceChat() {
const [messages, setMessages] = useState<Message[]>([])
const { state, error, connect, disconnect } = useVoiceAgent(
{
agentToken: process.env.NEXT_PUBLIC_AGENT_TOKEN!,
apiUrl: process.env.NEXT_PUBLIC_API_URL,
},
{
onUserTurnComplete: (text) => {
setMessages((prev) => [...prev, { role: "user", text }])
},
onResponse: (text) => {
setMessages((prev) => [...prev, { role: "agent", text }])
},
onError: (err) => {
console.error("Voice error:", err)
},
}
)
return (
<div>
<h2>Voice Chat</h2>
{error && <div className="error">{error}</div>}
<div className="messages">
{messages.map((msg, i) => (
<div key={i} className={msg.role}>
<strong>{msg.role}:</strong> {msg.text}
</div>
))}
</div>
<button
onClick={state === "idle" ? connect : disconnect}
disabled={state === "connecting"}
>
{getButtonLabel(state)}
</button>
</div>
)
}
function getButtonLabel(state: ChansState): string {
switch (state) {
case "idle": return "Start Conversation"
case "connecting": return "Connecting..."
case "waiting": return "Waiting for agent..."
case "ready": return "Listening... (click to stop)"
case "processing": return "Processing..."
case "speaking": return "Agent speaking..."
default: return "Stop"
}
}

States

The hook returns a state value indicating the current connection status:

StateDescription
idleNot connected
connectingEstablishing connection
waitingConnected, waiting for agent
readyAgent connected, listening for speech
processingUser spoke, waiting for response
speakingAgent is responding
errorAn error occurred

Next