JSPM

@jchaffin/voicekit

0.2.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 36
  • Score
    100M100P100Q76625F
  • License MIT

A provider-agnostic React library for building voice-enabled AI agents

Package Exports

  • @jchaffin/voicekit
  • @jchaffin/voicekit/deepgram
  • @jchaffin/voicekit/elevenlabs
  • @jchaffin/voicekit/livekit
  • @jchaffin/voicekit/openai
  • @jchaffin/voicekit/server

Readme

@jchaffin/voicekit

A React library for building voice-enabled AI agents using OpenAI's Realtime API.

Installation

npm install @jchaffin/voicekit @openai/agents

Quick Start

1. Create a session endpoint

// app/api/session/route.ts
import { createSessionHandler } from '@jchaffin/voicekit/server';

export const POST = createSessionHandler();

// Or with options:
export const POST = createSessionHandler({
  model: 'gpt-realtime',
  voice: 'alloy'
});

2. Define your agent

import { createAgent, defineTool } from '@jchaffin/voicekit';

// Define tools
const weatherTool = defineTool({
  name: 'get_weather',
  description: 'Get current weather for a location',
  parameters: {
    location: { type: 'string', description: 'City name' }
  },
  required: ['location'],
  execute: async ({ location }) => {
    const res = await fetch(`/api/weather?city=${location}`);
    return res.json();
  }
});

// Create agent
const agent = createAgent({
  name: 'Assistant',
  instructions: `
    You are a helpful voice assistant.
    Help users check the weather and answer questions.
  `,
  tools: [weatherTool]
});

3. Wrap your app with VoiceProvider

import { VoiceProvider } from '@jchaffin/voicekit';

function App() {
  return (
    <VoiceProvider agent={agent}>
      <YourApp />
    </VoiceProvider>
  );
}

4. Use the useVoice hook

import { useVoice } from '@jchaffin/voicekit';

function VoiceChat() {
  const { 
    status, 
    connect, 
    disconnect, 
    transcript, 
    sendMessage 
  } = useVoice();

  return (
    <div>
      <button onClick={status === 'CONNECTED' ? disconnect : connect}>
        {status === 'CONNECTED' ? 'End Call' : 'Start Call'}
      </button>
      
      <div>
        {transcript.map(msg => (
          <p key={msg.id}>
            <strong>{msg.role}:</strong> {msg.text}
          </p>
        ))}
      </div>
      
      <input 
        type="text"
        onKeyDown={(e) => {
          if (e.key === 'Enter') {
            sendMessage(e.currentTarget.value);
            e.currentTarget.value = '';
          }
        }}
        placeholder="Type a message..."
      />
    </div>
  );
}

API Reference

UI Components

<VoiceChat>

Complete voice chat interface - drop in and go.

import { VoiceProvider, VoiceChat, createAgent } from '@jchaffin/voicekit';

const agent = createAgent({ name: 'Bot', instructions: 'Be helpful' });

function App() {
  return (
    <VoiceProvider agent={agent}>
      <VoiceChat height="400px" />
    </VoiceProvider>
  );
}

Props:

  • height - Chat area height (default: '400px')
  • showHeader - Show status header (default: true)
  • showInput - Show text input (default: true)
  • emptyState - Custom empty state content
  • header - Custom header content
  • footer - Custom footer content

Individual Components

import { 
  Transcript,      // Message list
  StatusIndicator, // Connection status dot
  ConnectButton,   // Start/end button  
  ChatInput        // Text input
} from '@jchaffin/voicekit';

// Use within VoiceProvider
<StatusIndicator />
<Transcript messages={transcript} />
<ConnectButton connectText="Start Call" disconnectText="End Call" />
<ChatInput placeholder="Say something..." />

Core Components

<VoiceProvider>

Wraps your app to provide voice functionality.

