npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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" | undefined

agentState는 에이전트가 발행하는 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을 사용하세요.
  • 앱이나 번들에 포함된 키는 추출될 수 있습니다. 회수 가능한 전용 키를 사용하고, 노출이 확인되면 즉시 로테이션하세요.