Maîtriser les Événements WebSocket
Mis à jour le 29 juillet 2026
Une conversation faite d’événements JSON
Sous la surface, un échange vocal avec le Voice Agent n’est qu’une suite de messages JSON qui circulent dans les deux sens sur la connexion WebSocket. Chaque message porte un champ type qui dit ce qu’il est. Tant que vous ne connaissez pas ce vocabulaire, votre client fonctionne par chance ; dès que vous le maîtrisez, vous savez exactement où intervenir pour couper une réponse, afficher une transcription ou rattraper une erreur.
Les événements se répartissent en deux familles selon leur sens de circulation. Ceux que vous émettez pilotent la session ; ceux que vous recevez vous racontent ce qui se passe côté serveur.
Ce que votre application envoie
Vos messages sortants couvrent quatre besoins : configurer la session, alimenter le buffer audio, manipuler l’historique de conversation et contrôler la génération des réponses.
| Événement | Rôle |
|---|---|
session.update | Configure ou reconfigure la session (voix, instructions, outils, VAD, format audio) |
input_audio_buffer.append | Envoie un chunk d’audio encodé en base64, en continu pendant que l’utilisateur parle |
input_audio_buffer.commit | Valide le contenu actuel du buffer comme message de l’utilisateur — nécessaire uniquement en mode manuel |
input_audio_buffer.clear | Vide le buffer audio sans le traiter |
conversation.item.create | Ajoute un élément à la conversation : message texte, historique préalable ou résultat d’un appel de fonction |
conversation.item.delete | Supprime un élément de la conversation par son identifiant |
response.create | Demande au modèle de générer une réponse — automatique en mode VAD, explicite en mode manuel |
response.cancel | Annule une réponse en cours de génération |
Deux de ces messages méritent qu’on s’y arrête. conversation.item.create est votre porte d’entrée pour injecter du contexte : c’est par lui que vous replacez l’historique d’un appel précédent au début d’une nouvelle session, contournant ainsi la limite de trente minutes. Quant à input_audio_buffer.clear, il rend service quand l’utilisateur a manifestement parlé pour ne rien dire — un raclement de gorge capté par un micro trop sensible — et que vous préférez repartir d’un buffer propre plutôt que de laisser le modèle interpréter du bruit.
Ce que le serveur vous renvoie
Le flux entrant est plus dense, parce qu’il commente en direct chaque étape du traitement.
| Événement | Signification |
|---|---|
session.created | La session est ouverte |
session.updated | Une mise à jour de configuration a été prise en compte |
conversation.created | La conversation est établie |
input_audio_buffer.speech_started | Le VAD détecte que l’utilisateur commence à parler |
input_audio_buffer.speech_stopped | Le VAD détecte que l’utilisateur a cessé de parler |
input_audio_buffer.committed | Le buffer audio a été validé, par le VAD ou manuellement |
response.created | Une réponse est en cours de génération |
response.output_audio.delta | Un chunk d’audio de réponse, en base64 |
response.output_audio.done | L’audio de réponse est complet |
response.output_audio_transcript.delta | La transcription texte de l’audio, en streaming |
response.done | La réponse est entièrement terminée |
conversation.item.input_audio_transcription.completed | La transcription du message de l’utilisateur est disponible |
response.text.delta | Du texte en streaming, pour les réponses non vocales |
response.function_call_arguments.delta | Les arguments d’un appel de fonction arrivent en streaming |
response.function_call_arguments.done | L’appel de fonction est complet, prêt à être exécuté |
error | Une erreur récupérable s’est produite |
Le dernier appelle une mise en garde. Recevoir error ne signifie pas que la session est perdue : ces erreurs sont récupérables, et un client qui ferme la connexion au premier error venu casse une conversation qui aurait pu continuer. Journalisez, informez éventuellement l’utilisateur, mais laissez la socket ouverte.
Le squelette d’un client
En pratique, tout se joue dans un aiguillage sur msg.type. Voici la forme minimale d’un client JavaScript :
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
switch (msg.type) {
case "session.created":
// Envoyer session.update avec la configuration
break;
case "input_audio_buffer.speech_started":
// L'utilisateur parle : couper l'audio de reponse en cours
break;
case "response.output_audio.delta":
// Decoder le base64 et jouer l'audio
playAudioChunk(msg.delta);
break;
case "response.function_call_arguments.done":
// Executer la fonction et renvoyer le resultat
handleFunctionCall(msg);
break;
case "error":
console.error("Erreur Voice Agent:", msg.error);
break;
}
};
Quatre branches suffisent à faire tourner un agent : configurer à l’ouverture, réagir à la prise de parole, jouer l’audio entrant, exécuter les fonctions. Le reste des événements sert à enrichir l’interface et peut attendre une seconde itération.
Le cas délicat : l’interruption
Le barge-in, c’est-à-dire l’utilisateur qui reprend la parole alors que l’agent est en train de répondre, est le moment où une implémentation approximative se voit. Le serveur annule de lui-même la réponse en cours et se met à en générer une nouvelle à partir de ce qu’il vient d’entendre. Mais lui a arrêté d’émettre, tandis que votre application, elle, tient encore dans son buffer de sortie plusieurs secondes d’audio déjà reçues.
Si vous ne faites rien, l’utilisateur continue d’entendre la phrase qu’il vient d’interrompre pendant qu’il parle par-dessus : l’effet est celui d’un agent qui n’écoute pas. Dès la réception de speech_started, coupez donc la lecture audio en cours, videz le buffer de sortie pour ne pas jouer de son devenu obsolète, et laissez le serveur traiter la nouvelle entrée. Ces deux gestes tiennent en quelques lignes et font toute la différence entre un agent qu’on peut couper et un agent qui parle dans le vide.
Points clés à retenir
- Les événements client couvrent la configuration, l’envoi audio, la gestion de conversation et le contrôle des réponses
- Les événements serveur informent sur la détection de parole, les chunks audio, les transcriptions et les appels de fonctions
- Le VAD gère automatiquement les interruptions (barge-in)
- L’événement
errorest récupérable : ne fermez pas la connexion, gérez l’erreur - En mode manuel, vous devez appeler
commitpuisresponse.createexplicitement