<VoiceProvider 
  agent={agent}
  sessionEndpoint="/api/session"  // Optional, defaults to /api/session
  model="gpt-4o-realtime-preview" // Optional
  language="en"                    // Optional
  onStatusChange={(status) => {}}  // Optional
  onTranscriptUpdate={(msgs) => {}} // Optional
  onToolCall={(name, input, result) => {}} // Optional
  onError={(error) => {}}          // Optional
>
  {children}
</VoiceProvider>

Hooks

useVoice()

Main hook for voice interaction.

const {
  status,        // 'DISCONNECTED' | 'CONNECTING' | 'CONNECTED'
  connect,       // () => Promise<void>
  disconnect,    // () => Promise<void>
  transcript,    // TranscriptMessage[]
  clearTranscript, // () => void
  sendMessage,   // (text: string) => void
  interrupt,     // () => void
  mute,          // (muted: boolean) => void
  isMuted,       // boolean
  agent,         // RealtimeAgent
} = useVoice();

useToolResult(toolName)

Listen for results from a specific tool.

const { result, input, hasResult, clear } = useToolResult('get_weather');

useToolListener(toolName, handler)

Register a callback for tool results.

useToolListener('get_weather', (input, result) => {
  console.log('Weather:', result);
});

useToolResults()

Get all tool results.

const { results, lastResult, clear } = useToolResults();

Tool Builders

defineTool(config)

Create a tool with type inference.

const tool = defineTool({
  name: 'tool_name',
  description: 'What the tool does',
  parameters: {
    param1: { type: 'string', description: 'Description' },
    param2: { type: 'number', default: 10 }
  },
  required: ['param1'],
  execute: async ({ param1, param2 }) => {
    // Implementation
    return { success: true };
  }
});

createNavigationTool(sections)

Create a tool for single-page app navigation.

const navTool = createNavigationTool(['about', 'projects', 'contact']);

createAPITool(config)

Create a tool that calls an API endpoint.

const searchTool = createAPITool({
  name: 'search',
  description: 'Search the database',
  parameters: { query: { type: 'string' } },
  required: ['query'],
  endpoint: '/api/search',
  method: 'POST'
});

createEventTool(config)

Create a tool that dispatches DOM events for UI updates.

const modalTool = createEventTool({
  name: 'show_modal',
  description: 'Show a modal',
  parameters: { title: { type: 'string' } },
  eventType: 'voice:show-modal'
});

Agent Builders

createAgent(config)

Create a voice agent.

const agent = createAgent({
  name: 'Assistant',
  instructions: 'You are helpful.',
  tools: [tool1, tool2]
});

createAgentFromTemplate(config)

Create an agent using structured templates.

const agent = createAgentFromTemplate({
  name: 'Support Bot',
  role: 'customer support agent',
  personality: 'Friendly and helpful',
  capabilities: ['Answer questions', 'Track orders'],
  constraints: ['Never share private data'],
  tools: [orderTool]
});

Server API

Import from @jchaffin/voicekit/server for server-side utilities.

createSessionHandler(config?)

Creates a request handler for Next.js App Router or similar frameworks.

import { createSessionHandler } from '@jchaffin/voicekit/server';

// Basic
export const POST = createSessionHandler();

// With config
export const POST = createSessionHandler({
  apiKey: process.env.CUSTOM_KEY,  // defaults to OPENAI_API_KEY
  model: 'gpt-realtime',
  voice: 'alloy'
});

getEphemeralKey(config?)

Get an ephemeral key directly (for Express, Fastify, etc.)

import { getEphemeralKey } from '@jchaffin/voicekit/server';

app.post('/api/session', async (req, res) => {
  const result = await getEphemeralKey();
  if (result.error) {
    return res.status(500).json({ error: result.error });
  }
  res.json({ ephemeralKey: result.ephemeralKey });
});

handleOptions() / corsHeaders()

CORS helpers for preflight requests.

import { handleOptions, corsHeaders } from '@jchaffin/voicekit/server';

export function OPTIONS() {
  return handleOptions();
}

License

MIT