@vox-ai/client
v0.3.0
Published
vox.ai JavaScript SDK
Downloads
869
Readme
@vox-ai/client
vox.ai voice agent와 브라우저에서 직접 연결하기 위한 JavaScript SDK.
설치
npm install @vox-ai/client
# or
yarn add @vox-ai/client
# or
pnpm add @vox-ai/client빠른 시작
import { Conversation } from "@vox-ai/client";
// 마이크 권한 요청 (UI에서 사전 안내 권장)
await navigator.mediaDevices.getUserMedia({ audio: true });
const conversation = await Conversation.startSession({
agentId: "YOUR_AGENT_ID",
apiKey: "YOUR_API_KEY",
onStatusChange: (status) => console.log("status:", status),
onAgentStateChange: (agentState) => console.log("agentState:", agentState),
onMessage: (message) => console.log(`${message.source}: ${message.text}`),
onError: (error) => console.error("error:", error.message),
});세션 옵션
Conversation.startSession(options)에 전달하는 설정.
visitorId를 생략하면 SDK가 브라우저 localStorage의 안정적인 visitor ID를
자동으로 전송합니다. 같은 브라우저·조직의
후속 세션은 같은 익명 customer에 이어지고, 저장소가 차단된 경우에는 현재 페이지
수명 동안만 같은 customer를 재사용합니다. 브라우저가 아닌 서버 런타임에서는
서로 다른 요청을 잘못 합치지 않도록 자동 visitor ID를 만들지 않습니다.
visitorId는 개발자가 관리하는 방문자 식별자입니다. vox.ai 내부 Customer UUID를
입력하는 필드가 아닙니다. 같은 visitorId는 같은 조직에서 같은 Customer를
재사용합니다. 에이전트의 Memory가 켜져 있으면 첫 응답 전에 해당 Customer와
에이전트 범위의 Memory를 자동으로 불러옵니다.
| 옵션 | 타입 | 필수 | 설명 |
|------|------|------|------|
| agentId | string | O | Agent ID |
| apiKey | string | O | API key |
| agentVersion | string | | Agent version ("current", "production", "v1" 등, default: "current") |
| textOnly | boolean | | Text-only session (true면 mic/audio 없이 chat mode로 연결, default: false) |
| dynamicVariables | Record<string, string \| number \| boolean> | | Agent prompt에 주입할 dynamic variables |
| metadata | Record<string, unknown> | | Call metadata (webhook, call log에 포함) |
| visitorId | string | | 방문자를 명시적으로 재사용할 안정적인 ID. 생략하면 브라우저별로 자동 생성 |
| sourceType | string | | Deprecated no-op. SDK 계보 등록에는 사용되지 않음 |
sourceType은 하위 호환을 위해 타입에만 남아 있는 deprecated no-op입니다. 값을
전달해도 요청의 source_type이나 X-Vox-Client 헤더는 바뀌지 않습니다.
Wrapper SDK 계보 등록
@vox-ai/client를 감싸는 wrapper SDK는 모듈 로드 시점에 자기 레이어를
등록합니다.
import { registerClientLayer } from "@vox-ai/client";
registerClientLayer({
name: "react-sdk",
version: "1.2.0",
});name은 소문자 영문·숫자·하이픈만 사용하고,version은 영문·숫자와.,+,-만 사용- 같은
name을 여러 번 등록하면 최초 등록만 유지 - 등록된 레이어는 바깥 wrapper부터
X-Vox-Client헤더에 전송 - 잘못된 값은 조용히 무시되며 등록 때문에 세션 시작이 실패하지 않음
콜백
| 콜백 | 시그니처 | 설명 |
|------|----------|------|
| onConnect | () => void | 연결 성공 |
| onDisconnect | () => void | 연결 종료 |
| onStatusChange | (status: ConversationStatus) => void | Status 변경 ("disconnected" → "connecting" → "connected") |
| onAgentStateChange | (agentState: AgentState) => void | LiveKit lk.agent.state 변경 ("initializing", "idle", "listening", "thinking", "speaking") |
| onMessage | (message: ConversationMessage) => void | 메시지 수신 (user transcription, agent response) |
| onError | (error: Error) => void | 에러 발생 |
메서드
세션 제어
// 세션 종료
await conversation.endSession();
// 세션 ID 조회
const id = conversation.getId();
// 현재 세션 메시지 조회
const messages = conversation.getMessages();메시지 전송
// 텍스트 메시지 전송 (음성 대신 텍스트 입력)
await conversation.sendUserMessage("안녕하세요");메시지 히스토리
const messages = conversation.getMessages();
messages.forEach((message) => {
console.log(message.source, message.text, message.isFinal);
});getMessages()는 현재 세션에서 주고받은 메시지를 timestamp 순으로 반환- 동일
id의 streaming update는 최신 메시지로 반영
Text Only
const conversation = await Conversation.startSession({
agentId: "YOUR_AGENT_ID",
apiKey: "YOUR_API_KEY",
textOnly: true,
});
await conversation.sendUserMessage("텍스트로만 대화할게요");- text-only session은 microphone 권한을 요청하지 않음
- 에이전트 응답은 LiveKit text stream으로 수신됨
- audio 전용 API는 안전한 no-op 또는 zero-value를 반환
마이크 제어
// 음소거
await conversation.setMicMuted(true);
// 음소거 해제
await conversation.setMicMuted(false);
// 현재 음소거 상태 조회
const isMuted = conversation.getMicMuted();볼륨 제어
// Agent 음성 볼륨 설정 (0.0 ~ 1.0)
conversation.setVolume({ volume: 0.5 });상태 조회
const status = conversation.getStatus(); // "disconnected" | "connecting" | "connected"
const agentState = conversation.getAgentState();
// "initializing" | "idle" | "listening" | "thinking" | "speaking" | undefinedagentState는 에이전트가 발행하는 lk.agent.state 값을 그대로 노출합니다.
오디오 모니터링
// 입출력 볼륨 (0.0 ~ 1.0)
const inputVol = conversation.getInputVolume();
const outputVol = conversation.getOutputVolume();
// Frequency data (Uint8Array, 시각화용)
const inputFreq = conversation.getInputByteFrequencyData();
const outputFreq = conversation.getOutputByteFrequencyData();디바이스 전환
// 입력 디바이스 변경
await conversation.changeInputDevice({ inputDeviceId: "device-id" });
// 출력 디바이스 변경
await conversation.changeOutputDevice({ outputDeviceId: "device-id" });디바이스 목록은 navigator.mediaDevices.enumerateDevices()로 조회.
Dynamic Variables / Metadata
const conversation = await Conversation.startSession({
agentId: "YOUR_AGENT_ID",
apiKey: "YOUR_API_KEY",
agentVersion: "production",
dynamicVariables: {
userName: "홍길동",
userType: "premium",
accountBalance: 50000,
},
metadata: {
sessionId: "sess_abc123",
source: "mobile-app",
},
});dynamicVariables— Agent prompt에서{{userName}}형식으로 참조metadata— Outbound webhook과 call log에 포함
Export 타입
import type {
AgentState,
ConversationMessage,
ConversationSource,
ConversationStatus,
InputDeviceConfig,
OutputDeviceConfig,
SetVolumeParams,
StartSessionOptions,
} from "@vox-ai/client";참고
- 인증은
apiKey직접 전달 방식 - 내부 연결은 LiveKit WebRTC 기반
- 브라우저별 audio device 제약이 있을 수 있음
조직 API 키 보안
apiKey는 조직 범위 secret입니다. 신뢰할 수 없는 공개 페이지에는 SDK 대신 공개 widget ID를 사용하는 Widget을 사용하세요.- 앱이나 번들에 포함된 키는 추출될 수 있습니다. 회수 가능한 전용 키를 사용하고, 노출이 확인되면 즉시 로테이션하세요.
