1npx @inkibra/voice-cli init
@inkibra/voice-sdk and writes INKIBRA_API_KEY to .env.local. Keep that file and every provider credential server-side.12345678910111213141516171819202122232425262728import { liveVoicePcmFormat, type LiveVoiceAudioTransport, type LiveVoiceAudioTransportHandlers, type LiveVoiceAudioOutputCommand, } from "@inkibra/voice-sdk/server"; class ProviderAudioTransport implements LiveVoiceAudioTransport { readonly format = liveVoicePcmFormat; private handlers?: LiveVoiceAudioTransportHandlers; constructor(private provider: WebSocket) {} start(handlers: LiveVoiceAudioTransportHandlers) { this.handlers = handlers; // Parse provider input, decode its codec, resample it, then call: // handlers.input(pcm16le24k); } output(command: LiveVoiceAudioOutputCommand) { // Map enqueue, block-foreground, release, cancel, and done // onto the provider's playback queue, marks, and clear command. } stop() { this.provider.close(1000, "Inkibra session ended"); } }
start event and after validating its one-time call nonce:1234567891011121314151617181920212223242526import LiveVoice from "@inkibra/voice-sdk/server"; const session = await LiveVoice.connect({ apiKey: process.env.INKIBRA_API_KEY!, audio: new ProviderAudioTransport(providerSocket), prompt: "Help callers schedule an appointment.", conversation: { starts: "assistant", prompt: "Be concise and confirm dates before booking.", }, tools: { bookAppointment: { description: "Book a confirmed appointment", parameters: { type: "object", properties: { startsAt: { type: "string" }, }, required: ["startsAt"], }, execute: async ({ startsAt }) => calendar.book(startsAt), }, }, }); await session.closed;
apiKey, the SDK creates the short-lived session, opens and prepares the realtime connection, sends the developer configuration, executes server-side tools, and tears down both sides together. You can supply a short-lived token instead when your application creates sessions separately.123456const pcm8k = decodeMulaw(providerPayload); const pcm24k = inputResampler.push(pcm8k); for (const frame of frames(pcm24k, 480)) { handlers.input(new Uint8Array(frame.buffer)); }
audio.output(command) in order:| Command | Provider-adapter behavior |
enqueue with mode: "play" | Convert and enqueue the PCM for provider playback. |
enqueue with mode: "buffer" | Keep it private until the matching release. |
block-foreground | Keep foreground audio from overtaking a reaction. |
release | Release the named generation at the supplied gain. |
cancel | Discard unsent audio and clear provider playback. |
done | Place a provider playback mark after the generation's final audio. |
release breaks interruption handling. Ignoring cancel can make the caller hear speech that Inkibra has already rejected.start:123456handlers.receipt({ event: "completed", // started | completed | cancelled lane: "FOREGROUND", // FOREGROUND | REACTION generationId, playedSamples, });
started when provider playout begins.completed after the provider echoes the generation's mark.cancelled after clearing provider playback.playedSamples on Inkibra's 24 kHz sample clock.handlers.close(reason). When the provider socket fails, call handlers.error(error). The server SDK stops the Inkibra session and the provider transport exactly once.limit, a provider error, or closes the realtime socket, clear provider playback and end the call. Protocol version 1 treats a media disconnect as terminal; do not reconnect a new provider socket into the old session.