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/react

v1.2.0

Published

vox.ai React Library

Downloads

759

Readme

@vox-ai/react

vox.ai voice agent를 React 앱에서 사용하기 위한 hook 라이브러리.

설치

npm install @vox-ai/react
# or
yarn add @vox-ai/react
# or
pnpm add @vox-ai/react

빠른 시작

import { useConversation } from "@vox-ai/react";

export function VoiceWidget() {
  const conversation = useConversation({
    onConnect: () => console.log("연결됨"),
    onDisconnect: () => console.log("연결 종료"),
    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),
  });

  const start = async () => {
    // 마이크 권한 요청 (UI에서 사전 안내 권장)
    await navigator.mediaDevices.getUserMedia({ audio: true });

    const conversationId = await conversation.startSession({
      agentId: "YOUR_AGENT_ID",
      apiKey: "YOUR_API_KEY",
    });
    console.log("session started:", conversationId);
  };

  return (
    <div>
      <button onClick={start} disabled={conversation.status !== "disconnected"}>
        Start
      </button>
      <button onClick={conversation.endSession}>End</button>
      <p>Status: {conversation.status}</p>
      <p>Agent State: {conversation.agentState ?? "unknown"}</p>
      <p>Speaking: {conversation.isSpeaking ? "Yes" : "No"}</p>
    </div>
  );
}

useConversation(options?)

콜백 (hook 초기화 시 전달)

| 콜백 | 시그니처 | 설명 | |------|----------|------| | 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 | 에러 발생 |

Hook 옵션

| 옵션 | 타입 | 설명 | |------|------|------| | textOnly | boolean | Text-only session 기본값. true면 microphone/audio 없이 chat mode로 연결 |

React State

| State | 타입 | 설명 | |-------|------|------| | status | ConversationStatus | "disconnected" | "connecting" | "connected" | | agentState | AgentState \| undefined | 에이전트가 발행한 lk.agent.state 값 | | isSpeaking | boolean | agentState === "speaking" 기반 편의 값 | | micMuted | boolean | 마이크 음소거 상태 | | messages | ConversationMessage[] | 현재 세션에서 주고받은 메시지 배열 |

JS SDK의 getStatus(), getAgentState(), getMicMuted()에 대응. React에서는 state로 제공되므로 자동 re-render.

메서드

세션 제어

// 세션 시작 — conversationId를 반환
const conversationId = await conversation.startSession({
  agentId: "YOUR_AGENT_ID",
  apiKey: "YOUR_API_KEY",
});

// 세션 종료
await conversation.endSession();

// 세션 ID 조회
const id = conversation.getId();

// Agent state 조회
const agentState = conversation.getAgentState();

// 현재 세션 메시지 조회
const messages = conversation.getMessages();

startSession 옵션

| 옵션 | 타입 | 필수 | 설명 | |------|------|------|------| | agentId | string | O | Agent ID | | apiKey | string | O | API key | | agentVersion | string | | Agent version ("current", "production", "v1" 등, default: "current") | | textOnly | boolean | | Hook 기본값을 override하는 per-session text-only 설정 | | dynamicVariables | Record<string, string \| number \| boolean> | | Agent prompt에 주입할 dynamic variables | | metadata | Record<string, unknown> | | Call metadata (webhook, call log에 포함) | | visitorId | string | | 같은 브라우저 방문자를 하나의 customer로 재사용할 안정적인 ID. 생략하면 자동 생성 |

visitorId@vox-ai/client 0.2.1 이상에서 지원합니다. vox.ai 내부 Customer UUID를 입력하는 필드가 아닙니다. 에이전트의 Memory가 켜져 있으면 첫 응답 전에 해당 Customer와 에이전트 범위의 Memory를 자동으로 불러옵니다.

메시지 전송

// 텍스트 메시지 전송 (음성 대신 텍스트 입력)
await conversation.sendUserMessage("안녕하세요");

메시지 히스토리

conversation.messages.forEach((message) => {
  console.log(message.source, message.text, message.isFinal);
});

const snapshot = conversation.getMessages();
  • messages는 React state라서 메시지 갱신 시 자동 re-render
  • getMessages()는 현재 시점의 메시지 배열 snapshot 반환

마이크 제어

// 음소거
await conversation.setMicMuted(true);

// 음소거 해제
await conversation.setMicMuted(false);

// 현재 상태는 conversation.micMuted 로 확인

볼륨 제어

// Agent 음성 볼륨 설정 (0.0 ~ 1.0)
conversation.setVolume({ volume: 0.5 });

오디오 모니터링

// 입출력 볼륨 (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 conversationId = 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에 포함

Text Only

const conversation = useConversation({
  textOnly: true,
});

await conversation.startSession({
  agentId: "YOUR_AGENT_ID",
  apiKey: "YOUR_API_KEY",
});

await conversation.sendUserMessage("텍스트로만 테스트할게요");
  • text-only session은 microphone 권한을 요청하지 않음
  • 에이전트 응답은 LiveKit text stream으로 수신됨
  • audio 전용 API는 안전한 no-op 또는 zero-value를 반환

Export 타입

import type {
  AgentState,
  ConversationMessage,
  ConversationSource,
  ConversationStatus,
  InputDeviceConfig,
  OutputDeviceConfig,
  SetVolumeParams,
  StartConversationOptions,
  UseConversationOptions,
} from "@vox-ai/react";

JS SDK와의 관계

| JS SDK (@vox-ai/client) | React SDK (@vox-ai/react) | |---------------------------|----------------------------| | Conversation.startSession(opts) | conversation.startSession(opts) | | getMessages() | messages / getMessages() | | getStatus() | status (React state) | | getAgentState() | agentState (React state) | | getMicMuted() | micMuted (React state) | | 나머지 method/callback | 동일 |

참고

  • 인증은 apiKey 직접 전달 방식
  • 내부 연결은 LiveKit WebRTC 기반
  • 브라우저별 audio device 제약이 있을 수 있음

조직 API 키 보안

  • apiKey는 조직 범위 secret입니다. 신뢰할 수 없는 공개 페이지에는 SDK 대신 공개 widget ID를 사용하는 Widget을 사용하세요.
  • 앱이나 번들에 포함된 키는 추출될 수 있습니다. 회수 가능한 전용 키를 사용하고, 노출이 확인되면 즉시 로테이션하세요.