Voice Conversations
Start a real-time audio conversation between your user and a Stellar agent. The SDK handles microphone capture, audio playback, and the WebSocket connection.
import { createStellarClient } from "@stellar-ai/agent-sdk";
const client = createStellarClient();
const conversation = await client.startConversation({
auth: {
strategy: "publicToken",
token: "<your-public-access-token>",
},
agentId: "<your-agent-id>",
});
Each client supports one active voice conversation at a time. To start a new one, end the current conversation with conversation.end() first, or you'll get a CONVERSATION_ALREADY_ACTIVE error.
In browser or Capacitor WebView environments, request microphone access before starting:
await navigator.mediaDevices.getUserMedia({ audio: true });
Eventsโ
Subscribe to events using .on(). All event methods return the conversation instance for chaining.
conversation
.on("stateChanged", ({ state }) => {
console.log("State:", state);
})
.on("error", ({ error, code }) => {
console.error("Error:", code, error);
})
.on("started", ({ clientId }) => {
console.log("Started with client ID:", clientId);
})
.on("handover", ({ handoverType, phoneNumber, queueId, announcement }) => {
console.log("Handover:", handoverType);
})
.on("actionExecuted", ({ actionName, requestBody, responseBody }) => {
console.log("Action:", actionName);
});
| Event | Payload | Description |
|---|---|---|
stateChanged | { state } | Connection state changed (connecting, connected, disconnected, error) |
error | { error, code } | An error occurred |
started | { clientId, conversationId? } | Conversation started successfully |
handover | { handoverType, phoneNumber?, queueId?, announcement? } | Agent initiated a handover |
actionExecuted | { actionName, requestBody?, responseBody? } | Agent executed a tool or action |
Handover eventโ
The handover event fires when the agent initiates a transfer. It uses HandoverType.PHONE for phone transfers and HandoverType.QUEUE for queue-based routing:
import { HandoverType } from "@stellar-ai/agent-sdk";
conversation.on("handover", ({ handoverType, phoneNumber, queueId, announcement }) => {
if (handoverType === HandoverType.PHONE) {
// Transfer the call to phoneNumber
} else if (handoverType === HandoverType.QUEUE) {
// Route to the queue identified by queueId
}
});
Phone handovers include phoneNumber, queue handovers include queueId, and both may include an announcement.
Action executed eventโ
The actionExecuted event fires when the agent runs a tool or action during the conversation. You can use this to update your UI in response to agent actions โ for example, displaying order details the agent just looked up.
conversation.on("actionExecuted", ({ actionName, requestBody, responseBody }) => {
if (actionName === "lookupOrder") {
const order = JSON.parse(responseBody);
showOrderDetails(order);
}
});
Methodsโ
endโ
End the conversation and close the connection. After calling end, discard the instance.
await conversation.end();
mute and unmuteโ
Control the microphone. When muted, the SDK stops capturing audio but keeps the WebSocket connection open.
conversation.mute();
console.log(conversation.isMuted); // true
conversation.unmute();
console.log(conversation.isMuted); // false
isMutedโ
A boolean property indicating whether the microphone is currently muted.
stateโ
The current connection state: connecting, connected, disconnected, or error.
console.log(conversation.state); // "connected"
on, off, and onceโ
on(event, handler)โ subscribe to an event. Returns the instance for chaining.off(event, handler)โ unsubscribe a handler.once(event, handler)โ subscribe for a single occurrence, then auto-unsubscribe.
Next stepsโ
- Text chat โ messaging-based conversations with streaming responses
- TypeScript SDK โ installation, authentication, and shared configuration