Skip to main content

Event Bus

The normalized event bus is Kith's primary contract. Adapters emit these events; consumers subscribe to them. Everything else is an implementation detail.

Event Types

EventWhenKey Fields
turn_startA new conversational turn beginsturnId, role ("user" or "assistant")
turn_endA turn completesturnId, role
tts_startTTS synthesis begins for a chunkturnId, chunkId
tts_audio_chunkA slice of synthesized audioturnId, chunkId, audioB64, mimeType
tts_endTTS synthesis completes for a chunkturnId, chunkId
stt_partialPartial speech-to-text transcriptionturnId, text
stt_finalFinal speech-to-text transcriptionturnId, text
viseme_frameA single viseme for lip syncturnId, viseme, weight, offsetMs
emotion_stateEmotional state hint for avatarstate, intensity
barge_in_detectedUser interrupted the assistantturnId
reconnectRuntime reconnected after disconnectattempt
errorSomething went wrongmessage, retriable

Subscribing

const unsub = voice.on((event) => {
switch (event.type) {
case "tts_audio_chunk":
// Play audio
break;
case "emotion_state":
// Tint avatar
break;
case "barge_in_detected":
// Stop playback
break;
}
});

// Later: unsub();

Event Flow

A typical voice.speak("Hello! haha") produces this sequence:

emotion_state { state: "neutral", intensity: 0.5 }
turn_start { turnId: "t1", role: "assistant" }
tts_start { turnId: "t1", chunkId: "c1" }
tts_audio_chunk × N
tts_end { turnId: "t1", chunkId: "c1" }
turn_end { turnId: "t1", role: "assistant" }

All events include a timestamp field (Unix ms).

Router vs Runtime Events

  • Runtime events come from the sidecar: turn_start, turn_end, tts_*, stt_*, viseme_frame, barge_in_detected, reconnect, error.
  • Router-synthesized events come from VoiceRouter: emotion_state (parsed from emojis in the input text).

Subscribe via voice.on() (not runtime.on()) to get both.