Data channels
Le back-end et la tablette échangent des messages JSON via trois familles de topics sur le DataChannel LiveKit. Chaque message est validé par un schéma Zod exporté depuis @kohami/shared.
| Famille | Direction | Exemples de topics |
|---|---|---|
kohami.widget.data | back vers tablette | weather:result, news:result, quiz:question, vision:result, assistance:session_started |
kohami.user.* | tablette vers back | kohami.user.alert_button_pressed, user:weather, user:request_quiz |
kohami.agent.events | back vers tablette | turn_state, tool_invoked, stt_fallback_active, onboarding_completed |
Le transport LiveKit est reliable par défaut (ordre préservé par publisher et par topic). Le back-end publie séquentiellement (résultat d'abord, puis tool-open). La tablette peut donc se reposer sur l'ordre.
Souscription côté tablette
import { Room, RoomEvent } from "livekit-client";
import type {
AvcSuspicionDetectedEvent,
NewsResultEvent,
QuizQuestionEvent,
TurnStateEvent,
WeatherResultEvent,
} from "@kohami/shared";
type AnyKohamiEvent =
| WeatherResultEvent
| NewsResultEvent
| QuizQuestionEvent
| AvcSuspicionDetectedEvent
| TurnStateEvent;
function handleDataPacket(payload: Uint8Array): void {
const raw = new TextDecoder().decode(payload);
const event = JSON.parse(raw) as AnyKohamiEvent;
switch (event.kind) {
case "weather:result":
renderWeatherCard(event);
break;
case "news:result":
renderNewsList(event);
break;
case "quiz:question":
renderQuiz(event);
break;
case "turn_state":
updateAvatarSpeakingState(event);
break;
default:
console.warn("Unknown event kind", event);
}
}
room.on(RoomEvent.DataReceived, (payload) => {
handleDataPacket(payload);
});Publication côté tablette (inbound)
async function publishUserAction(
room: Room,
event: { kind: string; [key: string]: unknown }
): Promise<void> {
const payload = new TextEncoder().encode(JSON.stringify(event));
await room.localParticipant.publishData(payload, {
reliable: true,
topic: "kohami.user.alert_button_pressed",
});
}Validez systématiquement le payload avec le schéma Zod correspondant avant publication :
import { UserWeatherInboundSchema } from "@kohami/shared";
const validated = UserWeatherInboundSchema.parse({
kind: "user:weather",
location: { lat: 48.8566, lon: 2.3522 },
});Topics par famille
Outbound kohami.widget.data
Voir le catalogue exhaustif dans Events catalogue. Format général :
{
kind: "<topic-name>", // discriminant string
// payload spécifique au topic
}Inbound kohami.user.*
Le préfixe kohami.user.* regroupe toutes les actions initiées par le senior depuis la tablette. Liste actuelle :
kohami.user.alert_button_pressed, bouton d'alerte presséuser:weather, tap sur la card météouser:news, tap sur la card newsuser:request_quizouuser:request_guess, lancement d'un mini-jeu cognitifuser:answer_quizouuser:answer_guess, réponse soumise (incluantisCorrect)user:appointment_acknowledged, accusé de réception d'un rendez-voususer:medication_takenouuser:medication_snoozed, gestion d'un rappel médicamentuser:onboarding_recap_acknowledged, fin de l'étape de récap onboarding
Agent events kohami.agent.events
Le voice-worker publie des événements de cycle de vie :
turn_state, état du tour (agent_thinking,agent_speaking,agent_idle)tool_invoked, un outil a été appelé (getCurrentWeather,contactAidant, etc.)tool_calloutool_result, début ou fin d'un appel d'outil avec payloadonboarding_completed, fin de l'extraction d'onboarding par tourstt_fallback_active,tts_fallback_active,llm_fallback_active, bascule en mode dégradéwake_word_detected, détection du mot d'éveil (si activé)error, frame d'erreur (voir Gestion d'erreurs)
Tous les schémas sont exportés depuis @kohami/shared via AgentEventSchema (discriminated union).
Ordering garanti
Le back-end publie les events dans un ordre strict pour les widgets :
- Le résultat d'abord (
weather:result,news:result,quiz:question, etc.) - Le tool-open ensuite (
kohami.tool.openavecnamerestreint à l'enumWIDGET_TOOL_NAMES)
Le transport reliable de LiveKit garantit l'ordre per-publisher, ce qui suffit côté tablette pour afficher la card avant de la mettre au premier plan.
Orchestrateur et politique de modèles
Comment KOHAMI route un tour de parole à travers l'orchestrateur trois flux (cache, mémoire, agent), le rôle de chaque sous-agent Mistral structuré, et surtout pourquoi chaque composant utilise Medium ou Small, jamais Large.
Onboarding state
Machine d'états du onboarding adaptatif J1 à J5, extraction par tour, événements DataChannel associés.